-
Notifications
You must be signed in to change notification settings - Fork 30k
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
net: refactor Server.prototype.listen #4039
Conversation
The test The solution is either to change the failing test, or reintroduce the inconsistency. |
@@ -846,12 +846,16 @@ function connect(self, address, port, addressType, localAddress, localPort) { | |||
} | |||
|
|||
|
|||
// Check that the port number is not NaN when coerced to a number, | |||
// is an integer and that it falls within the legal range of port numbers. | |||
// Check that port is undefined, a number or a string. |
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 understand why you made the changes, but it seems odd that this function accepts undefined
as a valid port, and also that sometimes it returns a boolean and other times throws.
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 split into two functions: One that checks the type and one that does the coercion to number (port | 0
) and throws if not valid.
e6b3224
to
effa0fc
Compare
I made some updates, the CI should pass now. |
This change would remove a test introduced in 57c56558. /cc @indutny @raymondfeng Even if the change should happen (about which I have no opinion, at least right now), the test should probably be modified so that it checks the new expected behavior rather than deleting it. |
But then I think it should be moved to parallel/test-net-listen-port-option.js. |
acdc60a
to
1e3ed36
Compare
The problem is this: I don't believe this is a big deal. I don't think anybody uses fractions in the port, and I guess that most people don't want to listen on a random port. And if they do, they will probably omit the port or use What do you think? |
The |
Marking as semver-major because of the functional changes. It's possible we can downgrade this to semver-minor tho. |
1e3ed36
to
282e42f
Compare
rebased |
@jscissr ... thank you :-) I'll queue this up for a review shortly. Sorry that it's taken so long :-/ |
Thanks @jasnell! In case you don't make a new major version anytime soon, I could also split the refactoring from the (breaking) consistency improvement, which means just a few extra lines that could be removed in the next major. |
7da4fd4
to
c7066fb
Compare
* move `listenAfterLookup` out of `Server.prototype.listen` * rename `listenAfterLookup` to `lookupAndListen` for consistency with `lookupAndConnect` * self -> this
This is mostly preparation, `options` will be used later.
This removes the ifs directly dealing with arguments.
return typeof cb === 'function' ? [options, cb] : [options]; | ||
if (typeof cb !== 'function') | ||
cb = null; | ||
return [options, cb]; |
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 comment for normalizeArgs()
needs to be updated now too.
I'm LGTM. @mscdex can you check if it is ok for you? |
Requested by @mscdex
@nodejs/collaborators Can we get some other quick LGTM? New CI: https://ci.nodejs.org/job/node-test-pull-request/4017/ @jasnell I'll like to get this landed for v7. |
CI is passing. |
// It is the same as the argument of Socket.prototype.connect(). | ||
function normalizeConnectArgs(args) { | ||
// This is also used by Server.prototype.listen(). |
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.
This should probably say that it is used by listen()
and connect()
. Just saying "also" doesn't mean much when the "connect" part is removed.
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.
@cjihrig I can fix the comment when I land. Is LGTM apart from this?
This is getting a LGTM from me, if @mcollina will fix the comment when landing |
@mcollina ... ok, I'll be cutting the branch right about at noon pacific today so there's still some time. the change LGTM |
Landed as fd6af98 |
This PR simplifies Server.prototype.listen, removing some redundancy and inconsistency. Because listen and connect have a similar function signature, normalizeConnectArgs can be reused for listen. listenAfterLookup renamed to lookupAndListen for consistency with lookupAndConnect, and moved out of Server.prototype.listen. PR-URL: #4039 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Glen Keane <glenkeane.94@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
It would appear this has broken passing https://github.com/yoshuawuyts/crash-reporter-service/blob/master/tests/lib.js#L40 Was that intended behavior? If not we should land a fix edit: ref --> https://twitter.com/yoshuawuyts/status/820527120740913154 |
The main discussion is in: #4039 (comment). Yes it was a wanted fix, as I think that we should validate ports in a consistent manner. Specifically, in node v6 passing It has also passed a long amount of CITGM runs for all the v7 releases. |
+1 for consistency in validation, but I think passing null as port in option object should not throw. I would expect calling Basically, in an options object, we should not distinguish between |
@sam-github I'm not convinced about that. We support |
@mcollina Imagine configuration coming out of node-config YAML files, and default.yaml has a port which is overridden by mcollina.yaml (NODE_ENV=mcollina) which sets port to |
@ronkorving why do not set it to |
@mcollina its easy to get keys set, config files, default handling, etc. Object.assign, util._extend can both clear keys by setting them to undefined, for example, but can't delete keys. Can you explain why you think its more robust? I've found the exact opposite. In Javascript, |
@mcollina Setting it to 0 is very explicitly setting it to that value. Trying to unset it so it uses whatever the default may be (in this case 0) has different semantics. You can state the first is always superior, but I guess my point is that there are various ways to look at this (of which at least one case can run into the |
@sam-github I generally think that massively overloaded method are extremely hard to maintain, optimize and keep secure. In this particular case, If it was for me, I would remove the default value for Having said so, fire a PR and we will discuss it there. Even if I disagree, it seems a lot of people care about passing |
Much of node's API is undocumented, unfortunately, so its hard to argue intentions. I agree with you on massively overloaded methods, but not here. if ("PORT" in process.env)
server.listen(process.env.PORT, ...) // use the port
else
server.listen(...) // use the default is, IMO, unfortunate, I'd rather server.listen(process.env.PORT, ...) // if the env var is not defined, you get the default behaviour This pattern shows up quite often when loading config, not just env vars, which is why its important to base behaviour on a key's value, not its presence, its why: var config = {}; // probably read from a config file or DB, note there is no PORT
server.listen({port: config.port}, .. // options.port exists, but value is undefined should be the same as server.listen({}, .. // options.port key does not exist |
Just to clarify, this does not work in v6, but it does in v7 with this very change: var net = require('net')
net.createServer().listen(process.env.PORT, function () {
console.log('server listening on', this.address())
}) also var config = {}
console.log(config.port) // => undefined
server.listen(config.port) // you get the default behavior
config.port = null
console.log(config.port) // => null
server.listen(config.port) // it throws, because null is not a valid port IMHO it's working as you want, with the added benefit of preventing bad values you would have to come from somewhere unexpectedly. |
This PR simplifies
Server.prototype.listen
, removing some redundancy and inconsistency.Because
listen
andconnect
have a similar function signature,normalizeConnectArgs
can be reused forlisten
.listenAfterLookup
renamed tolookupAndListen
for consistency withlookupAndConnect
, and moved out ofServer.prototype.listen
.Functional differences
To improve consistency, I actually made some small functional changes:
port
was checked with this complicated code if set in a config object:But if set as first argument, it was only coerced to a number with
var port = toNumber(arguments[0]);
.Now, it is consistently using the first way,
toNumber
is not used anymore.However this is a breaking change, because before invalid ports resulted in using a random port instead of throwing.
addressType
was sometimesnull
and sometimes4
, if no address is given.Now it is always
4
.host
was checked like this:Now it is checked with
if (typeof arguments[1] === 'string')
, this is consistent withconnect
.