aboutsummaryrefslogtreecommitdiffstats
path: root/net/http
diff options
context:
space:
mode:
Diffstat (limited to 'net/http')
-rw-r--r--net/http/codes.lua3
-rw-r--r--net/http/parser.lua35
-rw-r--r--net/http/server.lua13
3 files changed, 39 insertions, 12 deletions
diff --git a/net/http/codes.lua b/net/http/codes.lua
index bc31c7dd..1090e545 100644
--- a/net/http/codes.lua
+++ b/net/http/codes.lua
@@ -55,6 +55,7 @@ local response_codes = {
[428] = "Precondition Required";
[429] = "Too Many Requests";
[431] = "Request Header Fields Too Large";
+ [451] = "Unavailable For Legal Reasons";
[500] = "Internal Server Error";
[501] = "Not Implemented";
@@ -70,4 +71,4 @@ local response_codes = {
};
for k,v in pairs(response_codes) do response_codes[k] = k.." "..v; end
-return setmetatable(response_codes, { __index = function(t, k) return k.." Unassigned"; end })
+return setmetatable(response_codes, { __index = function(_, k) return k.." Unassigned"; end })
diff --git a/net/http/parser.lua b/net/http/parser.lua
index 6d7187da..fabbddad 100644
--- a/net/http/parser.lua
+++ b/net/http/parser.lua
@@ -1,5 +1,6 @@
local tonumber = tonumber;
local assert = assert;
+local t_insert, t_concat = table.insert, table.concat;
local url_parse = require "socket.url".parse;
local urldecode = require "util.http".urldecode;
@@ -27,7 +28,9 @@ local httpstream = {};
function httpstream.new(success_cb, error_cb, parser_type, options_cb)
local client = true;
if not parser_type or parser_type == "server" then client = false; else assert(parser_type == "client", "Invalid parser type"); end
- local buf = "";
+ local buf, buflen, buftable = {}, 0, true;
+ local bodylimit = tonumber(options_cb and options_cb().body_size_limit) or 10*1024*1024;
+ local buflimit = tonumber(options_cb and options_cb().buffer_size_limit) or bodylimit * 2;
local chunked, chunk_size, chunk_start;
local state = nil;
local packet;
@@ -35,9 +38,10 @@ function httpstream.new(success_cb, error_cb, parser_type, options_cb)
local have_body;
local error;
return {
- feed = function(self, data)
+ feed = function(_, data)
if error then return nil, "parse has failed"; end
if not data then -- EOF
+ if buftable then buf, buftable = t_concat(buf), false; end
if state and client and not len then -- reading client body until EOF
packet.body = buf;
success_cb(packet);
@@ -46,9 +50,17 @@ function httpstream.new(success_cb, error_cb, parser_type, options_cb)
end
return;
end
- buf = buf..data;
- while #buf > 0 do
+ if buftable then
+ t_insert(buf, data);
+ else
+ buf = { buf, data };
+ buftable = true;
+ end
+ buflen = buflen + #data;
+ if buflen > buflimit then error = true; return error_cb("max-buffer-size-exceeded"); end
+ while buflen > 0 do
if state == nil then -- read request
+ if buftable then buf, buftable = t_concat(buf), false; end
local index = buf:find("\r\n\r\n", nil, true);
if not index then return; end -- not enough data
local method, path, httpversion, status_code, reason_phrase;
@@ -79,6 +91,7 @@ function httpstream.new(success_cb, error_cb, parser_type, options_cb)
if not first_line then error = true; return error_cb("invalid-status-line"); end
chunked = have_body and headers["transfer-encoding"] == "chunked";
len = tonumber(headers["content-length"]); -- TODO check for invalid len
+ if len and len > bodylimit then error = true; return error_cb("content-length-limit-exceeded"); end
if client then
-- FIXME handle '100 Continue' response (by skipping it)
if not have_body then len = 0; end
@@ -115,11 +128,13 @@ function httpstream.new(success_cb, error_cb, parser_type, options_cb)
};
end
buf = buf:sub(index + 4);
+ buflen = #buf;
state = true;
end
if state then -- read body
if client then
if chunked then
+ if buftable then buf, buftable = t_concat(buf), false; end
if not buf:find("\r\n", nil, true) then
return;
end -- not enough data
@@ -132,25 +147,29 @@ function httpstream.new(success_cb, error_cb, parser_type, options_cb)
state, chunk_size = nil, nil;
buf = buf:gsub("^.-\r\n\r\n", ""); -- This ensure extensions and trailers are stripped
success_cb(packet);
- elseif #buf - chunk_start - 2 >= chunk_size then -- we have a chunk
+ elseif buflen - chunk_start - 2 >= chunk_size then -- we have a chunk
packet.body = packet.body..buf:sub(chunk_start, chunk_start + (chunk_size-1));
buf = buf:sub(chunk_start + chunk_size + 2);
chunk_size, chunk_start = nil, nil;
else -- Partial chunk remaining
break;
end
- elseif len and #buf >= len then
+ elseif len and buflen >= len then
+ if buftable then buf, buftable = t_concat(buf), false; end
if packet.code == 101 then
- packet.body, buf = buf, "";
+ packet.body, buf, buflen, buftable = buf, {}, 0, true;
else
packet.body, buf = buf:sub(1, len), buf:sub(len + 1);
+ buflen = #buf;
end
state = nil; success_cb(packet);
else
break;
end
- elseif #buf >= len then
+ elseif buflen >= len then
+ if buftable then buf, buftable = t_concat(buf), false; end
packet.body, buf = buf:sub(1, len), buf:sub(len + 1);
+ buflen = #buf;
state = nil; success_cb(packet);
else
break;
diff --git a/net/http/server.lua b/net/http/server.lua
index ba45ede0..8aa28f5c 100644
--- a/net/http/server.lua
+++ b/net/http/server.lua
@@ -22,6 +22,7 @@ local incomplete = {};
local listener = {};
local hosts = {};
local default_host;
+local options = {};
local function is_wildcard_event(event)
return event:sub(-2, -1) == "/*";
@@ -31,7 +32,7 @@ local function is_wildcard_match(wildcard_event, event)
end
local _handlers = events._handlers;
-local recent_wildcard_events = cache.new(10000, function (key, value)
+local recent_wildcard_events = cache.new(10000, function (key, value) -- luacheck: ignore 212/value
rawset(_handlers, key, nil);
end);
@@ -133,7 +134,10 @@ function listener.onconnect(conn)
sessions[conn] = nil;
conn:close();
end
- sessions[conn] = parser_new(success_cb, error_cb);
+ local function options_cb()
+ return options;
+ end
+ sessions[conn] = parser_new(success_cb, error_cb, "server", options_cb);
end
function listener.ondisconnect(conn)
@@ -170,7 +174,7 @@ local headerfix = setmetatable({}, {
end
});
-function _M.hijack_response(response, listener)
+function _M.hijack_response(response, listener) -- luacheck: ignore
error("TODO");
end
function handle_request(conn, request, finish_cb)
@@ -350,6 +354,9 @@ end
function _M.fire_event(event, ...)
return events.fire_event(event, ...);
end
+function _M.set_option(name, value)
+ options[name] = value;
+end
_M.listener = listener;
_M.codes = codes;