Uh oh!
There was an error while loading. Please reload this page.
add headers impl - #38986
Conversation
jasnell
commented
Jun 10, 2021
Wooo! Obviously still needs the docs. When those are added, let's be sure to mark this experimental for now. |
devsnek
commented
Jun 10, 2021
Any reason this isn't just a map of arrays? functionvalidateName(name){if(!name.match(/^[!#$%&'*+\-.^`|~\w]+$/)){thrownewERR_OUT_OF_RANGE('name','a valid header name',name);}returntoUSVString(name).toLowerCase();}functionvalidateValue(value){value=toUSVString(value).replace(/^[\r\n\t]+/g,'').replace(/[\r\n\t]+$/,'');if(/[\0\r\n]/.test(value)){thrownewERR_OUT_OF_RANGE('name','a valid header value',value);}returnvalue;}classHeaders{
#headers =newSafeMap();constructor(init=undefined){if(init){if(initinstanceofHeaders){this.#headers =newSafeMap([...init.#headers]);}elseif(ArrayIsArray(init)){for(constheaderofinit){if(header.length!==2){thrownewERR_OUT_OF_RANGE();}this.append(header[0],header[1]);}}else{for(constpairofObjectEntries(init)){this.append(pair[0],pair[1]);}}}}append(name,value){value=validateValue(value);name=validateName(name);constexisting=this.#headers.get(name.toLowerCase());if(existing){existing.push(value);}else{this.#headers.set(name.toLowerCase(),[value]);}}delete(name){name=validateName(name);this.#headers.delete(name);}get(name){name=validateName(name);constvalues=this.#headers.get(name);if(!values){returnnull;}returnvalues.join(', ');}has(name){name=validateName(name);returnthis.#headers.has(name);}set(name,value){value=validateValue(value);name=validateName(name);this.#headers.set(name,[value]);}} |
I believe this was previously considered, but a flat array of strings was assumed to be more efficient in regards to space and speed. Emphasis on assumed; would require some benchmarking and more research on arrays vs Map |
targos
commented
Jun 10, 2021
How do we want to expose this and the other fetch features ( before they become globals)? |
devsnek
commented
Jun 10, 2021
benchmarks would be good. |
timdp
commented
Jun 10, 2021
Yeah, I remember assuming that. 🙂 It'd indeed be interesting to benchmark! |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Ethan-Arrowood
commented
Jun 13, 2021
@devsnek here is some preliminary benchmarks: https://gist.github.com/Ethan-Arrowood/e132fb72e5ef4156dfc0de3b80ef3c16 A The iteration of |
Alright this PR is ready for review. All docs and tests from undici-fetch have been copied over (and transformed to the Node way). This is my first large API addition to Node so I'm probably missing some things 🤷♂️ (Note i'm currently working through all the linter issues now) |
aduh95
left a comment
There was a problem hiding this comment.
You need to run the linter on the markdown file, there are a few CI errors that are reported
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
bl-ue
left a comment
There was a problem hiding this comment.
Which is prefered for indention in the docs: tabs or spaces, and how many? I noticed you're using both a single tab and two spaces for indentation here.
Ethan-Arrowood
commented
Jun 21, 2021
How do I get the node linter to auto fix? |
aduh95
commented
Jun 21, 2021
You can do |
Ethan-Arrowood
commented
Jun 21, 2021
And how do I deal with strings that exceed 80 characters in length? The linter isn't fixing those automatically |
targos
commented
Jun 21, 2021
Unfortunately, ESLint doesn't have an auto-fix for this rule. I usually reformat the code with Prettier in these cases. |
Ethan-Arrowood
commented
Jun 21, 2021
Do you just |
Uh oh!
There was an error while loading. Please reload this page.
Actually, nevermind. What I want to do here is not going to work. I was thinking of using the |
Ethan-Arrowood
commented
Jul 7, 2021
Thank you for the review @jasnell
I originally built something like this but the moment you do anything more than an array you lose some of the major speed and memory performance benefits that makes this implementation unique (and potentially viable). I was rather thinking of extracting some of the methods I'm using in this class and making them a sort of 'Headers List Utility Set' that you can then utilize in your own Headers class implementation and still reap the same perf benefits of an underlying array. We sorta already have that since the binary search / sort is its own function, and so are the normalize/validate functions. |
Co-authored-by: James M Snell <jasnell@gmail.com>
Ethan-Arrowood
commented
Jul 22, 2021
Summary of changes today:
I can tell we are getting very close with this 🙌 |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Co-authored-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
Co-authored-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
Co-authored-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
Co-authored-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
| * [Domain](domain.md) | ||
| * [Errors](errors.md) | ||
| * [Events](events.md) | ||
| * [Fetch](fetch.md) |
There was a problem hiding this comment.
I am a bit concerned that folks will misinterpret this as being a full fetch implementation...
There was a problem hiding this comment.
What would be the best way to introduce this without implementing all of fetch?
I could make a new feature/fetch branch and we can merge all fetch work to that until its completely ready. I'm really eager to start integrating undici-fetch with the streams/web api
Uh oh!
There was an error while loading. Please reload this page.
| fill(this, init); | ||
| } | ||
| append(name, value) { |
There was a problem hiding this comment.
I think we have to add an argument length check for the public methods. When you call .append() or .append('foo') on Chrome/Edge/FireFox/Safari you get a TypeError about invalid arg length / missing arguments. Should I use the ERR_MISSING_ARGS to accomplish this?
Ethan-Arrowood
commented
Aug 10, 2021
Do we want to close this PR in favor of adding Fetch via Undici instead? Fetch in Undici core is now under active development by @ronag |
dnalborczyk
commented
Oct 22, 2021
@aduh95 why would this require a |
aduh95
commented
Oct 22, 2021
Adding new globals is considered |
dnalborczyk
commented
Oct 22, 2021
I think https://nodejs.org/api/http.html#messagerawheaders I also think it should be added (lazily?) to Incoming and Outgoing messages. |
thanks. I agree with @guybedford here: #20306 (comment) I don't see how or why node.js deviates from a browser in that context. |
Ethan-Arrowood
commented
Apr 15, 2022
Closing in favor of undici fetch 😉 |
This PR adds a Headers class implementation based on the WHATWG Fetch Spec. It leaves off many pieces of the spec due to the non-browser environment. Additionally, it deviates from the spec slightly for sake of performance improvements.
While it maintains support for spec based initialization, folks looking for most-performant solution should utilize a flattened array.
Header entries are kept sorted at all times so all read-based use cases are fast as possible. Writing is also kept fast by using a probe-based binary search/insert.
This code is based on my work in undici-fetch. The headers api is the most stable of the pieces and has no dependencies on other things like whatwg readablestreams, so it makes for a good-first-pr for fetch in Node! I also believe this class could be utilized by other HTTP aspects of the Node API - but the initial goal is relation to Fetch.