-
-
Notifications
You must be signed in to change notification settings - Fork 31.4k
url: use SafeSet to filter known special protocols #24703
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Conversation
can they just be changed to maps? |
@devsnek, They could be changed to Sets. There's no need to lookup a value. Would you prefer that? |
@mikesamuel i would definitely prefer using sets |
This seems to make the code harder to understand. We usually just go with |
I think the reason to no use null prototype objects was lookup performance. I don't know if it's still faster. |
Reworking to use sets. @lpinca, Re performance, https://github.com/anvaka/set-vs-object#conclusion is one microbenchmark. |
I changed it to use SafeSet (thanks @joyeecheung), squashed the commits, and changed the PR description to reflect that. |
I think my squash broke Travis's first commit message check :( |
@mikesamuel Can you update the commit message to something that describes the current approach? (e.g. something like |
Avoids a maintenance hazard when reviewers assume that `hostlessProtocol` and `slashedProtocol` are disjoint. The following may be counter-intuitive: ```js // These objects seem to have no keys in common const hostlessProtocol = { 'javascript': true }; const slashedProtocol = { 'http': true }; // A reasonable reviewer may assumes bothTrue is never truthy function bothTrue(lowerProto) { return hostlessProtocol[lowerProto] && slashedProtocol[lowerProto]; } // But console.log(Boolean(bothTrue('constructor'))); // true ``` This change uses SafeSet instead of plain-old objects. ---- Rejected alternative: We could have used object with a `null` prototype as lookup tables so that `lowerProto` is never treated as a key into `Object.prototype`. ```js const hostlessProtocol = { __proto__: null, 'javascript': true }; const slashedProtocol = { __proto__: null, 'http': true }; function bothTrue(lowerProto) { return hostlessProtocol[lowerProto] && slashedProtocol[lowerProto]; } console.log(Boolean(bothTrue('constructor'))); // false ```
@joyeecheung, done |
(Benchmark tradeoffs look perfectly acceptable to me, but second opinion welcome.) |
Resume Build CI: https://ci.nodejs.org/job/node-test-pull-request/19114/ |
Avoids a maintenance hazard when reviewers assume that `hostlessProtocol` and `slashedProtocol` are disjoint. The following may be counter-intuitive: ```js // These objects seem to have no keys in common const hostlessProtocol = { 'javascript': true }; const slashedProtocol = { 'http': true }; // A reasonable reviewer may assumes bothTrue is never truthy function bothTrue(lowerProto) { return hostlessProtocol[lowerProto] && slashedProtocol[lowerProto]; } // But console.log(Boolean(bothTrue('constructor'))); // true ``` This change uses SafeSet instead of plain-old objects. ---- Rejected alternative: We could have used object with a `null` prototype as lookup tables so that `lowerProto` is never treated as a key into `Object.prototype`. ```js const hostlessProtocol = { __proto__: null, 'javascript': true }; const slashedProtocol = { __proto__: null, 'http': true }; function bothTrue(lowerProto) { return hostlessProtocol[lowerProto] && slashedProtocol[lowerProto]; } console.log(Boolean(bothTrue('constructor'))); // false ``` PR-URL: nodejs#24703 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Landed in 0d23118. Thanks for the contribution! 🎉 |
Post-mortem: benchmark results. The most significant ones (with Benchmark results
Significant impact
|
Avoids a maintenance hazard when reviewers assume that `hostlessProtocol` and `slashedProtocol` are disjoint. The following may be counter-intuitive: ```js // These objects seem to have no keys in common const hostlessProtocol = { 'javascript': true }; const slashedProtocol = { 'http': true }; // A reasonable reviewer may assumes bothTrue is never truthy function bothTrue(lowerProto) { return hostlessProtocol[lowerProto] && slashedProtocol[lowerProto]; } // But console.log(Boolean(bothTrue('constructor'))); // true ``` This change uses SafeSet instead of plain-old objects. ---- Rejected alternative: We could have used object with a `null` prototype as lookup tables so that `lowerProto` is never treated as a key into `Object.prototype`. ```js const hostlessProtocol = { __proto__: null, 'javascript': true }; const slashedProtocol = { __proto__: null, 'http': true }; function bothTrue(lowerProto) { return hostlessProtocol[lowerProto] && slashedProtocol[lowerProto]; } console.log(Boolean(bothTrue('constructor'))); // false ``` PR-URL: #24703 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Avoids a maintenance hazard when reviewers assume that `hostlessProtocol` and `slashedProtocol` are disjoint. The following may be counter-intuitive: ```js // These objects seem to have no keys in common const hostlessProtocol = { 'javascript': true }; const slashedProtocol = { 'http': true }; // A reasonable reviewer may assumes bothTrue is never truthy function bothTrue(lowerProto) { return hostlessProtocol[lowerProto] && slashedProtocol[lowerProto]; } // But console.log(Boolean(bothTrue('constructor'))); // true ``` This change uses SafeSet instead of plain-old objects. ---- Rejected alternative: We could have used object with a `null` prototype as lookup tables so that `lowerProto` is never treated as a key into `Object.prototype`. ```js const hostlessProtocol = { __proto__: null, 'javascript': true }; const slashedProtocol = { __proto__: null, 'http': true }; function bothTrue(lowerProto) { return hostlessProtocol[lowerProto] && slashedProtocol[lowerProto]; } console.log(Boolean(bothTrue('constructor'))); // false ``` PR-URL: nodejs#24703 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Avoids a maintenance hazard when reviewers assume that `hostlessProtocol` and `slashedProtocol` are disjoint. The following may be counter-intuitive: ```js // These objects seem to have no keys in common const hostlessProtocol = { 'javascript': true }; const slashedProtocol = { 'http': true }; // A reasonable reviewer may assumes bothTrue is never truthy function bothTrue(lowerProto) { return hostlessProtocol[lowerProto] && slashedProtocol[lowerProto]; } // But console.log(Boolean(bothTrue('constructor'))); // true ``` This change uses SafeSet instead of plain-old objects. ---- Rejected alternative: We could have used object with a `null` prototype as lookup tables so that `lowerProto` is never treated as a key into `Object.prototype`. ```js const hostlessProtocol = { __proto__: null, 'javascript': true }; const slashedProtocol = { __proto__: null, 'http': true }; function bothTrue(lowerProto) { return hostlessProtocol[lowerProto] && slashedProtocol[lowerProto]; } console.log(Boolean(bothTrue('constructor'))); // false ``` PR-URL: #24703 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Avoids a maintenance hazard when reviewers assume that `hostlessProtocol` and `slashedProtocol` are disjoint. The following may be counter-intuitive: ```js // These objects seem to have no keys in common const hostlessProtocol = { 'javascript': true }; const slashedProtocol = { 'http': true }; // A reasonable reviewer may assumes bothTrue is never truthy function bothTrue(lowerProto) { return hostlessProtocol[lowerProto] && slashedProtocol[lowerProto]; } // But console.log(Boolean(bothTrue('constructor'))); // true ``` This change uses SafeSet instead of plain-old objects. ---- Rejected alternative: We could have used object with a `null` prototype as lookup tables so that `lowerProto` is never treated as a key into `Object.prototype`. ```js const hostlessProtocol = { __proto__: null, 'javascript': true }; const slashedProtocol = { __proto__: null, 'http': true }; function bothTrue(lowerProto) { return hostlessProtocol[lowerProto] && slashedProtocol[lowerProto]; } console.log(Boolean(bothTrue('constructor'))); // false ``` PR-URL: #24703 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAvoids a maintenance hazard when reviewers assume that
hostlessProtocol
andslashedProtocol
are disjoint.The following may be counter-intuitive:
This change uses SafeSet instead of plain-old objects.
Rejected alternative:
We could have used object with a
null
prototype as lookup tablesso that
lowerProto
is never treated as a key intoObject.prototype
.