-
Notifications
You must be signed in to change notification settings - Fork 570
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
The pseudo-header :status
is included in h2 fetch.
#2415
Comments
The RFC-7540 states that the pseudo headers are valid header field names, and should always be preserved in a request/response, especially as they belong to the For
From RFC-9110:
As they are scoped within Changing slightly what I said in the PR, I'm a little bit on the fence here but more into the fact of keeping them as it does not seems clearly to be violating the spec in any form, unless otherwise it does. cc: @KhafraDev |
The RFC (and as such, by the fetch spec) is adamant that colons are not allowed in header names: https://fetch.spec.whatwg.org/#header-name (which links to https://httpwg.org/specs/rfc9110.html#fields.names)
How the fetch spec intends for implementations to deal with these pseudo headers, I couldn't tell you. |
@metcoder95 I'd recommend either making an/searching for an issue in the whatwg repo for fetch, or even going on their matrix channel. |
Yeah, it firmly points to that RFC, which it's of course valid. However, it somehow feels counterintuitive with what the H2 version says, which seems to mark those headers as mandatory part of the response, otherwise should be considered malformed. On the request side its crystal clear, on the response is when the doubts arises. I'll follow up on this and see what I can find. |
Neither of the PRs addressing this issue are correct.
This is already fixed with a1342a7. |
Not quite fixed; we are meant to append the headers to the HeaderList (which doesn't include validation), not to the Headers instance directly. The http parser should already handle the validation for us. |
I believe the following code will throw an error if the HeadersIterator contains // H2 fetch
const response = await fetch("https://localhost");
for (const key of response.headers.keys()) {
// Error because key is sometimes `:status`.
const value = response.headers.get(key)
} |
@metcoder95 according to RFC 9113 "Pseudo-header fields are not HTTP header fields.". I don't think we should be receiving pseudo headers with normal headers, which is definitely causing this. My fix is partially correct, but this is no longer an issue with fetch afterwards. While we could handle it in fetch, it wouldn't be correct. Fetch is an abstraction on the http specs, it shouldn't be handling this lower-leveled behavior/validation/whatever. |
See what you mean, Quote:
I agree, I believe it's not a |
I think those 2 statements are separate - if pseudo-headers aren't header fields, undici is mishandling them (or at least the expectation that headers are actually headers is wrong?). Would it make sense to split them into their own property? what I'm proposing: import { Client, request } from 'undici'
const { headers, pseudoHeaders } = await request('https://h2', {
client: new Client({ allowH2: true })
}) |
This is a good proposal. However, there is one thing that concerns me. const http2 = require("http2");
const undici = require("undici");
// Node Http2
(async () => {
// H2 Server URI
const client = https.connect("https://localhost");
const req = client.request({ ":method": "GET", ":path": "/" });
req.on("response", (headers, flags) => {
console.log(headers[":status"]); // 200
console.log(typeof headers[":status"]); // 'number'
});
req.on("end", () => { client.destroy(); });
})();
// Current
(async () => {
const client = new undici.Client({ allowH2: true });
// H2 Server URI
const req = await undici.request("https://localhost", { client });
console.log(req.headers[":status"]); // 200
console.log(typeof req.headers[":status"]); // 'number'
})();
// Proposal
(async () => {
const client = new undici.Client({ allowH2: true });
// H2 Server URI
const req = await undici.request("https://localhost", { client });
console.log(req.headers[":status"]); // undefined
console.log(typeof req.headers[":status"]); // 'undefined'
console.log(typeof req.pseudoHeaders[":status"]); // 200
console.log(typeof req.pseudoHeaders[":status"]); // 'number'
})(); So I don't think you need to change anything except |
Being different from node's http/2 is fine, it's fundamentally not an issue in fetch, so there's nothing to fix in fetch. The spec states that pseudo headers are not header fields, so they shouldn't be passed as regular headers. IMO undici is doing something wrong if fake headers are being passed as real headers - to quote myself "the expectation that headers are actually headers is wrong". |
@KhafraDev |
I agree that diverging from Continuing with the headers, you are correct in assuming that they are not header fields in the sense that no other fields should follow the syntax, as pseudo headers are proper to the version of the protocol. This means that if the caller, when making a request, attempts to add a new header in the form The same happens on the server side, endpoints should not add other custom fields with the pseudo-header syntax, but it does not mean that they should not be exposed to the request handler (e.g. As
Happy to hear your thoughts @KhafraDev 🙂 |
Hi @KhafraDev @metcoder95, |
They aren't header fields because colons are forbidden from being in headers fields, I assume this is why they call these fake headers.
shouldn't undici be doing this already, at a lower level (and if not I'd love to get more info on why it's not)? Then no pseudo headers would need to be passed as headers while making the response's status available still, in a way where fetch doesn't need to be changed. |
I believe that's one of the reasons 😅
We do, we just don't remove the header from the response's headers; as this can be of interest to some implementers. When calling dispatch, the As we do not have a |
SGTM |
Bug Description
The pseudo-header
:status
can be obtained by h2 fetch.A fix for this problem is needed in #2410.
Reproducible By
There is a simple test.
Expected Behavior
The above test should succeed.
The pseudo-header
:status
is not passed toHeaders
.Logs & Screenshots
Environment
Windows 11
Node.js v21.1.0
Undici v5.27.2
Additional context
related to: #2409 #2410
The text was updated successfully, but these errors were encountered: