-
Notifications
You must be signed in to change notification settings - Fork 30.2k
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
Always call callbacks in lib/_http_outgoing.js #1143
Conversation
@@ -70,6 +70,27 @@ function OutgoingMessage() { | |||
this._header = null; | |||
this._headers = null; | |||
this._headerNames = {}; | |||
|
|||
var that = this; |
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.
usually, a variable name of self
would be used in this instance
I modified some code to make it adhere to the style used by io.js (proposed by @brendanashworth) |
Just found "make jslint", one more commit to make it pass that too. |
|
||
if (this.finished) { | ||
var err = new Error('write after end'); | ||
err = new Error('write after end'); |
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.
It would be slightly more memory-efficient here and elsewhere to create the Error object inside the nextTick callback.
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 error object is created outside because otherwise it wouldn't contain the correct stack trace.
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.
I guess that's a fair point. What's the motivation for emitting the exception as an error instead of throwing it? Both are going to be disruptive.
As a small aside, I notice that OutgoingMessage#write() still returns true, indicating it's okay to call it again. That seems like a buglet to me.
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.
I left all return values unchanged. Currently return values are pretty much only used as an indicator of whether
the write had to be buffered (false) or was written instantly (true).
The reason for not throwing at that point is that the user still has no reliable (documented!) way of checking the state of the stream beforehand. He would have to wrap every write in try catch...
That's another thing bugging me about the state of the current stream API.
But even having to check some field every time before I do a write... nope! I'd rather handle all errors at one point: in my callback.
More micro-commits! |
So. Is this ready to get merged? Will it get merged? If not I'm ready to make the necessary changes. |
|
||
for (var i = 0; i < outputCallbacks.length; i++) { | ||
var callback = outputCallbacks[i]; | ||
if (typeof callback === 'function') |
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 this check necessary? will a callback ever not be of type 'function'
?
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.
It could be null or undefined if the user didn't specify one...
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.
So maybe just:
if (callback)
callback(err);
I added some comments. Overall, I like what you've done with the code, but changing the tests to make them pass (as they didn't before? is this the case?) worries me. I'm unsure about the semver impact of this. |
I'd call not emitting/calling the callback with an error a bug. So this is a bugfix? I'm also confident that this will not break any existing code, as the callback is usually called when the write fails. This just fixes an edge case where it wasn't (which happens to be reproduced in the test). |
This PR is at least semver-minor, maybe semver-major. The big change is that HEAD responses with a body are now an error instead of a debug warning. It's pretty common for people to lump HEAD and GET responses together, even express.js used to do it at one time (and maybe it still does.) Looking at this PR again, it looks to me like a single commit that introduces two changes: one is that it forces callbacks to run always, the other is that it turns some warnings into errors. It's perhaps better to split it out so that the uncontroversial changes can at least go in. |
Mhh. Right. I forgot about that change while writing my response... I'll make the debug message -> error a separate PR. Edit: Which should get some discussion anyways. Should it even be an error or should the callback just be called indicating that the write succeeded? I think we can all agree that NOT I'm not sure what is be preferable, but the latter is a change that wouldn't break code which doesn't explicitly deal with HEAD requests (and is as such not a breaking change). |
Removed the controversial change from this PR |
if (this.finished) { | ||
if (data && data.length > 0) { | ||
//If the user tried to write data, tell him it failed |
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.
Style nit: please put a space after the slashes and use punctuation. I've been told some people take offense at gendered pronouns in comments.
I'm not sure how I feel about turning write-after-end into an error. It's arguably the proper thing to do but I worry that it's going to break a lot of existing code.
self.outputEncodings = []; | ||
self.outputCallbacks = []; | ||
|
||
for (var i = 0; i < outputCallbacks.length; i++) { |
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 there a reason you cache the variable and reset it rather than using it raw in the for
loop and resetting it afterwards?
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.
I worry the callback function over which we have no control might do something fishy and mess up our state while we're working with it. If such things are nothing we are supposed to be guarding against, then I'll change it of course.
Hi @laino! I'd still like to see this merged in, but it needs updates based on the comments and should probably be resubmitted as a new PR to |
Yes. I'll definitely do that sometime soon. Thanks for the reminder - I somehow forgot about this PR. |
Sweet! No problem. I'm going to close this for now and await a new PR to |
Fixes #1047
The changes will make sure that callbacks given to end() or write() will always be called, with or without an error depending on the circumstances.
A summary of the changes: