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: align destroy w streams #32182

Closed
wants to merge 3 commits into from

Conversation

ronag
Copy link
Member

@ronag ronag commented Mar 10, 2020

This further aligns ClientRequest with streams

Streams that are prematurely destroyed without
error through .destroy() do usually not emit
an error.

Align ClientRequest with this behavior.

This changes the behavior to not error when:

  • abort() from req.socket has been assigned until req.res has been assigned.
  • destroy() until req.res has been assigned.
Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines

@ronag ronag added http Issues or PRs related to the http subsystem. semver-major PRs that contain breaking changes and should be released in the next major version. labels Mar 10, 2020
Streams that are prematurely destroyed without
error through .destroy() do usually not emit
an error.

Align ClientRequest with this behavior.
@ronag ronag force-pushed the http-client-destroy-no-err branch from afea05b to fa3b428 Compare March 10, 2020 17:59
@nodejs-github-bot

This comment has been minimized.

@ronag
Copy link
Member Author

ronag commented Mar 10, 2020

I'm not 100% sure this is a good idea since I suppose people are used to destroy() and get an error if the request is incomplete (in certain situations which is probably not entirely clear for everyone). Which makes me wonder whether abort() should also error in this case. There is an inconsistency here regardless.

Though I would much prefer the behavior proposed in this PR.

@ronag ronag requested review from BridgeAR and lpinca March 10, 2020 19:41
@ronag ronag added the wip Issues and PRs that are still a work in progress. label Mar 10, 2020
@ronag ronag force-pushed the http-client-destroy-no-err branch from 2144f3f to 7ef95e4 Compare March 10, 2020 22:32
@ronag ronag removed the wip Issues and PRs that are still a work in progress. label Mar 10, 2020
@nodejs-github-bot
Copy link
Collaborator

@BridgeAR BridgeAR removed their request for review March 11, 2020 14:54
@@ -375,9 +375,6 @@ function _destroy(req, socket, err) {
socket.destroy(err);
} else {
socket.emit('free');
if (!req.aborted && !err) {
err = connResetException('socket hang up');
Copy link
Member

Choose a reason for hiding this comment

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

I don't like to remove this.

Copy link
Member Author

Choose a reason for hiding this comment

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

Any specific reason? If I call e.g. .destroy() on a fs stream it won't cause any error (or any other stream I can think of at the moment).

Is it backwards compat which is you concern?

Copy link
Member

Choose a reason for hiding this comment

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

It's an informative error that is being removed for no good reason. What's the problem with it? It doesn't work 100% like stream.destroy() but it is really so problematic to justify a semver-major change?

Copy link
Member Author

@ronag ronag Mar 11, 2020

Choose a reason for hiding this comment

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

I would argue that destroying/aborting a stream is not an error and emitting an error is weird/confusing since for me that would indicate something went wrong / unexpected happened.

I do agree that the worth of the change is questionable though.

@ronag
Copy link
Member Author

ronag commented Mar 11, 2020

Just to give some motivation to this change. Most people (as far as I know) currently use abort() due to suboptimal behaviour for destroy() in the past. It would in my opinion be appropriate to doc deprecate abort(). However, in that case it would also be good if destroy() behaved in the same "sane" way as abort() does.

@lpinca
Copy link
Member

lpinca commented Mar 12, 2020

abort() behavior was changed in #20077 and I was -0 on it. This goes one step further and completely remove the "socket hang up" error.

@ronag
Copy link
Member Author

ronag commented Mar 12, 2020

abort() behavior was changed in #20077 and I was -0 on it. This goes one step further and completely remove the "socket hang up" error.

Ah, I forgot about that. Got it. I'll leave this open for a few more days in case anyone else has further input and close it otherwise.

@ronag ronag requested review from mcollina and BridgeAR March 12, 2020 07:16
@@ -58,8 +58,7 @@ const assert = require('assert');
server.listen(0, common.mustCall(() => {
const options = { port: server.address().port };
const req = http.get(options, common.mustNotCall());
req.on('error', common.mustCall((err) => {
assert.strictEqual(err.code, 'ECONNRESET');
req.on('close', common.mustCall((err) => {
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 this change is not correct.

A user is currently adding req.on('error') and req.on('response'). They are not adding req.on('close').

This comment was marked as off-topic.

Copy link
Member Author

@ronag ronag Mar 12, 2020

Choose a reason for hiding this comment

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

This confuses me a little though, abort() is what most people use (I think?) and then according to your comment above they are already broken.

I think we have two options here:

  • Make destroy() not force an error. (This PR currently)
  • Make abort() force an error.

Having the two of them behave differently is confusing.

Copy link
Member Author

Choose a reason for hiding this comment

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

Just to clarify, this is not about swallowing errors. This is about forcing an error.

Copy link
Member

Choose a reason for hiding this comment

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

The current behavior of http.request() implies that either 'error' is fired or 'response' is fired. Firing nothing wil definitely create a memory leak.

Copy link
Member Author

@ronag ronag Mar 12, 2020

Choose a reason for hiding this comment

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

Then abort() has been broken for a long time, because you can call abort() and get neither 'error' nor 'response'.

This happens if abort() is called before the request has received a socket (previously through the short circuit in onSocket).

Should I change this PR to fix that instead?

Firing nothing wil definitely create a memory leak.

'close' is always fired, but I think I get your point.

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 talking about code that has already been written and will break in subtle ways.

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'll open a separate PR to fix abort

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. semver-major PRs that contain breaking changes and should be released in the next major version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants