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
parents f77ae9685eb6
children 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",