1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
-- Prosody IM
-- Copyright (C) 2008-2012 Matthew Wild
-- Copyright (C) 2008-2012 Waqas Hussain
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--
module:set_global();
module:depends("http_errors");
local moduleapi = require "core.moduleapi";
local url_parse = require "socket.url".parse;
local server = require "net.http.server";
server.set_default_host(module:get_option_string("http_default_host"));
local function normalize_path(path)
if path:sub(-1,-1) == "/" then path = path:sub(1, -2); end
if path:sub(1,1) ~= "/" then path = "/"..path; end
return path;
end
local function get_http_event(host, app_path, key)
local method, path = key:match("^(%S+)%s+(.+)$");
if not method then -- No path specified, default to "" (base path)
method, path = key, "";
end
if method:sub(1,1) == "/" then
return nil;
end
return method:upper().." "..host..app_path..path;
end
local function get_base_path(host_module, app_name, default_app_path)
return normalize_path(host_module:get_option("http_paths", {})[app_name] -- Host
or module:get_option("http_paths", {})[app_name] -- Global
or default_app_path); -- Default
end
-- Helper to deduce a module's external URL
function moduleapi.http_url(module, app_name, default_path)
app_name = app_name or (module.name:gsub("^http_", ""));
local ext = url_parse(module:get_option_string("http_external_url")) or {};
local services = portmanager.get_active_services();
local http_services = services:get("https") or services:get("http") or {};
for interface, ports in pairs(http_services) do
for port, services in pairs(ports) do
local path = get_base_path(module, app_name, default_path or "/"..app_name);
port = tonumber(ext.port) or port or 80;
if port == 80 then port = ""; else port = ":"..port; end
return (ext.scheme or services[1].service.name).."://"
..(ext.host or module.host)..port
..normalize_path(ext.path or "/")..(path:sub(2));
end
end
end
function module.add_host(module)
local host = module.host;
local apps = {};
module.environment.apps = apps;
local function http_app_added(event)
local app_name = event.item.name;
local default_app_path = event.item.default_path or "/"..app_name;
local app_path = get_base_path(module, app_name, default_app_path);
if not app_name then
-- TODO: Link to docs
module:log("error", "HTTP app has no 'name', add one or use module:provides('http', app)");
return;
end
apps[app_name] = apps[app_name] or {};
local app_handlers = apps[app_name];
for key, handler in pairs(event.item.route or {}) do
local event_name = get_http_event(host, app_path, key);
if event_name then
if type(handler) ~= "function" then
local data = handler;
handler = function () return data; end
elseif event_name:sub(-2, -1) == "/*" then
local base_path = event_name:match("/(.+)/*$");
local _handler = handler;
handler = function (event)
local path = event.request.path:sub(#base_path+1);
return _handler(event, path);
end;
end
if not app_handlers[event_name] then
app_handlers[event_name] = handler;
module:hook_object_event(server, event_name, handler);
else
module:log("warn", "App %s added handler twice for '%s', ignoring", app_name, event_name);
end
else
module:log("error", "Invalid route in %s, %q. See http://prosody.im/doc/developers/http#routes", app_name, key);
end
end
end
local function http_app_removed(event)
local app_handlers = apps[event.item.name];
apps[event.item.name] = nil;
for event, handler in pairs(app_handlers) do
module:unhook_object_event(server, event, handler);
end
end
module:handle_items("http-provider", http_app_added, http_app_removed);
server.add_host(host);
function module.unload()
server.remove_host(host);
end
end
module:add_item("net-provider", {
name = "http";
listener = server.listener;
default_port = 5280;
multiplex = {
pattern = "^[A-Z]";
};
});
module:add_item("net-provider", {
name = "https";
listener = server.listener;
default_port = 5281;
encryption = "ssl";
multiplex = {
pattern = "^[A-Z]";
};
});
|