net/http/parser.lua
author Kim Alvefur <zash@zash.se>
Thu, 28 Mar 2024 15:26:57 +0100
changeset 13472 98806cac64c3
parent 13383 977d92aff563
permissions -rw-r--r--
MUC: Switch to official XEP-0317 namespace for Hats (including compat) (thanks nicoco)
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;
12978
ba409c67353b net: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12893
diff changeset
     4
local urldecode = require "prosody.util.http".urldecode;
ba409c67353b net: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12893
diff changeset
     5
local dbuffer = require "prosody.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);
13382
db30ffbf2090 net.http.parser: Reject overlarge header section earlier
Kim Alvefur <zash@zash.se>
parents: 12893
diff changeset
    62
					if not index then
db30ffbf2090 net.http.parser: Reject overlarge header section earlier
Kim Alvefur <zash@zash.se>
parents: 12893
diff changeset
    63
						if buffer:length() > headlimit then
db30ffbf2090 net.http.parser: Reject overlarge header section earlier
Kim Alvefur <zash@zash.se>
parents: 12893
diff changeset
    64
							return error_cb("header-too-large");
db30ffbf2090 net.http.parser: Reject overlarge header section earlier
Kim Alvefur <zash@zash.se>
parents: 12893
diff changeset
    65
						end
db30ffbf2090 net.http.parser: Reject overlarge header section earlier
Kim Alvefur <zash@zash.se>
parents: 12893
diff changeset
    66
						-- not enough data
db30ffbf2090 net.http.parser: Reject overlarge header section earlier
Kim Alvefur <zash@zash.se>
parents: 12893
diff changeset
    67
						return;
db30ffbf2090 net.http.parser: Reject overlarge header section earlier
Kim Alvefur <zash@zash.se>
parents: 12893
diff changeset
    68
					end
10544
375d31225d53 net.http.parser: Silence warning about unused variable [luacheck]
Kim Alvefur <zash@zash.se>
parents: 8048
diff changeset
    69
					-- 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
    70
					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
    71
					local first_line;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    72
					local headers = {};
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
    73
					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
    74
						if first_line then
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    75
							local key, val = line:match("^([^%s:]+): *(.*)$");
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    76
							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
    77
							key = key:lower();
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    78
							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
    79
						else
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    80
							first_line = line;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    81
							if client then
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    82
								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
    83
								status_code = tonumber(status_code);
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    84
								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
    85
								have_body = not
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    86
									 ( (options_cb and options_cb().method == "HEAD")
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    87
									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
    88
									or (status_code >= 100 and status_code < 200) );
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    89
							else
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    90
								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
    91
								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
    92
							end
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    93
						end
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    94
					end
5291
01f7522049fb net.http.parser: Abort if no status line is received.
Kim Alvefur <zash@zash.se>
parents: 5259
diff changeset
    95
					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
    96
					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
    97
					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
    98
					if client then
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    99
						-- FIXME handle '100 Continue' response (by skipping it)
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   100
						if not have_body then len = 0; end
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   101
						packet = {
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   102
							code = status_code;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   103
							httpversion = httpversion;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   104
							headers = headers;
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   105
							body = false;
11188
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   106
							body_length = len;
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   107
							chunked = chunked;
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   108
							partial = true;
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   109
							-- COMPAT the properties below are deprecated
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   110
							responseversion = httpversion;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   111
							responseheaders = headers;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   112
						};
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   113
					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
   114
						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
   115
						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
   116
							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
   117
							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
   118
							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
   119
						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
   120
							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
   121
							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
   122
						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
   123
						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
   124
						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
   125
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   126
						len = len or 0;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   127
						packet = {
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   128
							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
   129
							url = parsed_url;
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   130
							path = path;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   131
							httpversion = httpversion;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   132
							headers = headers;
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   133
							body = false;
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   134
							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
   135
							chunked = chunked;
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   136
							partial = true;
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   137
						};
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   138
					end
12886
9ed628635dc6 net.http.parser: Improve handling of responses without content-length
Matthew Wild <mwild1@gmail.com>
parents: 11731
diff changeset
   139
					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
   140
						-- Early notification, for redirection
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   141
						success_cb(packet);
12886
9ed628635dc6 net.http.parser: Improve handling of responses without content-length
Matthew Wild <mwild1@gmail.com>
parents: 11731
diff changeset
   142
						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
   143
							error = true;
9ed628635dc6 net.http.parser: Improve handling of responses without content-length
Matthew Wild <mwild1@gmail.com>
parents: 11731
diff changeset
   144
							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
   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
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   147
					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
   148
						success_cb(packet);
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   149
						if not packet.body_sink then
11033
5550fc5e83f3 net.http.parser: Fix indentation
Kim Alvefur <zash@zash.se>
parents: 11025
diff changeset
   150
							packet.body_buffer = dbuffer.new(buflimit);
5550fc5e83f3 net.http.parser: Fix indentation
Kim Alvefur <zash@zash.se>
parents: 11025
diff changeset
   151
						end
11025
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   152
					end
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   153
					state = true;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   154
				end
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   155
				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
   156
					if chunked then
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   157
						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
   158
						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
   159
						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
   160
						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
   161
						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
   162
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   163
						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
   164
							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
   165
							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
   166
								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
   167
								body_buffer:collapse();
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   168
								packet.body = body_buffer:read_chunk() or "";
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   169
							end
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   170
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   171
							buffer:collapse();
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   172
							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
   173
							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
   174
							buffer:write(buf);
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   175
							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
   176
							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
   177
							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
   178
						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
   179
							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
   180
							(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
   181
							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
   182
						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
   183
							break;
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   184
						end
11025
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   185
					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
   186
						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
   187
						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
   188
							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
   189
								if len then
9ed628635dc6 net.http.parser: Improve handling of responses without content-length
Matthew Wild <mwild1@gmail.com>
parents: 11731
diff changeset
   190
									len = len - #chunk;
9ed628635dc6 net.http.parser: Improve handling of responses without content-length
Matthew Wild <mwild1@gmail.com>
parents: 11731
diff changeset
   191
								end
11025
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   192
								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
   193
							else
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   194
								error = true;
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   195
								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
   196
							end
9673c95895fb net.http.parser: Allow specifying sink for large request bodies
Kim Alvefur <zash@zash.se>
parents: 11024
diff changeset
   197
						end
11188
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   198
						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
   199
							state = nil;
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   200
							packet.partial = nil;
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   201
							success_cb(packet);
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   202
						end
12886
9ed628635dc6 net.http.parser: Improve handling of responses without content-length
Matthew Wild <mwild1@gmail.com>
parents: 11731
diff changeset
   203
					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
   204
						assert(not chunked)
12886
9ed628635dc6 net.http.parser: Improve handling of responses without content-length
Matthew Wild <mwild1@gmail.com>
parents: 11731
diff changeset
   205
						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
   206
						state = nil;
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   207
						packet.partial = nil;
2ede7f43ccfe net.http.parser: Expose 'partial', 'chunked' and 'body_length' on packets
Matthew Wild <mwild1@gmail.com>
parents: 11033
diff changeset
   208
						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
   209
					else
e5ec60dfb202 net.http.parser: Break loop when no more usable data in buffer
Matthew Wild <mwild1@gmail.com>
parents: 4879
diff changeset
   210
						break;
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   211
					end
11024
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   212
				else
7076ed654ac9 net.http.parser: Switch to util.dbuffer for buffering incoming data
Kim Alvefur <zash@zash.se>
parents: 10584
diff changeset
   213
					break;
4631
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   214
				end
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   215
			end
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   216
		end;
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   217
	};
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   218
end
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   219
fc5d3b053454 net.http.{server|codes|parser}: Initial commit.
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
   220
return httpstream;