-
-
Notifications
You must be signed in to change notification settings - Fork 35.5k
http: replace destroySoon with socket.end #36205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from 6 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
dd2e3ed
net: require two events to destroy a socket
mmomtchev e6699c6
net: replace destroySoon with socket.end()
mmomtchev 8f0e26c
net: close http connections with stream.end()
mmomtchev f780542
http: lint the PR
mmomtchev 3e1ba08
net: add a unit test for res.end
mmomtchev 1559f5c
http: replace destroySoon with socket.end
mmomtchev a1b606c
tls: support active closing for TLS sockets
mmomtchev 6038c95
remove useless change
mmomtchev 0dfd1f2
tls: use Writable.end (@ronag)
mmomtchev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| 'use strict'; | ||
| const common = require('../common'); | ||
|
|
||
| const http = require('http'); | ||
| const net = require('net'); | ||
|
|
||
| const data = 'hello'; | ||
| const server = http.createServer({}, common.mustCallAtLeast((req, res) => { | ||
| res.setHeader('content-length', data.length); | ||
| res.end(data); | ||
| }, 2)); | ||
|
|
||
| server.listen(0, function() { | ||
| const options = { | ||
| host: '127.0.0.1', | ||
| port: server.address().port, | ||
| allowHalfOpen: true | ||
| }; | ||
| const socket = net.connect(options, common.mustCall(() => { | ||
| socket.on('ready', common.mustCall(() => { | ||
| socket.write('GET /\n\n'); | ||
| socket.once('data', common.mustCall(() => { | ||
| socket.write('GET /\n\n'); | ||
| setTimeout(common.mustCall(() => { | ||
| socket.destroy(); | ||
| server.close(); | ||
| }), common.platformTimeout(10)); | ||
| })); | ||
| })); | ||
| })); | ||
| }); | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the timeout needed? Could we use some event on the other side?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You won't get anything on the second request - the server has already closed its end
The previous version will send a
RSTThe new one will silently swallow your request
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mcollina The more I look at this, the more I am starting to question this behavior
Because now it is correct from the socket standpoint, but not from the protocol
Normally, an HTTP/1.1 connection with
Connection: closeshould have a mandatory simultaneous closeIn this case, force-closing and sending back a
RSTif the other end continues writing is the correct behaviorWe got the TLS right, but not HTTP/1.1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But for this to work, we have to correctly identify the exact protocol version
Then enforce a mandatory simultaneous close in HTTP/1.1 and TLS/1.0
And drain the input side on HTTP/1.0 and TLS/1.1+
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@addaleax @lpinca @jasnell
What do you think?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the test, I think it is possible to remove the timeout by listening to the
'finish'event of the response socket (after callingresponse.end()to ensure that the listener will be added after the one that currently destroys the socket). When that event is emitted write again from the client socket.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lpinca I have no
responseobject, I am doing manual HTTP withnet?I fixed the gist and I ran it with a Node without the
readStopkludge instream_base_commons.js- it was still not very reliable detecting theRSTuntil I added a thirdwrite- ie. if you callsocket.write()to send some data and that data gets aRSTin return you won't get an error until youread- which you won't since theReadablehas ended - or call anotherwrite. Since this is very edge behavior anyway, I won't call it a bug.The test is still very random - usually naked HTTP servers (ie Apache) will read after
FINwhile the big load-balancers of the top sites won'tUh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have it on the server. Your server is an HTTP server, your client is a plain
net.Socket. Basically wait for the'finish'event to be emitted on theresponse, then wait for the'finish'event on the response socket (if it is not finished yet) and when it is emitted write again on the client socket.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason for this is that Node ignores
SIGPIPEon Linux - normally if you callwrite(the kernel call) in non-blocking mode, it will just schedule your write and return. This is what libuv does too. Then later, if thiswritegets aRSTin return - the only way to notify you would be aSIGPIPE- if you don't do any other calls on this descriptor and you have ignoredSIGPIPEyou won't get an error. But once again, this is a very edge behavior, I don't think it is worth it to try to fix it.Anyway, this confirms that HTTP's behavior, when it comes to closing the connection, is undefined and both implementations exist in the wild
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the extra
writethe gist should work even with a stock Node