Mercurial > prosody-modules
diff mod_rest/mod_rest.lua @ 4938:bc8832c6696b
upstream merge
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 11 May 2022 12:44:32 +0200 |
parents | c83b009b5bc5 |
children | e7b9bc629ecc |
line wrap: on
line diff
--- a/mod_rest/mod_rest.lua Wed May 11 12:43:26 2022 +0200 +++ b/mod_rest/mod_rest.lua Wed May 11 12:44:32 2022 +0200 @@ -1,6 +1,6 @@ -- RESTful API -- --- Copyright (c) 2019-2020 Kim Alvefur +-- Copyright (c) 2019-2022 Kim Alvefur -- -- This file is MIT/X11 licensed. @@ -230,16 +230,21 @@ end local function encode(type, s) + if type == "text/plain" then + return s:get_child_text("body") or ""; + elseif type == "application/xmpp+xml" then + return tostring(s); + end + local mapped, err = jsonmap.st2json(s); + if not mapped then return mapped, err; end if type == "application/json" then - return json.encode(jsonmap.st2json(s)); + return json.encode(mapped); elseif type == "application/x-www-form-urlencoded" then - return http.formencode(flatten(jsonmap.st2json(s))); + return http.formencode(flatten(mapped)); elseif type == "application/cbor" then - return cbor.encode(jsonmap.st2json(s)); - elseif type == "text/plain" then - return s:get_child_text("body") or ""; + return cbor.encode(mapped); end - return tostring(s); + error "unsupported encoding"; end local post_errors = errors.init("mod_rest", { @@ -332,8 +337,10 @@ local send_type = decide_type((request.headers.accept or "") ..",".. (request.headers.content_type or ""), supported_outputs) if echo then + local ret, err = errors.coerce(encode(send_type, payload)); + if not ret then return err; end response.headers.content_type = send_type; - return encode(send_type, payload); + return ret; end if payload.name == "iq" then @@ -409,23 +416,35 @@ -- Forward stanzas from XMPP to HTTP and return any reply local rest_url = module:get_option_string("rest_callback_url", nil); if rest_url then + local function get_url() return rest_url; end + if rest_url:find("%b{}") then + local httputil = require "util.http"; + local render_url = require"util.interpolation".new("%b{}", httputil.urlencode); + function get_url(stanza) + local at = stanza.attr; + return render_url(rest_url, { kind = stanza.name, type = at.type, to = at.to, from = at.from }); + end + end local send_type = module:get_option_string("rest_callback_content_type", "application/xmpp+xml"); if send_type == "json" then send_type = "application/json"; end module:set_status("info", "Not yet connected"); - http.request(rest_url, { + http.request(get_url(st.stanza("meta", { type = "info", to = module.host, from = module.host })), { method = "OPTIONS", }, function (body, code, response) if code == 0 then - return module:log_status("error", "Could not connect to callback URL %q: %s", rest_url, body); - else + module:log_status("error", "Could not connect to callback URL %q: %s", rest_url, body); + elseif code == 200 then module:set_status("info", "Connected"); - end - if code == 200 and response.headers.accept then - send_type = decide_type(response.headers.accept, supported_outputs); - module:log("debug", "Set 'rest_callback_content_type' = %q based on Accept header", send_type); + if response.headers.accept then + send_type = decide_type(response.headers.accept, supported_outputs); + module:log("debug", "Set 'rest_callback_content_type' = %q based on Accept header", send_type); + end + else + module:log_status("warn", "Unexpected response code %d from OPTIONS probe", code); + module:log("warn", "Endpoint said: %s", body); end end); @@ -448,7 +467,7 @@ stanza = st.clone(stanza, true); module:log("debug", "Sending[rest]: %s", stanza:top_tag()); - http.request(rest_url, { + http.request(get_url(stanza), { body = request_body, headers = { ["Content-Type"] = send_type, @@ -534,21 +553,19 @@ return true; end - if module:get_host_type() == "component" then - module:hook("iq/bare", handle_stanza, -1); - module:hook("message/bare", handle_stanza, -1); - module:hook("presence/bare", handle_stanza, -1); - module:hook("iq/full", handle_stanza, -1); - module:hook("message/full", handle_stanza, -1); - module:hook("presence/full", handle_stanza, -1); - module:hook("iq/host", handle_stanza, -1); - module:hook("message/host", handle_stanza, -1); - module:hook("presence/host", handle_stanza, -1); - else - -- Don't override everything on normal VirtualHosts - module:hook("iq/host", handle_stanza, -1); - module:hook("message/host", handle_stanza, -1); - module:hook("presence/host", handle_stanza, -1); + local send_kinds = module:get_option_set("rest_callback_stanzas", { "message", "presence", "iq" }); + + local event_presets = { + -- Don't override everything on normal VirtualHosts by default + ["local"] = { "host" }, + -- Comonents get to handle all kinds of stanzas + ["component"] = { "bare", "full", "host" }, + }; + local hook_events = module:get_option_set("rest_callback_events", event_presets[module:get_host_type()]); + for kind in send_kinds do + for event in hook_events do + module:hook(kind.."/"..event, handle_stanza, -1); + end end end