-
Notifications
You must be signed in to change notification settings - Fork 63
Description
As previously described in #310 (comment), when secure-socket is used in a server context, connections might sometimes hang. More specifically secure-socket will not emit incoming requests leaving the client waiting for a response until it times out.
reproduction
Here is a little reproduction using weblit, as it is easier to define a certificate with it with a self-signed certificate. You can also reproduce it with coro-http's server by applying the aforementioned PR.
Note, if you want to install the deps yourself, you will need to also apply PR#339.
secure-socket-reproduction.zip
Steps:
- run
luvit mainafter extracting the archive. - open your browser, devtools > network tab.
- try to access
https://localhost:8080/. - you will see a security warning due to self-signed certificate, this is not relevant, proceed.
- some resources will load, others will be in a loading state until they time out.
There is also a status tracker on the page itself which tell the same information.
explanation
This problem almost never happens when you are sending the requests normally, one by one. Although it seems like in a browser context when loading a full page, it will try to optimise the TLS transmission which results in the handshake code reading both the handshake related packets and the request data which gets written into the context buffer, but it's never read back again when the weblit server calls read().
solution
I've tried this patch to secure-socket/biowrap.lua which works great:
diff --git a/deps/secure-socket/biowrap.lua b/deps/secure-socket/biowrap.lua
index 6b89bd5..064d061 100644
--- a/deps/secure-socket/biowrap.lua
+++ b/deps/secure-socket/biowrap.lua
@@ -75,6 +75,7 @@ return function (ctx, isServer, socket, handshakeComplete, servername)
return closeSocket(socket)
end
+ ssocket.authenticated = true
handshakeComplete(nil, ssocket)
end
return flush(callback)
@@ -103,7 +104,17 @@ return function (ctx, isServer, socket, handshakeComplete, servername)
-- onPlain handler
function ssocket.read_start(_, onRead)
onPlain = onRead
- return socket:read_start(onCipher)
+ local success, err = socket:read_start(onCipher)
+ require'timer'.setTimeout(0, function()
+ if ssocket.authenticated and ssl:peek() then
+ while true do
+ local plain, op = ssl:read()
+ if not plain then break end
+ onRead(nil, plain)
+ end
+ end
+ end)
+ return success, err
end
-- When requested to write plain data, encrypt it and write to socket
~
although is a bit hacky with the timer usage, which is needed to delay the read() return until the coroutine has been suspended.