Mercurial > 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 |
| parents | b0449faca52b |
| children | 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); |
