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

Last updated: March 6, 2026