util/http.lua
author Kim Alvefur <zash@zash.se>
Sat, 23 Mar 2024 20:48:19 +0100
changeset 13465 c673ff1075bd
parent 13128 f15e23840780
permissions -rw-r--r--
mod_posix: Move everything to util.startup This allows greater control over the order of events. Notably, the internal ordering between daemonization, initialization of libunbound and setup of signal handling is sensitive. libunbound starts a separate thread for processing DNS requests. If this thread is started before signal handling has been set up, it will not inherit the signal handlers and instead behave as it would have before signal handlers were set up, i.e. cause the whole process to immediately exit. libunbound is usually initialized on the first DNS request, usually triggered by an outgoing s2s connection attempt. If daemonization happens before signals have been set up, signals may not be processed at all.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
5299
cc9d460aa779 util.http: New module for HTTP helper functions
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
     1
-- Prosody IM
cc9d460aa779 util.http: New module for HTTP helper functions
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
     2
-- Copyright (C) 2013 Florian Zeitz
cc9d460aa779 util.http: New module for HTTP helper functions
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
     3
--
cc9d460aa779 util.http: New module for HTTP helper functions
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
     4
-- This project is MIT/X11 licensed. Please see the
cc9d460aa779 util.http: New module for HTTP helper functions
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
     5
-- COPYING file in the source package for more information.
cc9d460aa779 util.http: New module for HTTP helper functions
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
     6
--
cc9d460aa779 util.http: New module for HTTP helper functions
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
     7
5471
34bfd26525f5 util.http: Refactor and import all necessary functions
Matthew Wild <mwild1@gmail.com>
parents: 5458
diff changeset
     8
local format, char = string.format, string.char;
9763
1af5106a2c34 util.http: Pre-generate urlencoding mappings (optimization)
Kim Alvefur <zash@zash.se>
parents: 9507
diff changeset
     9
local pairs, ipairs = pairs, ipairs;
5471
34bfd26525f5 util.http: Refactor and import all necessary functions
Matthew Wild <mwild1@gmail.com>
parents: 5458
diff changeset
    10
local t_insert, t_concat = table.insert, table.concat;
5299
cc9d460aa779 util.http: New module for HTTP helper functions
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
    11
9763
1af5106a2c34 util.http: Pre-generate urlencoding mappings (optimization)
Kim Alvefur <zash@zash.se>
parents: 9507
diff changeset
    12
local url_codes = {};
1af5106a2c34 util.http: Pre-generate urlencoding mappings (optimization)
Kim Alvefur <zash@zash.se>
parents: 9507
diff changeset
    13
for i = 0, 255 do
1af5106a2c34 util.http: Pre-generate urlencoding mappings (optimization)
Kim Alvefur <zash@zash.se>
parents: 9507
diff changeset
    14
	local c = char(i);
1af5106a2c34 util.http: Pre-generate urlencoding mappings (optimization)
Kim Alvefur <zash@zash.se>
parents: 9507
diff changeset
    15
	local u = format("%%%02x", i);
1af5106a2c34 util.http: Pre-generate urlencoding mappings (optimization)
Kim Alvefur <zash@zash.se>
parents: 9507
diff changeset
    16
	url_codes[c] = u;
1af5106a2c34 util.http: Pre-generate urlencoding mappings (optimization)
Kim Alvefur <zash@zash.se>
parents: 9507
diff changeset
    17
	url_codes[u] = c;
9789
ff88b03c343f util.http: Fix decoding of uppercase URL encoded chars
Kim Alvefur <zash@zash.se>
parents: 9763
diff changeset
    18
	url_codes[u:upper()] = c;
9763
1af5106a2c34 util.http: Pre-generate urlencoding mappings (optimization)
Kim Alvefur <zash@zash.se>
parents: 9507
diff changeset
    19
end
5471
34bfd26525f5 util.http: Refactor and import all necessary functions
Matthew Wild <mwild1@gmail.com>
parents: 5458
diff changeset
    20
local function urlencode(s)
9763
1af5106a2c34 util.http: Pre-generate urlencoding mappings (optimization)
Kim Alvefur <zash@zash.se>
parents: 9507
diff changeset
    21
	return s and (s:gsub("[^a-zA-Z0-9.~_-]", url_codes));
5458
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    22
end
5471
34bfd26525f5 util.http: Refactor and import all necessary functions
Matthew Wild <mwild1@gmail.com>
parents: 5458
diff changeset
    23
local function urldecode(s)
9763
1af5106a2c34 util.http: Pre-generate urlencoding mappings (optimization)
Kim Alvefur <zash@zash.se>
parents: 9507
diff changeset
    24
	return s and (s:gsub("%%%x%x", url_codes));
5458
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    25
end
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    26
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    27
local function _formencodepart(s)
9763
1af5106a2c34 util.http: Pre-generate urlencoding mappings (optimization)
Kim Alvefur <zash@zash.se>
parents: 9507
diff changeset
    28
	return s and (urlencode(s):gsub("%%20", "+"));
5458
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    29
end
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    30
5471
34bfd26525f5 util.http: Refactor and import all necessary functions
Matthew Wild <mwild1@gmail.com>
parents: 5458
diff changeset
    31
local function formencode(form)
5458
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    32
	local result = {};
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    33
	if form[1] then -- Array of ordered { name, value }
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    34
		for _, field in ipairs(form) do
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    35
			t_insert(result, _formencodepart(field.name).."=".._formencodepart(field.value));
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    36
		end
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    37
	else -- Unordered map of name -> value
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    38
		for name, value in pairs(form) do
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    39
			t_insert(result, _formencodepart(name).."=".._formencodepart(value));
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    40
		end
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    41
	end
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    42
	return t_concat(result, "&");
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    43
end
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    44
5471
34bfd26525f5 util.http: Refactor and import all necessary functions
Matthew Wild <mwild1@gmail.com>
parents: 5458
diff changeset
    45
local function formdecode(s)
5458
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    46
	if not s:match("=") then return urldecode(s); end
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    47
	local r = {};
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    48
	for k, v in s:gmatch("([^=&]*)=([^&]*)") do
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    49
		k, v = k:gsub("%+", "%%20"), v:gsub("%+", "%%20");
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    50
		k, v = urldecode(k), urldecode(v);
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    51
		t_insert(r, { name = k, value = v });
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    52
		r[k] = v;
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    53
	end
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    54
	return r;
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    55
end
84162b81c863 net.http, util.http: Move definitions of urlencode/decode and formencode/decode to util.http (possible to use them without unnecessary network-related dependencies)
Matthew Wild <mwild1@gmail.com>
parents: 5299
diff changeset
    56
5471
34bfd26525f5 util.http: Refactor and import all necessary functions
Matthew Wild <mwild1@gmail.com>
parents: 5458
diff changeset
    57
local function contains_token(field, token)
5299
cc9d460aa779 util.http: New module for HTTP helper functions
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
    58
	field = ","..field:gsub("[ \t]", ""):lower()..",";
cc9d460aa779 util.http: New module for HTTP helper functions
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
    59
	return field:find(","..token:lower()..",", 1, true) ~= nil;
cc9d460aa779 util.http: New module for HTTP helper functions
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
    60
end
cc9d460aa779 util.http: New module for HTTP helper functions
Florian Zeitz <florob@babelmonkeys.de>
parents:
diff changeset
    61
9507
cfbea3064aa9 mod_http: Move normalize_path to util.http
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
    62
local function normalize_path(path, is_dir)
cfbea3064aa9 mod_http: Move normalize_path to util.http
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
    63
	if is_dir then
cfbea3064aa9 mod_http: Move normalize_path to util.http
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
    64
		if path:sub(-1,-1) ~= "/" then path = path.."/"; end
cfbea3064aa9 mod_http: Move normalize_path to util.http
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
    65
	else
cfbea3064aa9 mod_http: Move normalize_path to util.http
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
    66
		if path:sub(-1,-1) == "/" then path = path:sub(1, -2); end
cfbea3064aa9 mod_http: Move normalize_path to util.http
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
    67
	end
cfbea3064aa9 mod_http: Move normalize_path to util.http
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
    68
	if path:sub(1,1) ~= "/" then path = "/"..path; end
cfbea3064aa9 mod_http: Move normalize_path to util.http
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
    69
	return path;
cfbea3064aa9 mod_http: Move normalize_path to util.http
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
    70
end
cfbea3064aa9 mod_http: Move normalize_path to util.http
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
    71
13128
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    72
--- Parse the RFC 7239 Forwarded header into array of key-value pairs.
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    73
local function parse_forwarded(forwarded)
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    74
	if type(forwarded) ~= "string" then
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    75
		return nil;
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    76
	end
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    77
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    78
	local fwd = {}; -- array
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    79
	local cur = {}; -- map, to which we add the next key-value pair
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    80
	for key, quoted, value, delim in forwarded:gmatch("(%w+)%s*=%s*(\"?)([^,;\"]+)%2%s*(.?)") do
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    81
		-- FIXME quoted quotes like "foo\"bar"
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    82
		-- unlikely when only dealing with IP addresses
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    83
		if quoted == '"' then
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    84
			value = value:gsub("\\(.)", "%1");
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    85
		end
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    86
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    87
		cur[key:lower()] = value;
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    88
		if delim == "" or delim == "," then
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    89
			t_insert(fwd, cur)
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    90
			if delim == "" then
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    91
				-- end of the string
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    92
				break;
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    93
			end
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    94
			cur = {};
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    95
		elseif delim ~= ";" then
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    96
			-- misparsed
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    97
			return false;
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    98
		end
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
    99
	end
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
   100
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
   101
	return fwd;
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
   102
end
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
   103
5471
34bfd26525f5 util.http: Refactor and import all necessary functions
Matthew Wild <mwild1@gmail.com>
parents: 5458
diff changeset
   104
return {
34bfd26525f5 util.http: Refactor and import all necessary functions
Matthew Wild <mwild1@gmail.com>
parents: 5458
diff changeset
   105
	urlencode = urlencode, urldecode = urldecode;
34bfd26525f5 util.http: Refactor and import all necessary functions
Matthew Wild <mwild1@gmail.com>
parents: 5458
diff changeset
   106
	formencode = formencode, formdecode = formdecode;
34bfd26525f5 util.http: Refactor and import all necessary functions
Matthew Wild <mwild1@gmail.com>
parents: 5458
diff changeset
   107
	contains_token = contains_token;
9507
cfbea3064aa9 mod_http: Move normalize_path to util.http
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
   108
	normalize_path = normalize_path;
13128
f15e23840780 util.http: Implement parser for RFC 7239 Forwarded header
Kim Alvefur <zash@zash.se>
parents: 9789
diff changeset
   109
	parse_forwarded = parse_forwarded;
5471
34bfd26525f5 util.http: Refactor and import all necessary functions
Matthew Wild <mwild1@gmail.com>
parents: 5458
diff changeset
   110
};