Mercurial > prosody-hg
comparison plugins/mod_http.lua @ 10411:db2a06b9ff98
Merge 0.11->trunk
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Sat, 16 Nov 2019 16:52:31 +0100 |
| parents | abfc05495d8b |
| children | 5ce6cbb5ce6a |
comparison
equal
deleted
inserted
replaced
| 10410:659b577f280c | 10411:db2a06b9ff98 |
|---|---|
| 5 -- This project is MIT/X11 licensed. Please see the | 5 -- This project is MIT/X11 licensed. Please see the |
| 6 -- COPYING file in the source package for more information. | 6 -- COPYING file in the source package for more information. |
| 7 -- | 7 -- |
| 8 | 8 |
| 9 module:set_global(); | 9 module:set_global(); |
| 10 module:depends("http_errors"); | 10 pcall(function () |
| 11 module:depends("http_errors"); | |
| 12 end); | |
| 11 | 13 |
| 12 local portmanager = require "core.portmanager"; | 14 local portmanager = require "core.portmanager"; |
| 13 local moduleapi = require "core.moduleapi"; | 15 local moduleapi = require "core.moduleapi"; |
| 14 local url_parse = require "socket.url".parse; | 16 local url_parse = require "socket.url".parse; |
| 15 local url_build = require "socket.url".build; | 17 local url_build = require "socket.url".build; |
| 16 local normalize_path = require "util.http".normalize_path; | 18 local normalize_path = require "util.http".normalize_path; |
| 19 local set = require "util.set"; | |
| 17 | 20 |
| 18 local server = require "net.http.server"; | 21 local server = require "net.http.server"; |
| 19 | 22 |
| 20 server.set_default_host(module:get_option_string("http_default_host")); | 23 server.set_default_host(module:get_option_string("http_default_host")); |
| 21 | 24 |
| 22 server.set_option("body_size_limit", module:get_option_number("http_max_content_size")); | 25 server.set_option("body_size_limit", module:get_option_number("http_max_content_size")); |
| 23 server.set_option("buffer_size_limit", module:get_option_number("http_max_buffer_size")); | 26 server.set_option("buffer_size_limit", module:get_option_number("http_max_buffer_size")); |
| 27 | |
| 28 -- CORS settigs | |
| 29 local opt_methods = module:get_option_set("access_control_allow_methods", { "GET", "OPTIONS" }); | |
| 30 local opt_headers = module:get_option_set("access_control_allow_headers", { "Content-Type" }); | |
| 31 local opt_credentials = module:get_option_boolean("access_control_allow_credentials", false); | |
| 32 local opt_max_age = module:get_option_number("access_control_max_age", 2 * 60 * 60); | |
| 24 | 33 |
| 25 local function get_http_event(host, app_path, key) | 34 local function get_http_event(host, app_path, key) |
| 26 local method, path = key:match("^(%S+)%s+(.+)$"); | 35 local method, path = key:match("^(%S+)%s+(.+)$"); |
| 27 if not method then -- No path specified, default to "" (base path) | 36 if not method then -- No path specified, default to "" (base path) |
| 28 method, path = key, ""; | 37 method, path = key, ""; |
| 81 end | 90 end |
| 82 module:log("warn", "No http ports enabled, can't generate an external URL"); | 91 module:log("warn", "No http ports enabled, can't generate an external URL"); |
| 83 return "http://disabled.invalid/"; | 92 return "http://disabled.invalid/"; |
| 84 end | 93 end |
| 85 | 94 |
| 95 local function apply_cors_headers(response, methods, headers, max_age, allow_credentials, origin) | |
| 96 response.headers.access_control_allow_methods = tostring(methods); | |
| 97 response.headers.access_control_allow_headers = tostring(headers); | |
| 98 response.headers.access_control_max_age = tostring(max_age) | |
| 99 response.headers.access_control_allow_origin = origin or "*"; | |
| 100 if allow_credentials then | |
| 101 response.headers.access_control_allow_credentials = "true"; | |
| 102 end | |
| 103 end | |
| 104 | |
| 86 function module.add_host(module) | 105 function module.add_host(module) |
| 87 local host = module.host; | 106 local host = module.host; |
| 88 if host ~= "*" then | 107 if host ~= "*" then |
| 89 host = module:get_option_string("http_host", host); | 108 host = module:get_option_string("http_host", host); |
| 90 end | 109 end |
| 99 module:log("error", "HTTP app has no 'name', add one or use module:provides('http', app)"); | 118 module:log("error", "HTTP app has no 'name', add one or use module:provides('http', app)"); |
| 100 return; | 119 return; |
| 101 end | 120 end |
| 102 apps[app_name] = apps[app_name] or {}; | 121 apps[app_name] = apps[app_name] or {}; |
| 103 local app_handlers = apps[app_name]; | 122 local app_handlers = apps[app_name]; |
| 123 | |
| 124 local app_methods = opt_methods; | |
| 125 | |
| 126 local function cors_handler(event_data) | |
| 127 local request, response = event_data.request, event_data.response; | |
| 128 apply_cors_headers(response, app_methods, opt_headers, opt_max_age, opt_credentials, request.headers.origin); | |
| 129 end | |
| 130 | |
| 131 local function options_handler(event_data) | |
| 132 cors_handler(event_data); | |
| 133 return ""; | |
| 134 end | |
| 135 | |
| 104 for key, handler in pairs(event.item.route or {}) do | 136 for key, handler in pairs(event.item.route or {}) do |
| 105 local event_name = get_http_event(host, app_path, key); | 137 local event_name = get_http_event(host, app_path, key); |
| 106 if event_name then | 138 if event_name then |
| 139 local method = event_name:match("^%S+"); | |
| 140 if not app_methods:contains(method) then | |
| 141 app_methods = app_methods + set.new{ method }; | |
| 142 end | |
| 143 local options_event_name = event_name:gsub("^%S+", "OPTIONS"); | |
| 107 if type(handler) ~= "function" then | 144 if type(handler) ~= "function" then |
| 108 local data = handler; | 145 local data = handler; |
| 109 handler = function () return data; end | 146 handler = function () return data; end |
| 110 elseif event_name:sub(-2, -1) == "/*" then | 147 elseif event_name:sub(-2, -1) == "/*" then |
| 111 local base_path_len = #event_name:match("/.+$"); | 148 local base_path_len = #event_name:match("/.+$"); |
| 117 module:hook_object_event(server, event_name:sub(1, -3), redir_handler, -1); | 154 module:hook_object_event(server, event_name:sub(1, -3), redir_handler, -1); |
| 118 elseif event_name:sub(-1, -1) == "/" then | 155 elseif event_name:sub(-1, -1) == "/" then |
| 119 module:hook_object_event(server, event_name:sub(1, -2), redir_handler, -1); | 156 module:hook_object_event(server, event_name:sub(1, -2), redir_handler, -1); |
| 120 end | 157 end |
| 121 if not app_handlers[event_name] then | 158 if not app_handlers[event_name] then |
| 122 app_handlers[event_name] = handler; | 159 app_handlers[event_name] = { |
| 160 main = handler; | |
| 161 cors = cors_handler; | |
| 162 options = options_handler; | |
| 163 }; | |
| 123 module:hook_object_event(server, event_name, handler); | 164 module:hook_object_event(server, event_name, handler); |
| 165 module:hook_object_event(server, event_name, cors_handler, 1); | |
| 166 module:hook_object_event(server, options_event_name, options_handler, -1); | |
| 124 else | 167 else |
| 125 module:log("warn", "App %s added handler twice for '%s', ignoring", app_name, event_name); | 168 module:log("warn", "App %s added handler twice for '%s', ignoring", app_name, event_name); |
| 126 end | 169 end |
| 127 else | 170 else |
| 128 module:log("error", "Invalid route in %s, %q. See https://prosody.im/doc/developers/http#routes", app_name, key); | 171 module:log("error", "Invalid route in %s, %q. See https://prosody.im/doc/developers/http#routes", app_name, key); |
| 137 end | 180 end |
| 138 | 181 |
| 139 local function http_app_removed(event) | 182 local function http_app_removed(event) |
| 140 local app_handlers = apps[event.item.name]; | 183 local app_handlers = apps[event.item.name]; |
| 141 apps[event.item.name] = nil; | 184 apps[event.item.name] = nil; |
| 142 for event_name, handler in pairs(app_handlers) do | 185 for event_name, handlers in pairs(app_handlers) do |
| 143 module:unhook_object_event(server, event_name, handler); | 186 module:unhook_object_event(server, event_name, handlers.main); |
| 187 module:unhook_object_event(server, event_name, handlers.cors); | |
| 188 local options_event_name = event_name:gsub("^%S+", "OPTIONS"); | |
| 189 module:unhook_object_event(server, options_event_name, handlers.options); | |
| 144 end | 190 end |
| 145 end | 191 end |
| 146 | 192 |
| 147 module:handle_items("http-provider", http_app_added, http_app_removed); | 193 module:handle_items("http-provider", http_app_added, http_app_removed); |
| 148 | 194 |
| 193 module:provides("net", { | 239 module:provides("net", { |
| 194 name = "https"; | 240 name = "https"; |
| 195 listener = server.listener; | 241 listener = server.listener; |
| 196 default_port = 5281; | 242 default_port = 5281; |
| 197 encryption = "ssl"; | 243 encryption = "ssl"; |
| 198 ssl_config = { | |
| 199 verify = "none"; | |
| 200 }; | |
| 201 multiplex = { | 244 multiplex = { |
| 202 pattern = "^[A-Z]"; | 245 pattern = "^[A-Z]"; |
| 203 }; | 246 }; |
| 204 }); | 247 }); |
