Mercurial > prosody-modules
comparison mod_rest/mod_rest.lua @ 3795:f51308fcba83
mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Mon, 30 Dec 2019 04:07:25 +0100 |
parents | 4b258329e6e4 |
children | d1ad10b76b00 |
comparison
equal
deleted
inserted
replaced
3794:4b258329e6e4 | 3795:f51308fcba83 |
---|---|
3 -- Copyright (c) 2019 Kim Alvefur | 3 -- Copyright (c) 2019 Kim Alvefur |
4 -- | 4 -- |
5 -- This file is MIT/X11 licensed. | 5 -- This file is MIT/X11 licensed. |
6 | 6 |
7 local errors = require "util.error"; | 7 local errors = require "util.error"; |
8 local http = require "net.http"; | |
8 local id = require "util.id"; | 9 local id = require "util.id"; |
9 local jid = require "util.jid"; | 10 local jid = require "util.jid"; |
11 local st = require "util.stanza"; | |
10 local xml = require "util.xml"; | 12 local xml = require "util.xml"; |
11 | 13 |
12 local allow_any_source = module:get_host_type() == "component"; | 14 local allow_any_source = module:get_host_type() == "component"; |
13 local validate_from_addresses = module:get_option_boolean("validate_from_addresses", true); | 15 local validate_from_addresses = module:get_option_boolean("validate_from_addresses", true); |
14 | 16 |
76 module:provides("http", { | 78 module:provides("http", { |
77 route = { | 79 route = { |
78 POST = handle_post; | 80 POST = handle_post; |
79 }; | 81 }; |
80 }); | 82 }); |
83 | |
84 -- Forward stanzas from XMPP to HTTP and return any reply | |
85 local rest_url = module:get_option_string("rest_callback_url", nil); | |
86 if rest_url then | |
87 | |
88 local function handle_stanza(event) | |
89 local stanza, origin = event.stanza, event.origin; | |
90 local reply_needed = stanza.name == "iq"; | |
91 | |
92 http.request(rest_url, { | |
93 body = tostring(stanza), | |
94 headers = { | |
95 ["Content-Type"] = "application/xmpp+xml", | |
96 ["Content-Language"] = stanza.attr["xml:lang"], | |
97 Accept = "application/xmpp+xml, text/plain", | |
98 }, | |
99 }, function (body, code, response) | |
100 if (code == 202 or code == 204) and not reply_needed then | |
101 -- Delivered, no reply | |
102 return; | |
103 end | |
104 local reply, reply_text; | |
105 | |
106 if response.headers["content-type"] == "application/xmpp+xml" then | |
107 local parsed, err = xml.parse(body); | |
108 if not parsed then | |
109 module:log("warn", "REST callback responded with invalid XML: %s, %q", err, body); | |
110 elseif parsed.name ~= stanza.name then | |
111 module:log("warn", "REST callback responded with the wrong stanza type, got %s but expected %s", parsed.name, stanza.name); | |
112 else | |
113 parsed.attr.to, parsed.attr.from = stanza.attr.from, stanza.attr.to; | |
114 if parsed.name == "iq" then | |
115 parsed.attr.id = stanza.attr.id; | |
116 end | |
117 reply = parsed; | |
118 end | |
119 elseif response.headers["content-type"] == "text/plain" then | |
120 reply = st.reply(stanza); | |
121 if body ~= "" then | |
122 reply_text = body; | |
123 end | |
124 elseif body ~= "" then -- ignore empty body | |
125 module:log("debug", "Callback returned response of unhandled type %q", response.headers["content-type"]); | |
126 end | |
127 | |
128 if not reply then | |
129 local code_hundreds = code - (code % 100); | |
130 if code_hundreds == 200 then | |
131 reply = st.reply(stanza); | |
132 if stanza.name ~= "iq" then | |
133 reply.attr.id = id.medium(); | |
134 end | |
135 if reply_text and reply.name == "message" then | |
136 reply:body(reply_text, { ["xml:lang"] = response.headers["content-language"] }); | |
137 end | |
138 -- TODO presence/status=body ? | |
139 elseif code_hundreds == 400 then | |
140 reply = st.error_reply(stanza, "modify", "bad-request", reply_text); | |
141 elseif code_hundreds == 500 then | |
142 reply = st.error_reply(stanza, "cancel", "internal-server-error", reply_text); | |
143 else | |
144 reply = st.error_reply(stanza, "cancel", "undefined-condition", reply_text); | |
145 end | |
146 end | |
147 | |
148 origin.send(reply); | |
149 end); | |
150 | |
151 return true; | |
152 end | |
153 | |
154 if module:get_host_type() == "component" then | |
155 module:hook("iq/bare", handle_stanza, -1); | |
156 module:hook("message/bare", handle_stanza, -1); | |
157 module:hook("presence/bare", handle_stanza, -1); | |
158 module:hook("iq/full", handle_stanza, -1); | |
159 module:hook("message/full", handle_stanza, -1); | |
160 module:hook("presence/full", handle_stanza, -1); | |
161 module:hook("iq/host", handle_stanza, -1); | |
162 module:hook("message/host", handle_stanza, -1); | |
163 module:hook("presence/host", handle_stanza, -1); | |
164 else | |
165 -- Don't override everything on normal VirtualHosts | |
166 module:hook("iq/host", handle_stanza, -1); | |
167 module:hook("message/host", handle_stanza, -1); | |
168 module:hook("presence/host", handle_stanza, -1); | |
169 end | |
170 end |