Article - Talk ejabberd HTTP request handlers
The web server embedded in ejabberd can be extended by writing your own
modules.
Tutorial
Assume that you want to write a simple “mod_http_hello” module to handle
all requests whose URL path begins with “/hello”, such as:
- http://localhost:5280/hello/world
- http://localhost:5280/hello/hedgehog
Start by writing a “mod_http_hello.erl” file that contains request
handlers, which are clauses of the process/2 function. For
example, to handle a request with the “/hello/world” path:
process(_LocalPath = ["world"], _Request) ->
{xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}],
[{xmlelement, "head", [],
[{xmlelement, "title", [], []}]},
{xmlelement, "body", [],
[{xmlelement, "p", [], [{xmlcdata, "Hello, world!"}]}]}]};
The entire mod_http_hello.erl file would look like:
%%%----------------------------------------------------------------------
%%% File : mod_http_hello.erl
%%% Author : Your Name <your [at] email [dot] org>
%%% Purpose : Sample module that extends embedded ejabberd HTTP server
%%% Created :
%%% Id :
%%%----------------------------------------------------------------------
-module(mod_http_hello).
-author('your@email.org').
-vsn('').
-define(ejabberd_debug, true).
-behaviour(gen_mod).
-export([
start/2,
stop/1,
process/2
]).
-include("ejabberd.hrl").
-include("jlib.hrl").
-include("ejabberd_http.hrl").
%%%----------------------------------------------------------------------
%%% REQUEST HANDLERS
%%%----------------------------------------------------------------------
process(["world"], _Request) ->
{xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}],
[{xmlelement, "head", [],
[{xmlelement, "title", [], []}]},
{xmlelement, "body", [],
[{xmlelement, "p", [], [{xmlcdata, "Hello, world!"}]}]}]};
process(["produce_error"], _Request) ->
{400, [], {xmlelement, "h1", [],
[{xmlcdata, "400 Bad Request"}]}};
process(LocalPath, _Request) ->
{xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}],
[{xmlelement, "head", [],
[{xmlelement, "title", [], []}]},
{xmlelement, "body", [],
[{xmlelement, "p", [], [{xmlcdata, io_lib:format("Called with path: ~p", [LocalPath])}]}]}]}.
%%%----------------------------------------------------------------------
%%% BEHAVIOUR CALLBACKS
%%%----------------------------------------------------------------------
start(_Host, _Opts) ->
ok.
stop(_Host) ->
ok.
Modify ejabberd.cfg so that mod_http_hello is loaded when ejabberd starts:
{modules,
[
%% ...
{mod_http_hello, []},
%% ...
]}.
Also in ejabberd.cfg, configure ejabberd_http so that it dispatches requests beginning with “/hello/” to mod_http_hello:
{5280, ejabberd_http, [http_poll, web_admin,
{request_handlers, [{["hello"], mod_http_hello}]}]}
API
Apart from callbacks required by gen_mod, your module only has to implement (one or more clauses of) process/2:
- your_http_module:process(LocalPath, Request)
The process/2 function handles an HTTP request. It returns the data to be sent back to the client, optionally with a status code and additional headers.
process/2 will be called with two arguments: LocalPath and Request.
The LocalPath argument is a list containing the part of the requested URL path that is “local to the module”.
Example: mod_foo was configured in ejabberd.cfg to handle requests whose path begins with “/a/b”:
{5280, ejabberd_http, [http_poll, web_admin,
{request_handlers, [{["a", "b"], mod_foo}]}]}
User requests the URL:
http://server:5280/a/b/c/d
Path “local to the module” will be:
["c", "d"]
Usually you will want to select a handler based on the local path instead of the full path (Request#request.path), so that server administrators can make the module available under the path prefix of their choice.
The Request argument is a record containing information about the HTTP request as defined in ejabberd_http.hrl. It consists of the following fields:
{
"request",
method, %% HTTP method ("GET" or "POST")
path, %% Full path to requested resource
%% e.g. for "http://server:5280/a/b/c/d": ["a", "b", "c", "d"]
q, %% Query part of the URL
%% e.g. for "http://server:5280/a/b/c/d?foo=bar": [{"foo", "bar"}]
us, %% Authenticated user and server. Used in ejabberd_web_admin for now.
%% e.g. for "foo@jabber.server.org": {"foo", "jabber.server.org"}
auth, %% Information provided for HTTP-auth (if any)
%% e.g. for a user "john" who entered the password "secret": {"john", "secret"}
lang = "", %% Language code
data = "", %% POST data
}
