mod_component_http/mod_component_http.lua
author Matthew Wild <mwild1@gmail.com>
Fri, 23 Sep 2022 22:41:15 +0100
changeset 5058 62480053c87b
parent 2999 032589c801d7
permissions -rw-r--r--
mod_cloud_notify_encrypted: Additional debug logging when enabling/skipping
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2954
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     1
local http = require "net.http";
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     2
local json = require "util.json";
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     3
local st = require "util.stanza";
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     4
local xml = require "util.xml";
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     5
local unpack = rawget(_G, "unpack") or table.unpack;
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     6
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     7
local url = module:get_option_string("component_post_url");
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     8
assert(url, "Missing required config option 'component_post_url'");
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     9
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    10
local stanza_kinds = module:get_option_set("post_stanza_types", { "message" });
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    11
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    12
local http_error_map = {
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    13
	[0]   = { "cancel", "remote-server-timeout", "Connection failure" };
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    14
	-- 4xx
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    15
	[400] = { "modify", "bad-request" };
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    16
	[401] = { "auth", "not-authorized" };
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    17
	[402] = { "auth", "forbidden", "Payment required" };
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    18
	[403] = { "auth", "forbidden" };
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    19
	[404] = { "cancel", "item-not-found" };
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    20
	[410] = { "cancel", "gone" };
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    21
	-- 5xx
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    22
	[500] = { "cancel", "internal-server-error" };
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    23
	[501] = { "cancel", "feature-not-implemented" };
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    24
	[502] = { "cancel", "remote-server-timeout", "Bad gateway" };
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    25
	[503] = { "wait", "remote-server-timeout", "Service temporarily unavailable" };
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    26
	[504] = { "wait", "remote-server-timeout", "Gateway timeout" };
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    27
}
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    28
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    29
local function error_reply(stanza, code)
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    30
	local error = http_error_map[code] or { "cancel", "service-unavailable" };
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    31
	return st.error_reply(stanza, unpack(error, 1, 3));
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    32
end
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    33
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    34
function handle_stanza(event)
2962
13acce68a89c mod_component_http: Fix to use module:send() instead of origin.send() (thanks Wiktor)
Matthew Wild <mwild1@gmail.com>
parents: 2956
diff changeset
    35
	local stanza = event.stanza;
2954
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    36
	local request_body = json.encode({
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    37
		to = stanza.attr.to;
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    38
		from = stanza.attr.from;
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    39
		kind = stanza.name;
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    40
		body = stanza.name == "message" and stanza:get_child_text("body") or nil;
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    41
		stanza = tostring(stanza);
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    42
	});
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    43
	http.request(url, {
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    44
		body = request_body;
2999
032589c801d7 mod_component_http: Fix parameter order, see Prosody trunk e2919978673e for more info
Matthew Wild <mwild1@gmail.com>
parents: 2962
diff changeset
    45
	}, function (response_text, code, response)
2956
e8462d6dbc6d mod_component_http: Fix some [luacheck] warnings
Matthew Wild <mwild1@gmail.com>
parents: 2954
diff changeset
    46
		if stanza.attr.type == "error" then return; end -- Avoid error loops, don't reply to error stanzas
2954
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    47
		if code == 200 and response_text and response.headers["content-type"] == "application/json" then
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    48
			local response_data = json.decode(response_text);
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    49
			if response_data.stanza then
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    50
				local reply_stanza = xml.parse(response_data.stanza);
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    51
				if reply_stanza then
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    52
					reply_stanza.attr.from, reply_stanza.attr.to = stanza.attr.to, stanza.attr.from;
2962
13acce68a89c mod_component_http: Fix to use module:send() instead of origin.send() (thanks Wiktor)
Matthew Wild <mwild1@gmail.com>
parents: 2956
diff changeset
    53
					module:send(reply_stanza);
2954
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    54
				else
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    55
					module:log("warn", "Unable to parse reply stanza");
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    56
				end
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    57
			else
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    58
				local stanza_kind = response_data.kind or "message";
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    59
				local to = response_data.to or stanza.attr.from;
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    60
				local from = response_data.from or stanza.attr.to;
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    61
				local reply_stanza = st.stanza(stanza_kind, {
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    62
					to = to, from = from;
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    63
					type = response_data.type or (stanza_kind == "message" and "chat") or nil;
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    64
				});
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    65
				if stanza_kind == "message" and response_data.body then
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    66
					reply_stanza:tag("body"):text(tostring(response_data.body)):up();
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    67
				end
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    68
				module:log("debug", "Sending %s", tostring(reply_stanza));
2962
13acce68a89c mod_component_http: Fix to use module:send() instead of origin.send() (thanks Wiktor)
Matthew Wild <mwild1@gmail.com>
parents: 2956
diff changeset
    69
				module:send(reply_stanza);
2954
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    70
			end
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    71
		elseif code >= 200 and code <= 299 then
2962
13acce68a89c mod_component_http: Fix to use module:send() instead of origin.send() (thanks Wiktor)
Matthew Wild <mwild1@gmail.com>
parents: 2956
diff changeset
    72
			return;
2954
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    73
		else
2962
13acce68a89c mod_component_http: Fix to use module:send() instead of origin.send() (thanks Wiktor)
Matthew Wild <mwild1@gmail.com>
parents: 2956
diff changeset
    74
			module:send(error_reply(stanza, code));
2954
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    75
		end
2962
13acce68a89c mod_component_http: Fix to use module:send() instead of origin.send() (thanks Wiktor)
Matthew Wild <mwild1@gmail.com>
parents: 2956
diff changeset
    76
		return true;
2954
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    77
	end);
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    78
	return true;
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    79
end
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    80
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    81
for stanza_kind in stanza_kinds do
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    82
	for _, jid_type in ipairs({ "host", "bare", "full" }) do
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    83
		module:hook(stanza_kind.."/"..jid_type, handle_stanza);
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    84
	end
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    85
end
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    86
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    87
-- Simple handler for an always-online JID that allows everyone to subscribe to presence
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    88
local function default_presence_handler(event)
2956
e8462d6dbc6d mod_component_http: Fix some [luacheck] warnings
Matthew Wild <mwild1@gmail.com>
parents: 2954
diff changeset
    89
	local stanza = event.stanza;
2954
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    90
	module:log("debug", "Handling %s", tostring(stanza));
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    91
	if stanza.attr.type == "probe" then
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    92
		module:send(st.presence({ to = stanza.attr.from, from = stanza.attr.to.."/default" }));
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    93
	elseif stanza.attr.type == "subscribe" then
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    94
		module:send(st.presence({ type = "subscribed", to = stanza.attr.from, from = stanza.attr.to.."/default" }));
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    95
		module:send(st.presence({ to = stanza.attr.from, from = stanza.attr.to.."/default" }));
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    96
	elseif stanza.attr.type == "unsubscribe" then
2956
e8462d6dbc6d mod_component_http: Fix some [luacheck] warnings
Matthew Wild <mwild1@gmail.com>
parents: 2954
diff changeset
    97
		module:send(st.presence({ type = "unavailable", to = stanza.attr.from, from = stanza.attr.to.."/default" }));
2954
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    98
	end
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    99
	return true;
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   100
end
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   101
18e6d437003f mod_component_http: Allow implementing a component over HTTP
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   102
module:hook("presence/bare", default_presence_handler, -1);