Add getStructured/setStructured to Headers - #1943
Conversation
Adds new APIs to the Headers class for getting/setting structured header fields.
|
@jasnell are you building up towards RFC 9421: HTTP Message Signatures support? I'd be happy to help. |
|
@panva ... That's definitely one of the items on the agenda, yes. |
|
Would it be useful to have a spec of a canonical mapping of SF to JSON? |
|
... like the one used in the test suite? |
I would think so, yes |
|
Any reason why this needs to be baked in into |
|
"Something based on strings" is just what Headers already provides. Using an additional parser/serializer is obviously possible but adds an additional dependency which is what this is aiming to eliminate. |
| constrained profile of string rather than a separate type. When serializing | ||
| via {{Headers/setStructured()}}, strings that conform to | ||
| <a>structured field token</a> syntax are serialized as tokens; all other | ||
| strings are serialized as quoted structured field strings. |
There was a problem hiding this comment.
This string->token implicit conversion is not going to work for some uses of the API. Is it possible to override the type? For instance, by adding a value as {value: "v", sfType: "string"} or something like that? Otherwise, there are cases where a SF-defined value will expect a string and get a token that it will choke one.
|
What is the thinking about this sort of thing? const cc = response.headers.getStructured("Cache-Control", "dictionary");Presumably, this just runs the string through the identified SF parser, which might work out fine (or not), caveat emptor and all that jazz. |
| <li><p>If <var>jsValue</var> is an | ||
| <a href="https://tc39.es/ecma262/#sec-isinteger">integral number</a>, | ||
| return a <a>structured field integer</a> with <var>jsValue</var>'s value. | ||
|
|
||
| <li><p>Otherwise, return a <a>structured field decimal</a> with | ||
| <var>jsValue</var>'s value. |
There was a problem hiding this comment.
What do you do with values outside of the range that SF requires support for? Would 6e110 be presented with all 110 digits?
There was a problem hiding this comment.
No, in that case the correct response would be to return null. The fallback would be to just use the existing get method.
There was a problem hiding this comment.
Is that because 6e110 doesn't fit in a double? I'm thinking of those cases where the range of permissible values in a JS Number is outside the range of permissible SF integers. What then? Translate, and let the application enjoy the (possible) surprise (possible because there is nothing preventing an implementation from accepting more than the minimal range).
You need this to be explicit in the algorithm.
| <p class=note>Serializing structured fields is entirely optional. | ||
| Implementations that do not support structured field serialization are | ||
| fully compliant with this specification. The minimum conformance | ||
| requirement is that {{Headers/setStructured()}} does not throw for valid | ||
| inputs — an implementation that silently ignores the call is compliant. | ||
| Whether to actually serialize and set the header is an implementation | ||
| decision. |
There was a problem hiding this comment.
This seems like it could be an interoperability nightmare. I think that you need to support SF serialization if you add this.
There was a problem hiding this comment.
I've been going back and forth on this, to be honest. But, you're right.
Yes. If it can be parsed as the specified type, then it will be. Otherwise null is returned. |
Adds new APIs to the Headers class for getting/setting structured header fields.
Structured fields are defined in RFC 8941. Newer HTTP header definitions build on it. Fetch's handling of all header values as strings works but loses some of the utility. This commit adds new
getStructured/setStructuredAPIS toHeadersfor getting/setting header field values as structured fields. The existingget/set/append/etc are left untouched. Header iteration is left untouched. It remains possible to get all fields as strings.There are currently ~36 standard headers that use structured header fields:
Dictionary
PrioritySignatureSignature-InputAccept-SignatureContent-DigestRepr-DigestWant-Content-DigestContent-Digestwith algorithm preferencesWant-Repr-DigestRepr-Digestwith algorithm preferencesCDN-Cache-ControlUse-As-DictionaryList
Cache-Statushit,fwd,ttl, etc.)Proxy-StatusAccept-CHClient-Cert-ChainAccept-QueryCache-GroupsCache-Group-InvalidationItem
Client-CertCapsule-ProtocolDeprecationAvailable-DictionaryDictionary-IDConcealed-Auth-ExportCross-Origin-Embedder-PolicyCross-Origin-Embedder-Policy-Report-OnlyCross-Origin-Opener-PolicyCross-Origin-Opener-Policy-Report-OnlyOrigin-Agent-ClusterSec-Fetch-DestSec-Fetch-ModeSec-Fetch-SiteSec-Fetch-UserSec-Purposeprefetch(Token)Examples
Reading the
Priorityheader (Dictionary)Compared with strings:
Reading Cache-Status (List)
Reading Content-Digest (Dictionary with Byte Sequences)
Reading Sec-Purpose (Item)
Writing Priority (Dictionary — plain object form)
Writing Cache-Status (List with parameters)
Writing Content-Digest (Dictionary with Byte Sequence)
Graceful fallback when unsupported
Token vs String serialization
All input forms for dictionaries and parameters (HeadersInit pattern)
(See WHATWG Working Mode: Changes for more details.)
💥 Error: 422 Unprocessable Entity 💥
PR Preview failed to build. (Last tried on Jul 21, 2026, 12:38 AM UTC).
More
PR Preview relies on a number of web services to run. There seems to be an issue with the following one:
🚨 Spec Generator - Spec Generator is the web service used to build bikeshed/ReSpec specs
🔗 Related URL
Error output:
[ { "lineNum": "8762:15", "messageType": "fatal", "text": "Saw a [[ opening a biblio or section autolink, but couldn't parse the following contents. If you didn't intend this to be a biblio autolink, escape the initial [ as &bs[;" }, { "lineNum": "7994:12", "messageType": "warning", "text": "The var 'result' (in global scope) is only used once.\nIf this is not a typo, please add an ignore='' attribute to the <var>." }, { "lineNum": "8291:16", "messageType": "warning", "text": "The var 'bareItem' (in algorithm 'convert a structured field item to a JavaScript object') is only used once.\nIf this is not a typo, please add an ignore='' attribute to the <var>." }, { "lineNum": "8003:3", "messageType": "lint", "text": "RFC2119 keyword in non-normative section (use: might, can, has to, or override with <span class=allow-2119>): must be one of \"" }, { "lineNum": "8885:1", "messageType": "lint", "text": "RFC2119 keyword in non-normative section (use: might, can, has to, or override with <span class=allow-2119>): Parsing structured fields and converting the result to\nJavaScript objects is entirely optional. Implementations that do not\nsupport structured field parsing are fully compliant with this\nspecification by having " }, { "lineNum": "8885:1", "messageType": "lint", "text": "RFC2119 keyword in non-normative section (use: might, can, has to, or override with <span class=allow-2119>): method itself is required.\n\n" }, { "lineNum": "8929:1", "messageType": "lint", "text": "RFC2119 keyword in non-normative section (use: might, can, has to, or override with <span class=allow-2119>): Serializing structured fields is entirely optional.\nImplementations that do not support structured field serialization are\nfully compliant with this specification. The minimum conformance\nrequirement is that " }, { "lineNum": null, "messageType": "failure", "text": "Did not generate, due to errors exceeding the allowed error level." } ]This seems to be an issue with the Spec Generator service. PR Preview doesn't manage this service and so has no control over it. If you've identified an issue with it, you can report the issue to the maintainers of Spec Generator directly. Please be courteous. Thank you!
If you don't have enough information above to solve the error by yourself or if the issue doesn't seem related to Spec Generator, you can file an issue with PR Preview.