mod_rest/mod_rest.lua
author Kim Alvefur <zash@zash.se>
Sat, 25 Jan 2020 01:55:23 +0100
changeset 3862 29c39876c4af
parent 3847 c065b7670c89
child 3865 ede3d1724dd1
permissions -rw-r--r--
mod_rest: Ensure iq responses have type result if they're not errors
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
3798
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     1
-- RESTful API
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     2
--
3807
dc2b5a412286 mod_rest: Log sent and received stanzas in style of mod_c2s etc
Kim Alvefur <zash@zash.se>
parents: 3806
diff changeset
     3
-- Copyright (c) 2019-2020 Kim Alvefur
3798
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     4
--
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     5
-- This file is MIT/X11 licensed.
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     6
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     7
local errors = require "util.error";
3799
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
     8
local http = require "net.http";
3798
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     9
local id = require "util.id";
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    10
local jid = require "util.jid";
3817
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    11
local json = require "util.json";
3799
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
    12
local st = require "util.stanza";
3798
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    13
local xml = require "util.xml";
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    14
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    15
local allow_any_source = module:get_host_type() == "component";
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    16
local validate_from_addresses = module:get_option_boolean("validate_from_addresses", true);
3806
f88e07630e4e mod_rest: Add support for simple Bearer token auth
Kim Alvefur <zash@zash.se>
parents: 3805
diff changeset
    17
local secret = assert(module:get_option_string("rest_credentials"), "rest_credentials is a required setting");
f88e07630e4e mod_rest: Add support for simple Bearer token auth
Kim Alvefur <zash@zash.se>
parents: 3805
diff changeset
    18
local auth_type = assert(secret:match("^%S+"), "Format of rest_credentials MUST be like 'Bearer secret'");
f88e07630e4e mod_rest: Add support for simple Bearer token auth
Kim Alvefur <zash@zash.se>
parents: 3805
diff changeset
    19
assert(auth_type == "Bearer", "Only 'Bearer' is supported in rest_credentials");
f88e07630e4e mod_rest: Add support for simple Bearer token auth
Kim Alvefur <zash@zash.se>
parents: 3805
diff changeset
    20
3817
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    21
local jsonmap = module:require"jsonmap";
3806
f88e07630e4e mod_rest: Add support for simple Bearer token auth
Kim Alvefur <zash@zash.se>
parents: 3805
diff changeset
    22
-- Bearer token
f88e07630e4e mod_rest: Add support for simple Bearer token auth
Kim Alvefur <zash@zash.se>
parents: 3805
diff changeset
    23
local function check_credentials(request)
f88e07630e4e mod_rest: Add support for simple Bearer token auth
Kim Alvefur <zash@zash.se>
parents: 3805
diff changeset
    24
	return request.headers.authorization == secret;
f88e07630e4e mod_rest: Add support for simple Bearer token auth
Kim Alvefur <zash@zash.se>
parents: 3805
diff changeset
    25
end
3798
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    26
3814
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
    27
local function parse(mimetype, data)
3829
802087d3155a mod_rest: Fix traceback on missing content-type header
Kim Alvefur <zash@zash.se>
parents: 3828
diff changeset
    28
	mimetype = mimetype and mimetype:match("^[^; ]*");
3814
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
    29
	if mimetype == "application/xmpp+xml" then
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
    30
		return xml.parse(data);
3817
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    31
	elseif mimetype == "application/json" then
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    32
		local parsed, err = json.decode(data);
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    33
		if not parsed then
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    34
			return parsed, err;
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    35
		end
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    36
		return jsonmap.json2st(parsed);
3814
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
    37
	elseif mimetype == "text/plain" then
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
    38
		return st.message({ type = "chat" }, data);
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
    39
	end
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
    40
	return nil, "unknown-payload-type";
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
    41
end
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
    42
3817
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    43
local supported_types = { "application/xmpp+xml", "application/json" };
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    44
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    45
local function decide_type(accept)
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    46
	-- assumes the accept header is sorted
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    47
	local ret = supported_types[1];
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    48
	for i = 2, #supported_types do
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    49
		if (accept:find(supported_types[i], 1, true) or 1000) < (accept:find(ret, 1, true) or 1000) then
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    50
			ret = supported_types[i];
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    51
		end
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    52
	end
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    53
	return ret;
3815
eb25110696cd mod_rest: Factor out response content type selection
Kim Alvefur <zash@zash.se>
parents: 3814
diff changeset
    54
end
eb25110696cd mod_rest: Factor out response content type selection
Kim Alvefur <zash@zash.se>
parents: 3814
diff changeset
    55
3816
f027b8b1e794 mod_rest: Factor out serialization of outgoing stanzas
Kim Alvefur <zash@zash.se>
parents: 3815
diff changeset
    56
local function encode(type, s)
3817
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    57
	if type == "application/json" then
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    58
		return json.encode(jsonmap.st2json(s));
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    59
	elseif type == "text/plain" then
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    60
		return s:get_child_text("body") or "";
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
    61
	end
3816
f027b8b1e794 mod_rest: Factor out serialization of outgoing stanzas
Kim Alvefur <zash@zash.se>
parents: 3815
diff changeset
    62
	return tostring(s);
f027b8b1e794 mod_rest: Factor out serialization of outgoing stanzas
Kim Alvefur <zash@zash.se>
parents: 3815
diff changeset
    63
end
f027b8b1e794 mod_rest: Factor out serialization of outgoing stanzas
Kim Alvefur <zash@zash.se>
parents: 3815
diff changeset
    64
3798
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    65
local function handle_post(event)
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    66
	local request, response = event.request, event.response;
3806
f88e07630e4e mod_rest: Add support for simple Bearer token auth
Kim Alvefur <zash@zash.se>
parents: 3805
diff changeset
    67
	if not request.headers.authorization then
f88e07630e4e mod_rest: Add support for simple Bearer token auth
Kim Alvefur <zash@zash.se>
parents: 3805
diff changeset
    68
		response.headers.www_authenticate = ("%s realm=%q"):format(auth_type, module.host.."/"..module.name);
f88e07630e4e mod_rest: Add support for simple Bearer token auth
Kim Alvefur <zash@zash.se>
parents: 3805
diff changeset
    69
		return 401;
f88e07630e4e mod_rest: Add support for simple Bearer token auth
Kim Alvefur <zash@zash.se>
parents: 3805
diff changeset
    70
	elseif not check_credentials(request) then
f88e07630e4e mod_rest: Add support for simple Bearer token auth
Kim Alvefur <zash@zash.se>
parents: 3805
diff changeset
    71
		return 401;
f88e07630e4e mod_rest: Add support for simple Bearer token auth
Kim Alvefur <zash@zash.se>
parents: 3805
diff changeset
    72
	end
3814
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
    73
	local payload, err = parse(request.headers.content_type, request.body);
3798
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    74
	if not payload then
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    75
		-- parse fail
3847
c065b7670c89 mod_rest: Return a friendly message for parse errors
Kim Alvefur <zash@zash.se>
parents: 3846
diff changeset
    76
		return errors.new({ code = 400, text = "Failed to parse payload" }, { error = err, type = request.headers.content_type, data = request.body });
3798
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    77
	end
3805
d59fb4dcf100 mod_rest: Verify that @xmlns is left empty
Kim Alvefur <zash@zash.se>
parents: 3803
diff changeset
    78
	if payload.attr.xmlns then
3808
d74509cd35fb mod_rest: Use HTTP status 422 for stanza problems
Kim Alvefur <zash@zash.se>
parents: 3807
diff changeset
    79
		return errors.new({ code = 422, text = "'xmlns' attribute must be empty" });
3809
683b06c0348f mod_rest: Validate stanza kind earlier
Kim Alvefur <zash@zash.se>
parents: 3808
diff changeset
    80
	elseif payload.name ~= "message" and payload.name ~= "presence" and payload.name ~= "iq" then
683b06c0348f mod_rest: Validate stanza kind earlier
Kim Alvefur <zash@zash.se>
parents: 3808
diff changeset
    81
		return errors.new({ code = 422, text = "Invalid stanza, must be 'message', 'presence' or 'iq'." });
3805
d59fb4dcf100 mod_rest: Verify that @xmlns is left empty
Kim Alvefur <zash@zash.se>
parents: 3803
diff changeset
    82
	end
3798
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    83
	local to = jid.prep(payload.attr.to);
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    84
	if not to then
3808
d74509cd35fb mod_rest: Use HTTP status 422 for stanza problems
Kim Alvefur <zash@zash.se>
parents: 3807
diff changeset
    85
		return errors.new({ code = 422, text = "Invalid destination JID" });
3798
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    86
	end
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    87
	local from = module.host;
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    88
	if allow_any_source and payload.attr.from then
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    89
		from = jid.prep(payload.attr.from);
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    90
		if not from then
3808
d74509cd35fb mod_rest: Use HTTP status 422 for stanza problems
Kim Alvefur <zash@zash.se>
parents: 3807
diff changeset
    91
			return errors.new({ code = 422, text = "Invalid source JID" });
3798
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    92
		end
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    93
		if validate_from_addresses and not jid.compare(from, module.host) then
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    94
			return errors.new({ code = 403, text = "Source JID must belong to current host" });
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    95
		end
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    96
	end
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    97
	payload.attr = {
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    98
		from = from,
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    99
		to = to,
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   100
		id = payload.attr.id or id.medium(),
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   101
		type = payload.attr.type,
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   102
		["xml:lang"] = payload.attr["xml:lang"],
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   103
	};
3807
dc2b5a412286 mod_rest: Log sent and received stanzas in style of mod_c2s etc
Kim Alvefur <zash@zash.se>
parents: 3806
diff changeset
   104
	module:log("debug", "Received[rest]: %s", payload:top_tag());
3820
8473fd2d09c1 mod_rest: Default to replying with same type as request
Kim Alvefur <zash@zash.se>
parents: 3819
diff changeset
   105
	local send_type = decide_type((request.headers.accept or "") ..",".. request.headers.content_type)
3798
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   106
	if payload.name == "iq" then
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   107
		if payload.attr.type ~= "get" and payload.attr.type ~= "set" then
3808
d74509cd35fb mod_rest: Use HTTP status 422 for stanza problems
Kim Alvefur <zash@zash.se>
parents: 3807
diff changeset
   108
			return errors.new({ code = 422, text = "'iq' stanza must be of type 'get' or 'set'" });
3836
0d4146cf9fbc mod_rest: Enforce single child policy for outgoing it stanzas
Kim Alvefur <zash@zash.se>
parents: 3829
diff changeset
   109
		elseif #payload.tags ~= 1 then
0d4146cf9fbc mod_rest: Enforce single child policy for outgoing it stanzas
Kim Alvefur <zash@zash.se>
parents: 3829
diff changeset
   110
			return errors.new({ code = 422, text = "'iq' stanza must have exactly one child tag" });
3798
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   111
		end
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   112
		return module:send_iq(payload):next(
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   113
			function (result)
3807
dc2b5a412286 mod_rest: Log sent and received stanzas in style of mod_c2s etc
Kim Alvefur <zash@zash.se>
parents: 3806
diff changeset
   114
				module:log("debug", "Sending[rest]: %s", result.stanza:top_tag());
3815
eb25110696cd mod_rest: Factor out response content type selection
Kim Alvefur <zash@zash.se>
parents: 3814
diff changeset
   115
				response.headers.content_type = send_type;
3816
f027b8b1e794 mod_rest: Factor out serialization of outgoing stanzas
Kim Alvefur <zash@zash.se>
parents: 3815
diff changeset
   116
				return encode(send_type, result.stanza);
3798
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   117
			end,
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   118
			function (error)
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   119
				if error.context.stanza then
3815
eb25110696cd mod_rest: Factor out response content type selection
Kim Alvefur <zash@zash.se>
parents: 3814
diff changeset
   120
					response.headers.content_type = send_type;
3807
dc2b5a412286 mod_rest: Log sent and received stanzas in style of mod_c2s etc
Kim Alvefur <zash@zash.se>
parents: 3806
diff changeset
   121
					module:log("debug", "Sending[rest]: %s", error.context.stanza:top_tag());
3816
f027b8b1e794 mod_rest: Factor out serialization of outgoing stanzas
Kim Alvefur <zash@zash.se>
parents: 3815
diff changeset
   122
					return encode(send_type, error.context.stanza);
3798
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   123
				else
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   124
					return error;
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   125
				end
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   126
			end);
3809
683b06c0348f mod_rest: Validate stanza kind earlier
Kim Alvefur <zash@zash.se>
parents: 3808
diff changeset
   127
	else
3800
d1ad10b76b00 mod_rest: Catch one (1) reply to a POST-ed stanza from an internal source
Kim Alvefur <zash@zash.se>
parents: 3799
diff changeset
   128
		local origin = {};
d1ad10b76b00 mod_rest: Catch one (1) reply to a POST-ed stanza from an internal source
Kim Alvefur <zash@zash.se>
parents: 3799
diff changeset
   129
		function origin.send(stanza)
3807
dc2b5a412286 mod_rest: Log sent and received stanzas in style of mod_c2s etc
Kim Alvefur <zash@zash.se>
parents: 3806
diff changeset
   130
			module:log("debug", "Sending[rest]: %s", stanza:top_tag());
3815
eb25110696cd mod_rest: Factor out response content type selection
Kim Alvefur <zash@zash.se>
parents: 3814
diff changeset
   131
			response.headers.content_type = send_type;
3816
f027b8b1e794 mod_rest: Factor out serialization of outgoing stanzas
Kim Alvefur <zash@zash.se>
parents: 3815
diff changeset
   132
			response:send(encode(send_type, stanza));
3800
d1ad10b76b00 mod_rest: Catch one (1) reply to a POST-ed stanza from an internal source
Kim Alvefur <zash@zash.se>
parents: 3799
diff changeset
   133
			return true;
d1ad10b76b00 mod_rest: Catch one (1) reply to a POST-ed stanza from an internal source
Kim Alvefur <zash@zash.se>
parents: 3799
diff changeset
   134
		end
3818
0dede5b0ab27 mod_rest: Fix return status when sending and forgetting
Kim Alvefur <zash@zash.se>
parents: 3817
diff changeset
   135
		module:send(payload, origin);
0dede5b0ab27 mod_rest: Fix return status when sending and forgetting
Kim Alvefur <zash@zash.se>
parents: 3817
diff changeset
   136
		return 202;
3798
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   137
	end
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   138
end
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   139
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   140
-- Handle stanzas submitted via HTTP
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   141
module:depends("http");
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   142
module:provides("http", {
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   143
		route = {
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   144
			POST = handle_post;
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   145
		};
4b258329e6e4 mod_rest: Initial commit of another RESTful API module
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   146
	});
3799
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   147
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   148
-- Forward stanzas from XMPP to HTTP and return any reply
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   149
local rest_url = module:get_option_string("rest_callback_url", nil);
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   150
if rest_url then
3815
eb25110696cd mod_rest: Factor out response content type selection
Kim Alvefur <zash@zash.se>
parents: 3814
diff changeset
   151
	local send_type = module:get_option_string("rest_callback_content_type", "application/xmpp+xml");
3817
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
   152
	if send_type == "json" then
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
   153
		send_type = "application/json";
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
   154
	end
3799
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   155
3801
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   156
	local code2err = {
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   157
		[400] = { condition = "bad-request"; type = "modify" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   158
		[401] = { condition = "not-authorized"; type = "auth" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   159
		[402] = { condition = "not-authorized"; type = "auth" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   160
		[403] = { condition = "forbidden"; type = "auth" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   161
		[404] = { condition = "item-not-found"; type = "cancel" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   162
		[406] = { condition = "not-acceptable"; type = "modify" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   163
		[408] = { condition = "remote-server-timeout"; type = "wait" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   164
		[409] = { condition = "conflict"; type = "cancel" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   165
		[410] = { condition = "gone"; type = "cancel" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   166
		[411] = { condition = "bad-request"; type = "modify" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   167
		[412] = { condition = "bad-request"; type = "modify" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   168
		[413] = { condition = "resource-constraint"; type = "modify" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   169
		[414] = { condition = "resource-constraint"; type = "modify" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   170
		[415] = { condition = "bad-request"; type = "modify" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   171
		[429] = { condition = "resource-constraint"; type = "wait" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   172
		[431] = { condition = "resource-constraint"; type = "wait" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   173
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   174
		[500] = { condition = "internal-server-error"; type = "cancel" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   175
		[501] = { condition = "feature-not-implemented"; type = "modify" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   176
		[502] = { condition = "remote-server-timeout"; type = "wait" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   177
		[503] = { condition = "service-unavailable"; type = "cancel" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   178
		[504] = { condition = "remote-server-timeout"; type = "wait" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   179
		[507] = { condition = "resource-constraint"; type = "wait" };
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   180
	};
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   181
3799
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   182
	local function handle_stanza(event)
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   183
		local stanza, origin = event.stanza, event.origin;
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   184
		local reply_needed = stanza.name == "iq";
3802
9b4fd2553365 mod_rest: Handle receipt requests on message stanzas
Kim Alvefur <zash@zash.se>
parents: 3801
diff changeset
   185
		local receipt;
9b4fd2553365 mod_rest: Handle receipt requests on message stanzas
Kim Alvefur <zash@zash.se>
parents: 3801
diff changeset
   186
3828
a0b8ec44a36b mod_rest: Stanzas of type error don't need a reply
Kim Alvefur <zash@zash.se>
parents: 3825
diff changeset
   187
		if stanza.attr.type == "error" then
a0b8ec44a36b mod_rest: Stanzas of type error don't need a reply
Kim Alvefur <zash@zash.se>
parents: 3825
diff changeset
   188
			reply_needed = false;
a0b8ec44a36b mod_rest: Stanzas of type error don't need a reply
Kim Alvefur <zash@zash.se>
parents: 3825
diff changeset
   189
		end
a0b8ec44a36b mod_rest: Stanzas of type error don't need a reply
Kim Alvefur <zash@zash.se>
parents: 3825
diff changeset
   190
3802
9b4fd2553365 mod_rest: Handle receipt requests on message stanzas
Kim Alvefur <zash@zash.se>
parents: 3801
diff changeset
   191
		if stanza.name == "message" and stanza.attr.id and stanza:get_child("urn:xmpp:receipts", "request") then
9b4fd2553365 mod_rest: Handle receipt requests on message stanzas
Kim Alvefur <zash@zash.se>
parents: 3801
diff changeset
   192
			reply_needed = true;
9b4fd2553365 mod_rest: Handle receipt requests on message stanzas
Kim Alvefur <zash@zash.se>
parents: 3801
diff changeset
   193
			receipt = st.stanza("received", { xmlns = "urn:xmpp:receipts", id = stanza.id });
9b4fd2553365 mod_rest: Handle receipt requests on message stanzas
Kim Alvefur <zash@zash.se>
parents: 3801
diff changeset
   194
		end
3799
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   195
3816
f027b8b1e794 mod_rest: Factor out serialization of outgoing stanzas
Kim Alvefur <zash@zash.se>
parents: 3815
diff changeset
   196
		local request_body = encode(send_type, stanza);
3803
a1f1f703d604 mod_rest: Allow collection of original stanza after sending HTTP request
Kim Alvefur <zash@zash.se>
parents: 3802
diff changeset
   197
a1f1f703d604 mod_rest: Allow collection of original stanza after sending HTTP request
Kim Alvefur <zash@zash.se>
parents: 3802
diff changeset
   198
		-- Keep only the top level element and let the rest be GC'd
a1f1f703d604 mod_rest: Allow collection of original stanza after sending HTTP request
Kim Alvefur <zash@zash.se>
parents: 3802
diff changeset
   199
		stanza = st.clone(stanza, true);
a1f1f703d604 mod_rest: Allow collection of original stanza after sending HTTP request
Kim Alvefur <zash@zash.se>
parents: 3802
diff changeset
   200
3807
dc2b5a412286 mod_rest: Log sent and received stanzas in style of mod_c2s etc
Kim Alvefur <zash@zash.se>
parents: 3806
diff changeset
   201
		module:log("debug", "Sending[rest]: %s", stanza:top_tag());
3799
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   202
		http.request(rest_url, {
3803
a1f1f703d604 mod_rest: Allow collection of original stanza after sending HTTP request
Kim Alvefur <zash@zash.se>
parents: 3802
diff changeset
   203
				body = request_body,
3799
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   204
				headers = {
3815
eb25110696cd mod_rest: Factor out response content type selection
Kim Alvefur <zash@zash.se>
parents: 3814
diff changeset
   205
					["Content-Type"] = send_type,
3799
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   206
					["Content-Language"] = stanza.attr["xml:lang"],
3817
aa1ad69c7c10 mod_rest: Add JSON support
Kim Alvefur <zash@zash.se>
parents: 3816
diff changeset
   207
					Accept = table.concat(supported_types, ", ");
3799
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   208
				},
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   209
			}, function (body, code, response)
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   210
				if (code == 202 or code == 204) and not reply_needed then
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   211
					-- Delivered, no reply
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   212
					return;
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   213
				end
3814
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
   214
				local reply;
3799
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   215
3814
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
   216
				local parsed, err = parse(response.headers["content-type"], body);
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
   217
				if not parsed then
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
   218
					module:log("warn", "Failed parsing data from REST callback: %s, %q", err, body);
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
   219
				elseif parsed.name ~= stanza.name then
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
   220
					module:log("warn", "REST callback responded with the wrong stanza type, got %s but expected %s", parsed.name, stanza.name);
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
   221
				else
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
   222
					parsed.attr = {
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
   223
						from = stanza.attr.to,
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
   224
						to = stanza.attr.from,
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
   225
						id = parsed.attr.id or id.medium();
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
   226
						type = parsed.attr.type,
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
   227
						["xml:lang"] = parsed.attr["xml:lang"],
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
   228
					};
3825
11272a3233ce mod_rest: Fix replying to groupchat messages
Kim Alvefur <zash@zash.se>
parents: 3820
diff changeset
   229
					if parsed.name == "message" and parsed.attr.type == "groupchat" then
11272a3233ce mod_rest: Fix replying to groupchat messages
Kim Alvefur <zash@zash.se>
parents: 3820
diff changeset
   230
						parsed.attr.to = jid.bare(stanza.attr.from);
11272a3233ce mod_rest: Fix replying to groupchat messages
Kim Alvefur <zash@zash.se>
parents: 3820
diff changeset
   231
					end
3862
29c39876c4af mod_rest: Ensure iq responses have type result if they're not errors
Kim Alvefur <zash@zash.se>
parents: 3847
diff changeset
   232
					if not stanza.attr.type and parsed:get_child("error") then
29c39876c4af mod_rest: Ensure iq responses have type result if they're not errors
Kim Alvefur <zash@zash.se>
parents: 3847
diff changeset
   233
						parsed.attr.type = "error";
29c39876c4af mod_rest: Ensure iq responses have type result if they're not errors
Kim Alvefur <zash@zash.se>
parents: 3847
diff changeset
   234
					end
29c39876c4af mod_rest: Ensure iq responses have type result if they're not errors
Kim Alvefur <zash@zash.se>
parents: 3847
diff changeset
   235
					if parsed.attr.type == "error" then
3814
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
   236
						parsed.attr.id = stanza.attr.id;
3862
29c39876c4af mod_rest: Ensure iq responses have type result if they're not errors
Kim Alvefur <zash@zash.se>
parents: 3847
diff changeset
   237
					elseif parsed.name == "iq" then
29c39876c4af mod_rest: Ensure iq responses have type result if they're not errors
Kim Alvefur <zash@zash.se>
parents: 3847
diff changeset
   238
						parsed.attr.id = stanza.attr.id;
29c39876c4af mod_rest: Ensure iq responses have type result if they're not errors
Kim Alvefur <zash@zash.se>
parents: 3847
diff changeset
   239
						parsed.attr.type = "result";
3799
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   240
					end
3814
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
   241
					reply = parsed;
3799
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   242
				end
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   243
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   244
				if not reply then
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   245
					local code_hundreds = code - (code % 100);
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   246
					if code_hundreds == 200 then
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   247
						reply = st.reply(stanza);
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   248
						if stanza.name ~= "iq" then
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   249
							reply.attr.id = id.medium();
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   250
						end
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   251
						-- TODO presence/status=body ?
3801
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   252
					elseif code2err[code] then
ed5d7586a61e mod_rest: Map various HTTP status codes to XMPP stanza errors
Kim Alvefur <zash@zash.se>
parents: 3800
diff changeset
   253
						reply = st.error_reply(stanza, errors.new(code, nil, code2err));
3799
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   254
					elseif code_hundreds == 400 then
3814
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
   255
						reply = st.error_reply(stanza, "modify", "bad-request", body);
3799
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   256
					elseif code_hundreds == 500 then
3814
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
   257
						reply = st.error_reply(stanza, "cancel", "internal-server-error", body);
3799
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   258
					else
3814
91ff86fc3b20 mod_rest: Factor out payload parsing
Kim Alvefur <zash@zash.se>
parents: 3811
diff changeset
   259
						reply = st.error_reply(stanza, "cancel", "undefined-condition", body);
3799
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   260
					end
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   261
				end
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   262
3802
9b4fd2553365 mod_rest: Handle receipt requests on message stanzas
Kim Alvefur <zash@zash.se>
parents: 3801
diff changeset
   263
				if receipt then
9b4fd2553365 mod_rest: Handle receipt requests on message stanzas
Kim Alvefur <zash@zash.se>
parents: 3801
diff changeset
   264
					reply:add_direct_child(receipt);
9b4fd2553365 mod_rest: Handle receipt requests on message stanzas
Kim Alvefur <zash@zash.se>
parents: 3801
diff changeset
   265
				end
9b4fd2553365 mod_rest: Handle receipt requests on message stanzas
Kim Alvefur <zash@zash.se>
parents: 3801
diff changeset
   266
3807
dc2b5a412286 mod_rest: Log sent and received stanzas in style of mod_c2s etc
Kim Alvefur <zash@zash.se>
parents: 3806
diff changeset
   267
				module:log("debug", "Received[rest]: %s", reply:top_tag());
dc2b5a412286 mod_rest: Log sent and received stanzas in style of mod_c2s etc
Kim Alvefur <zash@zash.se>
parents: 3806
diff changeset
   268
3799
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   269
				origin.send(reply);
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   270
			end);
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   271
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   272
		return true;
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   273
	end
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   274
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   275
	if module:get_host_type() == "component" then
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   276
		module:hook("iq/bare", handle_stanza, -1);
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   277
		module:hook("message/bare", handle_stanza, -1);
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   278
		module:hook("presence/bare", handle_stanza, -1);
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   279
		module:hook("iq/full", handle_stanza, -1);
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   280
		module:hook("message/full", handle_stanza, -1);
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   281
		module:hook("presence/full", handle_stanza, -1);
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   282
		module:hook("iq/host", handle_stanza, -1);
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   283
		module:hook("message/host", handle_stanza, -1);
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   284
		module:hook("presence/host", handle_stanza, -1);
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   285
	else
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   286
		-- Don't override everything on normal VirtualHosts
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   287
		module:hook("iq/host", handle_stanza, -1);
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   288
		module:hook("message/host", handle_stanza, -1);
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   289
		module:hook("presence/host", handle_stanza, -1);
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   290
	end
f51308fcba83 mod_rest: Allow specifying a webhook/callback to handle incoming stanzas
Kim Alvefur <zash@zash.se>
parents: 3798
diff changeset
   291
end
3846
501c7edc8c37 mod_rest: Encode errors as JSON
Kim Alvefur <zash@zash.se>
parents: 3836
diff changeset
   292
501c7edc8c37 mod_rest: Encode errors as JSON
Kim Alvefur <zash@zash.se>
parents: 3836
diff changeset
   293
local http_server = require "net.http.server";
501c7edc8c37 mod_rest: Encode errors as JSON
Kim Alvefur <zash@zash.se>
parents: 3836
diff changeset
   294
module:hook_object_event(http_server, "http-error", function (event)
501c7edc8c37 mod_rest: Encode errors as JSON
Kim Alvefur <zash@zash.se>
parents: 3836
diff changeset
   295
	local request, response = event.request, event.response;
501c7edc8c37 mod_rest: Encode errors as JSON
Kim Alvefur <zash@zash.se>
parents: 3836
diff changeset
   296
	if true or decide_type(request and request.headers.accept or "") == "application/json" then
501c7edc8c37 mod_rest: Encode errors as JSON
Kim Alvefur <zash@zash.se>
parents: 3836
diff changeset
   297
		if response then
501c7edc8c37 mod_rest: Encode errors as JSON
Kim Alvefur <zash@zash.se>
parents: 3836
diff changeset
   298
			response.headers.content_type = "application/json";
501c7edc8c37 mod_rest: Encode errors as JSON
Kim Alvefur <zash@zash.se>
parents: 3836
diff changeset
   299
		end
501c7edc8c37 mod_rest: Encode errors as JSON
Kim Alvefur <zash@zash.se>
parents: 3836
diff changeset
   300
		return json.encode({
501c7edc8c37 mod_rest: Encode errors as JSON
Kim Alvefur <zash@zash.se>
parents: 3836
diff changeset
   301
				type = "error",
501c7edc8c37 mod_rest: Encode errors as JSON
Kim Alvefur <zash@zash.se>
parents: 3836
diff changeset
   302
				error = event.error,
501c7edc8c37 mod_rest: Encode errors as JSON
Kim Alvefur <zash@zash.se>
parents: 3836
diff changeset
   303
				code = event.code,
501c7edc8c37 mod_rest: Encode errors as JSON
Kim Alvefur <zash@zash.se>
parents: 3836
diff changeset
   304
			});
501c7edc8c37 mod_rest: Encode errors as JSON
Kim Alvefur <zash@zash.se>
parents: 3836
diff changeset
   305
	end
501c7edc8c37 mod_rest: Encode errors as JSON
Kim Alvefur <zash@zash.se>
parents: 3836
diff changeset
   306
end, 10);