From 7abfe39cc3a0949c8bde868dd3811bf33149897d Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 28 Oct 2018 16:49:28 +0100 Subject: net.server_select: Deprecate connection:lock_read() method --- net/server_select.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/server_select.lua b/net/server_select.lua index bc86742c..1c016633 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -456,8 +456,8 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport maxreadlen = readlen or maxreadlen return bufferlen, maxreadlen, maxsendlen end - --TODO: Deprecate handler.lock_read = function (self, switch) + out_error( "server.lua, lock_read() is deprecated, use pause() and resume()" ) if switch == true then local tmp = _readlistlen _readlistlen = removesocket( _readlist, socket, _readlistlen ) -- cgit v1.2.3 From eff5acbce1361ea628ac44fe8cb980ed876c6661 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 28 Oct 2018 16:51:58 +0100 Subject: net.server_event: Deprecate :lock_read here too --- net/server_event.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/server_event.lua b/net/server_event.lua index 11bd6a29..ca80c3f2 100644 --- a/net/server_event.lua +++ b/net/server_event.lua @@ -253,6 +253,7 @@ end --TODO: Deprecate function interface_mt:lock_read(switch) + log("warn", ":lock_read is deprecated, use :pasue() and :resume()"); if switch then return self:pause(); else -- cgit v1.2.3 From 9fe357101e6a870bc94ec27577abc022c62bc6da Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 28 Oct 2018 16:53:10 +0100 Subject: net.server_select: Move code from :lock_read into :pause and :resume --- net/server_select.lua | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/net/server_select.lua b/net/server_select.lua index 1c016633..51a74c94 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -459,26 +459,28 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport handler.lock_read = function (self, switch) out_error( "server.lua, lock_read() is deprecated, use pause() and resume()" ) if switch == true then - local tmp = _readlistlen - _readlistlen = removesocket( _readlist, socket, _readlistlen ) - _readtimes[ handler ] = nil - if _readlistlen ~= tmp then - noread = true - end + return self:pause() elseif switch == false then - if noread then - noread = false - _readlistlen = addsocket(_readlist, socket, _readlistlen) - _readtimes[ handler ] = _currenttime - end + return self:resume() end return noread end handler.pause = function (self) - return self:lock_read(true); + local tmp = _readlistlen + _readlistlen = removesocket( _readlist, socket, _readlistlen ) + _readtimes[ handler ] = nil + if _readlistlen ~= tmp then + noread = true + end + return noread; end handler.resume = function (self) - return self:lock_read(false); + if noread then + noread = false + _readlistlen = addsocket(_readlist, socket, _readlistlen) + _readtimes[ handler ] = _currenttime + end + return noread; end handler.lock = function( self, switch ) handler.lock_read (switch) -- cgit v1.2.3 From 38ea739022f4adeca620b4c8bb736bacb60e1d06 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 28 Oct 2018 16:54:08 +0100 Subject: server_select: Fix :lock method This always unlocks reading. I don't believe this is used anywhere. server_event does not implement this. --- net/server_select.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/server_select.lua b/net/server_select.lua index 51a74c94..d74da130 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -483,7 +483,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport return noread; end handler.lock = function( self, switch ) - handler.lock_read (switch) + handler.lock_read (self, switch) if switch == true then handler.write = idfalse local tmp = _sendlistlen -- cgit v1.2.3 From 55e3a7a8aacae7cc401753da0f32947b0eab5d16 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 28 Oct 2018 16:55:21 +0100 Subject: net.server_select: Deprecate :lock method Exists only in server_select and I found nothing using it --- net/server_select.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/server_select.lua b/net/server_select.lua index d74da130..e30ac8fe 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -483,6 +483,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport return noread; end handler.lock = function( self, switch ) + out_error( "server.lua, lock() is deprecated" ) handler.lock_read (self, switch) if switch == true then handler.write = idfalse -- cgit v1.2.3 From 556eddb7913324503e77bfdce49b8edb55cbc59f Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 28 Oct 2018 17:08:50 +0100 Subject: net.server_select: Replace use of deprecated :lock_read in server.link --- net/server_select.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/server_select.lua b/net/server_select.lua index e30ac8fe..475f05b8 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -719,7 +719,7 @@ local function link(sender, receiver, buffersize) function receiver.sendbuffer() _sendbuffer(); if sender_locked and receiver.bufferlen() < buffersize then - sender:lock_read(false); -- Unlock now + sender:resume(); -- Unlock now sender_locked = nil; end end @@ -729,7 +729,7 @@ local function link(sender, receiver, buffersize) _readbuffer(); if not sender_locked and receiver.bufferlen() >= buffersize then sender_locked = true; - sender:lock_read(true); + sender:pause(); end end sender:set_mode("*a"); -- cgit v1.2.3 From 5834d45f487f3875987620843914c47a3824feb7 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 28 Oct 2018 17:11:18 +0100 Subject: net.server_select: Still allow buffering outgoing data on write-locked connections --- net/server_select.lua | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'net') diff --git a/net/server_select.lua b/net/server_select.lua index 475f05b8..745e1f49 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -424,9 +424,8 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport bufferlen = bufferlen + #data if bufferlen > maxsendlen then _closelist[ handler ] = "send buffer exceeded" -- cannot close the client at the moment, have to wait to the end of the cycle - handler.write = idfalse -- don't write anymore return false - elseif socket and not _sendlist[ socket ] then + elseif not nosend and socket and not _sendlist[ socket ] then _sendlistlen = addsocket(_sendlist, socket, _sendlistlen) end bufferqueuelen = bufferqueuelen + 1 @@ -486,7 +485,6 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport out_error( "server.lua, lock() is deprecated" ) handler.lock_read (self, switch) if switch == true then - handler.write = idfalse local tmp = _sendlistlen _sendlistlen = removesocket( _sendlist, socket, _sendlistlen ) _writetimes[ handler ] = nil @@ -494,7 +492,6 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport nosend = true end elseif switch == false then - handler.write = write if nosend then nosend = false write( "" ) -- cgit v1.2.3 From 3899c7ac4b50242ccfc78edc6d5e3d6c3b954008 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 25 Oct 2018 15:12:59 +0200 Subject: net.server: Add an API for holding writes of outgoing data --- net/server_epoll.lua | 20 ++++++++++++++++++-- net/server_event.lua | 13 +++++++++++++ net/server_select.lua | 31 +++++++++++++++++++------------ 3 files changed, 50 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 4b40c7d5..cdf3e8fe 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -409,8 +409,10 @@ function interface:write(data) else self.writebuffer = { data }; end - self:setwritetimeout(); - self:set(nil, true); + if not self._write_lock then + self:setwritetimeout(); + self:set(nil, true); + end return #data; end interface.send = interface.write; @@ -590,6 +592,20 @@ function interface:pausefor(t) end); end +function interface:pause_writes() + self._write_lock = true; + self:setwritetimeout(false); + self:set(nil, false); +end + +function interface:resume_writes() + self._write_lock = nil; + if self.writebuffer[1] then + self:setwritetimeout(); + self:set(nil, true); + end +end + -- Connected! function interface:onconnect() if self.conn and not self.peername and self.conn.getpeername then diff --git a/net/server_event.lua b/net/server_event.lua index ca80c3f2..70757e03 100644 --- a/net/server_event.lua +++ b/net/server_event.lua @@ -273,6 +273,19 @@ function interface_mt:resume() end end +function interface_mt:pause_writes() + return self:_lock(self.nointerface, self.noreading, true); +end + +function interface_mt:resume_writes() + self:_lock(self.nointerface, self.noreading, false); + if self.writecallback and not self.eventwrite then + self.eventwrite = addevent( base, self.conn, EV_WRITE, self.writecallback, cfg.WRITE_TIMEOUT ); -- register callback + return true; + end +end + + function interface_mt:counter(c) if c then self._connections = self._connections + c diff --git a/net/server_select.lua b/net/server_select.lua index 745e1f49..693cee5e 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -485,20 +485,27 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport out_error( "server.lua, lock() is deprecated" ) handler.lock_read (self, switch) if switch == true then - local tmp = _sendlistlen - _sendlistlen = removesocket( _sendlist, socket, _sendlistlen ) - _writetimes[ handler ] = nil - if _sendlistlen ~= tmp then - nosend = true - end + handler.pause_writes (self) elseif switch == false then - if nosend then - nosend = false - write( "" ) - end + handler.resume_writes (self) end return noread, nosend end + handler.pause_writes = function (self) + local tmp = _sendlistlen + _sendlistlen = removesocket( _sendlist, socket, _sendlistlen ) + _writetimes[ handler ] = nil + if _sendlistlen ~= tmp then + nosend = true + end + end + handler.resume_writes = function (self) + if nosend then + nosend = false + write( "" ) + end + end + local _readbuffer = function( ) -- this function reads data local buffer, err, part = receive( socket, pattern ) -- receive buffer with "pattern" if not err or (err == "wantread" or err == "timeout") then -- received something @@ -716,7 +723,7 @@ local function link(sender, receiver, buffersize) function receiver.sendbuffer() _sendbuffer(); if sender_locked and receiver.bufferlen() < buffersize then - sender:resume(); -- Unlock now + sender:lock_read(false); -- Unlock now sender_locked = nil; end end @@ -726,7 +733,7 @@ local function link(sender, receiver, buffersize) _readbuffer(); if not sender_locked and receiver.bufferlen() >= buffersize then sender_locked = true; - sender:pause(); + sender:lock_read(true); end end sender:set_mode("*a"); -- cgit v1.2.3 From 1f9b825c34e068f951cf4154ceb71580aea23eb0 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 28 Oct 2018 18:22:17 +0100 Subject: net.server_epoll: Reschedule delayed timers relative to current time This should normally never happen, but can be reproduced by suspending the process a while. --- net/server_epoll.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index cdf3e8fe..ce8996a8 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -106,9 +106,13 @@ local function runtimers(next_delay, min_wait) end local new_timeout = f(now); if new_timeout then - -- Schedule for 'delay' from the time actually scheduled, - -- not from now, in order to prevent timer drift. - timer[1] = t + new_timeout; + -- Schedule for 'delay' from the time actually scheduled, not from now, + -- in order to prevent timer drift, unless it already drifted way out of sync. + if (t + new_timeout) > ( now - new_timeout ) then + timer[1] = t + new_timeout; + else + timer[1] = now + new_timeout; + end resort_timers = true; else t_remove(timers, i); -- cgit v1.2.3 From fb768f193f73d360a61758b5a46e14d81c967151 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 29 Oct 2018 02:13:09 +0100 Subject: net.server_epoll: Use method to update peername on connect --- net/server_epoll.lua | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index ce8996a8..f7e5ae49 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -612,9 +612,7 @@ end -- Connected! function interface:onconnect() - if self.conn and not self.peername and self.conn.getpeername then - self.peername, self.peerport = self.conn:getpeername(); - end + self:updatenames(); self.onconnect = noop; self:on("connect"); end -- cgit v1.2.3 From 874cf01e2b01cf96392763957ef1df9f77dedc24 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 29 Nov 2018 16:53:22 +0100 Subject: net.websocket.frames: Prefer Lua 5.2 built-in bit module over LuaJIT version When running on Lua 5.2 this makes sense since bit32 is usually already loaded. It's sensible to prefer this going forward in case of incompatibilities between the two variants. --- net/websocket/frames.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/websocket/frames.lua b/net/websocket/frames.lua index ba25d261..b5aebb40 100644 --- a/net/websocket/frames.lua +++ b/net/websocket/frames.lua @@ -9,7 +9,7 @@ local softreq = require "util.dependencies".softreq; local random_bytes = require "util.random".bytes; -local bit = assert(softreq"bit" or softreq"bit32", +local bit = assert(softreq"bit32" or softreq"bit", "No bit module found. See https://prosody.im/doc/depends#bitop"); local band = bit.band; local bor = bit.bor; -- cgit v1.2.3 From 2b289f34f929a69424a22bb0de3b668a58ba80cd Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 8 Dec 2018 17:09:55 +0100 Subject: various: Don't rely on _G.unpack existing --- net/resolvers/basic.lua | 1 + net/resolvers/manual.lua | 1 + net/resolvers/service.lua | 1 + net/websocket/frames.lua | 1 + 4 files changed, 4 insertions(+) (limited to 'net') diff --git a/net/resolvers/basic.lua b/net/resolvers/basic.lua index 9a3c9952..56f9c77d 100644 --- a/net/resolvers/basic.lua +++ b/net/resolvers/basic.lua @@ -1,5 +1,6 @@ local adns = require "net.adns"; local inet_pton = require "util.net".pton; +local unpack = table.unpack or unpack; -- luacheck: ignore 113 local methods = {}; local resolver_mt = { __index = methods }; diff --git a/net/resolvers/manual.lua b/net/resolvers/manual.lua index c0d4e5d5..dbc40256 100644 --- a/net/resolvers/manual.lua +++ b/net/resolvers/manual.lua @@ -1,5 +1,6 @@ local methods = {}; local resolver_mt = { __index = methods }; +local unpack = table.unpack or unpack; -- luacheck: ignore 113 -- Find the next target to connect to, and -- pass it to cb() diff --git a/net/resolvers/service.lua b/net/resolvers/service.lua index b5a2d821..d1b8556c 100644 --- a/net/resolvers/service.lua +++ b/net/resolvers/service.lua @@ -1,5 +1,6 @@ local adns = require "net.adns"; local basic = require "net.resolvers.basic"; +local unpack = table.unpack or unpack; -- luacheck: ignore 113 local methods = {}; local resolver_mt = { __index = methods }; diff --git a/net/websocket/frames.lua b/net/websocket/frames.lua index b5aebb40..c3333020 100644 --- a/net/websocket/frames.lua +++ b/net/websocket/frames.lua @@ -16,6 +16,7 @@ local bor = bit.bor; local bxor = bit.bxor; local lshift = bit.lshift; local rshift = bit.rshift; +local unpack = table.unpack or unpack; -- luacheck: ignore 113 local t_concat = table.concat; local s_byte = string.byte; -- cgit v1.2.3 From 5a608450d505944cbac268f28e48751c8fa3ee10 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 8 Dec 2018 17:10:51 +0100 Subject: lint: Remove use of the 143 error code Does not appear to be invoked by anything --- net/websocket/frames.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/websocket/frames.lua b/net/websocket/frames.lua index c3333020..86752109 100644 --- a/net/websocket/frames.lua +++ b/net/websocket/frames.lua @@ -22,8 +22,8 @@ local t_concat = table.concat; local s_byte = string.byte; local s_char= string.char; local s_sub = string.sub; -local s_pack = string.pack; -- luacheck: ignore 143 -local s_unpack = string.unpack; -- luacheck: ignore 143 +local s_pack = string.pack; +local s_unpack = string.unpack; if not s_pack and softreq"struct" then s_pack = softreq"struct".pack; -- cgit v1.2.3 From 726a7996dd944551c5a4007872ae06dd7f3facae Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 8 Dec 2018 21:17:39 +0100 Subject: net.server_epoll: Call onconnect right after accept()ing a new client --- net/server_epoll.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 13c8315a..3088b55b 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -577,6 +577,8 @@ function interface:onacceptable() client:init(); if self.tls_direct then client:starttls(self.tls_ctx); + else + client:onconnect(); end end -- cgit v1.2.3 From e6e285898bd7dab34cf8c4c0ac5a748334f65ff0 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 8 Dec 2018 21:28:48 +0100 Subject: net.server_epoll: Bail on callback error An error calling a callback would be considered a truthy return value, which is not right. --- net/server_epoll.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 3088b55b..b2165b1d 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -180,6 +180,7 @@ function interface:on(what, ...) local ok, err = pcall(listener, self, ...); if not ok then log("error", "Error calling on%s: %s", what, err); + return; end return err; end -- cgit v1.2.3 From 619990cf1f9ce75c60252b54da31ba7597fe57b8 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 9 Dec 2018 20:53:33 +0100 Subject: net.connlisteners: Remove deprecated stub module This was deprecated in 0.9.x Removing so auto-completion chooses net/connect.lua instead of net/conn --- net/connlisteners.lua | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 net/connlisteners.lua (limited to 'net') diff --git a/net/connlisteners.lua b/net/connlisteners.lua deleted file mode 100644 index 9b8f88c3..00000000 --- a/net/connlisteners.lua +++ /dev/null @@ -1,18 +0,0 @@ --- COMPAT w/pre-0.9 -local log = require "util.logger".init("net.connlisteners"); -local traceback = debug.traceback; - -local _ENV = nil; --- luacheck: std none - -local function fail() - log("error", "Attempt to use legacy connlisteners API. For more info see https://prosody.im/doc/developers/network"); - log("error", "Legacy connlisteners API usage, %s", traceback("", 2)); -end - -return { - register = fail; - get = fail; - start = fail; - -- epic fail -}; -- cgit v1.2.3 From 4da406588e5177c0b663f2658336888b29795d13 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 24 Dec 2018 03:00:27 +0100 Subject: net.adns: Silence individual luacheck warnings instead of ignoring entire file --- net/adns.lua | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/adns.lua b/net/adns.lua index 560e4b53..4fa01f8a 100644 --- a/net/adns.lua +++ b/net/adns.lua @@ -14,7 +14,7 @@ local log = require "util.logger".init("adns"); local coroutine, tostring, pcall = coroutine, tostring, pcall; local setmetatable = setmetatable; -local function dummy_send(sock, data, i, j) return (j-i)+1; end +local function dummy_send(sock, data, i, j) return (j-i)+1; end -- luacheck: ignore 212 local _ENV = nil; -- luacheck: std none @@ -29,8 +29,7 @@ local function new_async_socket(sock, resolver) local peername = ""; local listener = {}; local handler = {}; - local err; - function listener.onincoming(conn, data) + function listener.onincoming(conn, data) -- luacheck: ignore 212/conn if data then resolver:feed(handler, data); end @@ -46,9 +45,12 @@ local function new_async_socket(sock, resolver) resolver:servfail(conn); -- Let the magic commence end end - handler, err = server.wrapclient(sock, "dns", 53, listener); - if not handler then - return nil, err; + do + local err; + handler, err = server.wrapclient(sock, "dns", 53, listener); + if not handler then + return nil, err; + end end handler.settimeout = function () end @@ -89,7 +91,7 @@ function async_resolver_methods:lookup(handler, qname, qtype, qclass) end)(resolver:peek(qname, qtype, qclass)); end -function query_methods:cancel(call_handler, reason) +function query_methods:cancel(call_handler, reason) -- luacheck: ignore 212/reason log("warn", "Cancelling DNS lookup for %s", tostring(self[4])); self[1].cancel(self[2], self[3], self[4], self[5], call_handler); end -- cgit v1.2.3 From a40e044c0327b838e4a4e161e92798ed3ceadcf5 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 9 Feb 2019 20:34:00 +0100 Subject: net.server_epoll: Separate timeout for initial connection attempts server_event has this separation already --- net/server_epoll.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 807e0b4c..a80b33a9 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -41,6 +41,9 @@ local default_config = { __index = { -- How long to wait for a socket to become writable after queuing data to send send_timeout = 60; + -- How long to wait for a socket to become writable after creation + connect_timeout = 20; + -- Some number possibly influencing how many pending connections can be accepted tcp_backlog = 128; @@ -585,7 +588,7 @@ end -- Initialization function interface:init() - self:setwritetimeout(); + self:setwritetimeout(cfg.connect_timeout); return self:add(true, true); end -- cgit v1.2.3 From ce03153c84ca4f2ef38daa09ab078d6e1a092469 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 9 Feb 2019 20:54:35 +0100 Subject: net.server_epoll: Increase send_timeout to 3 minutes (to match server_event) The separate connect_timeout means we can afford a longer send_timeout --- net/server_epoll.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index a80b33a9..fdf006f6 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -39,7 +39,7 @@ local default_config = { __index = { read_timeout = 14 * 60; -- How long to wait for a socket to become writable after queuing data to send - send_timeout = 60; + send_timeout = 180; -- How long to wait for a socket to become writable after creation connect_timeout = 20; -- cgit v1.2.3 From 3cb132326dd6489e14a26071f87d68bf277a5a70 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 13 Sep 2018 21:16:37 +0200 Subject: net.server: New API for creating server listeners server.listen(interface, port, listeners, options); --- net/server_epoll.lua | 18 ++++++++++++++---- net/server_event.lua | 22 ++++++++++++++++------ net/server_select.lua | 30 ++++++++++++++++++++++-------- 3 files changed, 52 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index fdf006f6..5609f058 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -637,7 +637,7 @@ function interface:onconnect() self:on("connect"); end -local function addserver(addr, port, listeners, read_size, tls_ctx) +local function listen(addr, port, listeners, config) local conn, err = socket.bind(addr, port, cfg.tcp_backlog); if not conn then return conn, err; end conn:settimeout(0); @@ -645,10 +645,10 @@ local function addserver(addr, port, listeners, read_size, tls_ctx) conn = conn; created = gettime(); listeners = listeners; - read_size = read_size; + read_size = config and config.read_size; onreadable = interface.onacceptable; - tls_ctx = tls_ctx; - tls_direct = tls_ctx and true or false; + tls_ctx = config and config.tls_ctx; + tls_direct = config and config.tls_direct; sockname = addr; sockport = port; }, interface_mt); @@ -656,6 +656,15 @@ local function addserver(addr, port, listeners, read_size, tls_ctx) return server; end +-- COMPAT +local function addserver(addr, port, listeners, read_size, tls_ctx) + return listen(addr, port, listeners, { + read_size = read_size; + tls_ctx = tls_ctx; + tls_direct = tls_ctx and true or false; + }); +end + -- COMPAT local function wrapclient(conn, addr, port, listeners, read_size, tls_ctx) local client = wrapsocket(conn, nil, read_size, listeners, tls_ctx); @@ -792,6 +801,7 @@ return { addserver = addserver; addclient = addclient; add_task = addtimer; + listen = listen; at = at; loop = loop; closeall = closeall; diff --git a/net/server_event.lua b/net/server_event.lua index 70757e03..b78bf412 100644 --- a/net/server_event.lua +++ b/net/server_event.lua @@ -649,7 +649,7 @@ local function handleclient( client, ip, port, server, pattern, listener, sslctx return interface end -local function handleserver( server, addr, port, pattern, listener, sslctx ) -- creates an server interface +local function handleserver( server, addr, port, pattern, listener, sslctx, startssl ) -- creates an server interface debug "creating server interface..." local interface = { _connections = 0; @@ -695,7 +695,7 @@ local function handleserver( server, addr, port, pattern, listener, sslctx ) -- interface._connections = interface._connections + 1 -- increase connection count local clientinterface = handleclient( client, client_ip, client_port, interface, pattern, listener, sslctx ) --vdebug( "client id:", clientinterface, "startssl:", startssl ) - if has_luasec and sslctx then + if has_luasec and startssl then clientinterface:starttls(sslctx, true) else clientinterface:_start_session( true ) @@ -714,9 +714,9 @@ local function handleserver( server, addr, port, pattern, listener, sslctx ) -- return interface end -local function addserver( addr, port, listener, pattern, sslctx, startssl ) -- TODO: check arguments - --vdebug( "creating new tcp server with following parameters:", addr or "nil", port or "nil", sslctx or "nil", startssl or "nil") - if sslctx and not has_luasec then +local function listen(addr, port, listener, config) + config = config or {} + if config.sslctx and not has_luasec then debug "fatal error: luasec not found" return nil, "luasec not found" end @@ -725,11 +725,20 @@ local function addserver( addr, port, listener, pattern, sslctx, startssl ) -- debug( "creating server socket on "..addr.." port "..port.." failed:", err ) return nil, err end - local interface = handleserver( server, addr, port, pattern, listener, sslctx, startssl ) -- new server handler + local interface = handleserver( server, addr, port, config.read_size, listener, config.tls_ctx, config.tls_direct) -- new server handler debug( "new server created with id:", tostring(interface)) return interface end +local function addserver( addr, port, listener, pattern, sslctx ) -- TODO: check arguments + --vdebug( "creating new tcp server with following parameters:", addr or "nil", port or "nil", sslctx or "nil", startssl or "nil") + return listen( addr, port, listener, { + read_size = pattern, + tls_ctx = sslctx, + tls_direct = not not sslctx, + }); +end + local function wrapclient( client, ip, port, listeners, pattern, sslctx ) local interface = handleclient( client, ip, port, nil, pattern, listeners, sslctx ) interface:_start_connection(sslctx) @@ -890,6 +899,7 @@ return { event_base = base, addevent = newevent, addserver = addserver, + listen = listen, addclient = addclient, wrapclient = wrapclient, setquitting = setquitting, diff --git a/net/server_select.lua b/net/server_select.lua index f616116e..d82936e6 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -68,6 +68,7 @@ local idfalse local closeall local addsocket local addserver +local listen local addtimer local getserver local wrapserver @@ -157,7 +158,7 @@ _maxsslhandshake = 30 -- max handshake round-trips ----------------------------------// PRIVATE //-- -wrapserver = function( listeners, socket, ip, serverport, pattern, sslctx ) -- this function wraps a server -- FIXME Make sure FD < _maxfd +wrapserver = function( listeners, socket, ip, serverport, pattern, sslctx, ssldirect ) -- this function wraps a server -- FIXME Make sure FD < _maxfd if socket:getfd() >= _maxfd then out_error("server.lua: Disallowed FD number: "..socket:getfd()) @@ -244,13 +245,13 @@ wrapserver = function( listeners, socket, ip, serverport, pattern, sslctx ) -- t local client, err = accept( socket ) -- try to accept if client then local ip, clientport = client:getpeername( ) - local handler, client, err = wrapconnection( handler, listeners, client, ip, serverport, clientport, pattern, sslctx ) -- wrap new client socket + local handler, client, err = wrapconnection( handler, listeners, client, ip, serverport, clientport, pattern, sslctx, ssldirect ) -- wrap new client socket if err then -- error while wrapping ssl socket return false end connections = connections + 1 out_put( "server.lua: accepted new client connection from ", tostring(ip), ":", tostring(clientport), " to ", tostring(serverport)) - if dispatch and not sslctx then -- SSL connections will notify onconnect when handshake completes + if dispatch and not ssldirect then -- SSL connections will notify onconnect when handshake completes return dispatch( handler ); end return; @@ -264,7 +265,7 @@ wrapserver = function( listeners, socket, ip, serverport, pattern, sslctx ) -- t return handler end -wrapconnection = function( server, listeners, socket, ip, serverport, clientport, pattern, sslctx ) -- this function wraps a client to a handler object +wrapconnection = function( server, listeners, socket, ip, serverport, clientport, pattern, sslctx, ssldirect ) -- this function wraps a client to a handler object if socket:getfd() >= _maxfd then out_error("server.lua: Disallowed FD number: "..socket:getfd()) -- PROTIP: Switch to libevent @@ -666,7 +667,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport _socketlist[ socket ] = handler _readlistlen = addsocket(_readlist, socket, _readlistlen) - if sslctx and has_luasec then + if sslctx and ssldirect and has_luasec then out_put "server.lua: auto-starting ssl negotiation..." handler.autostart_ssl = true; local ok, err = handler:starttls(sslctx); @@ -741,9 +742,13 @@ end ----------------------------------// PUBLIC //-- -addserver = function( addr, port, listeners, pattern, sslctx ) -- this function provides a way for other scripts to reg a server +listen = function ( addr, port, listeners, config ) addr = addr or "*" + config = config or {} local err + local sslctx = config.tls_ctx; + local ssldirect = config.tls_direct; + local pattern = config.read_size; if type( listeners ) ~= "table" then err = "invalid listener table" elseif type ( addr ) ~= "string" then @@ -764,7 +769,7 @@ addserver = function( addr, port, listeners, pattern, sslctx ) -- this function out_error( "server.lua, [", addr, "]:", port, ": ", err ) return nil, err end - local handler, err = wrapserver( listeners, server, addr, port, pattern, sslctx ) -- wrap new server socket + local handler, err = wrapserver( listeners, server, addr, port, pattern, sslctx, ssldirect ) -- wrap new server socket if not handler then server:close( ) return nil, err @@ -777,6 +782,14 @@ addserver = function( addr, port, listeners, pattern, sslctx ) -- this function return handler end +addserver = function( addr, port, listeners, pattern, sslctx ) -- this function provides a way for other scripts to reg a server + return listen(addr, port, listeners, { + read_size = pattern; + tls_ctx = sslctx; + tls_direct = sslctx and true or false; + }); +end + getserver = function ( addr, port ) return _server[ addr..":"..port ]; end @@ -985,7 +998,7 @@ end --// EXPERIMENTAL //-- local wrapclient = function( socket, ip, serverport, listeners, pattern, sslctx ) - local handler, socket, err = wrapconnection( nil, listeners, socket, ip, serverport, "clientport", pattern, sslctx ) + local handler, socket, err = wrapconnection( nil, listeners, socket, ip, serverport, "clientport", pattern, sslctx, sslctx) if not handler then return nil, err end _socketlist[ socket ] = handler if not sslctx then @@ -1121,6 +1134,7 @@ return { stats = stats, closeall = closeall, addserver = addserver, + listen = listen, getserver = getserver, setlogger = setlogger, getsettings = getsettings, -- cgit v1.2.3 From a1ef28548caaf3dc474b4c638aee917e2ca1563d Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 10 Mar 2019 19:35:34 +0100 Subject: net.server_epoll: Add support for SNI (#409) --- net/server_epoll.lua | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 5609f058..3c8b2613 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -509,6 +509,13 @@ function interface:tlshandskake() end conn:settimeout(0); self.conn = conn; + if conn.sni then + if self.servername then + conn:sni(self.servername); + elseif self._server and self._server.hosts then + conn:sni(self._server.hosts, true); + end + end self:on("starttls"); self.ondrain = nil; self.onwritable = interface.tlshandskake; @@ -649,6 +656,7 @@ local function listen(addr, port, listeners, config) onreadable = interface.onacceptable; tls_ctx = config and config.tls_ctx; tls_direct = config and config.tls_direct; + hosts = config and config.sni_hosts; sockname = addr; sockport = port; }, interface_mt); -- cgit v1.2.3 From af5e6fcb649c43591524e5f00bf178428718123a Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 10 Mar 2019 19:32:54 +0100 Subject: net.server_event: Add SNI support (#409) Snippet adapted from server_epoll --- net/server_event.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'net') diff --git a/net/server_event.lua b/net/server_event.lua index b78bf412..6c9b941d 100644 --- a/net/server_event.lua +++ b/net/server_event.lua @@ -164,6 +164,15 @@ function interface_mt:_start_ssl(call_onconnect) -- old socket will be destroyed debug( "fatal error while ssl wrapping:", err ) return false end + + if self.conn.sni then + if self.servername then + self.conn:sni(self.servername); + elseif self._server and self._server.hosts then + self.conn:sni(self._server.hosts, true); + end + end + self.conn:settimeout( 0 ) -- set non blocking local handshakecallback = coroutine_wrap(function( event ) local _, err @@ -665,6 +674,7 @@ local function handleserver( server, addr, port, pattern, listener, sslctx, star _ip = addr, _port = port, _pattern = pattern, _sslctx = sslctx; + hosts = {}; } interface.id = tostring(interface):match("%x+$"); interface.readcallback = function( event ) -- server handler, called on incoming connections -- cgit v1.2.3 From 5fb7d2d35a2c24a9152931d29d614c2aa8714c7e Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 10 Mar 2019 19:32:33 +0100 Subject: net.server_select: SNI support (#409) --- net/server_select.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'net') diff --git a/net/server_select.lua b/net/server_select.lua index d82936e6..b52cc6d7 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -184,6 +184,7 @@ wrapserver = function( listeners, socket, ip, serverport, pattern, sslctx, ssldi handler.sslctx = function( ) return sslctx end + handler.hosts = {} -- sni handler.remove = function( ) connections = connections - 1 if handler then @@ -627,11 +628,20 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport out_put( "server.lua: attempting to start tls on " .. tostring( socket ) ) local oldsocket, err = socket socket, err = ssl_wrap( socket, sslctx ) -- wrap socket + if not socket then out_put( "server.lua: error while starting tls on client: ", tostring(err or "unknown error") ) return nil, err -- fatal error end + if socket.sni then + if self.servername then + socket:sni(self.servername); + elseif self.server() and self.server().hosts then + socket:sni(self.server().hosts, true); + end + end + socket:settimeout( 0 ) -- add the new socket to our system -- cgit v1.2.3 From 5d2608e150b7a739c0b1658fd2e9031af9ad2991 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 11 Mar 2019 13:00:51 +0100 Subject: net.server: Only add alternate SNI contexts if at least one is provided Fixes use of when a client sends SNI, which would send no certificate otherwise. --- net/server_epoll.lua | 2 +- net/server_event.lua | 2 +- net/server_select.lua | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 3c8b2613..4bdc2e21 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -512,7 +512,7 @@ function interface:tlshandskake() if conn.sni then if self.servername then conn:sni(self.servername); - elseif self._server and self._server.hosts then + elseif self._server and type(self._server.hosts) == "table" and next(self._server.hosts) ~= nil then conn:sni(self._server.hosts, true); end end diff --git a/net/server_event.lua b/net/server_event.lua index 6c9b941d..2bee614a 100644 --- a/net/server_event.lua +++ b/net/server_event.lua @@ -168,7 +168,7 @@ function interface_mt:_start_ssl(call_onconnect) -- old socket will be destroyed if self.conn.sni then if self.servername then self.conn:sni(self.servername); - elseif self._server and self._server.hosts then + elseif self._server and type(self._server.hosts) == "table" and next(self._server.hosts) ~= nil then self.conn:sni(self._server.hosts, true); end end diff --git a/net/server_select.lua b/net/server_select.lua index b52cc6d7..4b156409 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -637,7 +637,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport if socket.sni then if self.servername then socket:sni(self.servername); - elseif self.server() and self.server().hosts then + elseif self._server and type(self._server.hosts) == "table" and next(self._server.hosts) ~= nil then socket:sni(self.server().hosts, true); end end -- cgit v1.2.3 From 50f89a9f96e4a37cb367c732fefd9ae40a6d82f9 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 12 Mar 2019 23:13:51 +0100 Subject: net.server_epoll: Optimize timer handling --- net/server_epoll.lua | 83 +++++++++++++++++++--------------------------------- 1 file changed, 30 insertions(+), 53 deletions(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 4bdc2e21..4037f7ab 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -6,9 +6,7 @@ -- -local t_sort = table.sort; local t_insert = table.insert; -local t_remove = table.remove; local t_concat = table.concat; local setmetatable = setmetatable; local tostring = tostring; @@ -20,6 +18,7 @@ local log = require "util.logger".init("server_epoll"); local socket = require "socket"; local luasec = require "ssl"; local gettime = require "util.time".now; +local indexedbheap = require "util.indexedbheap"; local createtable = require "util.table".create; local inet = require "util.net"; local inet_pton = inet.pton; @@ -69,22 +68,24 @@ local fds = createtable(10, 0); -- FD -> conn -- Timer and scheduling -- -local timers = {}; +local timers = indexedbheap.create(); local function noop() end local function closetimer(t) t[1] = 0; t[2] = noop; + timers:remove(t.id); end --- Set to true when timers have changed -local resort_timers = false; +local function reschedule(t, time) + t[1] = time; + timers:reprioritize(t.id, time); +end -- Add absolute timer local function at(time, f) - local timer = { time, f, close = closetimer }; - t_insert(timers, timer); - resort_timers = true; + local timer = { time, f, close = closetimer, reschedule = reschedule, id = nil }; + timer.id = timers:insert(timer, time); return timer; end @@ -97,54 +98,32 @@ end -- Return time until next timeout local function runtimers(next_delay, min_wait) -- Any timers at all? - if not timers[1] then - return next_delay; - end + local now = gettime(); + local peek = timers:peek(); + while peek do - if resort_timers then - -- Sort earliest timers to the end - t_sort(timers, function (a, b) return a[1] > b[1]; end); - resort_timers = false; - end - - -- Iterate from the end and remove completed timers - for i = #timers, 1, -1 do - local timer = timers[i]; - local t, f = timer[1], timer[2]; - -- Get time for every iteration to increase accuracy - local now = gettime(); - if t > now then - -- This timer should not fire yet - local diff = t - now; - if diff < next_delay then - next_delay = diff; - end + if peek > now then + next_delay = peek - now; break; end - local new_timeout = f(now); - if new_timeout then - -- Schedule for 'delay' from the time actually scheduled, not from now, - -- in order to prevent timer drift, unless it already drifted way out of sync. - if (t + new_timeout) > ( now - new_timeout ) then - timer[1] = t + new_timeout; - else - timer[1] = now + new_timeout; - end - resort_timers = true; - else - t_remove(timers, i); + + local _, timer, id = timers:pop(); + local ok, ret = pcall(timer[2], now); + if ok and type(ret) == "number" then + local next_time = now+ret; + timer[1] = next_time; + timers:insert(timer, next_time); end - end - if resort_timers or next_delay < min_wait then - -- Timers may be added from within a timer callback. - -- Those would not be considered for next_delay, - -- and we might sleep for too long, so instead - -- we return a shorter timeout so we can - -- properly sort all new timers. - next_delay = min_wait; + peek = timers:peek(); + end + if peek == nil then + return next_delay; end + if next_delay < min_wait then + return min_wait; + end return next_delay; end @@ -251,8 +230,7 @@ function interface:setreadtimeout(t) end t = t or cfg.read_timeout; if self._readtimeout then - self._readtimeout[1] = gettime() + t; - resort_timers = true; + self._readtimeout:reschedule(gettime() + t); else self._readtimeout = addtimer(t, function () if self:on("readtimeout") then @@ -276,8 +254,7 @@ function interface:setwritetimeout(t) end t = t or cfg.send_timeout; if self._writetimeout then - self._writetimeout[1] = gettime() + t; - resort_timers = true; + self._writetimeout:reschedule(gettime() + t); else self._writetimeout = addtimer(t, function () self:on("disconnect", "write timeout"); -- cgit v1.2.3 From dc241cf18e1976c79296b8857fdd5b5bb50d43c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Sat, 23 Mar 2019 01:57:12 +0000 Subject: net/server_event: fix typo in comment --- net/server_event.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/server_event.lua b/net/server_event.lua index 2bee614a..42c9af2e 100644 --- a/net/server_event.lua +++ b/net/server_event.lua @@ -658,7 +658,7 @@ local function handleclient( client, ip, port, server, pattern, listener, sslctx return interface end -local function handleserver( server, addr, port, pattern, listener, sslctx, startssl ) -- creates an server interface +local function handleserver( server, addr, port, pattern, listener, sslctx, startssl ) -- creates a server interface debug "creating server interface..." local interface = { _connections = 0; -- cgit v1.2.3 From 20eaa5d17bcff2a0f861b48f23ec3b3d4290f583 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 24 Mar 2019 19:07:39 +0100 Subject: net.server_event: Allow writing into buffer of write-locked connections Check for 'nointerface' flag instead, whatever that means. --- net/server_event.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/server_event.lua b/net/server_event.lua index 42c9af2e..fde79d86 100644 --- a/net/server_event.lua +++ b/net/server_event.lua @@ -304,7 +304,7 @@ end -- Public methods function interface_mt:write(data) - if self.nowriting then return nil, "locked" end + if self.nointerface then return nil, "locked"; end --vdebug( "try to send data to client, id/data:", self.id, data ) data = tostring( data ) local len = #data @@ -316,7 +316,7 @@ function interface_mt:write(data) end t_insert(self.writebuffer, data) -- new buffer self.writebufferlen = total - if not self.eventwrite then -- register new write event + if not self.eventwrite and not self.nowriting then -- register new write event --vdebug( "register new write event" ) self.eventwrite = addevent( base, self.conn, EV_WRITE, self.writecallback, cfg.WRITE_TIMEOUT ) end -- cgit v1.2.3 From e8f72c6d4f6bc28e54f93702eb4825de8c81229e Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 24 Mar 2019 20:12:22 +0100 Subject: net.server_select: Fix write pause/resume functions Nothing would happen if the write buffer was empty. Also simplified the code because it took too long to understand what `if _sendlistlen ~= tmp then` did. --- net/server_select.lua | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/server_select.lua b/net/server_select.lua index 4b156409..5d554655 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -497,14 +497,12 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport local tmp = _sendlistlen _sendlistlen = removesocket( _sendlist, socket, _sendlistlen ) _writetimes[ handler ] = nil - if _sendlistlen ~= tmp then - nosend = true - end + nosend = true end handler.resume_writes = function (self) - if nosend then - nosend = false - write( "" ) + nosend = false + if bufferlen > 0 then + _sendlistlen = addsocket(_sendlist, socket, _sendlistlen) end end -- cgit v1.2.3 From 6f6ac910564bf6ecdc0e6b70cf06bd84a24868fb Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 5 Apr 2019 16:10:51 +0200 Subject: net.http.files: Copy of mod_http_files The intent is to make it easier to reuse and simplify mod_http_files. Currently modules will use the serve() function exported by mod_http_files in order to serve their own files. This makes it unclear whether mod_http_files should be doing anything on its own. Moving the logic into a separate module should help here, as well as make re-use outside of prosody easier. --- net/http/files.lua | 198 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 net/http/files.lua (limited to 'net') diff --git a/net/http/files.lua b/net/http/files.lua new file mode 100644 index 00000000..1dae0d6d --- /dev/null +++ b/net/http/files.lua @@ -0,0 +1,198 @@ +-- Prosody IM +-- Copyright (C) 2008-2010 Matthew Wild +-- Copyright (C) 2008-2010 Waqas Hussain +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- + +module:depends("http"); +local server = require"net.http.server"; +local lfs = require "lfs"; + +local os_date = os.date; +local open = io.open; +local stat = lfs.attributes; +local build_path = require"socket.url".build_path; +local path_sep = package.config:sub(1,1); + +local base_path = module:get_option_path("http_files_dir", module:get_option_path("http_path")); +local cache_size = module:get_option_number("http_files_cache_size", 128); +local cache_max_file_size = module:get_option_number("http_files_cache_max_file_size", 4096); +local dir_indices = module:get_option_array("http_index_files", { "index.html", "index.htm" }); +local directory_index = module:get_option_boolean("http_dir_listing"); + +local mime_map = module:shared("/*/http_files/mime").types; +if not mime_map then + mime_map = { + html = "text/html", htm = "text/html", + xml = "application/xml", + txt = "text/plain", + css = "text/css", + js = "application/javascript", + png = "image/png", + gif = "image/gif", + jpeg = "image/jpeg", jpg = "image/jpeg", + svg = "image/svg+xml", + }; + module:shared("/*/http_files/mime").types = mime_map; + + local mime_types, err = open(module:get_option_path("mime_types_file", "/etc/mime.types", "config"), "r"); + if mime_types then + local mime_data = mime_types:read("*a"); + mime_types:close(); + setmetatable(mime_map, { + __index = function(t, ext) + local typ = mime_data:match("\n(%S+)[^\n]*%s"..(ext:lower()).."%s") or "application/octet-stream"; + t[ext] = typ; + return typ; + end + }); + end +end + +local forbidden_chars_pattern = "[/%z]"; +if prosody.platform == "windows" then + forbidden_chars_pattern = "[/%z\001-\031\127\"*:<>?|]" +end + +local urldecode = require "util.http".urldecode; +function sanitize_path(path) + if not path then return end + local out = {}; + + local c = 0; + for component in path:gmatch("([^/]+)") do + component = urldecode(component); + if component:find(forbidden_chars_pattern) then + return nil; + elseif component == ".." then + if c <= 0 then + return nil; + end + out[c] = nil; + c = c - 1; + elseif component ~= "." then + c = c + 1; + out[c] = component; + end + end + if path:sub(-1,-1) == "/" then + out[c+1] = ""; + end + return "/"..table.concat(out, "/"); +end + +local cache = require "util.cache".new(cache_size); + +function serve(opts) + if type(opts) ~= "table" then -- assume path string + opts = { path = opts }; + end + -- luacheck: ignore 431 + local base_path = opts.path; + local dir_indices = opts.index_files or dir_indices; + local directory_index = opts.directory_index; + local function serve_file(event, path) + local request, response = event.request, event.response; + local sanitized_path = sanitize_path(path); + if path and not sanitized_path then + return 400; + end + path = sanitized_path; + local orig_path = sanitize_path(request.path); + local full_path = base_path .. (path or ""):gsub("/", path_sep); + local attr = stat(full_path:match("^.*[^\\/]")); -- Strip trailing path separator because Windows + if not attr then + return 404; + end + + local request_headers, response_headers = request.headers, response.headers; + + local last_modified = os_date('!%a, %d %b %Y %H:%M:%S GMT', attr.modification); + response_headers.last_modified = last_modified; + + local etag = ('"%02x-%x-%x-%x"'):format(attr.dev or 0, attr.ino or 0, attr.size or 0, attr.modification or 0); + response_headers.etag = etag; + + local if_none_match = request_headers.if_none_match + local if_modified_since = request_headers.if_modified_since; + if etag == if_none_match + or (not if_none_match and last_modified == if_modified_since) then + return 304; + end + + local data = cache:get(orig_path); + if data and data.etag == etag then + response_headers.content_type = data.content_type; + data = data.data; + elseif attr.mode == "directory" and path then + if full_path:sub(-1) ~= "/" then + local dir_path = { is_absolute = true, is_directory = true }; + for dir in orig_path:gmatch("[^/]+") do dir_path[#dir_path+1]=dir; end + response_headers.location = build_path(dir_path); + return 301; + end + for i=1,#dir_indices do + if stat(full_path..dir_indices[i], "mode") == "file" then + return serve_file(event, path..dir_indices[i]); + end + end + + if directory_index then + data = server._events.fire_event("directory-index", { path = request.path, full_path = full_path }); + end + if not data then + return 403; + end + cache:set(orig_path, { data = data, content_type = mime_map.html; etag = etag; }); + response_headers.content_type = mime_map.html; + + else + local f, err = open(full_path, "rb"); + if not f then + module:log("debug", "Could not open %s. Error was %s", full_path, err); + return 403; + end + local ext = full_path:match("%.([^./]+)$"); + local content_type = ext and mime_map[ext]; + response_headers.content_type = content_type; + if attr.size > cache_max_file_size then + response_headers.content_length = attr.size; + module:log("debug", "%d > cache_max_file_size", attr.size); + return response:send_file(f); + else + data = f:read("*a"); + f:close(); + end + cache:set(orig_path, { data = data; content_type = content_type; etag = etag }); + end + + return response:send(data); + end + + return serve_file; +end + +function wrap_route(routes) + for route,handler in pairs(routes) do + if type(handler) ~= "function" then + routes[route] = serve(handler); + end + end + return routes; +end + +if base_path then + module:provides("http", { + route = { + ["GET /*"] = serve { + path = base_path; + directory_index = directory_index; + } + }; + }); +else + module:log("debug", "http_files_dir not set, assuming use by some other module"); +end + -- cgit v1.2.3 From 3ea6ca719574ce8a1bfa9532c5526da05f3ff5d9 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 5 Apr 2019 17:09:03 +0200 Subject: net.http.files: Make into standalone library --- net/http/files.lua | 78 ++++++++++-------------------------------------------- 1 file changed, 14 insertions(+), 64 deletions(-) (limited to 'net') diff --git a/net/http/files.lua b/net/http/files.lua index 1dae0d6d..0b898dc6 100644 --- a/net/http/files.lua +++ b/net/http/files.lua @@ -6,9 +6,10 @@ -- COPYING file in the source package for more information. -- -module:depends("http"); local server = require"net.http.server"; local lfs = require "lfs"; +local new_cache = require "util.cache".new; +local log = require "util.logger".init("net.http.files"); local os_date = os.date; local open = io.open; @@ -16,48 +17,14 @@ local stat = lfs.attributes; local build_path = require"socket.url".build_path; local path_sep = package.config:sub(1,1); -local base_path = module:get_option_path("http_files_dir", module:get_option_path("http_path")); -local cache_size = module:get_option_number("http_files_cache_size", 128); -local cache_max_file_size = module:get_option_number("http_files_cache_max_file_size", 4096); -local dir_indices = module:get_option_array("http_index_files", { "index.html", "index.htm" }); -local directory_index = module:get_option_boolean("http_dir_listing"); - -local mime_map = module:shared("/*/http_files/mime").types; -if not mime_map then - mime_map = { - html = "text/html", htm = "text/html", - xml = "application/xml", - txt = "text/plain", - css = "text/css", - js = "application/javascript", - png = "image/png", - gif = "image/gif", - jpeg = "image/jpeg", jpg = "image/jpeg", - svg = "image/svg+xml", - }; - module:shared("/*/http_files/mime").types = mime_map; - - local mime_types, err = open(module:get_option_path("mime_types_file", "/etc/mime.types", "config"), "r"); - if mime_types then - local mime_data = mime_types:read("*a"); - mime_types:close(); - setmetatable(mime_map, { - __index = function(t, ext) - local typ = mime_data:match("\n(%S+)[^\n]*%s"..(ext:lower()).."%s") or "application/octet-stream"; - t[ext] = typ; - return typ; - end - }); - end -end local forbidden_chars_pattern = "[/%z]"; -if prosody.platform == "windows" then +if package.config:sub(1,1) == "\\" then forbidden_chars_pattern = "[/%z\001-\031\127\"*:<>?|]" end local urldecode = require "util.http".urldecode; -function sanitize_path(path) +local function sanitize_path(path) --> util.paths or util.http? if not path then return end local out = {}; @@ -83,15 +50,16 @@ function sanitize_path(path) return "/"..table.concat(out, "/"); end -local cache = require "util.cache".new(cache_size); - -function serve(opts) +local function serve(opts) if type(opts) ~= "table" then -- assume path string opts = { path = opts }; end + local mime_map = opts.mime_map or { html = "text/html" }; + local cache = new_cache(opts.cache_size or 256); + local cache_max_file_size = tonumber(opts.cache_max_file_size) or 1024 -- luacheck: ignore 431 local base_path = opts.path; - local dir_indices = opts.index_files or dir_indices; + local dir_indices = opts.index_files or { "index.html", "index.htm" }; local directory_index = opts.directory_index; local function serve_file(event, path) local request, response = event.request, event.response; @@ -151,7 +119,7 @@ function serve(opts) else local f, err = open(full_path, "rb"); if not f then - module:log("debug", "Could not open %s. Error was %s", full_path, err); + log("debug", "Could not open %s. Error was %s", full_path, err); return 403; end local ext = full_path:match("%.([^./]+)$"); @@ -159,7 +127,7 @@ function serve(opts) response_headers.content_type = content_type; if attr.size > cache_max_file_size then response_headers.content_length = attr.size; - module:log("debug", "%d > cache_max_file_size", attr.size); + log("debug", "%d > cache_max_file_size", attr.size); return response:send_file(f); else data = f:read("*a"); @@ -174,25 +142,7 @@ function serve(opts) return serve_file; end -function wrap_route(routes) - for route,handler in pairs(routes) do - if type(handler) ~= "function" then - routes[route] = serve(handler); - end - end - return routes; -end - -if base_path then - module:provides("http", { - route = { - ["GET /*"] = serve { - path = base_path; - directory_index = directory_index; - } - }; - }); -else - module:log("debug", "http_files_dir not set, assuming use by some other module"); -end +return { + serve = serve; +} -- cgit v1.2.3 From f65c017ee107f86b353d5931e85a70e8c6067f1f Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 3 May 2019 20:54:24 +0200 Subject: Fix various spelling mistakes [codespell] --- net/server_select.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/server_select.lua b/net/server_select.lua index 5d554655..e14c126e 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -124,7 +124,7 @@ local _maxsslhandshake _server = { } -- key = port, value = table; list of listening servers _readlist = { } -- array with sockets to read from -_sendlist = { } -- arrary with sockets to write to +_sendlist = { } -- array with sockets to write to _timerlist = { } -- array of timer functions _socketlist = { } -- key = socket, value = wrapped socket (handlers) _readtimes = { } -- key = handler, value = timestamp of last data reading @@ -150,7 +150,7 @@ _checkinterval = 30 -- interval in secs to check idle clients _sendtimeout = 60000 -- allowed send idle time in secs _readtimeout = 14 * 60 -- allowed read idle time in secs -local is_windows = package.config:sub(1,1) == "\\" -- check the directory separator, to detemine whether this is Windows +local is_windows = package.config:sub(1,1) == "\\" -- check the directory separator, to determine whether this is Windows _maxfd = (is_windows and math.huge) or luasocket._SETSIZE or 1024 -- max fd number, limit to 1024 by default to prevent glibc buffer overflow, but not on Windows _maxselectlen = luasocket._SETSIZE or 1024 -- But this still applies on Windows -- cgit v1.2.3 From a371d01137d44a43cbeabe2590174fc36053bb2a Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 4 May 2019 04:48:40 +0200 Subject: net.http.files: Bump cache hits so they stay cached It's not an LRU cache unless this is done. --- net/http/files.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/http/files.lua b/net/http/files.lua index 0b898dc6..090b15c8 100644 --- a/net/http/files.lua +++ b/net/http/files.lua @@ -94,6 +94,7 @@ local function serve(opts) if data and data.etag == etag then response_headers.content_type = data.content_type; data = data.data; + cache:get(orig_path, data); elseif attr.mode == "directory" and path then if full_path:sub(-1) ~= "/" then local dir_path = { is_absolute = true, is_directory = true }; -- cgit v1.2.3 From c6ca3b473e60f56a20113a3ab9d8a33231aae0e5 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 29 Jun 2019 19:19:38 +0200 Subject: net.http.files: Fix cache handling Typo that broke the LRU-ness of the caching --- net/http/files.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/http/files.lua b/net/http/files.lua index 090b15c8..7ff81fc8 100644 --- a/net/http/files.lua +++ b/net/http/files.lua @@ -94,7 +94,7 @@ local function serve(opts) if data and data.etag == etag then response_headers.content_type = data.content_type; data = data.data; - cache:get(orig_path, data); + cache:set(orig_path, data); elseif attr.mode == "directory" and path then if full_path:sub(-1) ~= "/" then local dir_path = { is_absolute = true, is_directory = true }; -- cgit v1.2.3 From d06300c456ad2209a500e64a6efac1094d58bdea Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 25 May 2019 16:09:26 +0200 Subject: net.server_epoll: Return listener error message --- net/server_epoll.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 5f62d931..4061d755 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -162,7 +162,7 @@ function interface:on(what, ...) local ok, err = pcall(listener, self, ...); if not ok then log("error", "Error calling on%s: %s", what, err); - return; + return nil, err; end return err; end -- cgit v1.2.3 From 2b596d7bd69f1c67a53c8166cc7b59cda3efce17 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 25 May 2019 16:14:31 +0200 Subject: net.server_epoll: Add experimental option to close connections in case of listener error Sometimes such errors leave sessions in an inconsistent state, so it might be better to close them early. --- net/server_epoll.lua | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 4061d755..251f91f7 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -61,6 +61,10 @@ local default_config = { __index = { -- Maximum and minimum amount of time to sleep waiting for events (adjusted for pending timers) max_wait = 86400; min_wait = 1e-06; + + -- EXPERIMENTAL + -- Whether to kill connections in case of callback errors. + fatal_errors = false; }}; local cfg = default_config.__index; @@ -162,6 +166,10 @@ function interface:on(what, ...) local ok, err = pcall(listener, self, ...); if not ok then log("error", "Error calling on%s: %s", what, err); + if cfg.fatal_errors then + log("debug", "Closing %s due to error in listener", self); + self:destroy(); + end return nil, err; end return err; -- cgit v1.2.3 From d9649edc2c6a2c22d2cdc5c8fe577deb510580bf Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 23 Jul 2019 18:06:34 +0200 Subject: net.server_epoll: Return errors from creating sockets Prevents error from attempting to index nil conn on such failure. Silences luacheck warning about the 'err' variable being unused --- net/server_epoll.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 251f91f7..f296dd37 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -694,6 +694,7 @@ local function addclient(addr, port, listeners, read_size, tls_ctx, typ) return nil, "invalid socket type"; end local conn, err = create(); + if not conn then return conn, err; end local ok, err = conn:settimeout(0); if not ok then return ok, err; end local ok, err = conn:setpeername(addr, port); -- cgit v1.2.3 From e6a6668fb5ec2eb87ec51bc23613d5c5046549ed Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 24 Jul 2019 16:50:06 +0200 Subject: net.server_epoll: Deprecate libevent emulation layer --- net/server_epoll.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index f296dd37..b6f377fd 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -813,6 +813,7 @@ return { -- libevent emulation event = { EV_READ = "r", EV_WRITE = "w", EV_READWRITE = "rw", EV_LEAVE = -1 }; addevent = function (fd, mode, callback) + log("warn", "Using deprecated libevent emulation, please update code to use watchfd API instead"); local function onevent(self) local ret = self:callback(); if ret == -1 then -- cgit v1.2.3 From 0cd5fc425d98ae6bf94b4e06a3a2d8196a9ddaf4 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 26 Jul 2019 21:21:48 +0200 Subject: net.server_epoll: Overhaul logging with one log sink per connection --- net/server_epoll.lua | 64 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 23 deletions(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index b6f377fd..1ae92d87 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -14,7 +14,8 @@ local pcall = pcall; local type = type; local next = next; local pairs = pairs; -local log = require "util.logger".init("server_epoll"); +local logger = require "util.logger"; +local log = logger.init("server_epoll"); local socket = require "socket"; local luasec = require "ssl"; local gettime = require "util.time".now; @@ -23,6 +24,7 @@ local createtable = require "util.table".create; local inet = require "util.net"; local inet_pton = inet.pton; local _SOCKETINVALID = socket._SOCKETINVALID or -1; +local new_id = require "util.id".medium; local poller = require "util.poll" local EEXIST = poller.EEXIST; @@ -145,6 +147,15 @@ function interface_mt:__tostring() return ("FD %d"):format(self:getfd()); end +interface.log = log; +function interface:debug(msg, ...) --luacheck: ignore 212/self + self.log("debug", msg, ...); +end + +function interface:error(msg, ...) --luacheck: ignore 212/self + self.log("error", msg, ...); +end + -- Replace the listener and tell the old one function interface:setlistener(listeners, data) self:on("detach"); @@ -155,20 +166,21 @@ end -- Call a listener callback function interface:on(what, ...) if not self.listeners then - log("error", "%s has no listeners", self); + self:debug("Interface is missing listener callbacks"); return; end local listener = self.listeners["on"..what]; if not listener then - -- log("debug", "Missing listener 'on%s'", what); -- uncomment for development and debugging + -- self:debug("Missing listener 'on%s'", what); -- uncomment for development and debugging return; end local ok, err = pcall(listener, self, ...); if not ok then - log("error", "Error calling on%s: %s", what, err); if cfg.fatal_errors then - log("debug", "Closing %s due to error in listener", self); + self:debug("Closing due to error calling on%s: %s", what, err); self:destroy(); + else + self:debug("Error calling on%s: %s", what, err); end return nil, err; end @@ -281,15 +293,15 @@ function interface:add(r, w) local ok, err, errno = poll:add(fd, r, w); if not ok then if errno == EEXIST then - log("debug", "%s already registered!", self); + self:debug("FD already registered in poller! (EEXIST)"); return self:set(r, w); -- So try to change its flags end - log("error", "Could not register %s: %s(%d)", self, err, errno); + self:debug("Could not register in poller: %s(%d)", err, errno); return ok, err; end self._wantread, self._wantwrite = r, w; fds[fd] = self; - log("debug", "Watching %s", self); + self:debug("Registered in poller"); return true; end @@ -302,7 +314,7 @@ function interface:set(r, w) if w == nil then w = self._wantwrite; end local ok, err, errno = poll:set(fd, r, w); if not ok then - log("error", "Could not update poller state %s: %s(%d)", self, err, errno); + self:debug("Could not update poller state: %s(%d)", err, errno); return ok, err; end self._wantread, self._wantwrite = r, w; @@ -319,12 +331,12 @@ function interface:del() end local ok, err, errno = poll:del(fd); if not ok and errno ~= ENOENT then - log("error", "Could not unregister %s: %s(%d)", self, err, errno); + self:debug("Could not unregister: %s(%d)", err, errno); return ok, err; end self._wantread, self._wantwrite = nil, nil; fds[fd] = nil; - log("debug", "Unwatched %s", self); + self:debug("Unregistered from poller"); return true; end @@ -432,10 +444,10 @@ function interface:close() if self.writebuffer and self.writebuffer[1] then self:set(false, true); -- Flush final buffer contents self.write, self.send = noop, noop; -- No more writing - log("debug", "Close %s after writing", self); + self:debug("Close after writing"); self.ondrain = interface.close; else - log("debug", "Close %s now", self); + self:debug("Closing now"); self.write, self.send = noop, noop; self.close = noop; self:on("disconnect"); @@ -464,7 +476,7 @@ function interface:starttls(tls_ctx) if tls_ctx then self.tls_ctx = tls_ctx; end self.starttls = false; if self.writebuffer and self.writebuffer[1] then - log("debug", "Start TLS on %s after write", self); + self:debug("Start TLS after write"); self.ondrain = interface.starttls; self:set(nil, true); -- make sure wantwrite is set else @@ -474,7 +486,7 @@ function interface:starttls(tls_ctx) self.onwritable = interface.tlshandskake; self.onreadable = interface.tlshandskake; self:set(true, true); - log("debug", "Prepare to start TLS on %s", self); + self:debug("Prepared to start TLS"); end end @@ -483,12 +495,12 @@ function interface:tlshandskake() self:setreadtimeout(false); if not self._tls then self._tls = true; - log("debug", "Start TLS on %s now", self); + self:debug("Starting TLS now"); self:del(); local ok, conn, err = pcall(luasec.wrap, self.conn, self.tls_ctx); if not ok then conn, err = ok, conn; - log("error", "Failed to initialize TLS: %s", err); + self:debug("Failed to initialize TLS: %s", err); end if not conn then self:on("disconnect", err); @@ -512,22 +524,22 @@ function interface:tlshandskake() end local ok, err = self.conn:dohandshake(); if ok then - log("debug", "TLS handshake on %s complete", self); + self:debug("TLS handshake complete"); self.onwritable = nil; self.onreadable = nil; self:on("status", "ssl-handshake-complete"); self:setwritetimeout(); self:set(true, true); elseif err == "wantread" then - log("debug", "TLS handshake on %s to wait until readable", self); + self:debug("TLS handshake to wait until readable"); self:set(true, false); self:setreadtimeout(cfg.ssl_handshake_timeout); elseif err == "wantwrite" then - log("debug", "TLS handshake on %s to wait until writable", self); + self:debug("TLS handshake to wait until writable"); self:set(false, true); self:setwritetimeout(cfg.ssl_handshake_timeout); else - log("debug", "TLS handshake error on %s: %s", self, err); + self:debug("TLS handshake error: %s", err); self:on("disconnect", err); self:destroy(); end @@ -544,6 +556,7 @@ local function wrapsocket(client, server, read_size, listeners, tls_ctx) -- luas writebuffer = {}; tls_ctx = tls_ctx or (server and server.tls_ctx); tls_direct = server and server.tls_direct; + log = logger.init(("conn%s"):format(new_id())); }, interface_mt); conn:updatenames(); @@ -567,12 +580,12 @@ end function interface:onacceptable() local conn, err = self.conn:accept(); if not conn then - log("debug", "Error accepting new client: %s, server will be paused for %ds", err, cfg.accept_retry_interval); + self:debug("Error accepting new client: %s, server will be paused for %ds", err, cfg.accept_retry_interval); self:pausefor(cfg.accept_retry_interval); return; end local client = wrapsocket(conn, self, nil, self.listeners); - log("debug", "New connection %s", tostring(client)); + client:debug("New connection %s on server %s", client, self); client:init(); if self.tls_direct then client:starttls(self.tls_ctx); @@ -647,7 +660,9 @@ local function listen(addr, port, listeners, config) hosts = config and config.sni_hosts; sockname = addr; sockport = port; + log = logger.init(("serv%s"):format(new_id())); }, interface_mt); + server:debug("Server %s created", server); server:add(true, false); return server; end @@ -705,6 +720,7 @@ local function addclient(addr, port, listeners, read_size, tls_ctx, typ) if tls_ctx then client:starttls(tls_ctx); end + client:debug("Client %s created", client); return client, conn; end @@ -723,6 +739,7 @@ local function watchfd(fd, onreadable, onwritable) end; -- Otherwise it'll need to be something LuaSocket-compatible end + conn.log = logger.init(("fdwatch%s"):format(new_id())); conn:add(onreadable, onwritable); return conn; end; @@ -833,6 +850,7 @@ return { fds[fd] = nil; end; }, interface_mt); + conn.log = logger.init(("fdwatch%d"):format(conn:getfd())); local ok, err = conn:add(mode == "r" or mode == "rw", mode == "w" or mode == "rw"); if not ok then return ok, err; end return conn; -- cgit v1.2.3 From ad9b431b8c24e909e2f2bc693b60bf11dd130372 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 26 Jul 2019 21:23:53 +0200 Subject: net.server_epoll: Remove unused local [luacheck] --- net/server_epoll.lua | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 1ae92d87..ccf46928 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -9,7 +9,6 @@ local t_insert = table.insert; local t_concat = table.concat; local setmetatable = setmetatable; -local tostring = tostring; local pcall = pcall; local type = type; local next = next; -- cgit v1.2.3 From 5c48dbda51bac9bf58dff9be6bc19524734ac42a Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 18 Dec 2016 17:39:16 +0000 Subject: server_epoll: Add native support for per socket bandwith limits --- net/server_epoll.lua | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index ccf46928..49ad48ea 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -377,6 +377,14 @@ function interface:onreadable() end end if not self.conn then return; end + if self._limit and (data or partial) then + local cost = self._limit * #(data or partial); + if cost > cfg.min_wait then + self:setreadtimeout(false); + self:pausefor(cost); + return; + end + end if self._wantread and self.conn:dirty() then self:setreadtimeout(false); self:pausefor(cfg.read_retry_delay); @@ -609,6 +617,7 @@ end -- Pause connection for some time function interface:pausefor(t) + self:debug("Pause for %fs", t); if self._pausefor then self._pausefor:close(); end @@ -623,6 +632,14 @@ function interface:pausefor(t) end); end +function interface:setlimit(Bps) + if Bps > 0 then + self._limit = 1/Bps; + else + self._limit = nil; + end +end + function interface:pause_writes() self._write_lock = true; self:setwritetimeout(false); -- cgit v1.2.3 From 75bfec7731e0d42ad5733a62b9772db9c72aeef9 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 30 Jul 2019 02:35:17 +0200 Subject: net.*: Remove tostring call from logging Taken care of by loggingmanager now --- net/adns.lua | 8 ++++---- net/connect.lua | 2 +- net/http.lua | 4 ++-- net/websocket.lua | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/adns.lua b/net/adns.lua index 4fa01f8a..5050c23b 100644 --- a/net/adns.lua +++ b/net/adns.lua @@ -73,11 +73,11 @@ function async_resolver_methods:lookup(handler, qname, qtype, qclass) handler(peek); return; end - log("debug", "Records for %s not in cache, sending query (%s)...", qname, tostring(coroutine.running())); + log("debug", "Records for %s not in cache, sending query (%s)...", qname, coroutine.running()); local ok, err = resolver:query(qname, qtype, qclass); if ok then coroutine.yield(setmetatable({ resolver, qclass or "IN", qtype or "A", qname, coroutine.running()}, query_mt)); -- Wait for reply - log("debug", "Reply for %s (%s)", qname, tostring(coroutine.running())); + log("debug", "Reply for %s (%s)", qname, coroutine.running()); end if ok then ok, err = pcall(handler, resolver:peek(qname, qtype, qclass)); @@ -86,13 +86,13 @@ function async_resolver_methods:lookup(handler, qname, qtype, qclass) ok, err = pcall(handler, nil, err); end if not ok then - log("error", "Error in DNS response handler: %s", tostring(err)); + log("error", "Error in DNS response handler: %s", err); end end)(resolver:peek(qname, qtype, qclass)); end function query_methods:cancel(call_handler, reason) -- luacheck: ignore 212/reason - log("warn", "Cancelling DNS lookup for %s", tostring(self[4])); + log("warn", "Cancelling DNS lookup for %s", self[4]); self[1].cancel(self[2], self[3], self[4], self[5], call_handler); end diff --git a/net/connect.lua b/net/connect.lua index b812ffcd..d4de6fb4 100644 --- a/net/connect.lua +++ b/net/connect.lua @@ -38,7 +38,7 @@ local function attempt_connection(p) p:log("debug", "Next target to try is %s:%d", ip, port); local conn, err = server.addclient(ip, port, pending_connection_listeners, p.options.pattern or "*a", p.options.sslctx, conn_type, extra); if not conn then - log("debug", "Connection attempt failed immediately: %s", tostring(err)); + log("debug", "Connection attempt failed immediately: %s", err); p.last_error = err or "unknown reason"; return attempt_connection(p); end diff --git a/net/http.lua b/net/http.lua index fe5250ac..0e03fb3a 100644 --- a/net/http.lua +++ b/net/http.lua @@ -40,7 +40,7 @@ local listener = { default_port = 80, default_mode = "*a" }; local function handleerr(err) log("error", "Traceback[http]: %s", traceback(tostring(err), 2)); return err; end local function log_if_failed(req, ret, ...) if not ret then - log("error", "Request '%s': error in callback: %s", req.id, tostring((...))); + log("error", "Request '%s': error in callback: %s", req.id, (...)); if not req.suppress_errors then error(...); end @@ -150,7 +150,7 @@ function listener.onincoming(conn, data) local request = requests[conn]; if not request then - log("warn", "Received response from connection %s with no request attached!", tostring(conn)); + log("warn", "Received response from connection %s with no request attached!", conn); return; end diff --git a/net/websocket.lua b/net/websocket.lua index 469c6a58..bb26c100 100644 --- a/net/websocket.lua +++ b/net/websocket.lua @@ -131,7 +131,7 @@ end function websocket_methods:close(code, reason) if self.readyState < 2 then code = code or 1000; - log("debug", "closing WebSocket with code %i: %s" , code , tostring(reason)); + log("debug", "closing WebSocket with code %i: %s" , code , reason); self.readyState = 2; local conn = self.conn; conn:write(frames.build_close(code, reason, true)); @@ -245,7 +245,7 @@ local function connect(url, ex, listeners) or (protocol and not protocol[r.headers["sec-websocket-protocol"]]) then s.readyState = 3; - log("warn", "WebSocket connection to %s failed: %s", url, tostring(b)); + log("warn", "WebSocket connection to %s failed: %s", url, b); if s.onerror then s:onerror("connecting-failed"); end return; end -- cgit v1.2.3 From 2fb3c3041d82abe4b51cd03f210881c52fd53b03 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 30 Jul 2019 02:35:28 +0200 Subject: net.websocket: Fix log call to pass data via format string instead of concatenation --- net/websocket.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/websocket.lua b/net/websocket.lua index bb26c100..fb16b8bb 100644 --- a/net/websocket.lua +++ b/net/websocket.lua @@ -113,7 +113,7 @@ function websocket_listeners.onincoming(conn, buffer, err) -- luacheck: ignore 2 frame.MASK = true; -- RFC 6455 6.1.5: If the data is being sent by the client, the frame(s) MUST be masked conn:write(frames.build(frame)); elseif frame.opcode == 0xA then -- Pong frame - log("debug", "Received unexpected pong frame: " .. tostring(frame.data)); + log("debug", "Received unexpected pong frame: %s", frame.data); else return fail(s, 1002, "Reserved opcode"); end -- cgit v1.2.3 From bf79ad07b26e43fe579a8761865f61e74cc682b9 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 30 Jul 2019 02:36:15 +0200 Subject: net.adns: Remove unused local [luacheck] --- net/adns.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/adns.lua b/net/adns.lua index 5050c23b..d7266958 100644 --- a/net/adns.lua +++ b/net/adns.lua @@ -11,7 +11,7 @@ local new_resolver = require "net.dns".resolver; local log = require "util.logger".init("adns"); -local coroutine, tostring, pcall = coroutine, tostring, pcall; +local coroutine, pcall = coroutine, pcall; local setmetatable = setmetatable; local function dummy_send(sock, data, i, j) return (j-i)+1; end -- luacheck: ignore 212 -- cgit v1.2.3 From 469ce79a49fabbe0d42115fa7a2f1a27e3bae3f1 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 17 Aug 2019 15:40:52 +0200 Subject: net.resolvers.service: Fix DNS fallback --- net/resolvers/service.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/resolvers/service.lua b/net/resolvers/service.lua index d1b8556c..62d269e5 100644 --- a/net/resolvers/service.lua +++ b/net/resolvers/service.lua @@ -33,7 +33,11 @@ function methods:next(cb) -- Resolve DNS to target list local dns_resolver = adns.resolver(); - dns_resolver:lookup(function (answer) + dns_resolver:lookup(function (answer, err) + if not answer and not err then + -- net.adns returns nil if there are zero records or nxdomain + answer = {}; + end if answer then if #answer == 0 then if self.extra and self.extra.default_port then -- cgit v1.2.3 From 4cc299fc0214368012a2775b94c746d2290327a0 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 28 Aug 2019 01:41:00 +0200 Subject: net.server_epoll: Add support for opportunistic writes This tries to flush data to the underlying sockets when receiving writes. This should lead to fewer timer objects being around. On the other hand, this leads to more and smaller writes which may translate to more TCP/IP packets being sent, depending on how the kernel handles this. This trades throughput for lower latency. --- net/server_epoll.lua | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 49ad48ea..ef021851 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -66,6 +66,9 @@ local default_config = { __index = { -- EXPERIMENTAL -- Whether to kill connections in case of callback errors. fatal_errors = false; + + -- Attempt writes instantly + opportunistic_writes = false; }}; local cfg = default_config.__index; @@ -413,6 +416,7 @@ function interface:onwritable() for i = #buffer, 2, -1 do buffer[i] = nil; end + self:set(nil, true); self:setwritetimeout(); end if err == "wantwrite" or err == "timeout" then @@ -439,6 +443,10 @@ function interface:write(data) self.writebuffer = { data }; end if not self._write_lock then + if cfg.opportunistic_writes then + self:onwritable(); + return #data; + end self:setwritetimeout(); self:set(nil, true); end -- cgit v1.2.3 From 9afa1ac496bac9d9eaaf687edbdde3f0c7fb66e1 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 1 Sep 2019 01:55:55 +0200 Subject: net.server: Accept and save an 'extra' field for client connections This lets code attach some extra data to be attached to client connections. --- net/server_epoll.lua | 11 ++++++----- net/server_event.lua | 11 ++++++----- net/server_select.lua | 12 +++++++----- 3 files changed, 19 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index ef021851..96e7b201 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -560,7 +560,7 @@ function interface:tlshandskake() end end -local function wrapsocket(client, server, read_size, listeners, tls_ctx) -- luasocket object -> interface object +local function wrapsocket(client, server, read_size, listeners, tls_ctx, extra) -- luasocket object -> interface object client:settimeout(0); local conn = setmetatable({ conn = client; @@ -572,6 +572,7 @@ local function wrapsocket(client, server, read_size, listeners, tls_ctx) -- luas tls_ctx = tls_ctx or (server and server.tls_ctx); tls_direct = server and server.tls_direct; log = logger.init(("conn%s"):format(new_id())); + extra = extra; }, interface_mt); conn:updatenames(); @@ -701,8 +702,8 @@ local function addserver(addr, port, listeners, read_size, tls_ctx) end -- COMPAT -local function wrapclient(conn, addr, port, listeners, read_size, tls_ctx) - local client = wrapsocket(conn, nil, read_size, listeners, tls_ctx); +local function wrapclient(conn, addr, port, listeners, read_size, tls_ctx, extra) + local client = wrapsocket(conn, nil, read_size, listeners, tls_ctx, extra); if not client.peername then client.peername, client.peerport = addr, port; end @@ -715,7 +716,7 @@ local function wrapclient(conn, addr, port, listeners, read_size, tls_ctx) end -- New outgoing TCP connection -local function addclient(addr, port, listeners, read_size, tls_ctx, typ) +local function addclient(addr, port, listeners, read_size, tls_ctx, typ, extra) local create; if not typ then local n = inet_pton(addr); @@ -738,7 +739,7 @@ local function addclient(addr, port, listeners, read_size, tls_ctx, typ) if not ok then return ok, err; end local ok, err = conn:setpeername(addr, port); if not ok and err ~= "timeout" then return ok, err; end - local client = wrapsocket(conn, nil, read_size, listeners, tls_ctx) + local client = wrapsocket(conn, nil, read_size, listeners, tls_ctx, extra) local ok, err = client:init(); if not ok then return ok, err; end if tls_ctx then diff --git a/net/server_event.lua b/net/server_event.lua index fde79d86..950a7a5c 100644 --- a/net/server_event.lua +++ b/net/server_event.lua @@ -479,7 +479,7 @@ end -- End of client interface methods -local function handleclient( client, ip, port, server, pattern, listener, sslctx ) -- creates an client interface +local function handleclient( client, ip, port, server, pattern, listener, sslctx, extra ) -- creates an client interface --vdebug("creating client interfacce...") local interface = { type = "client"; @@ -515,6 +515,7 @@ local function handleclient( client, ip, port, server, pattern, listener, sslctx _serverport = (server and server:port() or nil), _sslctx = sslctx; -- parameters _usingssl = false; -- client is using ssl; + extra = extra; } if not has_luasec then interface.starttls = false; end interface.id = tostring(interface):match("%x+$"); @@ -749,14 +750,14 @@ local function addserver( addr, port, listener, pattern, sslctx ) -- TODO: chec }); end -local function wrapclient( client, ip, port, listeners, pattern, sslctx ) - local interface = handleclient( client, ip, port, nil, pattern, listeners, sslctx ) +local function wrapclient( client, ip, port, listeners, pattern, sslctx, extra ) + local interface = handleclient( client, ip, port, nil, pattern, listeners, sslctx, extra ) interface:_start_connection(sslctx) return interface, client --function handleclient( client, ip, port, server, pattern, listener, _, sslctx ) -- creates an client interface end -local function addclient( addr, serverport, listener, pattern, sslctx, typ ) +local function addclient( addr, serverport, listener, pattern, sslctx, typ, extra ) if sslctx and not has_luasec then debug "need luasec, but not available" return nil, "luasec not found" @@ -783,7 +784,7 @@ local function addclient( addr, serverport, listener, pattern, sslctx, typ ) local res, err = client:setpeername( addr, serverport ) -- connect if res or ( err == "timeout" ) then local ip, port = client:getsockname( ) - local interface = wrapclient( client, ip, serverport, listener, pattern, sslctx ) + local interface = wrapclient( client, ip, serverport, listener, pattern, sslctx, extra ) debug( "new connection id:", interface.id ) return interface, err else diff --git a/net/server_select.lua b/net/server_select.lua index e14c126e..de183331 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -266,7 +266,7 @@ wrapserver = function( listeners, socket, ip, serverport, pattern, sslctx, ssldi return handler end -wrapconnection = function( server, listeners, socket, ip, serverport, clientport, pattern, sslctx, ssldirect ) -- this function wraps a client to a handler object +wrapconnection = function( server, listeners, socket, ip, serverport, clientport, pattern, sslctx, ssldirect, extra ) -- this function wraps a client to a handler object if socket:getfd() >= _maxfd then out_error("server.lua: Disallowed FD number: "..socket:getfd()) -- PROTIP: Switch to libevent @@ -316,6 +316,8 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport local handler = bufferqueue -- saves a table ^_^ + handler.extra = extra + handler.dispatch = function( ) return dispatch end @@ -1005,8 +1007,8 @@ end --// EXPERIMENTAL //-- -local wrapclient = function( socket, ip, serverport, listeners, pattern, sslctx ) - local handler, socket, err = wrapconnection( nil, listeners, socket, ip, serverport, "clientport", pattern, sslctx, sslctx) +local wrapclient = function( socket, ip, serverport, listeners, pattern, sslctx, extra ) + local handler, socket, err = wrapconnection( nil, listeners, socket, ip, serverport, "clientport", pattern, sslctx, sslctx, extra) if not handler then return nil, err end _socketlist[ socket ] = handler if not sslctx then @@ -1025,7 +1027,7 @@ local wrapclient = function( socket, ip, serverport, listeners, pattern, sslctx return handler, socket end -local addclient = function( address, port, listeners, pattern, sslctx, typ ) +local addclient = function( address, port, listeners, pattern, sslctx, typ, extra ) local err if type( listeners ) ~= "table" then err = "invalid listener table" @@ -1062,7 +1064,7 @@ local addclient = function( address, port, listeners, pattern, sslctx, typ ) client:settimeout( 0 ) local ok, err = client:setpeername( address, port ) if ok or err == "timeout" or err == "Operation already in progress" then - return wrapclient( client, address, port, listeners, pattern, sslctx ) + return wrapclient( client, address, port, listeners, pattern, sslctx, extra ) else return nil, err end -- cgit v1.2.3 From fb692a2cedc46229966f4a84585f292abe850ba4 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 1 Sep 2019 01:58:38 +0200 Subject: net.server: Handle server name (SNI) as extra argument Code added in 75d2874502c3, 9a905888b96c and adc0672b700e uses this field. See #409 and #1408 --- net/server_epoll.lua | 6 ++++++ net/server_event.lua | 1 + net/server_select.lua | 3 +++ 3 files changed, 10 insertions(+) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 96e7b201..f48086e3 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -575,6 +575,12 @@ local function wrapsocket(client, server, read_size, listeners, tls_ctx, extra) extra = extra; }, interface_mt); + if extra then + if extra.servername then + conn.servername = extra.servername; + end + end + conn:updatenames(); return conn; end diff --git a/net/server_event.lua b/net/server_event.lua index 950a7a5c..2b791291 100644 --- a/net/server_event.lua +++ b/net/server_event.lua @@ -516,6 +516,7 @@ local function handleclient( client, ip, port, server, pattern, listener, sslctx _sslctx = sslctx; -- parameters _usingssl = false; -- client is using ssl; extra = extra; + servername = extra and extra.servername; } if not has_luasec then interface.starttls = false; end interface.id = tostring(interface):match("%x+$"); diff --git a/net/server_select.lua b/net/server_select.lua index de183331..e15f5298 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -317,6 +317,9 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport local handler = bufferqueue -- saves a table ^_^ handler.extra = extra + if extra then + handler.servername = extra.servername + end handler.dispatch = function( ) return dispatch -- cgit v1.2.3 From 92b963270a4e399096f66ac9353a99574915d2e7 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 1 Sep 2019 02:05:33 +0200 Subject: net.http: Pass server name along for SNI (fixes #1408) net.resolver.basic passes this 'extra' field along to server.addclient --- net/http.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/http.lua b/net/http.lua index 0e03fb3a..055fc936 100644 --- a/net/http.lua +++ b/net/http.lua @@ -260,7 +260,7 @@ local function request(self, u, ex, callback) sslctx = ex and ex.sslctx or self.options and self.options.sslctx; end - local http_service = basic_resolver.new(host, port_number); + local http_service = basic_resolver.new(host, port_number, "tcp", { servername = req.host }); connect(http_service, listener, { sslctx = sslctx }, req); self.events.fire_event("request", { http = self, request = req, url = u }); -- cgit v1.2.3 From 3dcfc5ee71761a90edbd32165725f38ffd323237 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 22 Jul 2019 01:58:57 +0200 Subject: util.bitops: Library to find appropriate bitwise library (closes #1395) --- net/websocket/frames.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/websocket/frames.lua b/net/websocket/frames.lua index 86752109..5e17df07 100644 --- a/net/websocket/frames.lua +++ b/net/websocket/frames.lua @@ -9,8 +9,7 @@ local softreq = require "util.dependencies".softreq; local random_bytes = require "util.random".bytes; -local bit = assert(softreq"bit32" or softreq"bit", - "No bit module found. See https://prosody.im/doc/depends#bitop"); +local bit = require "util.bitcompat"; local band = bit.band; local bor = bit.bor; local bxor = bit.bxor; -- cgit v1.2.3 From 2aedce23760830b08c7cdd76b1164f9e6f2fbea9 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 29 Sep 2019 14:50:04 +0200 Subject: net.server_epoll: Make it easy to override handler for incoming data --- net/server_epoll.lua | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index f48086e3..fd9e0416 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -189,6 +189,11 @@ function interface:on(what, ...) return err; end +-- Allow this one to be overridden +function interface:onincoming(...) + return self:on("incoming", ...); +end + -- Return the file descriptor number function interface:getfd() if self.conn then @@ -360,7 +365,7 @@ function interface:onreadable() local data, err, partial = self.conn:receive(self.read_size or cfg.read_size); if data then self:onconnect(); - self:on("incoming", data); + self:onincoming(data); else if err == "wantread" then self:set(true, nil); @@ -371,7 +376,7 @@ function interface:onreadable() end if partial and partial ~= "" then self:onconnect(); - self:on("incoming", partial, err); + self:onincoming(partial, err); end if err ~= "timeout" then self:on("disconnect", err); -- cgit v1.2.3 From 315959a49a675d2f95610828ddcc66d2f1fb535c Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 29 Sep 2019 15:00:28 +0200 Subject: net.server_epoll: Make log tag accessible as a field To allow referencing connections by id instead of tostring form --- net/server_epoll.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index fd9e0416..633b038c 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -567,6 +567,7 @@ end local function wrapsocket(client, server, read_size, listeners, tls_ctx, extra) -- luasocket object -> interface object client:settimeout(0); + local conn_id = ("conn%s"):format(new_id()); local conn = setmetatable({ conn = client; _server = server; @@ -576,7 +577,8 @@ local function wrapsocket(client, server, read_size, listeners, tls_ctx, extra) writebuffer = {}; tls_ctx = tls_ctx or (server and server.tls_ctx); tls_direct = server and server.tls_direct; - log = logger.init(("conn%s"):format(new_id())); + id = conn_id; + log = logger.init(conn_id); extra = extra; }, interface_mt); -- cgit v1.2.3 From 6e360554ffaa391f23a9e0bb93adde3f1bd32020 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 29 Sep 2019 15:02:05 +0200 Subject: net.server_epoll: Add debug logging for various connection events --- net/server_epoll.lua | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 633b038c..c3354006 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -630,10 +630,12 @@ function interface:init() end function interface:pause() + self:debug("Pause reading"); return self:set(false); end function interface:resume() + self:debug("Resume reading"); return self:set(true); end @@ -663,12 +665,14 @@ function interface:setlimit(Bps) end function interface:pause_writes() + self:debug("Pause writes"); self._write_lock = true; self:setwritetimeout(false); self:set(nil, false); end function interface:resume_writes() + self:debug("Resume writes"); self._write_lock = nil; if self.writebuffer[1] then self:setwritetimeout(); @@ -678,6 +682,7 @@ end -- Connected! function interface:onconnect() + self:debug("Connected"); self:updatenames(); self.onconnect = noop; self:on("connect"); @@ -784,6 +789,7 @@ end; -- Dump all data from one connection into another local function link(from, to) + from:debug("Linking to %s", to.id); from.listeners = setmetatable({ onincoming = function (_, data) from:pause(); -- cgit v1.2.3 From 4f848e3ea0c92e545b9d162d55959e4f281aca70 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 29 Sep 2019 15:18:40 +0200 Subject: net.server_epoll: Add some timeout related logging --- net/server_epoll.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index c3354006..250ce4d0 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -261,8 +261,10 @@ function interface:setreadtimeout(t) else self._readtimeout = addtimer(t, function () if self:on("readtimeout") then + self:debug("Read timeout, handled"); return cfg.read_timeout; else + self:debug("Read timeout, fatal"); self:on("disconnect", "read timeout"); self:destroy(); end @@ -284,6 +286,7 @@ function interface:setwritetimeout(t) self._writetimeout:reschedule(gettime() + t); else self._writetimeout = addtimer(t, function () + self:debug("Write timeout"); self:on("disconnect", "write timeout"); self:destroy(); end); -- cgit v1.2.3 From 5eea3358fd7f8ca8b0edb36769b393bb0f1423ca Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 29 Sep 2019 15:36:23 +0200 Subject: net.server_epoll: Handle read size argument to link --- net/server_epoll.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 250ce4d0..c2eb7b1c 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -791,7 +791,7 @@ local function watchfd(fd, onreadable, onwritable) end; -- Dump all data from one connection into another -local function link(from, to) +local function link(from, to, read_size) from:debug("Linking to %s", to.id); from.listeners = setmetatable({ onincoming = function (_, data) @@ -804,6 +804,7 @@ local function link(from, to) from:resume(); end, }, {__index=to.listeners}); + from:set_mode(read_size); from:set(true, nil); to:set(nil, true); end -- cgit v1.2.3 From 79b375cb53b2e160d18309c6f88b9fa70a88d2e5 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 29 Sep 2019 15:41:01 +0200 Subject: net.server_epoll: Fix link function to not replace listeners mod_proxy65 calls link twice, once for each direction. This would overwrite the listeners with one that has the previous listeners as metatable.__index, but none of the others. This takes advantage of 94c584d67533 to improve this. --- net/server_epoll.lua | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index c2eb7b1c..d2964888 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -793,17 +793,13 @@ end; -- Dump all data from one connection into another local function link(from, to, read_size) from:debug("Linking to %s", to.id); - from.listeners = setmetatable({ - onincoming = function (_, data) - from:pause(); + function from:onincoming(data) + self:pause(); to:write(data); - end, - }, {__index=from.listeners}); - to.listeners = setmetatable({ - ondrain = function () + end + function to:ondrain() from:resume(); - end, - }, {__index=to.listeners}); + end from:set_mode(read_size); from:set(true, nil); to:set(nil, true); -- cgit v1.2.3 From 2feedcb7d6875ff3ae40c615f3087de8a61c999e Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 29 Sep 2019 15:51:21 +0200 Subject: net.server_epoll: Ignore unused self argument [luacheck] --- net/server_epoll.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index d2964888..3aa37ee6 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -797,7 +797,7 @@ local function link(from, to, read_size) self:pause(); to:write(data); end - function to:ondrain() + function to:ondrain() -- luacheck: ignore 212/self from:resume(); end from:set_mode(read_size); -- cgit v1.2.3 From 90d58b619e2533d796e20235cfcd750a55152bf5 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 29 Sep 2019 17:30:54 +0200 Subject: net.server_epoll: Correct indentation --- net/server_epoll.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 3aa37ee6..ab513e93 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -795,10 +795,10 @@ local function link(from, to, read_size) from:debug("Linking to %s", to.id); function from:onincoming(data) self:pause(); - to:write(data); + to:write(data); end function to:ondrain() -- luacheck: ignore 212/self - from:resume(); + from:resume(); end from:set_mode(read_size); from:set(true, nil); -- cgit v1.2.3 From 5cadccc68af00a5d2dcd2ea09c03e713e4fa4739 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 5 Oct 2019 15:22:59 +0200 Subject: net.server_epoll: Return early when attepting to set write lock state to current state Reduces needless duplication of work and log messages.. --- net/server_epoll.lua | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index ab513e93..62db6c86 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -668,6 +668,9 @@ function interface:setlimit(Bps) end function interface:pause_writes() + if self._write_lock then + return + end self:debug("Pause writes"); self._write_lock = true; self:setwritetimeout(false); @@ -675,6 +678,9 @@ function interface:pause_writes() end function interface:resume_writes() + if not self._write_lock then + return + end self:debug("Resume writes"); self._write_lock = nil; if self.writebuffer[1] then -- cgit v1.2.3 From 153ebfe5d719d50312629bb9475bde5500f1da6e Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 5 Oct 2019 18:10:12 +0200 Subject: net.server_epoll: Log size of partial writes (debug) --- net/server_epoll.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 62db6c86..991383ec 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -420,6 +420,7 @@ function interface:onwritable() self:ondrain(); -- Be aware of writes in ondrain return; elseif partial then + self:debug("Sent %d out of %d buffered bytes", partial, #data); buffer[1] = data:sub(partial+1); for i = #buffer, 2, -1 do buffer[i] = nil; -- cgit v1.2.3 From 56e9e471e7501bffa576aa5eef51d9bf3c0561b5 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 6 Oct 2019 16:23:43 +0200 Subject: net.server_epoll: Log TLS version and cipher for all completed handshakes The similar logging in mod_c2s and mod_s2s does not cover all connections, like HTTPS or other Direct TLS ports. --- net/server_epoll.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 991383ec..6c65bcdd 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -548,7 +548,12 @@ function interface:tlshandskake() end local ok, err = self.conn:dohandshake(); if ok then - self:debug("TLS handshake complete"); + if self.conn.info then + local info = self.conn:info(); + self:debug("TLS handshake complete (%s with %s)", info.protocol, info.cipher); + else + self:debug("TLS handshake complete"); + end self.onwritable = nil; self.onreadable = nil; self:on("status", "ssl-handshake-complete"); -- cgit v1.2.3 From 193bc49cac95c2876afcd223379a93eff9855770 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 6 Oct 2019 19:34:03 +0200 Subject: net.server_epoll: Guard against nil return from TLS info method --- net/server_epoll.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 6c65bcdd..cccc8b5d 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -548,8 +548,8 @@ function interface:tlshandskake() end local ok, err = self.conn:dohandshake(); if ok then - if self.conn.info then - local info = self.conn:info(); + local info = self.conn.info and self.conn:info(); + if type(info) == "table" then self:debug("TLS handshake complete (%s with %s)", info.protocol, info.cipher); else self:debug("TLS handshake complete"); -- cgit v1.2.3 From 89a6f8d8c108bdf633d7d6589c260de833c56bf5 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 12 Oct 2019 18:27:02 +0200 Subject: net.http.server: Ensure HEAD requests are sent with empty body --- net/http/server.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 9b63d516..47680455 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -194,8 +194,11 @@ function handle_request(conn, request, finish_cb) response_conn_header = httpversion == "1.1" and "close" or nil end + local is_head_request = request.method == "HEAD"; + local response = { request = request; + is_head_request = is_head_request; status_code = 200; headers = { date = date_header, connection = response_conn_header }; persistent = persistent; @@ -291,16 +294,29 @@ local function prepare_header(response) return output; end _M.prepare_header = prepare_header; +function _M.send_head_response(response) + if response.finished then return; end + local output = prepare_header(response); + response.conn:write(t_concat(output)); + response:done(); +end function _M.send_response(response, body) if response.finished then return; end body = body or response.body or ""; response.headers.content_length = #body; + if response.is_head_request then + return _M.send_head_response(response) + end local output = prepare_header(response); t_insert(output, body); response.conn:write(t_concat(output)); response:done(); end function _M.send_file(response, f) + if response.is_head_request then + if f.close then f:close(); end + return _M.send_head_response(response); + end if response.finished then return; end local chunked = not response.headers.content_length; if chunked then response.headers.transfer_encoding = "chunked"; end -- cgit v1.2.3 From 8e485ec3200359adcc00731a371b4455d24bb562 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 12 Oct 2019 18:27:54 +0200 Subject: net.http.server: Re-fire unhandled HEAD requsts as GET events (fixes #1447) BC: This overloads the GET event. Previous commit ensures HEAD requests are sent without a body. --- net/http/server.lua | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 47680455..b649ff5f 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -229,6 +229,11 @@ function handle_request(conn, request, finish_cb) local payload = { request = request, response = response }; log("debug", "Firing event: %s", global_event); local result = events.fire_event(global_event, payload); + if result == nil and is_head_request then + local global_head_event = "GET "..request.path:match("[^?]*"); + log("debug", "Firing event: %s", global_head_event); + result = events.fire_event(global_head_event, payload); + end if result == nil then if not hosts[host] then if hosts[default_host] then @@ -249,6 +254,12 @@ function handle_request(conn, request, finish_cb) local host_event = request.method.." "..host..request.path:match("[^?]*"); log("debug", "Firing event: %s", host_event); result = events.fire_event(host_event, payload); + + if result == nil and is_head_request then + local host_head_event = "GET "..host..request.path:match("[^?]*"); + log("debug", "Firing event: %s", host_head_event); + result = events.fire_event(host_head_event, payload); + end end if result ~= nil then if result ~= true then -- cgit v1.2.3 From 30a72c72a392fdbee1e91946c9a72ed88a20b232 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 12 Oct 2019 19:30:29 +0200 Subject: net.http.server: Explicitly convert number to string, avoiding implicit coercion --- net/http/server.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index b649ff5f..bf24c97e 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -314,7 +314,7 @@ end function _M.send_response(response, body) if response.finished then return; end body = body or response.body or ""; - response.headers.content_length = #body; + response.headers.content_length = ("%d"):format(#body); if response.is_head_request then return _M.send_head_response(response) end -- cgit v1.2.3 From 9e6dce07bf7a9836eb8123bf198c8671d423157f Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 12 Oct 2019 19:31:48 +0200 Subject: net.http.files: Explicitly convert number to string, avoiding implicit coercion --- net/http/files.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/http/files.lua b/net/http/files.lua index 7ff81fc8..650c6f47 100644 --- a/net/http/files.lua +++ b/net/http/files.lua @@ -127,7 +127,7 @@ local function serve(opts) local content_type = ext and mime_map[ext]; response_headers.content_type = content_type; if attr.size > cache_max_file_size then - response_headers.content_length = attr.size; + response_headers.content_length = ("%d"):format(attr.size); log("debug", "%d > cache_max_file_size", attr.size); return response:send_file(f); else -- cgit v1.2.3 From 73d6c64bd7b061a8790919daac19e09cd00fa5e1 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 12 Oct 2019 19:51:29 +0200 Subject: net.server_epoll: Move a log message to improve ordering It was weird that it said "Prepared to start TLS" before "Client .. created" --- net/server_epoll.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index cccc8b5d..3b134312 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -775,10 +775,10 @@ local function addclient(addr, port, listeners, read_size, tls_ctx, typ, extra) local client = wrapsocket(conn, nil, read_size, listeners, tls_ctx, extra) local ok, err = client:init(); if not ok then return ok, err; end + client:debug("Client %s created", client); if tls_ctx then client:starttls(tls_ctx); end - client:debug("Client %s created", client); return client, conn; end -- cgit v1.2.3 From 3585385ab60126105f7e0c7900399ec05c56a781 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 12 Oct 2019 20:07:50 +0200 Subject: net.server_epoll: Fix to get remote IP on direct TLS connections A Direct TLS connection (eg HTTPS) gets turned into a LuaSec handle before the :updatenames call done in the :connect method. LuaSec does not expose the :getpeername and :getsockname methods, so the addresses remain obscured, making debugging trickier since the actual IP addrerss connected to does not show up. --- net/server_epoll.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 3b134312..7a414901 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -521,6 +521,7 @@ function interface:tlshandskake() self._tls = true; self:debug("Starting TLS now"); self:del(); + self:updatenames(); -- Can't getpeer/sockname after wrap() local ok, conn, err = pcall(luasec.wrap, self.conn, self.tls_ctx); if not ok then conn, err = ok, conn; -- cgit v1.2.3 From 3e8be00bbec2bfc691a2fd7fdb4dde33d39a55d4 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 12 Oct 2019 20:12:04 +0200 Subject: net.server_epoll: Handle getpeer/sockname returning a normal error These will sometimes return nil, "Transport not connected" but not throw a hard error. This shouldn't be treated as success. --- net/server_epoll.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 7a414901..3745b426 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -605,11 +605,11 @@ end function interface:updatenames() local conn = self.conn; local ok, peername, peerport = pcall(conn.getpeername, conn); - if ok then + if ok and peername then self.peername, self.peerport = peername, peerport; end local ok, sockname, sockport = pcall(conn.getsockname, conn); - if ok then + if ok and sockname then self.sockname, self.sockport = sockname, sockport; end end -- cgit v1.2.3 From 066ee6e7810f638be65445ef7161ee41b6e33f14 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 12 Oct 2019 20:15:31 +0200 Subject: server_epoll: Log full string represestation when connected Since they may have been unknown when the connection was created. --- net/server_epoll.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 3745b426..9feba360 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -698,8 +698,8 @@ end -- Connected! function interface:onconnect() - self:debug("Connected"); self:updatenames(); + self:debug("Connected (%s)", self); self.onconnect = noop; self:on("connect"); end -- cgit v1.2.3 From c5a70f10627bcdbc1b9f67e055574bbedc801fac Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 12 Oct 2019 20:22:07 +0200 Subject: net.server_epoll: Save IP and port from connection creation call Might come out of :getpeername different later but at least it's something. --- net/server_epoll.lua | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 9feba360..a2052875 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -775,6 +775,10 @@ local function addclient(addr, port, listeners, read_size, tls_ctx, typ, extra) if not ok and err ~= "timeout" then return ok, err; end local client = wrapsocket(conn, nil, read_size, listeners, tls_ctx, extra) local ok, err = client:init(); + if not client.peername then + -- otherwise not set until connected + client.peername, client.peerport = addr, port; + end if not ok then return ok, err; end client:debug("Client %s created", client); if tls_ctx then -- cgit v1.2.3 From 2b035680860450dd6ce9d3b853c26bd900752f8f Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 1 Nov 2019 23:18:29 +0100 Subject: net.http.codes: Avoid implicit number -> string coercion --- net/http/codes.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/http/codes.lua b/net/http/codes.lua index 8098b5c3..4327f151 100644 --- a/net/http/codes.lua +++ b/net/http/codes.lua @@ -82,5 +82,5 @@ local response_codes = { -- [512-599] = "Unassigned"; }; -for k,v in pairs(response_codes) do response_codes[k] = k.." "..v; end +for k,v in pairs(response_codes) do response_codes[k] = ("%03d %s"):format(k, v); end return setmetatable(response_codes, { __index = function(_, k) return k.." Unassigned"; end }) -- cgit v1.2.3 From 6a73014b9acdf69a7c415ac8f5fa173f83a68362 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 1 Nov 2019 22:25:54 +0100 Subject: net.http.server: Factor out handling of event response for easier reuse --- net/http/server.lua | 65 ++++++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 31 deletions(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index bf24c97e..991ef970 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -170,6 +170,38 @@ local headerfix = setmetatable({}, { end }); +local function handle_result(request, response, result) + if result == nil then + result = 404; + end + + if result == true then + return; + end + + local body; + local result_type = type(result); + if result_type == "number" then + response.status_code = result; + if result >= 400 then + body = events.fire_event("http-error", { request = request, response = response, code = result }); + end + elseif result_type == "string" then + body = result; + elseif result_type == "table" then + for k, v in pairs(result) do + if k ~= "headers" then + response[k] = v; + else + for header_name, header_value in pairs(v) do + response.headers[header_name] = header_value; + end + end + end + end + response:send(body); +end + function _M.hijack_response(response, listener) -- luacheck: ignore error("TODO"); end @@ -261,39 +293,10 @@ function handle_request(conn, request, finish_cb) result = events.fire_event(host_head_event, payload); end end - if result ~= nil then - if result ~= true then - local body; - local result_type = type(result); - if result_type == "number" then - response.status_code = result; - if result >= 400 then - payload.code = result; - body = events.fire_event("http-error", payload); - end - elseif result_type == "string" then - body = result; - elseif result_type == "table" then - for k, v in pairs(result) do - if k ~= "headers" then - response[k] = v; - else - for header_name, header_value in pairs(v) do - response.headers[header_name] = header_value; - end - end - end - end - response:send(body); - end - return; - end - -- if handler not called, return 404 - response.status_code = 404; - payload.code = 404; - response:send(events.fire_event("http-error", payload)); + return handle_result(request, response, result); end + local function prepare_header(response) local status_line = "HTTP/"..response.request.httpversion.." "..(response.status or codes[response.status_code]); local headers = response.headers; -- cgit v1.2.3 From fbab8ed06ac738e6aec96db67141f987b9d3c058 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 1 Nov 2019 22:28:39 +0100 Subject: net.http.server: Tail call because tail call! --- net/http/server.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 991ef970..0682d6ed 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -199,7 +199,7 @@ local function handle_result(request, response, result) end end end - response:send(body); + return response:send(body); end function _M.hijack_response(response, listener) -- luacheck: ignore -- cgit v1.2.3 From fdfe1e0b2bf8cea4e2e512fa8e25bface008a59b Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 1 Nov 2019 22:30:35 +0100 Subject: net.http.server: Handle util.error objects from http handlers --- net/http/server.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 0682d6ed..0d49dbce 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -13,6 +13,7 @@ local traceback = debug.traceback; local tostring = tostring; local cache = require "util.cache"; local codes = require "net.http.codes"; +local errors = require "util.error"; local blocksize = 2^16; local _M = {}; @@ -188,6 +189,8 @@ local function handle_result(request, response, result) end elseif result_type == "string" then body = result; + elseif errors.is_err(result) then + body = events.fire_event("http-error", { request = request, response = response, code = result.code, error = result }); elseif result_type == "table" then for k, v in pairs(result) do if k ~= "headers" then -- cgit v1.2.3 From 5cac177270b40336e9820619e9c6ab3973ad95b4 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 1 Nov 2019 22:31:15 +0100 Subject: net.http.server: Handle promises from http handlers --- net/http/server.lua | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index 0d49dbce..dc64728f 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -13,6 +13,7 @@ local traceback = debug.traceback; local tostring = tostring; local cache = require "util.cache"; local codes = require "net.http.codes"; +local promise = require "util.promise"; local errors = require "util.error"; local blocksize = 2^16; @@ -191,6 +192,13 @@ local function handle_result(request, response, result) body = result; elseif errors.is_err(result) then body = events.fire_event("http-error", { request = request, response = response, code = result.code, error = result }); + elseif promise.is_promise(result) then + result:next(function (ret) + handle_result(request, response, ret); + end, function (err) + handle_result(request, response, err); + end); + return true; elseif result_type == "table" then for k, v in pairs(result) do if k ~= "headers" then -- cgit v1.2.3 From 58990598f283f24f99dd5899669acc310b5437b1 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 5 Nov 2019 01:34:13 +0100 Subject: net.http.server: Treat promise rejection without value as a HTTP 500 error --- net/http/server.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index dc64728f..47f064a5 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -196,7 +196,7 @@ local function handle_result(request, response, result) result:next(function (ret) handle_result(request, response, ret); end, function (err) - handle_result(request, response, err); + handle_result(request, response, err or 500); end); return true; elseif result_type == "table" then -- cgit v1.2.3 From ecb6218ce7e485970e1bc56f9464df13e739f878 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 13 Nov 2019 22:34:25 +0100 Subject: server_event: Remove duplicated code (thanks waqas) readcallback() calls onreadtimeout() and runs the exact same code if onreadtimeout() doesn't return true, which it doesn't do. --- net/server_event.lua | 4 ---- 1 file changed, 4 deletions(-) (limited to 'net') diff --git a/net/server_event.lua b/net/server_event.lua index 2b791291..a8279c42 100644 --- a/net/server_event.lua +++ b/net/server_event.lua @@ -463,10 +463,6 @@ end function interface_mt:ontimeout() end function interface_mt:onreadtimeout() - self.fatalerror = "timeout during receiving" - debug( "connection failed:", self.fatalerror ) - self:_close() - self.eventread = nil end function interface_mt:ondrain() end -- cgit v1.2.3