local xpcall = xpcall;
local traceback = debug.traceback;
local tostring = tostring;
+local cache = require "util.cache";
local codes = require "net.http.codes";
+local blocksize = require "socket".BLOCKSIZE or 2048;
local _M = {};
local sessions = {};
+local incomplete = {};
local listener = {};
local hosts = {};
local default_host;
return wildcard_event:sub(1, -2) == event:sub(1, #wildcard_event-1);
end
-local recent_wildcard_events, max_cached_wildcard_events = {}, 10000;
+local _handlers = events._handlers;
+local recent_wildcard_events = cache.new(10000, function (key, value)
+ rawset(_handlers, key, nil);
+end);
local event_map = events._event_map;
setmetatable(events._handlers, {
end
rawset(handlers, curr_event, handlers_array);
if not event_map[curr_event] then -- Only wildcard handlers match, if any
- table.insert(recent_wildcard_events, curr_event);
- if #recent_wildcard_events > max_cached_wildcard_events then
- rawset(handlers, table.remove(recent_wildcard_events, 1), nil);
- end
+ recent_wildcard_events:set(curr_event, true);
end
return handlers_array;
end;
open_response.finished = true;
open_response:on_destroy();
end
+ incomplete[conn] = nil;
sessions[conn] = nil;
end
function listener.ondetach(conn)
sessions[conn] = nil;
+ incomplete[conn] = nil;
end
function listener.onincoming(conn, data)
sessions[conn]:feed(data);
end
+function listener.ondrain(conn)
+ local response = incomplete[conn];
+ if response and response._send_more then
+ response._send_more();
+ end
+end
+
local headerfix = setmetatable({}, {
__index = function(t, k)
local v = "\r\n"..k:gsub("_", "-"):gsub("%f[%w].", s_upper)..": ";
persistent = persistent;
conn = conn;
send = _M.send_response;
+ send_file = _M.send_file;
done = _M.finish_response;
finish_cb = finish_cb;
};
local event = request.method.." "..host..request.path:match("[^?]*");
local payload = { request = request, response = response };
- log("debug", event);
+ log("debug", "Firing event: %s", event);
local result = events.fire_event(event, payload);
if result ~= nil then
if result ~= true then
response.conn:write(t_concat(output));
response:done();
end
+function _M.send_file(response, f)
+ if response.finished then return; end
+ local chunked = not response.headers.content_length;
+ if chunked then response.headers.transfer_encoding = "chunked"; end
+ incomplete[response.conn] = response;
+ response._send_more = function ()
+ if response.finished then
+ incomplete[response.conn] = nil;
+ return;
+ end
+ local chunk = f:read(blocksize);
+ if chunk then
+ if chunked then
+ chunk = ("%x\r\n%s\r\n"):format(#chunk, chunk);
+ end
+ -- io.write("."); io.flush();
+ response.conn:write(chunk);
+ else
+ if chunked then
+ response.conn:write("0\r\n\r\n");
+ end
+ -- io.write("\n");
+ if f.close then f:close(); end
+ incomplete[response.conn] = nil;
+ return response:done();
+ end
+ end
+ response.conn:write(t_concat(prepare_header(response)));
+ return true;
+end
function _M.finish_response(response)
if response.finished then return; end
response.finished = true;
end
function _M.listen_on(port, interface, ssl)
- addserver(interface or "*", port, listener, "*a", ssl);
+ return addserver(interface or "*", port, listener, "*a", ssl);
end
function _M.add_host(host)
hosts[host] = true;