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