Software /
code /
prosody-modules
Changeset
4478:7ab0c423688a
mod_rest: Support GET for certain IQ queries
Example:
GET /rest/version/example.com
200 OK
{ version: { name: "thing", version: "1.0.0" } }
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sun, 28 Feb 2021 19:33:09 +0100 |
parents | 4477:8df6cc648963 |
children | 4479:356b5ad521a5 |
files | mod_rest/README.markdown mod_rest/mod_rest.lua mod_rest/openapi.yaml |
diffstat | 3 files changed, 151 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/mod_rest/README.markdown Sun Feb 28 19:25:45 2021 +0100 +++ b/mod_rest/README.markdown Sun Feb 28 19:33:09 2021 +0100 @@ -101,6 +101,23 @@ entities (connected clients or remote servers) will not be returned, but can be forwarded via the callback API described in the next section. +### Simple info queries + +A subset of IQ stanzas can be sent as simple GET requests + +``` +curl https://prosody.example:5281/rest/version/example.com \ + --oauth2-bearer dmVyeSBzZWNyZXQgdG9rZW4K \ + -H 'Accept: application/json' +``` + +The supported queries are + +- `disco` +- `items` +- `version` +- `ping` + ## Receiving stanzas TL;DR: Set this webhook callback URL, get XML `POST`-ed there.
--- a/mod_rest/mod_rest.lua Sun Feb 28 19:25:45 2021 +0100 +++ b/mod_rest/mod_rest.lua Sun Feb 28 19:33:09 2021 +0100 @@ -63,8 +63,17 @@ local function amend_from_path(data, path) local st_kind, st_type, st_to = path:match("^([mpi]%w+)/(%w+)/(.*)$"); if not st_kind then return; end - data.kind = st_kind; - data.type = st_type; + if st_kind == "iq" and st_type ~= "get" and st_type ~= "set" then + -- GET /iq/disco/jid + data = { + kind = "iq"; + type = "get"; + [st_type] = data; + } + else + data.kind = st_kind; + data.type = st_type; + end if st_to and st_to ~= "" then data.to = st_to; end @@ -112,6 +121,10 @@ return nil, "invalid-path"; end return jsonmap.json2st(parsed); + elseif not mimetype and path then + local parsed = amend_from_path({}, path); + if not parsed then return nil, "invalid-path"; end + return jsonmap.json2st(parsed); end return nil, "unknown-payload-type"; end @@ -188,7 +201,17 @@ mediatype = { code = 415, condition = "bad-format", text = "Unsupported media type" }, }); -local function handle_post(event, path) +-- GET → iq-get +local function parse_request(request, path) + if path and request.method == "GET" then + -- e.g. /verison/{to} + return parse(nil, nil, "iq/"..path); + else + return parse(request.headers.content_type, request.body, path); + end +end + +local function handle_request(event, path) local request, response = event.request, event.response; local from; local origin; @@ -203,7 +226,7 @@ end from = jid.join(origin.username, origin.host, origin.resource); end - local payload, err = parse(request.headers.content_type, request.body, path); + local payload, err = parse_request(request, path); if not payload then -- parse fail local ctx = { error = err, type = request.headers.content_type, data = request.body, }; @@ -245,7 +268,7 @@ }; module:log("debug", "Received[rest]: %s", payload:top_tag()); - local send_type = decide_type((request.headers.accept or "") ..",".. request.headers.content_type, supported_outputs) + local send_type = decide_type((request.headers.accept or "") ..",".. (request.headers.content_type or ""), supported_outputs) if payload.name == "iq" then function origin.send(stanza) module:send(stanza); @@ -292,8 +315,9 @@ module:depends("http"); module:provides("http", { route = { - POST = handle_post; - ["POST /*"] = handle_post; + POST = handle_request; + ["POST /*"] = handle_request; + ["GET /*"] = handle_request; }; });
--- a/mod_rest/openapi.yaml Sun Feb 28 19:25:45 2021 +0100 +++ b/mod_rest/openapi.yaml Sun Feb 28 19:33:09 2021 +0100 @@ -62,6 +62,109 @@ payload. 415: description: Unsupported mediatype. + /rest/ping/{to}: + get: + security: + - basic: [] + - token: [] + summary: Ping a local or remote server or other entity + responses: + 200: + content: + application/json: + schema: + type: object + application/xmpp+xml: + schema: + description: Single XMPP stanza in XML format. + example: | + <iq type="result"/> + description: OK + parameters: + - name: to + in: path + required: true + schema: + $ref: '#/components/schemas/to' + /rest/disco/{to}: + get: + security: + - basic: [] + - token: [] + summary: Query a remote entity for supported features + responses: + 200: + content: + application/json: + schema: + type: object + properties: + disco: + $ref: '#/components/schemas/disco' + application/xmpp+xml: + schema: + description: See XEP-0030 + description: OK + parameters: + - name: to + in: path + required: true + schema: + $ref: '#/components/schemas/to' + /rest/items/{to}: + get: + security: + - basic: [] + - token: [] + summary: Query an entity for related services, chat rooms or other items + responses: + 200: + content: + application/json: + schema: + type: object + properties: + disco: + $ref: '#/components/schemas/items' + application/xmpp+xml: + schema: + description: See XEP-0030 + description: OK + parameters: + - name: to + in: path + required: true + schema: + $ref: '#/components/schemas/to' + /rest/version/{to}: + get: + security: + - basic: [] + - token: [] + summary: Ask what software version is used + responses: + 200: + content: + application/json: + schema: + $ref: '#/components/schemas/stanza' + application/xmpp+xml: + schema: + description: Single XMPP stanza in XML format. + example: | + <iq type="result"> + <query xmlns="jabber:iq:version"> + <name>Exodus</name> + <version>0.7.0.4</version> + </query> + </iq> + description: OK + parameters: + - name: to + in: path + required: true + schema: + $ref: '#/components/schemas/to' /rest/{kind}/{type}/{to}: post: responses: