# HG changeset patch # User Kim Alvefur # Date 1614537189 -3600 # Node ID 7ab0c423688a43c3bad4eef70490bf78aec2f07a # Parent 8df6cc6489637a87e80f13ba1e5ab6ec28512889 mod_rest: Support GET for certain IQ queries Example: GET /rest/version/example.com 200 OK { version: { name: "thing", version: "1.0.0" } } diff -r 8df6cc648963 -r 7ab0c423688a mod_rest/README.markdown --- 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. diff -r 8df6cc648963 -r 7ab0c423688a mod_rest/mod_rest.lua --- 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; }; }); diff -r 8df6cc648963 -r 7ab0c423688a mod_rest/openapi.yaml --- 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: | + + 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: | + + + Exodus + 0.7.0.4 + + + description: OK + parameters: + - name: to + in: path + required: true + schema: + $ref: '#/components/schemas/to' /rest/{kind}/{type}/{to}: post: responses: