net/http/parser.lua
author Matthew Wild <mwild1@gmail.com>
Mon, 20 Feb 2023 18:10:15 +0000
branch0.12
changeset 12898 0598d822614f
parent 12893 94a99330ce87
child 12978 ba409c67353b
child 13382 db30ffbf2090
permissions -rw-r--r--
mod_websocket: Fire pre-session-close event (fixes #1800) This event was added in a7c183bb4e64 and is required to make mod_smacks know that a session was intentionally closed and shouldn't be hibernated (see fcea4d9e7502). Because this was missing from mod_websocket's session.close(), mod_smacks would always attempt to hibernate websocket sessions even if they closed cleanly. That mod_websocket has its own copy of session.close() is something to fix another day (probably not in the stable branch). So for now this commit makes the minimal change to get things working again. Thanks to Damian and the Jitsi team for reporting.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
     1
local tonumber = tonumber;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
     2
local assert = assert;
4866
d54999db3aa1 net.http.parser: Do full URL decoding and parsing (e.g. adds request.url.query when present)
Matthew Wild <mwild1@gmail.com>
parents: 4716
diff changeset
     3
local url_parse = require "socket.url".parse;
5460
274c10668fe8 net.http.parser: Depend on util.http instead of net.http for urlencode
Matthew Wild <mwild1@gmail.com>
parents: 5323
diff changeset
     4
local urldecode = require "util.http".urldecode;
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
     5
local dbuffer = require "util.dbuffer";
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
     6
4716
6eeb142a8073 mod_http_files, net.http.parser: Move path normalization to net.http.parser so that all modules can benefit
Matthew Wild <mwild1@gmail.com>
parents: 4712
diff changeset
     7
local function preprocess_path(path)
5222
61c47d26481d net.http.parser: Fix syntax error introduced in c5edb08fc7cb.
Waqas Hussain <waqas20@gmail.com>
parents: 5207
diff changeset
     8
	path = urldecode((path:gsub("//+", "/")));
4716
6eeb142a8073 mod_http_files, net.http.parser: Move path normalization to net.http.parser so that all modules can benefit
Matthew Wild <mwild1@gmail.com>
parents: 4712
diff changeset
     9
	if path:sub(1,1) ~= "/" then
6eeb142a8073 mod_http_files, net.http.parser: Move path normalization to net.http.parser so that all modules can benefit
Matthew Wild <mwild1@gmail.com>
parents: 4712
diff changeset
    10
		path = "/"..path;
6eeb142a8073 mod_http_files, net.http.parser: Move path normalization to net.http.parser so that all modules can benefit
Matthew Wild <mwild1@gmail.com>
parents: 4712
diff changeset
    11
	end
6eeb142a8073 mod_http_files, net.http.parser: Move path normalization to net.http.parser so that all modules can benefit
Matthew Wild <mwild1@gmail.com>
parents: 4712
diff changeset
    12
	local level = 0;
6eeb142a8073 mod_http_files, net.http.parser: Move path normalization to net.http.parser so that all modules can benefit
Matthew Wild <mwild1@gmail.com>
parents: 4712
diff changeset
    13
	for component in path:gmatch("([^/]+)/") do
6eeb142a8073 mod_http_files, net.http.parser: Move path normalization to net.http.parser so that all modules can benefit
Matthew Wild <mwild1@gmail.com>
parents: 4712
diff changeset
    14
		if component == ".." then
6eeb142a8073 mod_http_files, net.http.parser: Move path normalization to net.http.parser so that all modules can benefit
Matthew Wild <mwild1@gmail.com>
parents: 4712
diff changeset
    15
			level = level - 1;
6eeb142a8073 mod_http_files, net.http.parser: Move path normalization to net.http.parser so that all modules can benefit
Matthew Wild <mwild1@gmail.com>
parents: 4712
diff changeset
    16
		elseif component ~= "." then
6eeb142a8073 mod_http_files, net.http.parser: Move path normalization to net.http.parser so that all modules can benefit
Matthew Wild <mwild1@gmail.com>
parents: 4712
diff changeset
    17
			level = level + 1;
6eeb142a8073 mod_http_files, net.http.parser: Move path normalization to net.http.parser so that all modules can benefit
Matthew Wild <mwild1@gmail.com>
parents: 4712
diff changeset
    18
		end
6eeb142a8073 mod_http_files, net.http.parser: Move path normalization to net.http.parser so that all modules can benefit
Matthew Wild <mwild1@gmail.com>
parents: 4712
diff changeset
    19
		if level < 0 then
6eeb142a8073 mod_http_files, net.http.parser: Move path normalization to net.http.parser so that all modules can benefit
Matthew Wild <mwild1@gmail.com>
parents: 4712
diff changeset
    20
			return nil;
6eeb142a8073 mod_http_files, net.http.parser: Move path normalization to net.http.parser so that all modules can benefit
Matthew Wild <mwild1@gmail.com>
parents: 4712
diff changeset
    21
		end
6eeb142a8073 mod_http_files, net.http.parser: Move path normalization to net.http.parser so that all modules can benefit
Matthew Wild <mwild1@gmail.com>
parents: 4712
diff changeset
    22
	end
6eeb142a8073 mod_http_files, net.http.parser: Move path normalization to net.http.parser so that all modules can benefit
Matthew Wild <mwild1@gmail.com>
parents: 4712
diff changeset
    23
	return path;
6eeb142a8073 mod_http_files, net.http.parser: Move path normalization to net.http.parser so that all modules can benefit
Matthew Wild <mwild1@gmail.com>
parents: 4712
diff changeset
    24
end
6eeb142a8073 mod_http_files, net.http.parser: Move path normalization to net.http.parser so that all modules can benefit
Matthew Wild <mwild1@gmail.com>
parents: 4712
diff changeset
    25
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    26
local httpstream = {};
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    27
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    28
function httpstream.new(success_cb, error_cb, parser_type, options_cb)
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    29
	local client = true;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    30
	if not parser_type or parser_type == "server" then client = false; else assert(parser_type == "client", "Invalid parser type"); end
7581
65bf55fdf971 net.http.parser: Allow limits to be configurable via options callback
Kim Alvefur <zash@zash.se>
parents: 7580
diff changeset
    31
	local bodylimit = tonumber(options_cb and options_cb().body_size_limit) or 10*1024*1024;
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
    32
	-- https://stackoverflow.com/a/686243
11731
f3aee8a825cc Fix various spelling errors (thanks codespell)
Kim Alvefur <zash@zash.se>
parents: 11188
diff changeset
    33
	-- Individual headers can be up to 16k? What madness?
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
    34
	local headlimit = tonumber(options_cb and options_cb().head_size_limit) or 10*1024;
7581
65bf55fdf971 net.http.parser: Allow limits to be configurable via options callback
Kim Alvefur <zash@zash.se>
parents: 7580
diff changeset
    35
	local buflimit = tonumber(options_cb and options_cb().buffer_size_limit) or bodylimit * 2;
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
    36
	local buffer = dbuffer.new(buflimit);
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
    37
	local chunked;
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    38
	local state = nil;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    39
	local packet;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    40
	local len;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    41
	local have_body;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    42
	local error;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    43
	return {
7572
a15ce0014ac9 net.http.parser: Remove unused argument [luacheck]
Kim Alvefur <zash@zash.se>
parents: 6526
diff changeset
    44
		feed = function(_, data)
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    45
			if error then return nil, "parse has failed"; end
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    46
			if not data then -- EOF
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    47
				if state and client and not len then -- reading client body until EOF
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
    48
					buffer:collapse();
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
    49
					packet.body = buffer:read_chunk() or "";
11188
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
    50
					packet.partial = nil;
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    51
					success_cb(packet);
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
    52
					state = nil;
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
    53
				elseif buffer:length() ~= 0 then -- unexpected EOF
8048
55a56dc935f2 net.http: Pass error all the way to callback
Kim Alvefur <zash@zash.se>
parents: 7638
diff changeset
    54
					error = true; return error_cb("unexpected-eof");
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    55
				end
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    56
				return;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    57
			end
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
    58
			if not buffer:write(data) then error = true; return error_cb("max-buffer-size-exceeded"); end
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
    59
			while buffer:length() > 0 do
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    60
				if state == nil then -- read request
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
    61
					local index = buffer:sub(1, headlimit):find("\r\n\r\n", nil, true);
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    62
					if not index then return; end -- not enough data
10544
375d31225d53 net.http.parser: Silence warning about unused variable [luacheck]
Kim Alvefur <zash@zash.se>
parents: 8048
diff changeset
    63
					-- FIXME was reason_phrase meant to be passed on somewhere?
375d31225d53 net.http.parser: Silence warning about unused variable [luacheck]
Kim Alvefur <zash@zash.se>
parents: 8048
diff changeset
    64
					local method, path, httpversion, status_code, reason_phrase; -- luacheck: ignore reason_phrase
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    65
					local first_line;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    66
					local headers = {};
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
    67
					for line in buffer:read(index+3):gmatch("([^\r\n]+)\r\n") do -- parse request
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    68
						if first_line then
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    69
							local key, val = line:match("^([^%s:]+): *(.*)$");
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    70
							if not key then error = true; return error_cb("invalid-header-line"); end -- TODO handle multi-line and invalid headers
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    71
							key = key:lower();
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    72
							headers[key] = headers[key] and headers[key]..","..val or val;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    73
						else
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    74
							first_line = line;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    75
							if client then
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    76
								httpversion, status_code, reason_phrase = line:match("^HTTP/(1%.[01]) (%d%d%d) (.*)$");
5462
3ecae471d9dd net.http.parser: Convert status_code to a number before trying to compare it to numbers
Matthew Wild <mwild1@gmail.com>
parents: 5461
diff changeset
    77
								status_code = tonumber(status_code);
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    78
								if not status_code then error = true; return error_cb("invalid-status-line"); end
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    79
								have_body = not
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    80
									 ( (options_cb and options_cb().method == "HEAD")
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    81
									or (status_code == 204 or status_code == 304 or status_code == 301)
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    82
									or (status_code >= 100 and status_code < 200) );
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    83
							else
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    84
								method, path, httpversion = line:match("^(%w+) (%S+) HTTP/(1%.[01])$");
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    85
								if not method then error = true; return error_cb("invalid-status-line"); end
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    86
							end
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    87
						end
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    88
					end
5291
01f7522049fb net.http.parser: Abort if no status line is received.
Kim Alvefur <zash@zash.se>
parents: 5259
diff changeset
    89
					if not first_line then error = true; return error_cb("invalid-status-line"); end
5463
111953bfe767 net.http.parser: Fix chunked encoding response parsing, and make it more robust
Matthew Wild <mwild1@gmail.com>
parents: 5462
diff changeset
    90
					chunked = have_body and headers["transfer-encoding"] == "chunked";
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    91
					len = tonumber(headers["content-length"]); -- TODO check for invalid len
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    92
					if client then
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    93
						-- FIXME handle '100 Continue' response (by skipping it)
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    94
						if not have_body then len = 0; end
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    95
						packet = {
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    96
							code = status_code;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    97
							httpversion = httpversion;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    98
							headers = headers;
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
    99
							body = false;
11188
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   100
							body_length = len;
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   101
							chunked = chunked;
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   102
							partial = true;
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   103
							-- COMPAT the properties below are deprecated
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   104
							responseversion = httpversion;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   105
							responseheaders = headers;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   106
						};
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   107
					else
5259
c85c348253bd net.http.parser: Skip url.parse when we don't have a full URL (also fixes traceback on paths starting with '//').
Waqas Hussain <waqas20@gmail.com>
parents: 5222
diff changeset
   108
						local parsed_url;
c85c348253bd net.http.parser: Skip url.parse when we don't have a full URL (also fixes traceback on paths starting with '//').
Waqas Hussain <waqas20@gmail.com>
parents: 5222
diff changeset
   109
						if path:byte() == 47 then -- starts with /
c85c348253bd net.http.parser: Skip url.parse when we don't have a full URL (also fixes traceback on paths starting with '//').
Waqas Hussain <waqas20@gmail.com>
parents: 5222
diff changeset
   110
							local _path, _query = path:match("([^?]*).?(.*)");
c85c348253bd net.http.parser: Skip url.parse when we don't have a full URL (also fixes traceback on paths starting with '//').
Waqas Hussain <waqas20@gmail.com>
parents: 5222
diff changeset
   111
							if _query == "" then _query = nil; end
c85c348253bd net.http.parser: Skip url.parse when we don't have a full URL (also fixes traceback on paths starting with '//').
Waqas Hussain <waqas20@gmail.com>
parents: 5222
diff changeset
   112
							parsed_url = { path = _path, query = _query };
c85c348253bd net.http.parser: Skip url.parse when we don't have a full URL (also fixes traceback on paths starting with '//').
Waqas Hussain <waqas20@gmail.com>
parents: 5222
diff changeset
   113
						else
c85c348253bd net.http.parser: Skip url.parse when we don't have a full URL (also fixes traceback on paths starting with '//').
Waqas Hussain <waqas20@gmail.com>
parents: 5222
diff changeset
   114
							parsed_url = url_parse(path);
5323
4c30f638ff55 net.http.parser: Ensure full URL in status line contains a path.
Waqas Hussain <waqas20@gmail.com>
parents: 5322
diff changeset
   115
							if not(parsed_url and parsed_url.path) then error = true; return error_cb("invalid-url"); end
5259
c85c348253bd net.http.parser: Skip url.parse when we don't have a full URL (also fixes traceback on paths starting with '//').
Waqas Hussain <waqas20@gmail.com>
parents: 5222
diff changeset
   116
						end
4866
d54999db3aa1 net.http.parser: Do full URL decoding and parsing (e.g. adds request.url.query when present)
Matthew Wild <mwild1@gmail.com>
parents: 4716
diff changeset
   117
						path = preprocess_path(parsed_url.path);
4879
45bb378a4a98 net.http.parser: Keep the Host header no host is present in the URI
Kim Alvefur <zash@zash.se>
parents: 4866
diff changeset
   118
						headers.host = parsed_url.host or headers.host;
4712
4fc99f1b7570 net.http.parser: Handle full URLs in status line.
Waqas Hussain <waqas20@gmail.com>
parents: 4631
diff changeset
   119
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   120
						len = len or 0;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   121
						packet = {
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   122
							method = method;
4866
d54999db3aa1 net.http.parser: Do full URL decoding and parsing (e.g. adds request.url.query when present)
Matthew Wild <mwild1@gmail.com>
parents: 4716
diff changeset
   123
							url = parsed_url;
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   124
							path = path;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   125
							httpversion = httpversion;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   126
							headers = headers;
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   127
							body = false;
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   128
							body_sink = nil;
11188
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   129
							chunked = chunked;
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   130
							partial = true;
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   131
						};
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   132
					end
12886
9ed628635dc6 net.http.parser: Improve handling of responses without content-length
Matthew Wild <mwild1@gmail.com>
parents: 11731
diff changeset
   133
					if not len or len > bodylimit then
11025
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   134
						-- Early notification, for redirection
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   135
						success_cb(packet);
12886
9ed628635dc6 net.http.parser: Improve handling of responses without content-length
Matthew Wild <mwild1@gmail.com>
parents: 11731
diff changeset
   136
						if not packet.body_sink and (len and len > bodylimit) then
9ed628635dc6 net.http.parser: Improve handling of responses without content-length
Matthew Wild <mwild1@gmail.com>
parents: 11731
diff changeset
   137
							error = true;
9ed628635dc6 net.http.parser: Improve handling of responses without content-length
Matthew Wild <mwild1@gmail.com>
parents: 11731
diff changeset
   138
							return error_cb("content-length-limit-exceeded");
9ed628635dc6 net.http.parser: Improve handling of responses without content-length
Matthew Wild <mwild1@gmail.com>
parents: 11731
diff changeset
   139
						end
11025
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   140
					end
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   141
					if chunked and not packet.body_sink then
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   142
						success_cb(packet);
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   143
						if not packet.body_sink then
11033
5550fc5e83f3 net.http.parser: Fix indentation
Kim Alvefur <zash@zash.se>
parents: 11025
diff changeset
   144
							packet.body_buffer = dbuffer.new(buflimit);
5550fc5e83f3 net.http.parser: Fix indentation
Kim Alvefur <zash@zash.se>
parents: 11025
diff changeset
   145
						end
11025
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   146
					end
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   147
					state = true;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   148
				end
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   149
				if state then -- read body
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   150
					if chunked then
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   151
						local chunk_header = buffer:sub(1, 512); -- XXX How large do chunk headers grow?
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   152
						local chunk_size, chunk_start = chunk_header:match("^(%x+)[^\r\n]*\r\n()");
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   153
						if not chunk_size then return; end
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   154
						chunk_size = chunk_size and tonumber(chunk_size, 16);
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   155
						if not chunk_size then error = true; return error_cb("invalid-chunk-size"); end
12893
94a99330ce87 net.http.parser: Fix off-by-one error in chunk parser
Matthew Wild <mwild1@gmail.com>
parents: 12886
diff changeset
   156
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   157
						if chunk_size == 0 and chunk_header:find("\r\n\r\n", chunk_start-2, true) then
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   158
							local body_buffer = packet.body_buffer;
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   159
							if body_buffer then
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   160
								packet.body_buffer = nil;
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   161
								body_buffer:collapse();
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   162
								packet.body = body_buffer:read_chunk() or "";
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   163
							end
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   164
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   165
							buffer:collapse();
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   166
							local buf = buffer:read_chunk();
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   167
							buf = buf:gsub("^.-\r\n\r\n", ""); -- This ensure extensions and trailers are stripped
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   168
							buffer:write(buf);
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   169
							state, chunked = nil, nil;
11188
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   170
							packet.partial = nil;
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   171
							success_cb(packet);
12893
94a99330ce87 net.http.parser: Fix off-by-one error in chunk parser
Matthew Wild <mwild1@gmail.com>
parents: 12886
diff changeset
   172
						elseif buffer:length() - chunk_start - 1 >= chunk_size then -- we have a chunk
94a99330ce87 net.http.parser: Fix off-by-one error in chunk parser
Matthew Wild <mwild1@gmail.com>
parents: 12886
diff changeset
   173
							buffer:discard(chunk_start - 1);
11025
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   174
							(packet.body_sink or packet.body_buffer):write(buffer:read(chunk_size));
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   175
							buffer:discard(2); -- CRLF
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   176
						else -- Partial chunk remaining
5461
67b674f6a299 net.http.parser: Break when no more usable data in buffer (client part of e5ec60dfb202)
Matthew Wild <mwild1@gmail.com>
parents: 5460
diff changeset
   177
							break;
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   178
						end
11025
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   179
					elseif packet.body_sink then
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   180
						local chunk = buffer:read_chunk(len);
12886
9ed628635dc6 net.http.parser: Improve handling of responses without content-length
Matthew Wild <mwild1@gmail.com>
parents: 11731
diff changeset
   181
						while chunk and (not len or len > 0) do
11025
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   182
							if packet.body_sink:write(chunk) then
12886
9ed628635dc6 net.http.parser: Improve handling of responses without content-length
Matthew Wild <mwild1@gmail.com>
parents: 11731
diff changeset
   183
								if len then
9ed628635dc6 net.http.parser: Improve handling of responses without content-length
Matthew Wild <mwild1@gmail.com>
parents: 11731
diff changeset
   184
									len = len - #chunk;
9ed628635dc6 net.http.parser: Improve handling of responses without content-length
Matthew Wild <mwild1@gmail.com>
parents: 11731
diff changeset
   185
								end
11025
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   186
								chunk = buffer:read_chunk(len);
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   187
							else
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   188
								error = true;
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   189
								return error_cb("body-sink-write-failure");
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   190
							end
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   191
						end
11188
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   192
						if len == 0 then
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   193
							state = nil;
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   194
							packet.partial = nil;
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   195
							success_cb(packet);
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   196
						end
12886
9ed628635dc6 net.http.parser: Improve handling of responses without content-length
Matthew Wild <mwild1@gmail.com>
parents: 11731
diff changeset
   197
					elseif not len or buffer:length() >= len then -- or not len
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   198
						assert(not chunked)
12886
9ed628635dc6 net.http.parser: Improve handling of responses without content-length
Matthew Wild <mwild1@gmail.com>
parents: 11731
diff changeset
   199
						packet.body = len and buffer:read(len) or buffer:read_chunk() or "";
11188
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   200
						state = nil;
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   201
						packet.partial = nil;
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   202
						success_cb(packet);
4910
e5ec60dfb202 net.http.parser: Break loop when no more usable data in buffer
Matthew Wild <mwild1@gmail.com>
parents: 4879
diff changeset
   203
					else
e5ec60dfb202 net.http.parser: Break loop when no more usable data in buffer
Matthew Wild <mwild1@gmail.com>
parents: 4879
diff changeset
   204
						break;
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   205
					end
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   206
				else
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   207
					break;
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   208
				end
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   209
			end
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   210
		end;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   211
	};
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   212
end
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   213
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   214
return httpstream;