Welcome to Tigase HTTP API component guide

1. HTTP server

HTTP server instance is provided as httpServer by default. The server will only be active and enabled if either the HTTP API component or HTTP File Upload component is enabled. This project uses the default implementation of an http server provided by HttpServer found embedded in Java JDK.

Note
This implementation is good only for small installations of if there is no requirement for a high performance HTTP server. If this is do not match your requirements, it is recommended to use Jetty as the embedded HTTP server using Tigase HTTP API - Jetty HTTP Server project.

1.1. Dependencies

The default HTTP server implementation requires almost no dependencies as most calls are already embedded within JDK 8. However as a common API for processing HTTP requests is needed, as is the same for HTTP server from JDK and Jetty, we have decided to use HTTP Servlet API in version 3.1.

The required files can be downloaded from Tigase HTTP API project section or using following link servlet-api-3.1.jar

Please note that this file is included in dist-max, exe, and jar installer distributions of Tigase XMPP server.

1.2. Configuration Properties

The HTTP server can be configured using any of all of the following properties. Note that these settings only apply to the default implementation provided by Tigase HTTP API.

ports

This property is used to configure on which ports on HTTP server should listen for incoming connections. If it is not set then default port 8080 will be used

connections

It is used to group configurations passed to ports

{port}

For every {port} you can pass separate configuration. To do so you will need to replace {port} with port number, ie. 8080. For every port you can pass following properties:

socket

Sets type of socket used for handling incoming connections. Accepted values are:

  • plain - port will work in plain HTTP mode (default)

  • ssl - port will work in HTTPS mode

domain

This property is used to configure domain name of SSL certificate which should be used by HTTP server running on this port (if socket is set to ssl). If it is not set then default SSL certificate of Tigase XMPP Server will be used.

1.3. Examples

Below are few examples for use in DSL based configuration format and older properties based format.

1.3.1. HTTPS on port 8443 with SSL certificate for example.com

In configuration file httpServer related configuration should look like this:

httpServer {
    connections {
        8443 () {
            socket = ssl
            domain = 'example.com'
        }
    }
}

1.3.2. Changing port from 8080 to 8081

httpServer {
    connections {
        8080 (active: false) {}
        8081 () {}
    }
}

1.3.3. Usage of Jetty HTTP server as HTTP server

As mentioned before it is possible to use Jetty as HTTP server for improved performence. Jetty API can be used in one of two forms: Standalone and OSGi.

Standalone

In this case the Jetty instance is created and configured internally by Tigase HTTP API. This allows for the same configuration properties used as for default HTTP server configuration.

Configuration with use of standalone Jetty HTTP Server
httpServer (class: tigase.http.jetty.JettyStandaloneHttpServer) {
    ...
}
OSGi

This can only be used when Tigase is running inside OSGi container. If this is used Tigase HTTP API will try to retrieve Jetty HTTP server from OSGi container and use it.

Note
Jetty HTTP server instance is not configured by Tigase. We would only use this instance for deployment.
Configuration in OSGi mode with use of Jetty HTTP Server
httpServer (class: tigase.http.jetty.JettyOSGiHttpServer) {
    ...
}

2. HTTP API component

Tigase HTTP API component is a generic container used to provide other HTTP related features as modules. It is configured by default to run under name of http. Installations of Tigase XMPP Server run this component enabled by default under the same name even if not configured.

2.1. Common module configuration

2.1.1. Enabling/disabling module

Every module can be activated or disabled by adjusting it’s activity in following way:

http {
    %module_id% (active: false) {}
}
Note
You need to replace %module_id% with the id of module which you want to change activity (in this case, it will disable module).

2.1.2. Example

To disable REST module we would following entries can be used:

http {
    rest (active: false) {}
}

2.1.3. Context path

This property allows you to change the context path that is used by module. In other words, it allows you to change the prefix used by module. By default every module (with exception of the Index module) uses a context path that is the same as module id. For example, the REST module ID results in the context path /rest

Example

Changing context path for REST module to /api

http {
    rest {
        context-path = '/api'
    }
}

2.1.4. List of virtual hosts

This provies the ability to limit modules to be available only on listed virtual hosts, and allows to set context path to / for more than one module. Property accepts list of strings, which in the case of init.properties file format is list of comma separated domain names and in DSL it is written as list of strings (see Complex Example).

Example

Here we want to move the REST module to be available only for requests directed to api.example.com

http {
    rest {
        vhosts = [ 'api.example.com' ]
    }
}

2.1.5. Complex example

In this example we will disable the Index module and move REST module to http://api.example.com/ and http://rest.example.com.

http {
    index (active: false) {}
    rest {
        context-path = '/'
        vhosts = [ 'api.example.com', 'rest.example.com' ]
    }
}

3. HTTP File Upload component

Tigase’s HTTP File Upload component is an implementation of XEP-0363: HTTP File Upload specification. This allows file transfer between XMPP clients by uploading a file to HTTP server and sending only link to download file to recipient.

This implementation makes use of the HTTP server used by Tigase XMPP Server and Tigase HTTP API component to provide web server for file upload and download.

By default this component is disabled and needs to be enabled in configuration file before it can be used. Another requirement is that the proper database schema needs to be applied to database which will be used by component.

3.1. Enabling HTTP File Upload Component

Configuration
upload() {}

3.2. Metadata repository

Running the component requires a repository where it can store information about allocated slots. For this, a metadata repository is used. It is possible to specify a specific implementation of FileUploadRepository for every domain.

By default, metadata for all domains will be stored in the default repository. Implementation of which will be selected based on kind of data source defined as default.

3.2.1. DummyFileUploadRepository

This is very simple repository which does not store any data. Due to that, it can be very fast! However, it is not able to remove old uploads and apply any upload limits.

3.2.2. JDBCFileUploadRepository

This repository implementation stores data in database used to store procedures and functions. By default, data should be stored in the tig_hfu_slots table but it can be changed by modification of stored procedures or reconfiguration of the repository implementation to use different stored procedures and functions than provided.

3.3. Storage

Component contains a pluggable storage mechanism, which means that it is relatively easy to implement custom storage provisions. By default DirectoryStore based storage is used.

Currently following storage providers are available out of the box.

3.3.1. DirectoryStore

This storage mechanism places files in subdirectories with names that correspond to the id of allocated slot. If required, it is possible to group all slot directories allocated by single user in a directory containing this user name.

By default there is no redundancy if this store is used in clustered environment. Every file will be sotred on a single cluster node.

Available properties:

path

Contains path to directory in which subdirectory with files will be created on the local machine. (default: data/upload)

group-by-user

Configures if slots directories should be grouped in user directories. (default: false)

3.4. Logic

Logic is responsible for generation of URI and applying limits. It groups all configuration settings related to allocation of slots, etc.

Available properties:

local-only

Allow only users with accounts on the local XMPP server to use this component for slot allocation. (default: true)

max-file-size

Set maximum size of a single allocated slot (maximum file size) in bytes. (default: 5000)

port

Specifies the port which should be used in generating the upload and download URI. If it is not set, then secured (HTTPS) server port will be used if available, and plain HTTP in other case. (default: not set)

protocol

Protocol which should be used. This is only used in conjunction with port. Possible values are:

  • http

  • https

serverName

Server name to use as domain part in generated URI. (default: server hostname)

upload-uri-format

Template used in generation of URI for file upload. (default: {proto}://{serverName}:{port}/upload/{userJid}/{slotId}/{filename})

download-uri-format

Template used in generation of URI for file download. (default: {proto}://{serverName}:{port}/upload/{slotId}/{filename})

3.4.1. URI template format

Every block in the template between { and } is a named part which will be replaced by the property value during generation of URI for slot.

Blocks possible to use:

proto

Name of protocol.

serverName

Domain name of server.

port

Port on which HTTPS (or HTTP) server is listening.

userJid

JID of user requesting slot allocation.

domain

Domain of user requesting slot allocation.

slotId

Generated ID of slot.

filename

Name of file to upload.

Note
slotId and filename are required to be part of every URI template.
Warning
Inclusion of userJid or domain will speed up the lookup for slot id during upload and download operation if more than one metadata repository is configured. However, this may lead to leak of user JID or user domain if message with URI containing this part will be send to recipient which is unaware of the senders' JID (ie. in case of anonymous MUC room).

3.5. File upload expiration

From time to time it is required to remove expired file to make place for new uploads. This is done by the expiration task.

Available properties:

expiration-time

How long the server will keep uploaded files. Value in Java Period format (default: P30D - 30 days)

period

How often the server should look for expired files to remove. Value in Java Period format (default: P1D - 1 day)

delay

Time since server start up before the server should look for expired files to remove. Value in Java Period format (default: 0)

limit

Maximum number of files to remove during a single execution of expiration. (default: 10000)

3.6. Examples

3.6.1. Complex configuration example

Configuration with a separate repository for metadata to example.com pointing to file_upload data source, custom upload and download URI, maximum file size set to 10MB, expiration done every 6 hours and grouping of slot folders by user jid.

Complex configuration example
upload() {
    logic {
        local-only = false
        max-file-size = 10485760
        upload-uri-format = '{proto}://{serverName}:{port}/upload/{userJid}/{slotId}/{filename}'
        download-uri-format = '{proto}://{serverName}:{port}/upload/{domain}/{slotId}/{filename}'
    }

    expiration {
        period = P6H
    }

    repositoryPool {
        'example.com' () {
            data-source = "file_upload"
        }
    }

    store {
        group-by-user = true
    }
}

3.6.2. Example configuration for clustering with HA

Configuration for high availability in a cluster with common storage at /mnt/shared and both servers available as upload.example.com

Example configuration with HA
upload() {
    logic {
        upload-uri-format = '{proto}://upload.example.com:{port}/upload/{userJid}/{slotId}/{filename}'
        download-uri-format = '{proto}://upload.example.com:{port}/upload/{domain}/{slotId}/{filename}'
    }

    store {
        path = '/mnt/shared/upload'
    }
}

4. REST API

Tigase’s HTTP API component uses the REST module and Groovy scripts responsible for handling and processing incoming HTTP. The end result is Tigase’s REST API. This API may be useful for various integration scenarios.

In these sections we will describe the basic REST endpoints provided by Tigase HTTP API and explain the basics of creating new custom endpoints.

Other endpoints, specific to particular Tigase XMPP Server modules, are described in documentation for the modules providing them. You may also look at http://localhost:8080/rest/ on your local Tigase XMPP Server installation at HTTP API, which will provide you with basic usage examples for REST endpoints available at your installation.

For more informations about configuration of REST module please see section about [REST module].

4.1. Usage examples

Below you will find some usage examples of endpoints provided by the Tigase HTTP API project.

4.1.1. Retrieving user avatar

Request using GET method for url /rest/avatar/admin@test-domain.com will return the avatar image for user admin@test-domain.com if an avatar is set in user vcard. If not, response will return http error 404.

The example url to retrieve avatar of user admin@domain.com is http://localhost:8080/rest/avatar/admin@domain.com. Entering this url in a browser or REST client will execute GET request.

4.1.2. Retrieving list of available adhoc commands

using XML format

To retrieve list of commands request using GET method for `/rest/adhoc/sess-man@domain.com where sess-man@domain.com is the jid of a particular component. In this case it is the session manager. The JID of components will be based of what name is given to them in configuration. In this example entering following url http://localhost:8080/rest/adhoc/sess-man@domain.com in a browser or a REST client will retrieve a list of all ad-hoc commands available at sess-man@domain.com. This action is protected by authentication by using HTTP Basic Authentication. Valid credentials are credentials of users available in user database of this Tigase XMPP Server installation (username will be bare jid with domain part of jid, i.e. user@domain.com).

Below is example result of that request:

<items>
  <item>
    <jid>sess-man@domain.com</jid>
    <node>http://jabber.org/protocol/admin#get-active-users</node>
    <name>Get list of active users</name>
  </item>
  <item>
    <jid>sess-man@domain.com</jid>
    <node>del-script</node>
    <name>Remove command script</name>
  </item>
  <item>
    <jid>sess-man@domain.com</jid>
    <node>add-script</node>
    <name>New command script</name>
  </item>
</items>
using JSON format

To retrieve list of commands in JSON we need to pass Content-Type: application/json as an HTTP header of the request or add type parameter set to application/json. An example result is below:

{
    "items": [
        {
            "jid": "sess-man@domain.com",
            "node": "http://jabber.org/protocol/admin#get-active-users",
            "name": "Get list of active users"
        },
        {
            "jid": "sess-man@domain.com",
            "node": "del-script",
            "name": "Remove command script"
        },
        {
            "jid": "sess-man@domain.com",
            "node": "add-script",
            "name": "New command script"
        }
    ]
}

4.1.3. Executing commands using ad-hoc command

Retrieving list of active users
using XML

To execute command get active users a request using POST method for /rest/adhoc/sess-man@domain.com sending following content:

Note
This request requires authentication using HTTP Basic Authentication
Request in XML
<command>
  <node>http://jabber.org/protocol/admin#get-active-users</node>
  <fields>
    <item>
      <var>domainjid</var>
      <value>domain.com</value>
    </item>
    <item>
      <var>max_items</var>
      <value>25</value>
    </item>
  </fields>
</command>

In this request we passed all parameters needed to execute adhoc command. This includes the node of adhoc command, and values for fields required by that adhoc command. In this case, we’ve passed domain.com for domainjid field, and 25 for max_items field. We also need to pass Content-Type: text/xml in the HTTP header of request or add type parameter set to text/xml.

Below is an example result for request presented above:

Response in XML
<command>
  <jid>sess-man@domain.com</jid>
  <node>http://jabber.org/protocol/admin#get-active-users</node>
  <fields>
    <item>
      <var>Users: 2</var>
      <label>text-multi</label>
      <value>admin@domain.com</value>
      <value>user1@domain.com</value>
    </item>
  </fields>
</command>
using JSON

To execute the command to get active users in JSON format, request using POST method for /rest/adhoc/sess-man@domain.com sending the following content:

Note
Request requires authentication using HTTP Basic Authentication
Note
To use JSON it is required to set HTTP header Content-Type to application/json
Request in JSON
{
  "command" : {
    "node" : "http://jabber.org/protocol/admin#get-active-users",
    "fields" : [
      {
        "var" : "domainjid",
        "value" : "domain.com"
      },
      {
        "var" : "max_items",
        "value" : "25"
      }
    ]
  }
}

In this request we passed all the parameters needed to execute this adhoc command. We passed the node of adhoc command, and values for fields required by adhoc command. In this case, we’ve passed domain.com for domainjid field, and 25 for max_items field.

Response in JSON
{
    "command": {
        "jid": "sess-man@domain.com",
        "node": "http://jabber.org/protocol/admin#get-active-users",
        "fields": [
            {
                "var": "Users: 1",
                "label": "text-multi",
                "value": [
                  "admin@domain.com",
                  "user1@domain.com"
                ]
            }
        ]
    }
}
Ending user session

To execute command to get active users request using POST method for /rest/adhoc/sess-man@domain.com sending content explained below (may require authentication using Basic HTTP Authentication with admin credentials depending on configuration). sess-man@domain.com in URL is JID of session manager component which usually is in form of sess-man@domain where domain is hosted domain name.

using XML

To execute command using XML content you need to set HTTP header Content-Type to application/xml

Request in XML
<command>
  <node>http://jabber.org/protocol/admin#end-user-session</node>
  <fields>
    <item>
      <var>accountjids</var>
      <value>
        <item>test@domain.com</item>
      </value>
    </item>
  </fields>
</command>
</code></pre>

where test@domain.com is JID of user which should be disconnected.

As a result server will return following XML:

Response in XML
<command>
  <jid>sess-man@domain.com</jid>
  <node>http://jabber.org/protocol/admin#end-user-session</node>
  <fields>
    <item>
      <var>Notes</var>
      <type>text-multi</type>
      <value>Operation successful for user test@domain.com/resource</value>
     </item>
  </fields>
</command>

to confirm that user test@domain.com with resource resource was connected and it was disconnected.

If user was not connected server will return following response:

<command>
  <jid>sess-man@domain.com</jid>
  <node>http://jabber.org/protocol/admin#end-user-session</node>
  <fields />
</command>
using JSON

To execute command using XML content you need to set HTTP header Content-Type to application/json

Request in JSON
{
  "command" : {
    "node": "http://jabber.org/protocol/admin#end-user-session",
    "fields": [
      {
        "var" : "accountjids",
        "value" : [ "test@domain.com" ]
      }
    ]
  }
}

where test@domain.com is JID of user which should be disconnected.

As a result server will return following JSON:

Response in JSON
{
  "command" : {
    "jid" : "sess-man@domain.com",
    "node" : "http://jabber.org/protocol/admin#end-user-session",
    "fields" : [
      {
        "var" : "Notes",
        "type" : "text-multi",
        "value" : [
          "Operation successful for user test@domain.com/resource"
        ]
      }
    ]
  }
}

to confirm that user test@domain.com with resource resource was connected and it was disconnected.

If user was not connected server will return following response:

{
  "command" : {
    "jid" : "sess-man@domain.com",
    "node" : "http://jabber.org/protocol/admin#end-user-session",
    "fields" : []
  }
}

4.1.4. Sending any XMPP Stanza

XMPP messages or any other XMPP stanza can be sent using this new API by sending an HTTP POST request on (by default) http://localhost:8080/rest/stream/?api-key=@API_KEY@ with a serialized XMPP stanza as a content, where @API_KEY@ - is the API key for HTTP API configured in server configuration file. Additionally each request needs to be authorized by sending a valid administrator JID and password as user and password of HTTP Basic Authentication method. Content of the HTTP request should be encoded in UTF-8 and Content-Type header should be set to application/xml.

Handling of request

If a sent XMPP stanza does not contain from attribute, then the HTTP API component will provide it’s own JID. If a from attribute is provided then it will be preserved.

If an <iq/> stanza is being sent and no from attribute is set, then in the HTTP response the component will send a response received for sent <iq> stanza.

Successful requests will return HTTP response code 200.

Examples
Sending XMPP message with from set to the HTTP API component to full JID:

The following data needs to be sent as HTTP POST request content to /rest/stream/?api-key=@API_KEY@ which is the URL of the HTTP API component, in order to deliver message Example message 1 to test@example.com/resource-1.

<message xmlns="jabber:client" type="chat" to="test@example.com/resource-1">
    <body>Example message 1</body>
</message>
Sending XMPP message with from set to HTTP API component to bare JID:

The following data needs to be sent as HTTP POST request content to /rest/stream/?api-key=@API_KEY@ which is the URL of the HTTP API component, in order to deliver message Example message 1 to test@example.com@.

<message xmlns="jabber:client" type="chat" to="test@example.com">
    <body>Example message 1</body>
</message>
Sending XMPP message with from set to specified JID to recipients full JID:

The following data needs to be sent as HTTP POST request content to /rest/stream/?api-key=@API_KEY@ which is the URL of the HTTP API component, in order to deliver message Example message 1 to test@example.com/resource-1. This also sets the sender of message set to sender@example.com.

<message xmlns="jabber:client" type="chat" from="sender@example.com" to="test@example.com/resource-1">
    <body>Example message 1</body>
</message>

4.2. Scripting introduction

REST scripts in HTTP API component are used for processing all of requests incoming to REST endpoints.

To add a new action to the HTTP API component, you will need to create a script in Groovy in which there is an implementation of class extending tigase.http.rest.Handler class. URI of script will be created from the location of the script in the scripts folder. For example, if the TestHandler script with a regular expression will be set to /test, and will be placed in scripts/rest/tested, handler will be called for using the URI /rest/tested/test.

4.2.1. Properties

In extended classes you will need to set following properties:

regex

regular expression which is used to match the request URI and parse parameters that are embedded in the URI, ie.: /\/()@([^@\/])/

requiredRole

required role of user in order to be able to access this URI. If requiredRole is not null value, then authentication will be required. Possible values are:

  • null

  • user

  • admin

isAsync

if set to true, it will be possible to wait for results (ie. wait for response for IQ stanza).

4.2.2. Closure parameters

Extended class should also set closures for one or more of following properties: execGet, execPut, execPost, execDelete depending on which HTTP action or actions you need to support for the following URI. Each closure has a dynamic arguments list. Below is list of arguments passed to closure which describes how and when the list of arguments changes:

service

implementation of service interface (used to access database or send/receive XMPP stanzas).

callback

closure which needs to be called to return data (accepts only one argument of type String, byte[], Map. If data type Map is used, it will be encoded to JSON or XML depending on Content-Type header.

user

will be passed only if requiredRole is not set to null value. In other cases this argument will not be in arguments list!

content

parsed content of request. Will not be in arguments list if Content-Length of request is empty! If Content-Type is of type XML or JSON returned type will be Map in other cases it will be an instance of HttpServletRequest.

x

additional arguments passed to callback are groups from regular expression matching URI. Groups are not passed as list, but are added to list of arguments as next arguments.

If a property for the corresponding HTTP action is not set, then component will return HTTP error 404.