Software /
code /
prosody-modules
Comparison
mod_rest/mod_rest.lua @ 3929:bd687d586a8a
mod_rest: Separate lists of mediatypes for input, output and errors
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sat, 07 Mar 2020 16:12:49 +0100 |
parent | 3926:f77ae9685eb6 |
child | 3930:d5dafd617cd6 |
comparison
equal
deleted
inserted
replaced
3928:7e7ac4af6e0c | 3929:bd687d586a8a |
---|---|
81 return st.message({ type = "chat" }, data); | 81 return st.message({ type = "chat" }, data); |
82 end | 82 end |
83 return nil, "unknown-payload-type"; | 83 return nil, "unknown-payload-type"; |
84 end | 84 end |
85 | 85 |
86 local supported_types = { | 86 local function decide_type(accept, supported_types) |
87 -- assumes the accept header is sorted | |
88 local ret = supported_types[1]; | |
89 for i = 2, #supported_types do | |
90 if (accept:find(supported_types[i], 1, true) or 1000) < (accept:find(ret, 1, true) or 1000) then | |
91 ret = supported_types[i]; | |
92 end | |
93 end | |
94 return ret; | |
95 end | |
96 | |
97 local supported_inputs = { | |
87 "application/xmpp+xml", | 98 "application/xmpp+xml", |
88 "application/json", | 99 "application/json", |
89 "application/x-www-form-urlencoded", | 100 "application/x-www-form-urlencoded", |
90 "text/plain", | 101 "text/plain", |
91 }; | 102 }; |
92 | 103 |
93 local function decide_type(accept) | 104 local supported_outputs = { |
94 -- assumes the accept header is sorted | 105 "application/xmpp+xml", |
95 local ret = supported_types[1]; | 106 "application/json", |
96 for i = 2, #supported_types do | 107 }; |
97 if (accept:find(supported_types[i], 1, true) or 1000) < (accept:find(ret, 1, true) or 1000) then | |
98 ret = supported_types[i]; | |
99 end | |
100 end | |
101 return ret; | |
102 end | |
103 | 108 |
104 local function encode(type, s) | 109 local function encode(type, s) |
105 if type == "application/json" then | 110 if type == "application/json" then |
106 return json.encode(jsonmap.st2json(s)); | 111 return json.encode(jsonmap.st2json(s)); |
107 elseif type == "text/plain" then | 112 elseif type == "text/plain" then |
156 id = payload.attr.id or id.medium(), | 161 id = payload.attr.id or id.medium(), |
157 type = payload.attr.type, | 162 type = payload.attr.type, |
158 ["xml:lang"] = payload.attr["xml:lang"], | 163 ["xml:lang"] = payload.attr["xml:lang"], |
159 }; | 164 }; |
160 module:log("debug", "Received[rest]: %s", payload:top_tag()); | 165 module:log("debug", "Received[rest]: %s", payload:top_tag()); |
161 local send_type = decide_type((request.headers.accept or "") ..",".. request.headers.content_type) | 166 local send_type = decide_type((request.headers.accept or "") ..",".. request.headers.content_type, supported_outputs) |
162 if payload.name == "iq" then | 167 if payload.name == "iq" then |
163 function origin.send(stanza) | 168 function origin.send(stanza) |
164 module:send(stanza); | 169 module:send(stanza); |
165 end | 170 end |
166 if payload.attr.type ~= "get" and payload.attr.type ~= "set" then | 171 if payload.attr.type ~= "get" and payload.attr.type ~= "set" then |
222 return module:log_status("error", "Could not connect to callback URL %q: %s", rest_url, body); | 227 return module:log_status("error", "Could not connect to callback URL %q: %s", rest_url, body); |
223 else | 228 else |
224 module:set_status("info", "Connected"); | 229 module:set_status("info", "Connected"); |
225 end | 230 end |
226 if code == 200 and response.headers.accept then | 231 if code == 200 and response.headers.accept then |
227 send_type = decide_type(response.headers.accept); | 232 send_type = decide_type(response.headers.accept, supported_outputs); |
228 module:log("debug", "Set 'rest_callback_content_type' = %q based on Accept header", send_type); | 233 module:log("debug", "Set 'rest_callback_content_type' = %q based on Accept header", send_type); |
229 end | 234 end |
230 end); | 235 end); |
231 | 236 |
232 local code2err = { | 237 local code2err = { |
278 http.request(rest_url, { | 283 http.request(rest_url, { |
279 body = request_body, | 284 body = request_body, |
280 headers = { | 285 headers = { |
281 ["Content-Type"] = send_type, | 286 ["Content-Type"] = send_type, |
282 ["Content-Language"] = stanza.attr["xml:lang"], | 287 ["Content-Language"] = stanza.attr["xml:lang"], |
283 Accept = table.concat(supported_types, ", "); | 288 Accept = table.concat(supported_inputs, ", "); |
284 }, | 289 }, |
285 }, function (body, code, response) | 290 }, function (body, code, response) |
286 if code == 0 then | 291 if code == 0 then |
287 module:log_status("error", "Could not connect to callback URL %q: %s", rest_url, body); | 292 module:log_status("error", "Could not connect to callback URL %q: %s", rest_url, body); |
288 origin.send(st.error_reply(stanza, "wait", "recipient-unavailable", body)); | 293 origin.send(st.error_reply(stanza, "wait", "recipient-unavailable", body)); |
374 module:hook("message/host", handle_stanza, -1); | 379 module:hook("message/host", handle_stanza, -1); |
375 module:hook("presence/host", handle_stanza, -1); | 380 module:hook("presence/host", handle_stanza, -1); |
376 end | 381 end |
377 end | 382 end |
378 | 383 |
384 local supported_errors = { | |
385 "text/html", | |
386 "application/json", | |
387 }; | |
388 | |
379 local http_server = require "net.http.server"; | 389 local http_server = require "net.http.server"; |
380 module:hook_object_event(http_server, "http-error", function (event) | 390 module:hook_object_event(http_server, "http-error", function (event) |
381 local request, response = event.request, event.response; | 391 local request, response = event.request, event.response; |
382 if decide_type(request and request.headers.accept or "") == "application/json" then | 392 if decide_type(request and request.headers.accept or "", supported_errors) == "application/json" then |
383 if response then | 393 if response then |
384 response.headers.content_type = "application/json"; | 394 response.headers.content_type = "application/json"; |
385 end | 395 end |
386 return json.encode({ | 396 return json.encode({ |
387 type = "error", | 397 type = "error", |