Uh oh!
There was an error while loading. Please reload this page.
http: fix timeout reset after keep-alive timeout - #13549
Conversation
aqrln
commented
Jun 8, 2017
There was a problem hiding this comment.
Duh... looks like I was too fast on starting CI. These two lines should be swapped. It will actually work either way, but in this order socket.removeListener() is useless.
aqrln
commented
Jun 8, 2017
Whoa... all those |
aqrln
commented
Jun 9, 2017
The last commit should unbreak the CI, but even if it doesn't, it is a legit bugfix per se ¯\_(ツ)_/¯ |
mcollina
commented
Jun 9, 2017
@aqrln which original PR? |
There was a problem hiding this comment.
Can you add a comment explaining what those symbols do, and which value would they contain over time?
Can you also add a test for this beahavior in net, even if it is just internal?
There was a problem hiding this comment.
Why are these being attached here when they're (only) used by the http module? It seems like these should instead be set by http so as not to affect (performance-wise) those who use net directly.
There was a problem hiding this comment.
IMHO they must be in net because this information is only available in net: https://github.com/nodejs/node/pull/13549/files#diff-e6ef024c3775d787c38487a6309e491dR394
There was a problem hiding this comment.
Not necessarily, L394 could have an if.
(it's a classical point for polymorphism, but an if can accomplish "extendibility")
There was a problem hiding this comment.
They are updated by Socket.prototype.setTimeout() .
There was a problem hiding this comment.
Well, the current msecs for the socket is already available via socket._idleTimeout and http would already know what value it is setting, so I don't see why it needs to be done in net (or perhaps why anything additional needs to be stored on the socket itself at all).
There was a problem hiding this comment.
+1 if the net additions could be avoided.
There was a problem hiding this comment.
I'm not extremely happy with adding these properties to Socket too, but I don't have any other solution offhand. The problem is that the HTTP server needs the previous value of the timeout to restore it after the keep-alive timeout is not needed anymore, but it does not necessarily know what the value is. test-https-set-timeout-server used to fail before f381340eaff45e840f6a35a954333dc4b41bca57 because of using res.setTimeout(), which, well, may be resolved at the HTTP level, but a user could have used res.socket.setTimeout() directly, and there's not much we can in http in this case.
ChALkeR
commented
Jun 9, 2017
mcollina
commented
Jun 9, 2017
@aqrln can you amend your commit and add the original PR url? |
aqrln
commented
Jun 9, 2017
@mcollina sure. |
refack
left a comment
There was a problem hiding this comment.
LGTM % whatever is decided about who inits this[kLastTimeout] & this[kPrevTimeout]
There was a problem hiding this comment.
Not necessarily, L394 could have an if.
(it's a classical point for polymorphism, but an if can accomplish "extendibility")
There was a problem hiding this comment.
nit: Maybe call this one ...-slow-client-headers
There was a problem hiding this comment.
FWIW this filename is already exceptionally long :)
Though ...-client-headers might convey more information about what the test does, yes.
There was a problem hiding this comment.
nit: maybe put a comment
// simulate a client that sends headers slowlyThere was a problem hiding this comment.
nit:
// two requests to trigger `keepalive`refack
commented
Jun 9, 2017
CITGM (as I believe moving the init won't change API behaviour): https://ci.nodejs.org/view/Node.js-citgm/job/citgm-smoker/864/ |
aqrln
commented
Jun 9, 2017
@refack isn't it a bit premature to run it at this point? The PR is going to be updated to address the reviews, and probably not once. |
refack
commented
Jun 9, 2017
Maybe... but Jenkins was free, and if we find breakage it's interesting. |
aqrln
commented
Jun 9, 2017
@refack oh, it runs faster than I thought CITGM does :) |
Can you explain why the socket timeout should be used instead of |
aqrln
commented
Jun 9, 2017
@mscdex the timeout may be changed via, e.g., |
mscdex
commented
Jun 9, 2017
Here is an alternative patch for _http_server.js that passes all tests (including the ones in this PR) and avoids diff --git a/lib/_http_server.js b/lib/_http_server.js
index 357400e350..8e653a5f98 100644
--- a/lib/_http_server.js+++ b/lib/_http_server.js@@ -436,14 +436,6 @@ function socketOnData(server, socket, parser, state, d) {
assert(!socket._paused);
debug('SERVER socketOnData %d', d.length);
- if (state.keepAliveTimeoutSet) {- socket.setTimeout(0);- if (server.timeout) {- socket.setTimeout(server.timeout);- }- state.keepAliveTimeoutSet = false;- }-
var ret = parser.execute(d);
onParserExecuteCommon(server, socket, parser, state, ret, d);
}
@@ -451,6 +443,15 @@ function socketOnData(server, socket, parser, state, d) {
function onParserExecute(server, socket, parser, state, ret, d) {
socket._unrefTimer();
debug('SERVER socketOnParserExecute %d', ret);
++ if (state.keepAliveTimeoutSet) {+ if (server.timeout)+ socket.setTimeout(server.timeout);+ else+ socket.setTimeout(0);+ state.keepAliveTimeoutSet = false;+ }+
onParserExecuteCommon(server, socket, parser, state, ret, undefined);
}
@@ -545,6 +546,14 @@ function resOnFinish(req, res, socket, state, server) {
// new message. In this callback we setup the response object and pass it
// to the user.
function parserOnIncoming(server, socket, state, req, keepAlive) {
+ if (state.keepAliveTimeoutSet) {+ if (server.timeout)+ socket.setTimeout(server.timeout);+ else+ socket.setTimeout(0);+ state.keepAliveTimeoutSet = false;+ }+
state.incoming.push(req);
// If the writable end isn't consuming, then stop reading |
aqrln
commented
Jun 9, 2017
@mscdex awesome, thanks. It might be that I have gotten the reason of the failure wrong. |
Fix the logic of resetting the socket timeout of keep-alive HTTP connections and add two tests: * `test-http-server-keep-alive-timeout-slow-server` is a regression test for nodejsGH-13391. It ensures that the server-side keep-alive timeout will not fire during processing of a request. * `test-http-server-keep-alive-timeout-slow-headers` ensures that the regular socket timeout is restored as soon as a client starts sending a new request, not as soon as the whole message is received, so that the keep-alive timeout will not fire while, e.g., the client is sending large cookies. Refs: nodejs#2534Fixes: nodejs#13391
aqrln
commented
Jun 12, 2017
I'm not sure if the original block should also stay (instead of being removed as in my patch) in case the socket data stream switches from being handled directly in C++ land (for efficiency) to JS land when someone manually interacts with the socket (by reading data from it or such IIRC). @indutny added the JS stream stuff awhile back, maybe he can answer this. |
aqrln
commented
Jun 12, 2017
@mscdex hmm... moving the And btw, thanks a lot for showing the right direction, after taking a fresh look I could see that my previous patch was actually wrong and didn't work quite the way it was supposed to, duh. |
@aqrln That should cover both yeah. |
aqrln
commented
Jun 12, 2017
mscdex
commented
Jun 12, 2017
LGTM |
Oh, and this one is interesting (arm-fanned tests finally started to run): UPD: I can reproduce it with |
aqrln
commented
Jun 12, 2017
Increasing timeouts in |
Stress (-j 32 -repeat 1000) armv7-ubuntu1404: |
@refack 2 failures out of 2000 runs. I've increased the timeouts even more, let's try it. https://ci.nodejs.org/job/node-stress-single-test/nodes=armv7-ubuntu1404/1297/ UPD: forgot to change RUN_TIMES, actually ran it 2.5 times more times than I intended, and stopped it. Stress test is clean. |
aqrln
commented
Jun 12, 2017
aqrln
commented
Jun 13, 2017
Most machines are free at the moment anyway, so |
mscdex
commented
Jun 13, 2017
Perhaps instead of increasing the timeouts for all environments, use |
aqrln
commented
Jun 13, 2017
@mscdex yeah, that does sound like a good idea. |
aqrln
commented
Jun 13, 2017
mscdex
commented
Jun 13, 2017
LGTM |
aqrln
commented
Jun 13, 2017
aqrln
commented
Jun 13, 2017
Landed in d71718d. |
Fix the logic of resetting the socket timeout of keep-alive HTTP connections and add two tests: * `test-http-server-keep-alive-timeout-slow-server` is a regression test for GH-13391. It ensures that the server-side keep-alive timeout will not fire during processing of a request. * `test-http-server-keep-alive-timeout-slow-client-headers` ensures that the regular socket timeout is restored as soon as a client starts sending a new request, not as soon as the whole message is received, so that the keep-alive timeout will not fire while, e.g., the client is sending large cookies. Refs: #2534Fixes: #13391 PR-URL: #13549 Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Brian White <mscdex@mscdex.net>
Fix the logic of resetting the socket timeout of keep-alive HTTP connections and add two tests: * `test-http-server-keep-alive-timeout-slow-server` is a regression test for GH-13391. It ensures that the server-side keep-alive timeout will not fire during processing of a request. * `test-http-server-keep-alive-timeout-slow-client-headers` ensures that the regular socket timeout is restored as soon as a client starts sending a new request, not as soon as the whole message is received, so that the keep-alive timeout will not fire while, e.g., the client is sending large cookies. Refs: #2534Fixes: #13391 PR-URL: #13549 Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Brian White <mscdex@mscdex.net>
Fix the logic of resetting the socket timeout of keep-alive HTTP connections and add two tests: * `test-http-server-keep-alive-timeout-slow-server` is a regression test for GH-13391. It ensures that the server-side keep-alive timeout will not fire during processing of a request. * `test-http-server-keep-alive-timeout-slow-client-headers` ensures that the regular socket timeout is restored as soon as a client starts sending a new request, not as soon as the whole message is received, so that the keep-alive timeout will not fire while, e.g., the client is sending large cookies. Refs: #2534Fixes: #13391 PR-URL: #13549 Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Brian White <mscdex@mscdex.net>
socketOnDatais not called for headers, the HTTP parser consumesthe stream at that moment. Move the timeout reset logic to
onParserExecuteand add two tests:test-http-server-keep-alive-timeout-slow-serveris a regression testfor Http connections aborted after 5s / keepAliveTimeout #13391. It ensures that the server-side keep-alive timeout will
not fire during processing of a request.
test-http-server-keep-alive-timeout-slow-headersensures that theregular socket timeout is restored as soon as a client starts sending
a new request, not as soon as the whole message is received, so that
the keep-alive timeout will not fire while, e.g., the client is
sending large cookies.
Fixes: #13391
Checklist
make -j4 test(UNIX), orvcbuild test(Windows) passesAffected core subsystem(s)
http