Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework HTTP handler configuration #3636

Merged
merged 20 commits into from
Apr 27, 2022
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
d71d8d2
Export process/3 to merge processor functions when merging sections
chrzaszcz Apr 25, 2022
1a4b8ff
Move http handler config specs out of mongoose_config_spec
chrzaszcz Apr 25, 2022
62a55f9
Move merge_sections/2 to mongoose_config_utils
chrzaszcz Apr 25, 2022
0a5ccd0
Remove unused include
chrzaszcz Apr 25, 2022
1706de1
Add a new behaviour: mongoose_http_handler
chrzaszcz Apr 25, 2022
12d72a5
Add mongoose_http_handler callbacks to mongoose_domain_handler
chrzaszcz Apr 25, 2022
a84386c
Update options type in mod_bosh
chrzaszcz Apr 25, 2022
3f70340
Add mongoose_http_handler callbacks to mod_websockets
chrzaszcz Apr 25, 2022
3d4bfd9
Add mongoose_http_handler callbacks to mongoose_api
chrzaszcz Apr 25, 2022
b24ffda
Add mongoose_http_handler callbacks to mongoose_api_admin
chrzaszcz Apr 25, 2022
f45db8d
Add mongoose_http_handler callbacks to mongoose_api_client
chrzaszcz Apr 25, 2022
19a798a
Add mongoose_http_handler callbacks to mongoose_client_api
chrzaszcz Apr 25, 2022
a40f308
Move handler-related functionality out of ejabberd_cowboy
chrzaszcz Apr 25, 2022
f61348a
Update handler collection for system metrics
chrzaszcz Apr 25, 2022
aa71aef
Use the new, simplified format for mongoose_client_api
chrzaszcz Apr 25, 2022
3be89a9
Specify http options in maps in small tests
chrzaszcz Apr 25, 2022
22ebfd7
Update small tests for HTTP handler config options
chrzaszcz Apr 25, 2022
aac7f26
Update big test helpers after the changes in handler options
chrzaszcz Apr 25, 2022
8367450
Update docs for the changed HTTP handlers
chrzaszcz Apr 25, 2022
eeda654
Fix indentation
Apr 27, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions big_tests/tests/domain_rest_helper.erl
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,10 @@ listener_opts(Params) ->
transport => config([listen, http, transport], #{num_acceptors => 10})}).

domain_handler(Params) ->
{"localhost", "/api", mongoose_domain_handler, handler_opts(Params)}.
maps:merge(#{host => "localhost", path => "/api", module => mongoose_domain_handler},
handler_opts(Params)).

handler_opts(#{skip_auth := true}) ->
[];
#{};
handler_opts(_Params) ->
[{password, <<"secret">>}, {username, <<"admin">>}].
#{password => <<"secret">>, username => <<"admin">>}.
46 changes: 20 additions & 26 deletions big_tests/tests/rest_helper.erl
Original file line number Diff line number Diff line change
Expand Up @@ -277,36 +277,30 @@ start_admin_listener(Creds) ->
NewOpts = insert_creds(Opts, Creds),
rpc(mim(), mongoose_listener, start_listener, [NewOpts]).

insert_creds(Opts = #{handlers := Modules}, Creds) ->
{Host, Path, mongoose_api_admin, PathOpts} = lists:keyfind(mongoose_api_admin, 3, Modules),
NewPathOpts = inject_creds_to_opts(PathOpts, Creds),
NewModules = lists:keyreplace(mongoose_api_admin, 3, Modules,
{Host, Path, mongoose_api_admin, NewPathOpts}),
Opts#{handlers := NewModules}.

inject_creds_to_opts(PathOpts, any) ->
lists:keydelete(auth, 1, PathOpts);
inject_creds_to_opts(PathOpts, Creds) ->
case lists:keymember(auth, 1, PathOpts) of
true ->
lists:keyreplace(auth, 1, PathOpts, {auth, Creds});
false ->
lists:append(PathOpts, [{auth, Creds}])
end.
insert_creds(Opts = #{handlers := Handlers}, Creds) ->
NewHandlers = [inject_creds_to_opts(Handler, Creds) || Handler <- Handlers],
Opts#{handlers := NewHandlers}.

inject_creds_to_opts(Handler = #{module := mongoose_api_admin}, Creds) ->
case Creds of
{UserName, Password} ->
Handler#{username => UserName, password => Password};
any ->
maps:without([username, password], Handler)
end;
inject_creds_to_opts(Handler, _Creds) ->
Handler.

% @doc Checks whether a config for a port is an admin or client one.
% This is determined based on modules used. If there is any mongoose_api_admin module used,
% it is admin config. If not and there is at least one mongoose_api_client* module used,
% it's clients.
is_roles_config(#{module := ejabberd_cowboy, handlers := Modules}, admin) ->
lists:any(fun({_, _Path, Mod, _Args}) -> Mod == mongoose_api_admin; (_) -> false end, Modules);
is_roles_config(#{module := ejabberd_cowboy, handlers := Modules}, client) ->
ModulesTokens = lists:map(fun({_, _Path, Mod, _}) -> string:tokens(atom_to_list(Mod), "_");
(_) -> []
end, Modules),
lists:any(fun(["mongoose", "client", "api" | _T]) -> true; (_) -> false end, ModulesTokens);
% This is determined based on handler modules used.
is_roles_config(#{module := ejabberd_cowboy, handlers := Handlers}, Role) ->
RoleModule = role_to_module(Role),
lists:any(fun(#{module := Module}) -> Module =:= RoleModule end, Handlers);
is_roles_config(_, _) -> false.

role_to_module(admin) -> mongoose_api_admin;
role_to_module(client) -> mongoose_client_api.

mapfromlist(L) ->
Nl = lists:map(fun({K, {V}}) when is_list(V) ->
{binary_to_atom(K, utf8), mapfromlist(V)};
Expand Down
84 changes: 30 additions & 54 deletions doc/configuration/listen.md
Original file line number Diff line number Diff line change
Expand Up @@ -420,16 +420,16 @@ Recommended port number: 5280 for BOSH/WS.
There are the following options for each of the HTTP listeners:

### `listen.http.handlers`
* **Syntax:** each handler is specified in a subsection starting with `[[listen.http.handlers.type]]` where `type` is one of the allowed handler types, handling different connection types, e.g.
* **Syntax:** each handler is specified in a subsection starting with `[[listen.http.handlers.type]]` where `type` is one of the allowed handler types, handling different connection types:

* `mod_bosh` - for [BOSH](https://xmpp.org/extensions/xep-0124.html) connections,
* `mod_websockets` - for [WebSocket](https://tools.ietf.org/html/rfc6455) connections,
* `mongoose_api_*`, `mongoose_client_api_*`, ... - for REST API.
* `mongoose_api_admin`, `mongoose_api_client`(obsolete), `mongoose_client_api`, `mongoose_domain_handler`, `mongoose_api` - for REST API.

These types are described below in more detail.
The double-bracket syntax is used because there can be multiple handlers of a given type, so for each type there is a TOML array of one or more tables (subsections).

* **Default:** there is no default, all handlers need to be specified explicitly.
* **Default:** `[]` - no handlers enabled, all of them need to be specified explicitly.
* **Example:** two handlers, one for BOSH and one for WebSockets
```toml
[[listen.http.handlers.mod_bosh]]
Expand Down Expand Up @@ -459,10 +459,12 @@ Path for this handler.

### Handler types: BOSH - `mod_bosh`

The recommended configuration is shown in [Example 1](#example-1-bosh-and-ws) below.
To handle incoming BOSH traffic you need to configure the `mod_bosh` module in the `modules` section as well.

### Handler types: WebSockets - `mod_websockets`

The recommended configuration is shown in [Example 1](#example-1-bosh-and-ws) below.
Websocket connections as defined in [RFC 7395](https://tools.ietf.org/html/rfc7395).
You can pass the following optional parameters:

Expand Down Expand Up @@ -490,7 +492,7 @@ Maximum allowed incoming stanza size.
This limit is checked **after** the input data parsing, so it does not apply to the input data size itself.

#### `listen.http.handlers.mod_websockets.service`
* **Syntax:** an array of `listen.service.*` options
* **Syntax:** a table of `listen.service.*` options
* **Default:** not set
* **Example:**

Expand All @@ -506,6 +508,7 @@ See the [service](#xmpp-components-listenservice) listener section for details.

### Handler types: REST API - Admin - `mongoose_api_admin`

The recommended configuration is shown in [Example 2](#example-2-admin-api) below.
For more information about the API, see the [REST interface](../rest-api/Administration-backend.md) documentation.
The following options are supported for this handler:

Expand All @@ -523,19 +526,32 @@ When set, enables authentication for the admin API, otherwise it is disabled. Re

Required to enable authentication for the admin API.

### Handler types: REST API - Client

To enable the REST API for clients, several handlers need to be added:

* `mongoose_client_api_*` - handles individual API endpoints. You can add and remove these to enable particular functionality.
* `lasse_handler` - provides the [SSE handler](https://github.com/inaka/lasse) which is required for the client HTTP API, should not be changed.
* `cowboy_*` - hosts the Swagger web-based documentation, should not be changed, but can be removed to disable the API docs.
### Handler types: REST API - Client - `mongoose_client_api`

The recommended configuration is shown in [Example 3](#example-3-client-api) below.
Please refer to [REST interface](../rest-api/Client-frontend.md) documentation for more information.
The following options are supported for this handler:

#### `listen.http.handlers.mongoose_client_api.handlers`
* **Syntax:** array of strings - Erlang modules
* **Default:** all API handler modules enabled
* **Example:** `handlers = ["mongoose_client_api_messages", "mongoose_client_api_sse"]`

The client API consists of several modules, each of them implementing a subset of the functionality.
By default all modules are enabled, so you don't need to change this option.
For a list of allowed modules, you need to consult the [source code](https://github.com/esl/MongooseIM/blob/master/src/mongoose_client_api/mongoose_client_api.erl).

#### `listen.http.handlers.mongoose_client_api.docs`
* **Syntax:** boolean
* **Default:** `true`
* **Example:** `docs = "false"`

The Swagger documentation of the client API is hosted at the `/api-docs` path.
You can disable the hosted documentation by setting this option to `false`.

### Handler types: REST API - Domain management - `mongoose_domain_handler`

The recommended configuration is shown in [Example 4](#example-4-domain-api) below.
This handler enables dynamic domain management for different host types.
For more information about the API, see the [REST interface](../rest-api/Dynamic-domains.md) documentation.
The following options are supported for this handler:
Expand All @@ -562,7 +578,7 @@ The following option is required:

#### `listen.http.handlers.mongoose_api.handlers`
* **Syntax:** array of strings - Erlang modules
* **Default:** not set, this is a mandatory option for this handler
* **Default:** all API handler modules enabled
* **Example:** `handlers = ["mongoose_api_metrics"]`

### Transport options
Expand Down Expand Up @@ -720,49 +736,9 @@ REST API for clients.
transport.max_connections = 1024
protocol.compress = true

[[listen.http.handlers.lasse_handler]]
host = "_"
path = "/api/sse"
module = "mongoose_client_api_sse"

[[listen.http.handlers.mongoose_client_api_messages]]
[[listen.http.handlers.mongoose_client_api]]
host = "_"
path = "/api/messages/[:with]"

[[listen.http.handlers.mongoose_client_api_contacts]]
host = "_"
path = "/api/contacts/[:jid]"

[[listen.http.handlers.mongoose_client_api_rooms]]
host = "_"
path = "/api/rooms/[:id]"

[[listen.http.handlers.mongoose_client_api_rooms_config]]
host = "_"
path = "/api/rooms/[:id]/config"

[[listen.http.handlers.mongoose_client_api_rooms_users]]
host = "_"
path = "/api/rooms/:id/users/[:user]"

[[listen.http.handlers.mongoose_client_api_rooms_messages]]
host = "_"
path = "/api/rooms/[:id]/messages"

[[listen.http.handlers.cowboy_swagger_redirect_handler]]
host = "_"
path = "/api-docs"

[[listen.http.handlers.cowboy_swagger_json_handler]]
host = "_"
path = "/api-docs/swagger.json"

[[listen.http.handlers.cowboy_static]]
host = "_"
path = "/api-docs/[...]"
type = "priv_dir"
app = "cowboy_swagger"
content_path = "swagger"
path = "/api"
```

#### Example 4. Domain API
Expand Down
4 changes: 4 additions & 0 deletions doc/migrations/5.0.0_5.1.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

The configuration format has slightly changed and you might need to amend `mongooseim.toml`.

### Section `listen`

There is a new, simplified configuration format for `mongoose_client_api`. You need to change the `listen` section unless you have disabled the client API in your configuration file. Consult the [option description](../configuration/listen.md#handler-types-rest-api-client-mongoose_client_api) and the [example configuration](http://localhost:8000/configuration/listen/#example-3-client-api) for details.

### Section `acl`

The implicit check for user's domain in patterns is now configurable and the default behaviour (previously undocumented) is more consistent - the check is always performed unless disabled with `match = "all"`.
Expand Down
46 changes: 3 additions & 43 deletions rel/files/mongooseim.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
[[listen.http.handlers.mongoose_api_admin]]
host = "localhost"
path = "/api"

[[listen.http.handlers.mongoose_domain_handler]]
host = "localhost"
path = "/api"
Expand All @@ -74,49 +75,9 @@
{{{https_config}}}
{{/https_config}}

[[listen.http.handlers.lasse_handler]]
host = "_"
path = "/api/sse"
module = "mongoose_client_api_sse"

[[listen.http.handlers.mongoose_client_api_messages]]
host = "_"
path = "/api/messages/[:with]"

[[listen.http.handlers.mongoose_client_api_contacts]]
host = "_"
path = "/api/contacts/[:jid]"

[[listen.http.handlers.mongoose_client_api_rooms]]
host = "_"
path = "/api/rooms/[:id]"

[[listen.http.handlers.mongoose_client_api_rooms_config]]
host = "_"
path = "/api/rooms/[:id]/config"

[[listen.http.handlers.mongoose_client_api_rooms_users]]
host = "_"
path = "/api/rooms/:id/users/[:user]"

[[listen.http.handlers.mongoose_client_api_rooms_messages]]
host = "_"
path = "/api/rooms/[:id]/messages"

[[listen.http.handlers.cowboy_swagger_redirect_handler]]
[[listen.http.handlers.mongoose_client_api]]
host = "_"
path = "/api-docs"

[[listen.http.handlers.cowboy_swagger_json_handler]]
host = "_"
path = "/api-docs/swagger.json"

[[listen.http.handlers.cowboy_static]]
host = "_"
path = "/api-docs/[...]"
type = "priv_dir"
app = "cowboy_swagger"
content_path = "swagger"
path = "/api"
Premwoik marked this conversation as resolved.
Show resolved Hide resolved

[[listen.http]]
{{#http_api_old_endpoint}}
Expand All @@ -128,7 +89,6 @@
[[listen.http.handlers.mongoose_api]]
host = "localhost"
path = "/api"
handlers = ["mongoose_api_metrics", "mongoose_api_users"]

[[listen.c2s]]
port = {{{c2s_port}}}
Expand Down
3 changes: 3 additions & 0 deletions src/config/mongoose_config_parser_toml.erl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

-export([parse_file/1]).

%% Utilities for section manipulation
-export([process/3]).

-ifdef(TEST).
-export([process/1,
extract_errors/1]).
Expand Down
Loading