diff --git a/fetch.bs b/fetch.bs index fa6deae20..41e30620f 100755 --- a/fetch.bs +++ b/fetch.bs @@ -23,6 +23,15 @@ urlPrefix:https://httpwg.org/specs/rfc9651.html#;type:dfn;spec:rfc9651 url:text-parse;text:parsing structured fields url:;text:structured header url:token;text:structured field token + url:integer;text:structured field integer + url:decimal;text:structured field decimal + url:string;text:structured field string + url:boolean;text:structured field boolean + url:byte-sequence;text:structured field byte sequence + url:date;text:structured field date + url:displaystring;text:structured field display string + url:inner-list;text:structured field inner list + url:param;text:structured field parameters urlPrefix:https://httpwg.org/specs/rfc9110.html#;type:dfn;spec:http url:method.overview;text:method @@ -7897,6 +7906,16 @@ fetch("/music/pk/altes-kamuffel.flac") +
+enum StructuredFieldType { "item", "list", "dictionary" };
+
+
+The {{StructuredFieldType}} enum identifies the top-level type of a +structured field value as defined in [[RFC9651]]. + +
@@ -7912,6 +7931,8 @@ interface Headers {
sequence<ByteString> getSetCookie();
boolean has(ByteString name);
undefined set(ByteString name, ByteString value);
+ any getStructured(ByteString name, StructuredFieldType type);
+ undefined setStructured(ByteString name, StructuredFieldType type, any value);
iterable<ByteString, ByteString>;
};
@@ -7970,6 +7991,93 @@ new Headers(meta2);
Replaces the value of the first header whose name is name with value and removes any remaining headers whose name is name. +
result = headers . getStructured(name, type)
+ Parses the value of the header named name as a structured field + ([[RFC9651]]) of the given type and returns the result as a + JavaScript value. + +
Returns null if the header is not present or its value fails to parse as + the specified structured field type. + +
The type must be one of "item",
+ "list", or "dictionary".
+
+
Structured field values are converted to JavaScript as follows:
+ integers, decimals, and dates become numbers (dates as seconds since the
+ Unix epoch), strings and tokens both become strings, booleans become
+ booleans, and byte sequences become {{Uint8Array}}. Items are returned as
+ objects with value and params properties. Inner
+ lists are returned as objects with items and params
+ properties. Lists are returned as arrays. Dictionaries and parameters are
+ returned as {{Map}} objects.
+
+
Tokens are represented as plain strings, following the same + pattern as {{DOMString}}, {{USVString}}, and {{ByteString}} — they are a + constrained profile of string rather than a separate type. When serializing + via {{Headers/setStructured()}}, strings that conform to + structured field token syntax are serialized as tokens; all other + strings are serialized as quoted structured field strings. + +
+// Priority: u=3, i
+const p = headers.getStructured("Priority", "dictionary");
+// p is Map { "u" => { value: 3, params: Map {} },
+// "i" => { value: true, params: Map {} } }
+const urgency = p?.get("u")?.value ?? 3;
+
+// Cache-Status: cdn; hit; ttl=3600
+const cs = headers.getStructured("Cache-Status", "list");
+const cacheName = cs?.[0]?.value; // "cdn" (token, as a string)
+const ttl = cs?.[0]?.params.get("ttl"); // 3600
+
+// Sec-Purpose: prefetch
+const purpose = headers.getStructured("Sec-Purpose", "item");
+if (purpose?.value === "prefetch") { /* ... */ } // direct string comparison
+
+ headers . setStructured(name, type, value)
+ Serializes value as a structured field ([[RFC9651]]) of the + given type and replaces the header named name with the + result. + +
Throws a {{TypeError}} if value cannot be serialized as the + specified structured field type or if the headers are immutable. + +
For serialization, numbers serialize as integers or decimals (determined + by whether the number is an integer), booleans serialize as structured field + booleans, {{Uint8Array}} serializes as a byte sequence, and strings + serialize as tokens if they conform to structured field token syntax + or as quoted structured field strings otherwise. + +
+// Set Priority header — plain object, no params needed
+headers.setStructured("Priority", "dictionary", {
+ u: { value: 0 },
+ i: { value: true }
+});
+// Result: Priority: u=0, i
+
+// Token values are just strings
+headers.setStructured("Cache-Status", "list", [
+ { value: "MyProxy", params: { hit: true, ttl: 7200 } }
+]);
+// Result: Cache-Status: MyProxy;hit;ttl=7200
+// "MyProxy" matches token syntax, so it serializes unquoted.
+// params accepts a plain object, Map, or sequence of pairs.
+
+// Map and sequence forms also work (same as HeadersInit):
+headers.setStructured("Priority", "dictionary", new Map([
+ ["u", { value: 0 }],
+ ["i", { value: true }]
+]));
+
+ for(const [name, value] of headers)
headers can be iterated over. @@ -8075,6 +8183,587 @@ from a {{Headers}} object (headers), run these steps:
This is called when headers are modified by unprivileged code. +
The following algorithms convert between JavaScript values and the +abstract data types defined in [[RFC9651]]. They are used by +{{Headers/getStructured()}} and {{Headers/setStructured()}}. + +
To +convert a structured field bare item to a JavaScript value +given a bare item bareItem: + +
If bareItem is a structured field integer, + then return bareItem's value as a Number. + +
If bareItem is a structured field decimal, + then return bareItem's value as a Number. + +
If bareItem is a structured field string, + then return bareItem's value as a String. + +
If bareItem is a structured field token, + then return bareItem's value as a String. + +
If bareItem is a structured field boolean, + then return bareItem's value as a Boolean. + +
If bareItem is a structured field byte sequence, + then return a new {{Uint8Array}} in the current realm whose + contents are bareItem's byte sequence. + +
If bareItem is a structured field date, + then return bareItem's value (seconds since the Unix epoch) + as a Number. + +
If bareItem is a structured field display string, + then return bareItem's value as a String. +
Both structured field tokens and +structured field strings are returned as JavaScript Strings. +Tokens are a constrained profile of string — they conform to the +token syntax defined in [[RFC9651]] +(Section 3.3.4) +— and are represented as plain strings rather than a distinct type, +following the pattern of {{DOMString}}, {{USVString}}, and {{ByteString}}. +
To +convert structured field parameters to a JavaScript Map +given structured field parameters params: + +
Let result be a new {{Map}} object in the + current realm. + +
For each key → bareItem of + params: + +
Let jsValue be the result of + converting a structured field bare item to a JavaScript value + given bareItem. + +
Perform %Map.prototype.set% + on result with arguments key and jsValue. +
Return result. +
To +convert a structured field item to a JavaScript object +given a structured field item sfItem: + +
Let value be the result of + converting a structured field bare item to a JavaScript value + given sfItem's bare item. + +
Let params be the result of + converting structured field parameters to a JavaScript Map + given sfItem's structured field parameters. + +
Let result be + OrdinaryObjectCreate({{%Object.prototype%}}). + +
Perform
+ CreateDataPropertyOrThrow(result,
+ "value", value).
+
+
Perform
+ CreateDataPropertyOrThrow(result,
+ "params", params).
+
+
Return result. +
The returned object has the shape
+{ value: bareItem, params: Map }.
+
To +convert a structured field inner list to a JavaScript object +given a structured field inner list innerList: + +
Let items be an empty list. + +
For each sfItem of innerList's members: + +
Let converted be the result of + converting a structured field item to a JavaScript object + given sfItem. + +
Append converted to items. +
Let params be the result of + converting structured field parameters to a JavaScript Map + given innerList's structured field parameters. + +
Let jsArray be + CreateArrayFromList(items). + +
Let result be + OrdinaryObjectCreate({{%Object.prototype%}}). + +
Perform
+ CreateDataPropertyOrThrow(result,
+ "items", jsArray).
+
+
Perform
+ CreateDataPropertyOrThrow(result,
+ "params", params).
+
+
Return result. +
The returned object has the shape
+{ items: [{ value, params }, ...], params: Map }.
+An inner list is distinguished from an item by the presence of
+items rather than value.
+
To +convert a structured field member to a JavaScript value +given a structured field member member: + +
If member is a structured field item, return + the result of converting a structured field item to a JavaScript object + given member. + +
If member is a structured field inner list, return + the result of converting a structured field inner list to a JavaScript object + given member. +
To +convert a structured field to a JavaScript value +given a structured field value sfValue and a +{{StructuredFieldType}} type: + +
If type is "item":
+
+
Return the result of + converting a structured field item to a JavaScript object + given sfValue. +
If type is "list":
+
+
Let result be an empty list. + +
For each member of sfValue's members: + +
Let converted be the result of + converting a structured field member to a JavaScript value + given member. + +
Append converted to result. +
Return + CreateArrayFromList(result). +
If type is "dictionary":
+
+
Let result be a new {{Map}} object in the + current realm. + +
For each key → member of + sfValue's members (in order): + +
Let converted be the result of + converting a structured field member to a JavaScript value + given member. + +
Perform %Map.prototype.set% + on result with arguments key and converted. +
Return result. +
The following algorithms convert JavaScript values to structured field +values for use with {{Headers/setStructured()}}. + +
To +convert a JavaScript value to a structured field bare item +given a JavaScript value jsValue: + +
If Type(jsValue) + is Boolean, return a structured field boolean with jsValue's value. + +
If Type(jsValue) + is Number: + +
If jsValue is NaN, +∞, or −∞, + then throw a {{TypeError}}. + +
If jsValue is an + integral number, + return a structured field integer with jsValue's value. + +
Otherwise, return a structured field decimal with + jsValue's value. +
If Type(jsValue) + is String: + +
If jsValue conforms to the structured field token
+ syntax defined in [[RFC9651]]
+ (Section 3.3.4)
+ — i.e., it matches the production
+ ( ALPHA / "*" ) *( tchar / ":" / "/" )
+ — then return a structured field token with
+ jsValue's value.
+
+
Otherwise, return a structured field string with + jsValue's value. +
Strings that match token syntax are serialized as + unquoted tokens; all other strings are serialized as quoted structured + field strings. This follows the pattern of treating tokens as a + constrained profile of string, similar to {{DOMString}} vs + {{ByteString}}. + +
If jsValue is a {{Uint8Array}}, return a + structured field byte sequence whose contents are a copy of + jsValue's buffer. + +
Throw a {{TypeError}}. +
To +convert a JavaScript value to structured field parameters +given a JavaScript value jsParams: + +
Let params be an empty ordered map of + structured field parameters. + +
If jsParams is undefined or null, then return + params. + +
If jsParams is a {{Map}}: + +
For each key → jsValue of jsParams + (in insertion order): + +
If key is not a String, then throw a + {{TypeError}}. + +
Let bareItem be the result of + converting a JavaScript value to a structured field bare item + given jsValue. + +
Set params[key] to bareItem. +
Return params. +
If jsParams is a sequence: + +
For each pair of jsParams: + +
Let bareItem be the result of + converting a JavaScript value to a structured field bare item + given pair[1]. + +
Set params[pair[0]] to bareItem. +
Return params. +
Otherwise, jsParams is a record: + +
For each key → jsValue of + jsParams: + +
Let bareItem be the result of + converting a JavaScript value to a structured field bare item + given jsValue. + +
Set params[key] to bareItem. +
Return params. +
This accepts the same input shapes as {{HeadersInit}}: a
+{{Map}}, a sequence of key-value pairs, or a plain object (record).
+Additionally, undefined or null is accepted and treated as empty
+parameters, allowing the params property to be omitted from
+item and inner list objects passed to {{Headers/setStructured()}}.
+
To +convert a JavaScript object to a structured field item +given a JavaScript value jsObj: + +
If Type(jsObj)
+ is not Object, or jsObj does not have a property "value",
+ then throw a {{TypeError}}.
+
+
Let bareItem be the result of
+ converting a JavaScript value to a structured field bare item
+ given jsObj["value"].
+
+
Let jsParams be jsObj["params"]
+ if jsObj has a "params" property, or undefined
+ otherwise.
+
+
Let params be the result of + converting a JavaScript value to structured field parameters + given jsParams. + +
Return a structured field item whose bare item is + bareItem and whose structured field parameters are + params. +
To +convert a JavaScript object to a structured field inner list +given a JavaScript value jsObj: + +
If Type(jsObj)
+ is not Object, or jsObj does not have a property "items",
+ then throw a {{TypeError}}.
+
+
Let jsItems be jsObj["items"].
+
+
If jsItems is not iterable, then throw a + {{TypeError}}. + +
Let members be an empty list. + +
For each jsItem of jsItems: + +
Let sfItem be the result of + converting a JavaScript object to a structured field item + given jsItem. + +
Append sfItem to members. +
Let jsParams be jsObj["params"]
+ if jsObj has a "params" property, or undefined
+ otherwise.
+
+
Let params be the result of + converting a JavaScript value to structured field parameters + given jsParams. + +
Return a structured field inner list whose members are + members and whose structured field parameters are + params. +
To +convert a JavaScript object to a structured field member +given a JavaScript value jsObj: + +
If Type(jsObj)
+ is Object and jsObj has a property "items",
+ return the result of
+ converting a JavaScript object to a structured field inner list
+ given jsObj.
+
+
Otherwise, return the result of + converting a JavaScript object to a structured field item + given jsObj. +
To +convert a JavaScript value to a structured field +given a JavaScript value jsValue and a {{StructuredFieldType}} +type: + +
If type is "item":
+
+
Return the result of + converting a JavaScript object to a structured field item + given jsValue. +
If type is "list":
+
+
If jsValue is not iterable, then + throw a {{TypeError}}. + +
Let members be an empty list. + +
For each jsItem of jsValue: + +
Let member be the result of + converting a JavaScript object to a structured field member + given jsItem. + +
Append member to members. +
Return a structured field list whose members are members. +
If type is "dictionary":
+
+
Let dict be an empty structured field dictionary. + +
If jsValue is a {{Map}}: + +
For each key → jsMember of jsValue + (in insertion order): + +
If key is not a String, then throw a + {{TypeError}}. + +
Let member be the result of + converting a JavaScript object to a structured field member + given jsMember. + +
Set dict[key] to member. +
Otherwise, if jsValue is a sequence: + +
For each pair of jsValue: + +
Let member be the result of + converting a JavaScript object to a structured field member + given pair[1]. + +
Set dict[pair[0]] to member. +
Otherwise, if Type(jsValue) + is Object: + +
For each key → jsMember of + jsValue: + +
Let member be the result of + converting a JavaScript object to a structured field member + given jsMember. + +
Set dict[key] to member. +
Otherwise, throw a {{TypeError}}. + +
Return dict. +
Like {{HeadersInit}}, dictionaries accept a {{Map}}, a
+sequence of key-value pairs, or a plain object (record). This allows the
+ergonomic form
+{ u: { value: 3 }, i: { value: true } }
+in addition to
+new Map([["u", { value: 3 }], ["i", { value: true }]]).
+
The
new Headers(init)
@@ -8174,6 +8863,77 @@ method steps are:
The getStructured(name, type)
+method steps are:
+
+
If name is not a header name, then throw + a {{TypeError}}. + +
Let sfValue be the result of getting + a structured field value given name and type from + this's header list. + +
If sfValue is null, then return null. + +
Return the result of converting a structured field to a + JavaScript value given sfValue and type. +
Parsing structured fields and converting the result to +JavaScript objects is entirely optional. Implementations that do not +support structured field parsing are fully compliant with this +specification by having get a structured field value +return null. Returning null matches the behavior when the header is absent or +malformed, ensuring no feature-detection breakage. The presence of the +{{Headers/getStructured()}} method itself is required. + +
The setStructured(name, type, value)
+method steps are:
+
+
If name is not a header name, then throw + a {{TypeError}}. + +
If this's guard is "immutable",
+ then throw a {{TypeError}}.
+
+
Let sfValue be the result of + converting a JavaScript value to a structured field given + value and type. + +
Let serialized be the result of + serializing structured fields on sfValue. + +
If serialization fails, then throw a {{TypeError}}. + +
If validating (name, serialized) + for this returns false, then return. + +
If this's guard is
+ "request-no-cors" and (name, serialized)
+ is not a no-CORS-safelisted request-header, then return.
+
+
Set (name, serialized) + in this's header list. + +
If this's guard is
+ "request-no-cors", then remove privileged
+ no-CORS request-headers from this.
+
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. +
The value pairs to iterate over are the return value of running sort and combine with this's header list.