Skip to content
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

http: make request.abort() destroy the socket #10818

Merged
merged 1 commit into from
Jan 28, 2017

Conversation

lpinca
Copy link
Member

@lpinca lpinca commented Jan 15, 2017

request.abort() did not destroy the socket if it was called
before a socket was assigned to the request and the request
did not use an Agent or a Unix Domain Socket was used.

Fixes: #10812

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • commit message follows commit guidelines
Affected core subsystem(s)

http

@nodejs-github-bot nodejs-github-bot added http Issues or PRs related to the http subsystem. lts-watch-v6.x labels Jan 15, 2017
@jasnell
Copy link
Member

jasnell commented Jan 15, 2017

I think this is fine, but let's get some good review @nodejs/http @indutny @mscdex

const net = require('net');

const server = http.createServer(() => {
throw new Error('test invalidation');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use common.fail() instead of explicitly throwing (in the other test too).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I originally used common.fail() but I honestly don't like to use it with a non string argument.
In this case it will be called with the request object and the error message will be something like AssertionError: [object Object]. I find it horrible.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

common.fail() takes an optional string argument.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cjihrig are you suggesting to use this?

http.createServer(() => common.fail('whatever'));

I thought you wanted to pass it directly to http.createServer()

http.createServer(common.fail);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be OK with either. If you like the first one, go with that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if I don't like http.createServer(common.fail);, for the reason stated above, I changed it to that for consistency as there are other tests which use the same pattern.

socket.destroy();
} else {
socket.emit('free');
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not even sure if it's appropriate to emit 'free' and skip destroying the socket. ClientRequest#abort() always calls socket.destroy() when there is one.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bnoordhuis I think this is for keep-alive sockets?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bnoordhuis I guess you were referring to

node/lib/_http_client.js

Lines 296 to 299 in 77be180

if (this.socket) {
// in-progress
this.socket.destroy();
}
. I'm not sure either.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is when socket.emit('free'); was added: d0c7d93#diff-e3bc37430eb078ccbafe3aa3b570c91a, previously the socket was destroyed in all cases.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should always destroy(), I do not see a way for this socket to be reused even if there is an agent.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. There's really no safe way to reuse it. destroy() is the safest thing to do

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a test which should clarify why socket.emit('free') is used. It's for queued requests which are already aborted.

Copy link
Member Author

@lpinca lpinca Jan 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See f52c874b737ccb7e92d640b31e02c6efb3acd22c.

@lpinca
Copy link
Member Author

lpinca commented Jan 23, 2017

Is there anything I can do to move this forward?

@bnoordhuis
Copy link
Member

@lpinca
Copy link
Member Author

lpinca commented Jan 23, 2017

@bnoordhuis yeah, this commit d0c7d93#diff-e3bc37430eb078ccbafe3aa3b570c91a

Avoid sending unsent data and destroying otherwise legitimate sockets
for requests that are aborted while still in the agent queue. This
reduces stress on upstream systems who will likely respond to the
request but client app already knows that it will be dropped on the
floor and also helps avoid killing keep-alive connections.

@lpinca
Copy link
Member Author

lpinca commented Jan 23, 2017

The original PR doesn't seem to give more info: nodejs/node-v0.x-archive#7533

@lpinca
Copy link
Member Author

lpinca commented Jan 24, 2017

Also pinging other @nodejs/collaborators.

@mcollina
Copy link
Member

Copy link
Member

@bnoordhuis bnoordhuis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with some trepidation. Good job on the test coverage though.

Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. CITGM should be checked as well

@lpinca
Copy link
Member Author

lpinca commented Jan 26, 2017

@lpinca
Copy link
Member Author

lpinca commented Jan 26, 2017

I think CITGM failures (express and spdy) are not related to this change as I can also reproduce them with current master. browserify also failed in other CITGM runs.

@gibfahn
Copy link
Member

gibfahn commented Jan 26, 2017

The browserify failure is a module issue (nodejs/citgm#335), not sure about express and spdy.

There's also a failure on ember-cli: https://ci.nodejs.org/view/Node.js-citgm/job/citgm-smoker/546/nodes=ppcle-ubuntu1404/testReport/(root)/citgm/ember_cli_v2_11_0/

@lpinca
Copy link
Member Author

lpinca commented Jan 26, 2017

Yup but it doesn't seem to use abort() at all, not sure.

@lpinca
Copy link
Member Author

lpinca commented Jan 26, 2017

I've started one more CITGM run against master to see if it fails with express and spdy. If not I'll rebase this and run again.

@lpinca
Copy link
Member Author

lpinca commented Jan 26, 2017

There seem to be quite a bit of failures with master https://ci.nodejs.org/view/Node.js-citgm/job/citgm-smoker/547.

I'll wait a bit before rerunning against this PR.

@lpinca
Copy link
Member Author

lpinca commented Jan 27, 2017

#10558 is responsible for CITGM failures with express and spdy, so I've rebased this before #10558 was landed and re-ran

CI: https://ci.nodejs.org/job/node-test-pull-request/6079/
CITGM: https://ci.nodejs.org/view/Node.js-citgm/job/citgm-smoker/549/

There is one CITGM suspicious failure on ppcle-ubuntu1404 with spdy but I think it is not related as the failing test fails for spdy/3.1 but not for h2 and spdy/3. On top of this the test seems to not use request.abort() at all.

@mcollina
Copy link
Member

@lpinca LGTM.

I'm not 100% sure we should backport this to the LTS releases, but that's another discussion.

@lpinca
Copy link
Member Author

lpinca commented Jan 27, 2017

It's a bug-fix and I hope we can backport this. It's needed for ws where I found the issue.

@lpinca
Copy link
Member Author

lpinca commented Jan 27, 2017

If there are no objections I'll land this tomorrow.

const req = http.get({agent, port}, common.fail);
req.abort();

http.get({agent, port}, (res) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we have an assertion within this, I would wrap this in common.mustCall

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't add it as the test will fail for timeout if the function is not called but will add it if desired.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

`request.abort()` did not destroy the socket if it was called
before a socket was assigned to the request and the request
did not use an `Agent` or a Unix Domain Socket was used.

Fixes: nodejs#10812
PR-URL: nodejs#10818
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
@lpinca
Copy link
Member Author

lpinca commented Jan 28, 2017

Landed in 18d4ee9.

@lpinca lpinca closed this Jan 28, 2017
@lpinca lpinca merged commit 18d4ee9 into nodejs:master Jan 28, 2017
@lpinca lpinca deleted the fix/request-abort branch January 28, 2017 17:08
evanlucas pushed a commit that referenced this pull request Jan 31, 2017
`request.abort()` did not destroy the socket if it was called
before a socket was assigned to the request and the request
did not use an `Agent` or a Unix Domain Socket was used.

Fixes: #10812
PR-URL: #10818
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
@italoacasas italoacasas mentioned this pull request Jan 31, 2017
@jasnell
Copy link
Member

jasnell commented Mar 8, 2017

The tests fail with timeouts on v4.x. Will need a backport PR to land there.
Landing on v6

jasnell pushed a commit that referenced this pull request Mar 8, 2017
`request.abort()` did not destroy the socket if it was called
before a socket was assigned to the request and the request
did not use an `Agent` or a Unix Domain Socket was used.

Fixes: #10812
PR-URL: #10818
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
MylesBorins pushed a commit that referenced this pull request Mar 9, 2017
`request.abort()` did not destroy the socket if it was called
before a socket was assigned to the request and the request
did not use an `Agent` or a Unix Domain Socket was used.

Fixes: #10812
PR-URL: #10818
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
@MylesBorins MylesBorins mentioned this pull request Mar 9, 2017
MylesBorins pushed a commit that referenced this pull request Mar 11, 2017
`request.abort()` did not destroy the socket if it was called
before a socket was assigned to the request and the request
did not use an `Agent` or a Unix Domain Socket was used.

Fixes: #10812
PR-URL: #10818
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
@MylesBorins MylesBorins mentioned this pull request Mar 11, 2017
MylesBorins pushed a commit that referenced this pull request Mar 11, 2017
`request.abort()` did not destroy the socket if it was called
before a socket was assigned to the request and the request
did not use an `Agent` or a Unix Domain Socket was used.

Fixes: #10812
PR-URL: #10818
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
abhishekumar-tyagi pushed a commit to abhishekumar-tyagi/node that referenced this pull request May 5, 2024
`request.abort()` did not destroy the socket if it was called
before a socket was assigned to the request and the request
did not use an `Agent` or a Unix Domain Socket was used.

Fixes: nodejs/node#10812
PR-URL: nodejs/node#10818
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
http Issues or PRs related to the http subsystem.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

http: request.abort() does not destroy the socket when using a Unix Domain Socket
8 participants