Summary
- An HPACK dynamic-table index is meaningful only inside the correct encoding or decoding context, direction and sequence of an HTTP/2 connection.
- Reconstructing a header list is not a cache hit: cache keys, response storage, freshness, validation, authorization and application outcome remain separate evidence.
An observability panel reports hpack_cache_hit=true. The field block was short, the decoder found index 63, and the request continued. The label sounds economical and harmless. It also joins two mechanisms that HTTP keeps rigorously apart.
HPACK did remember something: field-name and field-value octets previously inserted into a compression table. It did not retrieve a stored response. It did not compare a URI, inspect Vary, calculate age, validate an entity tag or decide that one response could answer another request. The word “cache” turns successful reconstruction into authority that the compression layer never had.
Roberto Peon is central to this boundary because he co-authored RFC 7541 with Hervé Ruellan. His IETF Datatracker profile lists that HPACK specification and RFC 7540, the original HTTP/2 RFC. A QCon San Francisco 2012 biography describes him, at that time, as a Google engineer and SPDY co-creator. That dated record supplies history, not a claim about his present employer or office. The current HTTP/2 specification, RFC 9113, has different authors.
HPACK reconstructs an ordered list
RFC 7541 starts with a deliberately modest object. A header list is an ordered collection of name-value pairs. It can contain duplicate pairs. At the compression layer, names and values are opaque sequences of octets, and their order must survive compression and decompression.
That wording blocks a tempting inference. Seeing the octets cache-control and private does not mean HPACK has evaluated their HTTP meaning. The compressor can represent the pair literally, reference a table entry for its name, or reference an entry containing both name and value. The decoder's job is to reproduce the list in order. The HTTP implementation above it interprets the field.
An indexed representation is therefore not a citation to a universally named fact. It points into one of two tables. The static table is predefined and read-only. The dynamic table begins empty and changes as field blocks are processed. Its newest entry has the lowest dynamic position; older entries move toward eviction. Duplicate entries are legal.
Index 63 can mean one field now and another later. On a new connection it may not be valid at all. If an entry was evicted, the old number does not preserve it. A trace that records only “index 63 decoded” has retained the shortest part of the evidence and discarded the context that gave the number meaning.
One connection contains independent directions
For bidirectional HTTP, RFC 7541 makes an endpoint's encoding and decoding dynamic tables completely independent. A client uses one context to encode the field blocks it sends and another to decode those it receives. The server has the complementary pair. The request and response directions do not share one magic table.
RFC 9113 carries that design into the current HTTP/2 specification. Each endpoint has an HPACK encoder context and decoder context used for all field blocks on a connection. The dynamic table is the primary changing state of each context.
That scope matters in incident reconstruction. “The connection had this entry” is still incomplete. Which endpoint held it? In which direction? Before which field block? Under which maximum size? A decoder that is synchronized after block 40 may diverge after block 41 if it misses an insertion or applies an invalid size transition. The same numeric index in block 42 then resolves differently—or fails.
The contexts also explain why a receiver has to decompress a complete field block even if it intends to discard the associated message. The representations may update state used by later blocks. Ignoring one mutation would make the future undecodable.
Size control is a protocol sequence, not a storage policy
HTTP/2 begins a connection with 4,096 bytes as the initial maximum for the relevant HPACK tables. A decoder can advertise another maximum through SETTINGS_HEADER_TABLE_SIZE. The encoder may choose any effective size up to that limit and signals changes through HPACK's dynamic-table size update.
The default is not a census result. A deployed endpoint might reduce the limit, keep the maximum while using less, or disable useful dynamic indexing. More importantly, the reduction becomes operative through ordered settings and acknowledgment rules. When an acknowledged reduction requires a table-size update, the next field block has to carry it correctly.
Insertion can evict old entries until the table fits. An entry larger than the maximum clears the table rather than creating permanent state. The table is consequently a moving compression dictionary bounded by the decoder's resource authority, not an archive.
When state diverges, the blast radius reveals the dependency. RFC 9113 requires a receiver that cannot decompress a field block to terminate the connection with COMPRESSION_ERROR. A field block rides on a stream, but the context it mutates is shared by all field blocks in that direction on the connection. This is not proof that the application request was bad. It is proof that the connection's compression conversation cannot safely continue.
A response cache answers a different question
RFC 9111 defines an HTTP cache as a local store of response messages and the subsystem that controls storage, retrieval and deletion. Its operational promise is reuse: a prior response may satisfy a later request when the rules permit.
That decision needs a cache key, including at least the request method and target URI. It may also need the selecting fields named by Vary. The cache asks whether the stored response is fresh, allowed to be served stale, or successfully validated. It enforces directives such as no-store, private and no-cache, and it treats authorization-bearing requests under specific rules.
HPACK answers none of those questions. A dynamic table entry can preserve the octets of etag: "blue", but it does not store the corresponding representation or issue a conditional request. It can compress age: 300, but it does not run the freshness calculation. It can reconstruct vary: accept-language, but it does not compare a new request with the request that selected the stored response.
Consider cache-control: private. An encoder may put this field into its dynamic table because repetition makes it cheap to reference. That insertion neither creates a private cache nor prevents a shared cache from storing the response. Only the cache implementation, after parsing the message in context, applies the directive. The same octets can disappear from the compression table while the cached response remains, or remain in compression state when no response was cached.
The converse is equally important. A genuine cache hit can produce fields encoded literally, through the static table, or in a fresh compression context on a different connection. Calling an HPACK reference a cache hit makes dashboards correlate two events that are neither necessary nor sufficient for each other.
Successful decoding is narrow evidence
A valid indexed field proves a useful thing: at that point in the ordered conversation, the decoder possessed compatible compression state and reconstructed a field entry. That is enough to keep parsing the field block. It is not enough to trust the field.
HTTP/2 still requires validation of field names and values. TLS, where used, supplies channel properties under its own evidence. Intermediaries may have transformed a message. The origin may never have seen the request, and the application may reject or ignore it. Decompression cannot fill any of those columns.
This distinction becomes sharper around confidentiality. RFC 7541 warns that an attacker who can influence fields and observe compressed lengths can probe dynamic-table state. TLS encrypts content but reveals enough length information for compression behavior to matter. A short encoding is therefore not always a benign performance measurement.
HPACK offers a never-indexed literal representation for values that should not enter compression tables. An intermediary that receives that representation must preserve it when re-encoding. The signal is valuable, but it is not a secrecy theorem. A low-entropy value may still be guessed; length remains observable; another component might log it; and the application still owns its authorization policy.
Keep the two receipts apart
A defensible compression receipt begins with the connection identifier and endpoint roles. It records direction, stream and field-block sequence; the advertised table maximum and acknowledgment point; the effective table size before and after the block; insertions, evictions and size updates; whether each field was literal, indexed or never indexed; and the decode result. If the context was restored from a capture or inferred, that uncertainty stays explicit.
The HTTP receipt starts after reconstruction. It records parsed field semantics, method, target URI, response status and origin path. If caching is involved, it records the cache key, Vary inputs, storage decision, age and freshness calculation, validators, authorization-related rules, revalidation result and whether the returned representation satisfied the application.
One receipt may exist without the other. A packet trace can prove HPACK synchronization while lacking cache internals. A cache log can prove reuse while hiding wire compression. The honest record leaves those gaps blank. It never converts “the decoder remembered these octets” into “the system was entitled to reuse this response.”
Sources
Member Briefing
Deeper Profile Context
Sign in with the right membership level to unlock the full briefing and source notes.
Only for Strategic Circle
Strategic Circle
Open to all readers. Unlock profile briefings after joining and signing in.
Join Strategic CircleOnly for Leadership Alliance
Leadership Alliance
For qualified IP-asset owners and management; sign in to unlock alliance briefings.
Join Leadership Alliance
