Diff

mod_rest/mod_rest.lua @ 4477:8df6cc648963

mod_rest: Add more REST-looking way to send stanzas Example: POST /rest/message/chat/juliet@example.net { body: "Hello" } Becomes equivalent to POST /rest { kind: "message", type: "chat", to: "juliet@example.net", body: "Hello" } Sending messages as plain/text also becomes more convenient. IQ stazas are still weird, but we'll do something special for those.
author Kim Alvefur <zash@zash.se>
date Sun, 28 Feb 2021 19:25:45 +0100
parent 4250:8b489203e4d3
child 4478:7ab0c423688a
line wrap: on
line diff
--- a/mod_rest/mod_rest.lua	Sun Feb 28 18:55:18 2021 +0100
+++ b/mod_rest/mod_rest.lua	Sun Feb 28 19:25:45 2021 +0100
@@ -59,7 +59,19 @@
 	return nil;
 end
 
-local function parse(mimetype, data)
+-- (table, string) -> table
+local function amend_from_path(data, path)
+	local st_kind, st_type, st_to = path:match("^([mpi]%w+)/(%w+)/(.*)$");
+	if not st_kind then return; end
+	data.kind = st_kind;
+	data.type = st_type;
+	if st_to and st_to ~= "" then
+		data.to = st_to;
+	end
+	return data;
+end
+
+local function parse(mimetype, data, path) --> Stanza, error enum
 	mimetype = mimetype and mimetype:match("^[^; ]*");
 	if mimetype == "application/xmpp+xml" then
 		return xml.parse(data);
@@ -68,6 +80,7 @@
 		if not parsed then
 			return parsed, err;
 		end
+		if path and not amend_from_path(parsed, path) then return nil, "invalid-path"; end
 		return jsonmap.json2st(parsed);
 	elseif mimetype == "application/cbor" and have_cbor then
 		local parsed, err = cbor.decode(data);
@@ -83,9 +96,22 @@
 		for i = #parsed, 1, -1 do
 			parsed[i] = nil;
 		end
+		if path and not amend_from_path(parsed, path) then return nil, "invalid-path"; end
 		return jsonmap.json2st(parsed);
 	elseif mimetype == "text/plain" then
-		return st.message({ type = "chat" }, data);
+		if not path then
+			return st.message({ type = "chat" }, data);
+		end
+		local parsed = {};
+		if not amend_from_path(parsed, path) then return nil, "invalid-path"; end
+		if parsed.kind == "message" then
+			parsed.body = data;
+		elseif parsed.kind == "presence" then
+			parsed.show = data;
+		else
+			return nil, "invalid-path";
+		end
+		return jsonmap.json2st(parsed);
 	end
 	return nil, "unknown-payload-type";
 end
@@ -162,7 +188,7 @@
 	mediatype = { code = 415, condition = "bad-format", text = "Unsupported media type" },
 });
 
-local function handle_post(event)
+local function handle_post(event, path)
 	local request, response = event.request, event.response;
 	local from;
 	local origin;
@@ -177,7 +203,7 @@
 		end
 		from = jid.join(origin.username, origin.host, origin.resource);
 	end
-	local payload, err = parse(request.headers.content_type, request.body);
+	local payload, err = parse(request.headers.content_type, request.body, path);
 	if not payload then
 		-- parse fail
 		local ctx = { error = err, type = request.headers.content_type, data = request.body, };
@@ -267,6 +293,7 @@
 module:provides("http", {
 		route = {
 			POST = handle_post;
+			["POST /*"] = handle_post;
 		};
 	});