From d4c35255c06539fdc928b3b12df61f2ebd09ad64 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 28 Mar 2019 12:52:55 +0100 Subject: net.server_epoll: Skip delayed continuation read on paused connections This should prevent #1333 in cases where LuaSockets buffer is "dirty", i.e.?contains more data after a read, where it gets resumed with a short delay. --- 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 cffd3a84..c41266e1 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -373,7 +373,7 @@ function interface:onreadable() end end if not self.conn then return; end - if self.conn:dirty() then + if self._wantread and self.conn:dirty() then self:setreadtimeout(false); self:pausefor(cfg.read_retry_delay); else -- cgit v1.2.3 From dadf242556770176ea589426bf97444a550c4553 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 13 Apr 2019 18:16:28 +0200 Subject: net.dns: Close resolv.conf handle when done (fixes #1342) --- net/dns.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/dns.lua b/net/dns.lua index af5f1216..3902f95c 100644 --- a/net/dns.lua +++ b/net/dns.lua @@ -704,6 +704,7 @@ function resolver:adddefaultnameservers() -- - - - - adddefaultnameservers end end end + resolv_conf:close(); end if not self.server or #self.server == 0 then -- TODO log warning about no nameservers, adding localhost as the default nameserver -- cgit v1.2.3 From 36957928e1a7911c6dd19e58020c85512b47795d Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 4 May 2019 04:23:35 +0200 Subject: net.server_epoll: Restore wantread flag after pause (fixes #1354) If a chunk of data has been received that is larger than the amount read at a time, then the connection is paused for a short time after which it tries to read some more. If, after that, there is still more data to read, it should do the same thing. However, because the "want read" flag is removed and was restored after the delayed reading, it would not schedule another delayed read. --- 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 c41266e1..c279c579 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -600,10 +600,10 @@ function interface:pausefor(t) self:set(false); self._pausefor = addtimer(t, function () self._pausefor = nil; + self:set(true); if self.conn and self.conn:dirty() then self:onreadable(); end - self:set(true); end); end -- cgit v1.2.3 From dd837c451e8a09051fb042d7eded02a124dfb75e Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 8 Jul 2019 01:17:34 +0200 Subject: net.server_epoll: Backport timer optimization 6c2370f17027 from trunk (see #1388) The previous timer handling did not scale well and led to high CPU usage with many connections (each with at least an read timeout). --- net/server_epoll.lua | 77 ++++++++++++++++++++-------------------------------- 1 file changed, 29 insertions(+), 48 deletions(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index c279c579..0c03ae15 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; @@ -66,22 +65,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 @@ -94,50 +95,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; + local now = gettime(); + local peek = timers:peek(); + while peek do + + if peek > now then + next_delay = peek - now; + break; end - 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; + 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 - -- 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; + peek = timers:peek(); end - 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. - timer[1] = t + new_timeout; - resort_timers = true; - else - t_remove(timers, i); - end + if peek == nil then + return next_delay; 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; + if next_delay < min_wait then + return min_wait; end - return next_delay; end @@ -243,8 +226,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 @@ -268,8 +250,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 24c8edca2a25a6731d9924abc91b802e6d17e56c Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 2 Nov 2019 19:24:26 +0100 Subject: net.resolvers: Apply IDNA conversion to ascii for DNS lookups (fixes #1426) --- net/resolvers/basic.lua | 3 ++- net/resolvers/service.lua | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/resolvers/basic.lua b/net/resolvers/basic.lua index 9a3c9952..d8031a6b 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 idna_to_ascii = require "util.encodings".idna.to_ascii; local methods = {}; local resolver_mt = { __index = methods }; @@ -59,7 +60,7 @@ end local function new(hostname, port, conn_type, extra) return setmetatable({ - hostname = hostname; + hostname = idna_to_ascii(hostname); port = port; conn_type = conn_type or "tcp"; extra = extra; diff --git a/net/resolvers/service.lua b/net/resolvers/service.lua index b5a2d821..a76adb73 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 idna_to_ascii = require "util.encodings".idna.to_ascii; local methods = {}; local resolver_mt = { __index = methods }; @@ -58,7 +59,7 @@ end local function new(hostname, service, conn_type, extra) return setmetatable({ - hostname = hostname; + hostname = idna_to_ascii(hostname); service = service; conn_type = conn_type or "tcp"; extra = extra; -- cgit v1.2.3 From ae75d537f6a9f175f2ded30e0866aa2c092872f0 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 2 Nov 2019 19:36:19 +0100 Subject: net.resolvers: Abort on hostnames not passing IDNA validation Prevents error on trying to use nil. Needs better error reporting in the future. --- net/resolvers/basic.lua | 5 +++++ net/resolvers/service.lua | 5 +++++ 2 files changed, 10 insertions(+) (limited to 'net') diff --git a/net/resolvers/basic.lua b/net/resolvers/basic.lua index d8031a6b..cafef58b 100644 --- a/net/resolvers/basic.lua +++ b/net/resolvers/basic.lua @@ -18,6 +18,11 @@ function methods:next(cb) return; end + if not self.hostname then + -- FIXME report IDNA error + cb(nil); + end + local targets = {}; local n = 2; local function ready() diff --git a/net/resolvers/service.lua b/net/resolvers/service.lua index a76adb73..bb255c33 100644 --- a/net/resolvers/service.lua +++ b/net/resolvers/service.lua @@ -25,6 +25,11 @@ function methods:next(cb) return; end + if not self.hostname then + -- FIXME report IDNA error + cb(nil); + end + local targets = {}; local function ready() self.targets = targets; -- cgit v1.2.3 From f57d4a439ae2a3b013703e9091b549b7ba315d64 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 8 Nov 2019 00:54:56 +0100 Subject: net.resolvers: Fix traceback from hostname failing IDNA Related to #1426 --- net/resolvers/basic.lua | 1 + net/resolvers/service.lua | 1 + 2 files changed, 2 insertions(+) (limited to 'net') diff --git a/net/resolvers/basic.lua b/net/resolvers/basic.lua index cafef58b..f37e74a2 100644 --- a/net/resolvers/basic.lua +++ b/net/resolvers/basic.lua @@ -21,6 +21,7 @@ function methods:next(cb) if not self.hostname then -- FIXME report IDNA error cb(nil); + return; end local targets = {}; diff --git a/net/resolvers/service.lua b/net/resolvers/service.lua index bb255c33..34f14cba 100644 --- a/net/resolvers/service.lua +++ b/net/resolvers/service.lua @@ -28,6 +28,7 @@ function methods:next(cb) if not self.hostname then -- FIXME report IDNA error cb(nil); + return; end local targets = {}; -- cgit v1.2.3 From 34563dd70dfe21a8bfaedc7f34810b9c6d834be8 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 24 Nov 2019 04:23:51 +0100 Subject: net.resolvers.basic: Move IP literal check to constructor This is to prepare for fixing #1459. An IPv6 literal in [ ] brackets does not pass IDNA and resolving it fails there. --- net/resolvers/basic.lua | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/resolvers/basic.lua b/net/resolvers/basic.lua index f37e74a2..e3a94382 100644 --- a/net/resolvers/basic.lua +++ b/net/resolvers/basic.lua @@ -33,16 +33,6 @@ function methods:next(cb) self:next(cb); end - local is_ip = inet_pton(self.hostname); - if is_ip then - if #is_ip == 16 then - cb(self.conn_type.."6", self.hostname, self.port, self.extra); - elseif #is_ip == 4 then - cb(self.conn_type.."4", self.hostname, self.port, self.extra); - end - return; - end - -- Resolve DNS to target list local dns_resolver = adns.resolver(); dns_resolver:lookup(function (answer) @@ -65,11 +55,24 @@ function methods:next(cb) end local function new(hostname, port, conn_type, extra) + local ascii_host = idna_to_ascii(hostname); + local targets = nil; + + local is_ip = inet_pton(hostname); + if is_ip then + if #is_ip == 16 then + targets = { { conn_type.."6", hostname, port, extra } }; + elseif #is_ip == 4 then + targets = { { conn_type.."4", hostname, port, extra } }; + end + end + return setmetatable({ - hostname = idna_to_ascii(hostname); + hostname = ascii_host; port = port; conn_type = conn_type or "tcp"; extra = extra; + targets = targets; }, resolver_mt); end -- cgit v1.2.3 From a5450086e824443cff04adc9ed5ec3cca8301151 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 24 Nov 2019 04:26:44 +0100 Subject: net.resolvers.basic: Fix resolution of IPv6 literals (in brackets) (fixes #1459) --- net/resolvers/basic.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/resolvers/basic.lua b/net/resolvers/basic.lua index e3a94382..93182fda 100644 --- a/net/resolvers/basic.lua +++ b/net/resolvers/basic.lua @@ -59,6 +59,9 @@ local function new(hostname, port, conn_type, extra) local targets = nil; local is_ip = inet_pton(hostname); + if not is_ip and hostname:sub(1,1) == '[' then + is_ip = inet_pton(hostname:sub(2,-2)); + end if is_ip then if #is_ip == 16 then targets = { { conn_type.."6", hostname, port, extra } }; -- cgit v1.2.3 From d9c64e1f412ce232e44eac499f006292d8cc720b Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 24 Nov 2019 04:41:07 +0100 Subject: net.resolvers.basic: Normalise IP literals, ensures net.server is happy --- net/resolvers/basic.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/resolvers/basic.lua b/net/resolvers/basic.lua index 93182fda..08c71ef5 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 inet_ntop = require "util.net".ntop; local idna_to_ascii = require "util.encodings".idna.to_ascii; local methods = {}; @@ -63,6 +64,7 @@ local function new(hostname, port, conn_type, extra) is_ip = inet_pton(hostname:sub(2,-2)); end if is_ip then + hostname = inet_ntop(is_ip); if #is_ip == 16 then targets = { { conn_type.."6", hostname, port, extra } }; elseif #is_ip == 4 then -- cgit v1.2.3 From 66b1c21e0a25adb032f579a4334fe78c5aed29fe Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 11 Mar 2020 18:07:03 +0100 Subject: net.server_epoll: Fix indentation Some lines seem to have gotten the wrong indentation, possibly caused by Meld which often ignores lines with only whitespace changes and leaves their previous indentation. --- net/server_epoll.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 0c03ae15..2182d56a 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -102,7 +102,7 @@ local function runtimers(next_delay, min_wait) if peek > now then next_delay = peek - now; break; - end + end local _, timer, id = timers:pop(); local ok, ret = pcall(timer[2], now); @@ -110,10 +110,10 @@ local function runtimers(next_delay, min_wait) local next_time = now+ret; timer[1] = next_time; timers:insert(timer, next_time); - end + end peek = timers:peek(); - end + end if peek == nil then return next_delay; end -- cgit v1.2.3 From d12c7e9416b242120df35419220a332196cd8413 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 23 Jun 2020 15:39:31 +0200 Subject: net.http.server: Strip port from Host header in IPv6 friendly way (fix #1302) E.g. given `[::1]:5280` it would previously result in only `[` instead of the correct `[::1]` --- 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 9b63d516..d0bd3294 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -207,7 +207,7 @@ function handle_request(conn, request, finish_cb) }; conn._http_open_response = response; - local host = (request.headers.host or ""):match("[^:]+"); + local host = (request.headers.host or ""):gsub(":%d+$",""); -- Some sanity checking local err_code, err; -- cgit v1.2.3 From ba013abb83c578589b4ed413b5a330d9e835d764 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 23 Jun 2020 15:43:57 +0200 Subject: net.http.server: Fix reporting of missing Host header The "Missing or invalid 'Host' header" case was dead code previously because `host` was always at least an empty string. --- net/http/server.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/http/server.lua b/net/http/server.lua index d0bd3294..18704962 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -207,7 +207,8 @@ function handle_request(conn, request, finish_cb) }; conn._http_open_response = response; - local host = (request.headers.host or ""):gsub(":%d+$",""); + local host = request.headers.host; + if host then host = host:gsub(":%d+$",""); end -- Some sanity checking local err_code, err; -- cgit v1.2.3 From cc5eeb60cdba4f8aea1d45b7c8a5c2a532462d2e Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 7 Jul 2020 13:52:25 +0100 Subject: net.http: Fix traceback on invalid URL passed to request() --- net/http.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/http.lua b/net/http.lua index fe5250ac..0adac26c 100644 --- a/net/http.lua +++ b/net/http.lua @@ -183,14 +183,15 @@ end local function request(self, u, ex, callback) local req = url.parse(u); - req.url = u; - req.http = self; if not (req and req.host) then callback("invalid-url", 0, req); return nil, "invalid-url"; end + req.url = u; + req.http = self; + if not req.path then req.path = "/"; end -- cgit v1.2.3 From e3a2cc2d407e3b1736843dd90f898caf53a8cd3a Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 10 Jul 2020 13:00:02 +0100 Subject: net.resolvers.basic: Default conn_type to 'tcp' consistently if unspecified (thanks marc0s) Fixes a traceback when passed an IP address with no conn_type. --- net/resolvers/basic.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/resolvers/basic.lua b/net/resolvers/basic.lua index 08c71ef5..867ccf60 100644 --- a/net/resolvers/basic.lua +++ b/net/resolvers/basic.lua @@ -58,6 +58,7 @@ end local function new(hostname, port, conn_type, extra) local ascii_host = idna_to_ascii(hostname); local targets = nil; + conn_type = conn_type or "tcp"; local is_ip = inet_pton(hostname); if not is_ip and hostname:sub(1,1) == '[' then @@ -75,7 +76,7 @@ local function new(hostname, port, conn_type, extra) return setmetatable({ hostname = ascii_host; port = port; - conn_type = conn_type or "tcp"; + conn_type = conn_type; extra = extra; targets = targets; }, resolver_mt); -- cgit v1.2.3 From 1ec3ab3c2fc96368675e3b679cf50c3396ef8369 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 8 Aug 2020 13:11:11 +0100 Subject: net.http: Re-expose destroy_request() function This was accidentally turned private in 647adfd8f738 as part of refactoring for Lua 5.2+. --- net/http.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/http.lua b/net/http.lua index 0adac26c..14107bf4 100644 --- a/net/http.lua +++ b/net/http.lua @@ -302,4 +302,5 @@ return { urldecode = util_http.urldecode; formencode = util_http.formencode; formdecode = util_http.formdecode; + destroy_request = destroy_request; }; -- cgit v1.2.3 From 09fd5f5c24ce919563cdadf0919901664cc3de30 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 8 Aug 2020 13:13:50 +0100 Subject: net.http: Add request:cancel() method This is a new API that should be used in preference to http.destroy_request() when possible, as it ensures the callback is always called (with an error of course). APIs that have edge-cases where they don't call callbacks have, from experience, shown to be difficult to work with and often lead to unintentional leaks when the callback was expected to free up certain resources. --- net/http.lua | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'net') diff --git a/net/http.lua b/net/http.lua index 14107bf4..ae9d2974 100644 --- a/net/http.lua +++ b/net/http.lua @@ -56,6 +56,16 @@ local function destroy_request(request) end end +local function cancel_request(request, reason) + if request.callback then + request.callback(reason or "cancelled", 0, request); + request.callback = nil; + end + if request.conn then + destroy_request(request); + end +end + local function request_reader(request, data, err) if not request.parser then local function error_cb(reason) @@ -105,6 +115,7 @@ function listener.onconnect(conn) end req.reader = request_reader; req.state = "status"; + req.cancel = cancel_request; requests[req.conn] = req; -- cgit v1.2.3 From ce940fed493f2c138fa43e220c0ebef3c846f09d Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 17 Aug 2020 23:01:14 +0200 Subject: net.server: Backport client parts of SNI support from trunk (#409) Partial backports of the following commits from trunk: 6c804b6b2ca2 net.http: Pass server name along for SNI (fixes #1408) 75d2874502c3 net.server_select: SNI support (#409) 9a905888b96c net.server_event: Add SNI support (#409) adc0672b700e net.server_epoll: Add support for SNI (#409) d4390c427a66 net.server: Handle server name (SNI) as extra argument --- net/http.lua | 2 +- net/server_epoll.lua | 20 +++++++++++++++----- net/server_event.lua | 17 ++++++++++++----- net/server_select.lua | 19 ++++++++++++++----- 4 files changed, 42 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/net/http.lua b/net/http.lua index ae9d2974..0768cdab 100644 --- a/net/http.lua +++ b/net/http.lua @@ -272,7 +272,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 }); diff --git a/net/server_epoll.lua b/net/server_epoll.lua index 2182d56a..953bbb11 100644 --- a/net/server_epoll.lua +++ b/net/server_epoll.lua @@ -483,6 +483,9 @@ function interface:tlshandskake() end conn:settimeout(0); self.conn = conn; + if conn.sni and self.servername then + conn:sni(self.servername); + end self:on("starttls"); self.ondrain = nil; self.onwritable = interface.tlshandskake; @@ -512,7 +515,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; @@ -523,8 +526,15 @@ 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; + extra = extra; }, interface_mt); + if extra then + if extra.servername then + conn.servername = extra.servername; + end + end + conn:updatenames(); return conn; end @@ -617,8 +627,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 @@ -631,7 +641,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); @@ -653,7 +663,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 11bd6a29..746526ce 100644 --- a/net/server_event.lua +++ b/net/server_event.lua @@ -164,6 +164,11 @@ 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 and self.servername then + self.conn:sni(self.servername); + end + self.conn:settimeout( 0 ) -- set non blocking local handshakecallback = coroutine_wrap(function( event ) local _, err @@ -456,7 +461,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"; @@ -492,6 +497,8 @@ 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; + servername = extra and extra.servername; } if not has_luasec then interface.starttls = false; end interface.id = tostring(interface):match("%x+$"); @@ -716,14 +723,14 @@ local function addserver( addr, port, listener, pattern, sslctx, startssl ) -- return interface 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" @@ -750,7 +757,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 1a40a6d3..deb8fe48 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -264,7 +264,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, 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 @@ -314,6 +314,11 @@ 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 end @@ -624,6 +629,10 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport return nil, err -- fatal error end + if socket.sni and self.servername then + socket:sni(self.servername); + end + socket:settimeout( 0 ) -- add the new socket to our system @@ -977,8 +986,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 ) +local wrapclient = function( socket, ip, serverport, listeners, pattern, sslctx, extra ) + local handler, socket, err = wrapconnection( nil, listeners, socket, ip, serverport, "clientport", pattern, sslctx, extra) if not handler then return nil, err end _socketlist[ socket ] = handler if not sslctx then @@ -997,7 +1006,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" @@ -1034,7 +1043,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 0b3dfb6e44835e521e88359fb4b0ccc3d52f57c4 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 15 Sep 2020 09:08:21 +0100 Subject: net.http: Add feature discovery (currently just contains SNI) --- net/http.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/http.lua b/net/http.lua index 0768cdab..7335d210 100644 --- a/net/http.lua +++ b/net/http.lua @@ -314,4 +314,7 @@ return { formencode = util_http.formencode; formdecode = util_http.formdecode; destroy_request = destroy_request; + features = { + sni = true; + }; }; -- cgit v1.2.3 From f9550cb3416b5c579b7efabe85495951464868c8 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 17 Sep 2020 13:00:19 +0100 Subject: net.websocket.frames: Allow all methods to work on non-string objects Instead of using the string library, use methods from the passed object, which are assumed to be equivalent. This provides compatibility with objects from util.ringbuffer and util.dbuffer, for example. --- net/websocket/frames.lua | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/websocket/frames.lua b/net/websocket/frames.lua index ba25d261..e1b5527a 100644 --- a/net/websocket/frames.lua +++ b/net/websocket/frames.lua @@ -16,13 +16,12 @@ 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; 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; @@ -30,12 +29,12 @@ if not s_pack and softreq"struct" then end local function read_uint16be(str, pos) - local l1, l2 = s_byte(str, pos, pos+1); + local l1, l2 = str:byte(pos, pos+1); return l1*256 + l2; end -- FIXME: this may lose precision local function read_uint64be(str, pos) - local l1, l2, l3, l4, l5, l6, l7, l8 = s_byte(str, pos, pos+7); + local l1, l2, l3, l4, l5, l6, l7, l8 = str:byte(pos, pos+7); local h = lshift(l1, 24) + lshift(l2, 16) + lshift(l3, 8) + l4; local l = lshift(l5, 24) + lshift(l6, 16) + lshift(l7, 8) + l8; return h * 2^32 + l; @@ -63,9 +62,15 @@ end if s_unpack then function read_uint16be(str, pos) + if type(str) ~= "string" then + str, pos = str:sub(pos, pos+1), 1; + end return s_unpack(">I2", str, pos); end function read_uint64be(str, pos) + if type(str) ~= "string" then + str, pos = str:sub(pos, pos+7), 1; + end return s_unpack(">I8", str, pos); end end @@ -73,7 +78,7 @@ end local function parse_frame_header(frame) if #frame < 2 then return; end - local byte1, byte2 = s_byte(frame, 1, 2); + local byte1, byte2 = frame:byte(1, 2); local result = { FIN = band(byte1, 0x80) > 0; RSV1 = band(byte1, 0x40) > 0; @@ -102,7 +107,7 @@ local function parse_frame_header(frame) end if result.MASK then - result.key = { s_byte(frame, length_bytes+3, length_bytes+6) }; + result.key = { frame:byte(length_bytes+3, length_bytes+6) }; end return result, header_length; @@ -121,7 +126,7 @@ local function apply_mask(str, key, from, to) for i = from, to do local key_index = counter%key_len + 1; counter = counter + 1; - data[counter] = s_char(bxor(key[key_index], s_byte(str, i))); + data[counter] = s_char(bxor(key[key_index], str:byte(i))); end return t_concat(data); end @@ -189,7 +194,7 @@ local function parse_close(data) if #data >= 2 then code = read_uint16be(data, 1); if #data > 2 then - message = s_sub(data, 3); + message = data:sub(3); end end return code, message -- cgit v1.2.3 From d8be48981f7e64f984c05f88ecf381da831f7232 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 17 Sep 2020 13:04:46 +0100 Subject: mod_websocket: Switch partial frame buffering to util.dbuffer This improves performance and enforces stanza size limits earlier in the pipeline. --- 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 e1b5527a..65f9122c 100644 --- a/net/websocket/frames.lua +++ b/net/websocket/frames.lua @@ -20,8 +20,8 @@ local unpack = table.unpack or unpack; -- luacheck: ignore 113 local t_concat = table.concat; local s_char= string.char; -local s_pack = string.pack; -local s_unpack = string.unpack; +local s_pack = string.pack; -- luacheck: ignore 143 +local s_unpack = string.unpack; -- luacheck: ignore 143 if not s_pack and softreq"struct" then s_pack = softreq"struct".pack; -- cgit v1.2.3 From 3cd5ae91199caf59972c2d6d953fa3619da8a552 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 29 Sep 2020 13:58:32 +0100 Subject: net.websocket.frames: Additionally return partial frame if there is one --- 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 65f9122c..a0c0d4cd 100644 --- a/net/websocket/frames.lua +++ b/net/websocket/frames.lua @@ -141,7 +141,7 @@ end local function parse_frame(frame) local result, pos = parse_frame_header(frame); - if result == nil or #frame < (pos + result.length) then return; end + if result == nil or #frame < (pos + result.length) then return nil, nil, result; end result.data = parse_frame_body(frame, result, pos+1); return result, pos + result.length; end -- cgit v1.2.3