aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/mod_http.lua
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/mod_http.lua')
-rw-r--r--plugins/mod_http.lua94
1 files changed, 81 insertions, 13 deletions
diff --git a/plugins/mod_http.lua b/plugins/mod_http.lua
index 0cee26c4..c13a2363 100644
--- a/plugins/mod_http.lua
+++ b/plugins/mod_http.lua
@@ -11,24 +11,26 @@ pcall(function ()
module:depends("http_errors");
end);
-local portmanager = require "core.portmanager";
-local moduleapi = require "core.moduleapi";
+local portmanager = require "prosody.core.portmanager";
+local moduleapi = require "prosody.core.moduleapi";
local url_parse = require "socket.url".parse;
local url_build = require "socket.url".build;
-local normalize_path = require "util.http".normalize_path;
-local set = require "util.set";
+local http_util = require "prosody.util.http";
+local normalize_path = http_util.normalize_path;
+local set = require "prosody.util.set";
+local array = require "prosody.util.array";
-local ip_util = require "util.ip";
+local ip_util = require "prosody.util.ip";
local new_ip = ip_util.new_ip;
local match_ip = ip_util.match;
local parse_cidr = ip_util.parse_cidr;
-local server = require "net.http.server";
+local server = require "prosody.net.http.server";
server.set_default_host(module:get_option_string("http_default_host"));
-server.set_option("body_size_limit", module:get_option_number("http_max_content_size"));
-server.set_option("buffer_size_limit", module:get_option_number("http_max_buffer_size"));
+server.set_option("body_size_limit", module:get_option_number("http_max_content_size", nil, 0));
+server.set_option("buffer_size_limit", module:get_option_number("http_max_buffer_size", nil, 0));
-- CORS settings
local cors_overrides = module:get_option("http_cors_override", {});
@@ -36,7 +38,7 @@ local opt_methods = module:get_option_set("access_control_allow_methods", { "GET
local opt_headers = module:get_option_set("access_control_allow_headers", { "Content-Type" });
local opt_origins = module:get_option_set("access_control_allow_origins");
local opt_credentials = module:get_option_boolean("access_control_allow_credentials", false);
-local opt_max_age = module:get_option_number("access_control_max_age", 2 * 60 * 60);
+local opt_max_age = module:get_option_period("access_control_max_age", "2 hours");
local opt_default_cors = module:get_option_boolean("http_default_cors_enabled", true);
local function get_http_event(host, app_path, key)
@@ -75,11 +77,12 @@ end
local ports_by_scheme = { http = 80, https = 443, };
-- Helper to deduce a module's external URL
-function moduleapi.http_url(module, app_name, default_path)
+function moduleapi.http_url(module, app_name, default_path, mode)
app_name = app_name or (module.name:gsub("^http_", ""));
local external_url = url_parse(module:get_option_string("http_external_url"));
- if external_url then
+ if external_url and mode ~= "internal" then
+ -- Current URL does not depend on knowing which ports are used, only configuration.
local url = {
scheme = external_url.scheme;
host = external_url.host;
@@ -91,6 +94,36 @@ function moduleapi.http_url(module, app_name, default_path)
return url_build(url);
end
+ if prosody.process_type ~= "prosody" then
+ -- We generally don't open ports outside of Prosody, so we can't rely on
+ -- portmanager to tell us which ports and services are used and derive the
+ -- URL from that, so instead we derive it entirely from configuration.
+ local https_ports = module:get_option_array("https_ports", { 5281 });
+ local scheme = "https";
+ local port = tonumber(https_ports[1]);
+ if not port then
+ -- https is disabled and no http_external_url set
+ scheme = "http";
+ local http_ports = module:get_option_array("http_ports", { 5280 });
+ port = tonumber(http_ports[1]);
+ if not port then
+ return "http://disabled.invalid/";
+ end
+ end
+
+ local url = {
+ scheme = scheme;
+ host = module:get_option_string("http_host", module.global and module:get_option_string("http_default_host") or module.host);
+ port = port;
+ path = get_base_path(module, app_name, default_path or "/" .. app_name);
+ }
+ if ports_by_scheme[url.scheme] == url.port then
+ url.port = nil
+ end
+ return url_build(url);
+ end
+
+ -- Use portmanager to find the actual port of https or http services
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 -- luacheck: ignore 213/interface
@@ -112,12 +145,16 @@ function moduleapi.http_url(module, app_name, default_path)
return "http://disabled.invalid/";
end
+local function header_set_tostring(header_value)
+ return array(header_value:items()):concat(", ");
+end
+
local function apply_cors_headers(response, methods, headers, max_age, allow_credentials, allowed_origins, origin)
if allowed_origins and not allowed_origins[origin] then
return;
end
- response.headers.access_control_allow_methods = tostring(methods);
- response.headers.access_control_allow_headers = tostring(headers);
+ response.headers.access_control_allow_methods = header_set_tostring(methods);
+ response.headers.access_control_allow_headers = header_set_tostring(headers);
response.headers.access_control_max_age = tostring(max_age)
response.headers.access_control_allow_origin = origin or "*";
if allow_credentials then
@@ -292,7 +329,13 @@ module.add_host(module); -- set up handling on global context too
local trusted_proxies = module:get_option_set("trusted_proxies", { "127.0.0.1", "::1" })._items;
+--- deal with [ipv6]:port / ip:port format
+local function normal_ip(ip)
+ return ip:match("^%[([%x:]*)%]") or ip:match("^([%d.]+)") or ip;
+end
+
local function is_trusted_proxy(ip)
+ ip = normal_ip(ip);
if trusted_proxies[ip] then
return true;
end
@@ -308,6 +351,30 @@ end
local function get_forwarded_connection_info(request) --> ip:string, secure:boolean
local ip = request.ip;
local secure = request.secure; -- set by net.http.server
+
+ local forwarded = http_util.parse_forwarded(request.headers.forwarded);
+ if forwarded then
+ request.forwarded = forwarded;
+ for i = #forwarded, 1, -1 do
+ local proxy = forwarded[i]
+ if is_trusted_proxy(ip) then
+ ip = normal_ip(proxy["for"]);
+ secure = secure and proxy.proto == "https";
+ else
+ break
+ end
+ end
+ end
+
+ return ip, secure;
+end
+
+-- TODO switch to RFC 7239 by default once support is more common
+if module:get_option_boolean("http_legacy_x_forwarded", true) then
+function get_forwarded_connection_info(request) --> ip:string, secure:boolean
+ local ip = request.ip;
+ local secure = request.secure; -- set by net.http.server
+
local forwarded_for = request.headers.x_forwarded_for;
if forwarded_for then
-- luacheck: ignore 631
@@ -330,6 +397,7 @@ local function get_forwarded_connection_info(request) --> ip:string, secure:bool
return ip, secure;
end
+end
module:wrap_object_event(server._events, false, function (handlers, event_name, event_data)
local request = event_data.request;