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
Fix this
arg for URLSearchParams prototype call
#1111
Conversation
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 fact that tests were already passing is concerning. Please add a test case
The error is not reproducible in Node, which is why the tests are passing. It occurs in Electron though, which suggests it could be a difference in the implementation of From reading the current code, as well as the Proxy docs, it seems the current usage only works incidentally. From what I can tell, the object being bound to I'm happy to add a test if you can point me to a way to run the Mocha tests in Electron. I've tried this library, but it doesn't work (I get ES module errors originating from within Mocha's code about using |
The cause for this bug is inconsistent brand checks between Node.js' implementation of URLSearchParams compared to browser's. Consider the following: const u = new URLSearchParams();
u.get.call(Object.create(u), ''); In the browser (and hence Electron), the second line results in a thrown exception, usually with a message like "Invalid invocation" or something similar. However, Node.js uses a different style of brand checks that checks if the object has a special symbol property. Since property accesses fall back to the prototype object in JavaScript, Node.js is fine with this code, even though The v3 node-fetch way of implementing Headers depends on the Node.js behavior. The current code does: return URLSearchParams.prototype[p].call(
receiver,
String(name).toLowerCase(),
String(value)
); where As far as this PR goes, I think it is absolutely the right fix. In fact, I encourage people to merge this as soon as possible, since having a popular package like node-fetch depend on the incorrect behavior of Node.js itself prevents Node.js from fixing this bug. If you want to actually create a test for this PR, the best bet is to monkey-patch the Node.js URLSearchParams so that it acts more like the browser: // Monkey-patch URLSearchParams to do brand checks more accurately.
// This makes the implementation more similar to browsers (or Electron),
// and works around a Node.js bug.
const prevCtor = URLSearchParams;
const uspSet = new WeakSet();
URLSearchParams = function(...args) {
const obj = Reflect.construct(prevCtor, args, new.target);
uspSet.add(obj);
return obj;
};
Object.setPrototypeOf(URLSearchParams, prevCtor);
URLSearchParams.prototype = prevCtor.prototype;
URLSearchParams.prototype.constructor = URLSearchParams;
const prevHas = prevCtor.prototype.has;
URLSearchParams.prototype.has = function (...args) {
if (!uspSet.has(this)) {
throw new TypeError('has called on an object that is not a URLSearchParams');
}
return Reflect.apply(prevHas, this, args);
};
/////////////////////////////////////////////
const { Headers } = require('node-fetch');
const h = new Headers();
console.log(h.has('abc')); This code fragment throws an error under the current definition of That said, I think it's absolutely crazy that Headers is a subclass of URLSearchParams, and that canonical Headers objects are proxies. I have filed #1119 to consider reverting this new implementation. |
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.
As I mentioned in my comment, IMO testing this change is more trouble than it's worth. LGTM as it is.
Thanks for the details @TimothyGu, very illuminating. |
Look like we could have used some expertise in this PR, personally I am convinced by Timothy, but would be good to hear some feedbacks from node.js team members :) Same regarding #1119 too. |
What is the purpose of this pull request?
What changes did you make? (provide an overview)
Changed the
this
arg passed to the URLSearchParams prototype call in the Headers proxy handlers forappend()
,set()
,delete()
,has()
,getAll()
. Currently it's set toreceiver
, but it should betarget
, as it is with thekeys()
handler.Which issue (if any) does this pull request address?
#917
Is there anything you'd like reviewers to know?
Ran the tests in Node (v14.15.0) and everything continues to pass. Manually tested in Electron (v11.1.1, with Node v12.18.3 and Chrome v87.0.4280.88), and it fixes the issue described in #917.