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: allow async createConnection() #4638

Closed
wants to merge 1 commit into from

Conversation

mscdex
Copy link
Contributor

@mscdex mscdex commented Jan 12, 2016

This commit adds support for async createConnection() implementations and is still backwards compatible with synchronous createConnection() implementations.

This commit also makes the http client more friendly with generic stream objects produced by createConnection() by checking stream.writable instead of stream.destroyed as the latter is currently a net.Socket-ism and not set by the core stream implementations.

The original use case behind this PR is that it allows the creation of a minimal, custom Http.Agent that allows you to make in-process http requests over ssh. The async-ness comes into play because the way ssh works is you have to ask the server to start a TCP connection first. You could return some sort of dummy socket object, but ssh2 already provides a stream object when the server allows the TCP connection, so adding yet another object for every connection just makes things more complicated.

Note: I wasn't quite sure how to handle the errors passed to the oncreate() callback. The same problem exists for the synchronous use. How do you signal to the http client/agent that no socket was able to be created without returning a dummy object that emits an error or something?

@mscdex mscdex added the http Issues or PRs related to the http subsystem. label Jan 12, 2016
@jasnell jasnell added the semver-minor PRs that contain new features and should be released in the next minor version. label Jan 12, 2016
@mscdex
Copy link
Contributor Author

mscdex commented Jan 20, 2016

/cc @nodejs/collaborators Any comments/input on this?

@mcollina
Copy link
Member

It's 👍 for me, because the alternative way of doing this is to return a 'dummy' duplex, possibly built with duplexify that proxies to the real one.

However, I would add an example on why it is needed here and in the docs, otherwise is not exactly clear the case when this is useful.

Regarding errors, you should probably emit them in the req, as it is done here:

req.emit('error', err);

@trevnorris
Copy link
Contributor

var called = false;
var newSocket = self.createConnection(options);
if (newSocket)
oncreate(null, newSocket);
Copy link
Member

Choose a reason for hiding this comment

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

process.nextTick to be consistent?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You mean put a process.nextTick() inside oncreate() that wraps the majority of that code? Otherwise oncreate() could be executed immediately within createConnection() too....

Copy link
Member

Choose a reason for hiding this comment

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

Ah, ok... makes sense!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To me it should still fit with the old behavior as it is now without process.nextTick().

@mscdex
Copy link
Contributor Author

mscdex commented Jan 20, 2016

@mcollina The problem about errors is that there are some places where a request (or other suitable) object is not (yet) available when createConnection() is called. An example of this is inside http.Agent.prototype.createSocket(). Where would errors go in such cases?

Maybe adding error trapping and such would be better done in a separate PR?

@mcollina
Copy link
Member

@mscdex maybe I missing some bits, but isn't createSocket() accepting a request as a first argument? https://github.com/nodejs/node/blob/master/lib/_http_agent.js#L152.

I think error handling for this should be done as part of this PR, because the current API has a clear error model, while this swallow errors in the callback.

req.onSocket(this.createSocket(req, options));
this.createSocket(req, options, function(err, newSocket) {
if (!err)
req.onSocket(newSocket);
Copy link
Member

Choose a reason for hiding this comment

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

@mscdex I mean adding req.emit('error', err) as an else branch here.

@mscdex
Copy link
Contributor Author

mscdex commented Jan 20, 2016

@mcollina If you look a few lines below that you'll see that there is an if (req) {} check.

EDIT: Perhaps that conditional should be removed. I will look into that as well.

@mcollina
Copy link
Member

@mscdex I think that conditional should be removed as well. I don't see any point around where req can be null there. createSocket is only called by addRequest, and addRequest is only called from a single place:

self.agent.addRequest(self, options);
.

@mscdex mscdex force-pushed the http-async-createconnection branch from abf0619 to d245599 Compare January 21, 2016 00:51
@mscdex
Copy link
Contributor Author

mscdex commented Jan 21, 2016

PR updated according to suggestions

@mscdex
Copy link
Contributor Author

mscdex commented Jan 21, 2016

if (newSocket)
oncreate(null, newSocket);
function oncreate(err, s) {
if (called)
Copy link
Member

Choose a reason for hiding this comment

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

Should we throw an error instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Probably not, there wouldn't be any reliable way to catch such errors since this is done inside the agent and createSocket() could be called whenever it needs a new socket?

@mscdex
Copy link
Contributor Author

mscdex commented Jan 31, 2016

CI is green except for some unrelated test failures on pi1.

@jasnell
Copy link
Member

jasnell commented Feb 1, 2016

Needs a doc update too ... otherwise LGTM

@mscdex
Copy link
Contributor Author

mscdex commented Feb 1, 2016

@jasnell The createConnection isn't documented already so there's nothing to update, unless you're proposing to add it to the documentation.

@jasnell
Copy link
Member

jasnell commented Feb 1, 2016

Yeah, that's what I'm proposing :-)

@mcollina
Copy link
Member

mcollina commented Feb 2, 2016

LGTM.

I agree with @jasnell, we need to add this to the docs, it can be quite handy.
Also, it would become part of the API and it will need to adhere to semver.

@mscdex mscdex force-pushed the http-async-createconnection branch from d245599 to 0b04074 Compare February 4, 2016 03:17
@mscdex
Copy link
Contributor Author

mscdex commented Feb 4, 2016

@jasnell @mcollina Documentation added.

@mcollina
Copy link
Member

mcollina commented Feb 4, 2016

LGTM

1 similar comment
@jasnell
Copy link
Member

jasnell commented Feb 4, 2016

LGTM

@jasnell
Copy link
Member

jasnell commented Feb 4, 2016

New CI, just to be safe: https://ci.nodejs.org/job/node-test-pull-request/1546/

@mscdex mscdex force-pushed the http-async-createconnection branch from 0b04074 to 2ac8fc8 Compare February 4, 2016 19:24
This commit adds support for async createConnection()
implementations and is still backwards compatible with
synchronous createConnection() implementations.

This commit also makes the http client more friendly with
generic stream objects produced by createConnection() by
checking stream.writable instead of stream.destroyed as the
latter is currently a net.Socket-ism and not set by the core
stream implementations.
@mscdex mscdex force-pushed the http-async-createconnection branch from 2ac8fc8 to 4518b3a Compare February 4, 2016 19:24
@mscdex
Copy link
Contributor Author

mscdex commented Feb 4, 2016

Fixed lint issue. CI again: https://ci.nodejs.org/job/node-test-pull-request/1551/

mscdex added a commit that referenced this pull request Feb 11, 2016
This commit adds support for async createConnection()
implementations and is still backwards compatible with
synchronous createConnection() implementations.

This commit also makes the http client more friendly with
generic stream objects produced by createConnection() by
checking stream.writable instead of stream.destroyed as the
latter is currently a net.Socket-ism and not set by the core
stream implementations.

PR-URL: #4638
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: James M Snell <[email protected]>
@mscdex mscdex closed this Feb 11, 2016
@mscdex mscdex deleted the http-async-createconnection branch February 11, 2016 17:56
@mscdex
Copy link
Contributor Author

mscdex commented Feb 11, 2016

Landed in 9bee03a.

rvagg pushed a commit that referenced this pull request Feb 15, 2016
This commit adds support for async createConnection()
implementations and is still backwards compatible with
synchronous createConnection() implementations.

This commit also makes the http client more friendly with
generic stream objects produced by createConnection() by
checking stream.writable instead of stream.destroyed as the
latter is currently a net.Socket-ism and not set by the core
stream implementations.

PR-URL: #4638
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: James M Snell <[email protected]>
stefanmb pushed a commit to stefanmb/node that referenced this pull request Feb 23, 2016
This commit adds support for async createConnection()
implementations and is still backwards compatible with
synchronous createConnection() implementations.

This commit also makes the http client more friendly with
generic stream objects produced by createConnection() by
checking stream.writable instead of stream.destroyed as the
latter is currently a net.Socket-ism and not set by the core
stream implementations.

PR-URL: nodejs#4638
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: James M Snell <[email protected]>
@lekkas
Copy link

lekkas commented Mar 3, 2016

Sweet, allowing async createConnection() will facilitate creating tunnelling sockets. Will this get merged in the 4.x branch?

@mscdex
Copy link
Contributor Author

mscdex commented Mar 3, 2016

@lekkas That would be up to @nodejs/lts

@lekkas
Copy link

lekkas commented Mar 3, 2016

Thank you @mscdex and great work btw 👍

@jasnell
Copy link
Member

jasnell commented Mar 3, 2016

As a semver-minor it's not likely. So far the only semver-minor's we have added to LTS deal with lower level post mortem debugging support. I doubt there'd be enough justification on this one.

@lekkas
Copy link

lekkas commented Mar 7, 2016

Got it, thanks @jasnell

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-minor PRs that contain new features and should be released in the next minor version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants