HTTP Structured Fields
Structured fields define a standard set of data types and a strict parsing algorithm for HTTP header and trailer values. Instead of each new header inventing its own value syntax, structured fields provide reusable building blocks (integers, strings, tokens, lists, dictionaries, and parameters) with deterministic parsing and serialization rules.
Usage
Historically, every new HTTP header defined its own value format. Some used comma-separated lists, others used semicolons, quoted strings, or custom grammars. This inconsistency made parsing error- prone and required custom code for each header.
Structured fields solve this by providing a shared type system. A single parser handles any header built on structured fields. The specification defines exact algorithms for both parsing (reading) and serialization (writing), ensuring interoperability across implementations.
Headers using structured fields include Cache-Status, Priority, CDN-Cache-Control, Proxy-Status, Signature, Signature-Input, Content-Digest, Permissions-Policy, Client-Cert, the Sec-Fetch-* family, Deprecation, and many others. New HTTP header specifications default to structured fields.
Strict parsing
Structured field parsers either succeed completely or fail completely. There is no lenient mode or partial recovery. A single syntax error in the value makes the entire field invalid.
Top-level types
Every structured field value is one of three top-level types:
- List: an ordered array of members
- Dictionary: an ordered map of named members
- Item: a single value with optional parameters
The header's specification declares which top-level type applies. For example, Cache-Status is a List, while Priority is a Dictionary.
Data types
Structured fields define eight atomic data types (called "bare items"). Each type is identified by its first character during parsing.
Integer
A whole number in the range -999,999,999,999,999 to 999,999,999,999,999 (15 digits maximum). This range fits within the safe integer range of IEEE 754 double-precision floating point, ensuring compatibility with JavaScript.
Cache-Control: max-age=3600
The 3600 is an Integer, representing seconds
until the cached response becomes stale.
Priority: u=3
The 3 is an Integer representing the urgency
level.
Decimal
A number with a fractional component. The integer part has at most 12 digits, and the fractional part has 1 to 3 digits after the period.
Priority: u=0, i
A Decimal value in a response weight:
Example-Weight: 0.750
The value 0.750 has three fractional digits.
Values with more than three fractional digits are
rounded to the nearest thousandth during parsing.
String
A sequence of printable ASCII characters
(0x20 through 0x7E) enclosed in double quotes.
Only two escape sequences are valid: \" for a
literal quote and \\ for a literal backslash.
Proxy-Status: proxy.example.re; error="DNS resolution failed"
The "DNS resolution failed" is a String
parameter value describing the error.
Signature-Input: sig1=("@method" "@path" "content-type")
The values "@method", "@path", and
"content-type" inside the inner list are
Strings identifying the signed components.
ASCII only
Strings are limited to printable ASCII. For Unicode text intended for display, the Display String type (described below) is available.
Token
An unquoted value starting with a letter
(A-Z, a-z) or *, followed by letters,
digits, and characters from the HTTP token set
plus : and /. Tokens are common for
identifiers, media types, and
enumerated values.
Content-Type: text/html
The media type text/html is a Token. Tokens
do not need quoting.
Cross-Origin-Embedder-Policy: require-corp
The value require-corp is a Token.
Sec-Fetch-Dest: document
Byte Sequence
Binary data encoded as Base64 and
delimited by colons (:).
Client-Cert: :SGVsbG8gV29ybGQ=:
The Base64 content between the colons decodes to
the raw bytes of the client certificate. Padding
(=) is required.
Content-Digest: sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:
The digest value is a Byte Sequence representing the SHA-256 hash of the content.
Boolean
Either ?1 (true) or ?0 (false). The ?
prefix distinguishes booleans from integers.
Priority: u=3, i
The i parameter (incremental) has no explicit
value. In structured fields, a bare parameter
name without =value is shorthand for ?1
(true). This is equivalent to i=?1.
Sec-Fetch-User: ?1
A ?1 value indicating the navigation was
triggered by user activation.
Date
An integer representing seconds since the Unix
epoch (1970-01-01T00:00:00Z), prefixed with @.
Added in the 2024 revision.
Deprecation: @1704067200
The value @1704067200 represents
2024-01-01T00:00:00Z, the date the API was
deprecated.
Example-Timestamp: @1659578233
The value @1659578233 represents
2022-08-04T01:57:13Z.
New types
Date was added in the 2024 revision. Headers defined under the original specification do not use this type. Older parsers reject Date values.
Display String
A Unicode string for end-user display, prefixed
with % and enclosed in double quotes. Non-ASCII
bytes and special characters are percent-encoded
using lowercase hex. Added in the 2024 revision.
Example-Title: %"Caf%c3%a9 Menu"
The %c3%a9 decodes to "é" (UTF-8 encoding of
U+00E9). The full decoded value is "Café Menu".
Example-Greeting: %"Gr%c3%bc%c3%9fe"
The decoded value is "Grüße" (German for
"greetings"). The %c3%bc is "ü" and %c3%9f
is "ß".
Display Strings are for human-readable labels only. Machine-readable identifiers use the regular String type.
Container types
List
A comma-separated array of members. Each member is either an Item or an Inner List, and each member has optional parameters.
Cache-Status: cdn.example.re; hit, origin.example.re; fwd=miss
This List has two members. The first is a Token
cdn.example.re with a bare hit parameter.
The second is a Token origin.example.re with
a fwd parameter set to the Token miss.
Accept-CH: Sec-CH-UA, ECT, Device-Memory
A List of three Tokens.
An empty List is represented by omitting the header entirely. No syntax exists for an empty list value.
When a list-type header appears on multiple lines in the same HTTP message, the values are combined into a single comma-separated list (per HTTP field combination rules).
Inner List
A space-separated group of Items inside parentheses. Inner lists appear as members of a List or as values in a Dictionary.
Signature-Input: sig1=("@method" "@path" "content-type");created=1735689600;keyid="key-rsa"
The ("@method" "@path" "content-type") is an
Inner List of three Strings. The parameters
created and keyid attach to the Inner List
itself, not to individual items inside.
An empty inner list is valid:
Example-Groups: ()
Dictionary
An ordered map of key-value pairs, separated by commas. Keys are lowercase identifiers. Values are Items or Inner Lists, each with optional parameters.
Priority: u=3, i
This Dictionary has two members. The key u maps
to Integer 3. The key i has no explicit value,
which means Boolean ?1 (true).
CDN-Cache-Control: max-age=3600, stale-while-revalidate=60
A Dictionary with two keys mapping to Integers.
Content-Digest: sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:, sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX+TaPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:
A Dictionary with two keys, each mapping to a Byte Sequence containing a hash value.
Dictionary keys follow the same syntax as
parameter keys: start with a lowercase letter or
*, followed by lowercase letters, digits, _,
-, ., or *.
When a key appears more than once, the last value wins.
An empty Dictionary is represented by omitting the header entirely.
Parameters
Parameters are key-value pairs attached to an
Item or an Inner List. They appear after a
semicolon (;).
Proxy-Status: intermediary; error="connection timeout"; next-hop="origin.example.re"
The Token intermediary has two parameters:
error (a String) and next-hop (a String).
Cache-Status: cdn.example.re; hit; ttl=3600; key="https://example.re/page"; detail="memory"
Multiple parameters attach to the same item. Each parameter adds a semicolon-separated pair.
Parameter keys follow the same lowercase syntax as Dictionary keys. Parameter values are bare items (any of the eight types). Parameters themselves do not nest: a parameter value does not have its own parameters.
A bare parameter name without =value is
shorthand for ?1 (true):
Priority: u=1, i
The i parameter is equivalent to i=?1.
Serialization uses the shorthand form for true
booleans.
Parsing overview
The parser determines the type of a bare item by inspecting the first character:
| First character | Type |
|---|---|
- or digit |
Integer or Decimal |
" |
String |
Letter or * |
Token |
: |
Byte Sequence |
? |
Boolean |
@ |
Date |
% |
Display String |
Anything else fails the parse immediately.
After parsing the top-level value, any trailing non-whitespace content triggers a parse failure.
Key constraints
| Element | Constraint |
|---|---|
| Integer range | ±999,999,999,999,999 |
| Integer digits | 15 max |
| Decimal integer part | 12 digits max |
| Decimal fractional part | 1-3 digits |
| String charset | printable ASCII (0x20-0x7E) |
| String escapes | \" and \\ only |
| Token first character | A-Z, a-z, or * |
| Key first character | a-z or * |
| Key case | lowercase only |
| Boolean values | ?0 or ?1 |
| Date prefix | @ |
| Display String prefix | %" |
| Byte Sequence delimiters | :...: |
History
The original specification (2021) introduced structured field values with six bare item types: Integer, Decimal, String, Token, Byte Sequence, and Boolean.
A 2024 revision obsoleted the original and added two new types: Date and Display String. The revision is backward compatible. A current parser handles all valid original values. Headers defined under the original specification do not use the two new types to maintain compatibility with older parsers.
The specification was originally titled "Structured Headers" during its draft phase but was renamed to "Structured Fields" to cover both headers and trailers.
Example
A full request-response exchange using headers built on structured fields.
Request
GET /api/products HTTP/1.1
Host: www.example.re
Priority: u=0, i
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Accept: application/json
The Priority header is a Dictionary
with urgency 0 (highest) and incremental true.
The Sec-Fetch-Dest values are
Items containing a single Token.
Response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Digest: sha-256=:abc123base64value=:
Cache-Status: edge.example.re; hit; ttl=120, origin.example.re; fwd=bypass; detail="auth required"
CDN-Cache-Control: max-age=300, stale-while-revalidate=60
Proxy-Status: edge.example.re; next-hop="origin.example.re"
The Cache-Status List shows two
Caching layers. The first (edge) served from
cache with 120 seconds remaining. The second
(origin) was bypassed because Authentication
was
required. The CDN-Cache-Control
Dictionary instructs CDN caches to store for
5 minutes with a 60-second stale window. The
Content-Digest Dictionary maps
the sha-256 algorithm to a Byte Sequence
containing the hash.
Takeaway
Structured fields provide a common type system for HTTP header and trailer values, replacing the ad-hoc syntaxes of earlier headers with a consistent set of data types, container types, and parameters. The strict parsing rules guarantee interoperability. A single parser implementation handles any header built on structured fields.
See also
- RFC 9651: Structured Field Values for HTTP
- RFC 8941: Structured Field Values for HTTP (obsoleted)
- Cache-Status
- Priority
- CDN-Cache-Control
- Proxy-Status
- Signature
- Signature-Input
- Content-Digest
- Repr-Digest
- Client-Cert
- Deprecation
- Permissions-Policy
- HTTP headers