Software /
code /
prosody-modules
Comparison
mod_rest/mod_rest.lua @ 3810:91ff86fc3b20
mod_rest: Factor out payload parsing
To make it easier to add new format parsers in a single place
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Wed, 01 Jan 2020 15:43:47 +0100 |
parent | 3807:b0449faca52b |
child | 3811:eb25110696cd |
comparison
equal
deleted
inserted
replaced
3809:a70f5a6c7f01 | 3810:91ff86fc3b20 |
---|---|
18 assert(auth_type == "Bearer", "Only 'Bearer' is supported in rest_credentials"); | 18 assert(auth_type == "Bearer", "Only 'Bearer' is supported in rest_credentials"); |
19 | 19 |
20 -- Bearer token | 20 -- Bearer token |
21 local function check_credentials(request) | 21 local function check_credentials(request) |
22 return request.headers.authorization == secret; | 22 return request.headers.authorization == secret; |
23 end | |
24 | |
25 local function parse(mimetype, data) | |
26 mimetype = mimetype:match("^[^; ]*"); | |
27 if mimetype == "application/xmpp+xml" then | |
28 return xml.parse(data); | |
29 elseif mimetype == "text/plain" then | |
30 return st.message({ type = "chat" }, data); | |
31 end | |
32 return nil, "unknown-payload-type"; | |
23 end | 33 end |
24 | 34 |
25 local function handle_post(event) | 35 local function handle_post(event) |
26 local request, response = event.request, event.response; | 36 local request, response = event.request, event.response; |
27 if not request.headers.authorization then | 37 if not request.headers.authorization then |
28 response.headers.www_authenticate = ("%s realm=%q"):format(auth_type, module.host.."/"..module.name); | 38 response.headers.www_authenticate = ("%s realm=%q"):format(auth_type, module.host.."/"..module.name); |
29 return 401; | 39 return 401; |
30 elseif not check_credentials(request) then | 40 elseif not check_credentials(request) then |
31 return 401; | 41 return 401; |
32 end | 42 end |
33 if request.headers.content_type ~= "application/xmpp+xml" then | 43 local payload, err = parse(request.headers.content_type, request.body); |
34 return errors.new({ code = 415, text = "'application/xmpp+xml' expected" }); | |
35 end | |
36 local payload, err = xml.parse(request.body); | |
37 if not payload then | 44 if not payload then |
38 -- parse fail | 45 -- parse fail |
39 return errors.new({ code = 400, text = err }); | 46 return errors.new({ code = 400, text = err }); |
40 end | 47 end |
41 if payload.attr.xmlns then | 48 if payload.attr.xmlns then |
164 }, function (body, code, response) | 171 }, function (body, code, response) |
165 if (code == 202 or code == 204) and not reply_needed then | 172 if (code == 202 or code == 204) and not reply_needed then |
166 -- Delivered, no reply | 173 -- Delivered, no reply |
167 return; | 174 return; |
168 end | 175 end |
169 local reply, reply_text; | 176 local reply; |
170 | 177 |
171 if response.headers["content-type"] == "application/xmpp+xml" then | 178 local parsed, err = parse(response.headers["content-type"], body); |
172 local parsed, err = xml.parse(body); | 179 if not parsed then |
173 if not parsed then | 180 module:log("warn", "Failed parsing data from REST callback: %s, %q", err, body); |
174 module:log("warn", "REST callback responded with invalid XML: %s, %q", err, body); | 181 elseif parsed.name ~= stanza.name then |
175 elseif parsed.name ~= stanza.name then | 182 module:log("warn", "REST callback responded with the wrong stanza type, got %s but expected %s", parsed.name, stanza.name); |
176 module:log("warn", "REST callback responded with the wrong stanza type, got %s but expected %s", parsed.name, stanza.name); | 183 else |
177 else | 184 parsed.attr = { |
178 parsed.attr = { | 185 from = stanza.attr.to, |
179 from = stanza.attr.to, | 186 to = stanza.attr.from, |
180 to = stanza.attr.from, | 187 id = parsed.attr.id or id.medium(); |
181 id = parsed.attr.id or id.medium(); | 188 type = parsed.attr.type, |
182 type = parsed.attr.type, | 189 ["xml:lang"] = parsed.attr["xml:lang"], |
183 ["xml:lang"] = parsed.attr["xml:lang"], | 190 }; |
184 }; | 191 if parsed.name == "iq" or parsed.attr.type == "error" then |
185 if parsed.name == "iq" or parsed.attr.type == "error" then | 192 parsed.attr.id = stanza.attr.id; |
186 parsed.attr.id = stanza.attr.id; | |
187 end | |
188 reply = parsed; | |
189 end | 193 end |
190 elseif response.headers["content-type"] == "text/plain" then | 194 reply = parsed; |
191 reply = st.reply(stanza); | |
192 if body ~= "" then | |
193 reply_text = body; | |
194 end | |
195 elseif body ~= "" then -- ignore empty body | |
196 module:log("debug", "Callback returned response of unhandled type %q", response.headers["content-type"]); | |
197 end | 195 end |
198 | 196 |
199 if not reply then | 197 if not reply then |
200 local code_hundreds = code - (code % 100); | 198 local code_hundreds = code - (code % 100); |
201 if code_hundreds == 200 then | 199 if code_hundreds == 200 then |
202 reply = st.reply(stanza); | 200 reply = st.reply(stanza); |
203 if stanza.name ~= "iq" then | 201 if stanza.name ~= "iq" then |
204 reply.attr.id = id.medium(); | 202 reply.attr.id = id.medium(); |
205 end | 203 end |
206 if reply_text and reply.name == "message" then | |
207 reply:body(reply_text, { ["xml:lang"] = response.headers["content-language"] }); | |
208 end | |
209 -- TODO presence/status=body ? | 204 -- TODO presence/status=body ? |
210 elseif code2err[code] then | 205 elseif code2err[code] then |
211 reply = st.error_reply(stanza, errors.new(code, nil, code2err)); | 206 reply = st.error_reply(stanza, errors.new(code, nil, code2err)); |
212 elseif code_hundreds == 400 then | 207 elseif code_hundreds == 400 then |
213 reply = st.error_reply(stanza, "modify", "bad-request", reply_text); | 208 reply = st.error_reply(stanza, "modify", "bad-request", body); |
214 elseif code_hundreds == 500 then | 209 elseif code_hundreds == 500 then |
215 reply = st.error_reply(stanza, "cancel", "internal-server-error", reply_text); | 210 reply = st.error_reply(stanza, "cancel", "internal-server-error", body); |
216 else | 211 else |
217 reply = st.error_reply(stanza, "cancel", "undefined-condition", reply_text); | 212 reply = st.error_reply(stanza, "cancel", "undefined-condition", body); |
218 end | 213 end |
219 end | 214 end |
220 | 215 |
221 if receipt then | 216 if receipt then |
222 reply:add_direct_child(receipt); | 217 reply:add_direct_child(receipt); |