Prompt and context
A file service must transmit bytes as they are produced, so the server does not know the final length or digest when it sends response headers. The product wants clients to verify integrity after receiving end-of-message metadata, but requests may pass through CDNs, reverse proxies, and different HTTP versions. Design the response contract, including which fields belong in trailers, how to declare and verify them, how to record failures, and what to do when a client cannot receive trailers.
This fits backend, gateway, and infrastructure roles. The core is not memorizing a header name; it is deciding what recipients must know before the body and what can only be known after streaming, then making loss in intermediaries, connection truncation, and unsupported clients safe.
What the interviewer is testing
A strong answer separates integrity digests, signatures, length, and cache controls by timing, then declares an allowed trailer field such as Trailer: Digest. It explains that HTTP/1.1 chunked framing is only one transport mechanism and that intermediaries may discard trailers. The client distinguishes a missing digest, a mismatched digest, and an incomplete message; end-of-connection alone is not proof of verification.
Questions to clarify first
- Is the digest for accidental corruption, source authentication, or both? Does the threat model include a malicious intermediary?
- Is the client a browser, native SDK, internal service, or controllable Node.js client, and can it be upgraded?
- Which HTTP versions, CDNs, caches, and compression layers are in the path, and may they buffer the response?
- Can the client retry, use object versions, range requests, or resumable downloads?
- Must the response be cacheable, and does the digest cover the decoded content or the transferred representation?
A 30-second answer framework
“I would define the digest as integrity metadata for the representation, use a field whose definition permits trailer use, and send a Trailer header naming it. The server computes the digest while streaming and emits it at the end; the client marks the file usable only after the message is complete and the digest matches. Because intermediaries can discard trailers, I would not make them the only business-critical signal. Unsupported clients use a precomputed digest, signed manifest, or a fresh download. Truncation, a missing trailer, and a mismatch are observable failure states.”
Step-by-step solution
Step 1: define the digest and representation
First define which bytes are covered. Usually the digest is for the decoded representation; if the server sends compressed content, the client must know whether it verifies compressed bytes or decoded bytes. Put the algorithm, encoding, and object version in the contract so the field has one meaning across implementations.
An ordinary digest detects accidental corruption but does not authenticate the sender. A signature or trusted manifest is needed against malicious replacement. Length, routing, authentication, and cache controls that must be decided before the body should not depend on a trailer.
Step 2: declare trailers and choose framing
HTTP defines trailer fields as optional metadata known after the content and asks senders to list anticipated field names in the Trailer header. HTTP/1.1 often carries them with chunked framing; HTTP/2 has a separate trailer section, so trailers are not synonymous with chunked encoding.
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Trailer: Digest
Transfer-Encoding: chunked
<streamed bytes>
0
Digest: sha-256=:<base64-value>:The angle brackets are placeholders and remain inside a fenced code block. A production contract uses a registered field syntax that explicitly permits trailers. Do not invent an arbitrary field and assume every intermediary will forward it.
Step 3: define the client state machine
Client states should include reading, complete-awaiting-trailer, verified, missing-trailer, mismatch, and truncated. Deliver a usable file only after the body and message are complete and the digest matches. A closed connection without a complete message is truncation.
Fetch in a browser, a mobile SDK, and an internal service exposes trailers differently. The request token TE: trailers only indicates willingness to preserve trailer sections; it does not promise processing of a particular field. For an uncontrollable client, a precomputed object digest or manifest is more dependable.
Step 4: handle intermediaries and caches
RFC 9110 warns that intermediaries may discard trailers and may buffer or transform them when forwarding between HTTP versions. Compatibility tests for a CDN or proxy should check declaration retention, actual trailer retention, digest behavior after compression, and cache-hit responses.
The cache key must include the object version and representation encoding. If a cache does not preserve trailers, a hit cannot claim that the client verified the content. Store a manifest at the cache layer or use a precomputed Digest or signature field instead.
Step 5: handle failure and retry
A missing digest is not a matching digest, and an early close is not an empty digest. The client stores the reason, object version, and received byte count; the service records request ID, duration, and a summary of the intermediary path. Retry with a range request or a new object version when safe, and never publish a corrupt partial file as successful.
If the server crashes before computing or sending the trailer, it must not fabricate a normal 200 response. Downstream can quarantine the unverified object until a new download or a trusted manifest verifies it.
Step 6: choose a fallback contract
For small files, precompute the digest and place it in an ordinary response field. For large files, publish a signed manifest containing object version, length, digest, and expiry. Multipart upload and object storage often already provide part checksums; a metadata service can expose the final digest without making acceptance depend on trailers.
Make the fallback explicit in the same download contract: the client reports verified-by-trailer, verified-by-manifest, or unverified. Do not silently mix these states.
Step 7: permissions, signatures, and privacy
The digest is usually not sensitive, but object names, versions, and signature metadata may reveal resource existence. Authorize manifest responses per object, keep signing keys server-side, and distribute verification keys through trusted configuration. Never put user tokens, internal paths, or stack traces in trailers.
For signatures, fix the covered bytes, canonicalization, and expiry rules. Recompression or transcoding changes the signed bytes, so define whether the signature covers a resource version or a concrete representation.
Step 8: verify and observe
Test a matrix of controllable clients and real intermediaries: HTTP/1.1 chunked, HTTP/2, compression, cache hits, dropped trailers, truncation, wrong digests, duplicate fields, and backpressure on large files. Node.js documents that response.addTrailers() requires the Trailer header and that non-chunked responses may silently discard trailers; those conditions belong in integration assertions.
Track missing-digest rate, mismatch rate, truncation rate, retry success, intermediary versions, and verification latency. Alerts should distinguish one unsupported client from a CDN path that systematically drops trailers, rather than calling every compatibility downgrade content corruption.
Trade-offs and boundaries
Trailers fit integrity or post-processing metadata that is only known after generation, allowing a file to stream without first buffering it to compute a digest. The trade-off is inconsistent support in clients and intermediaries, and trailers cannot carry routing, authentication, length, or cache semantics that must be decided before the body.
Precomputed digests and manifests cache, retry, and verify across clients more easily, but add metadata reads and version synchronization. Signatures provide stronger source assurance than a digest, at the cost of key rotation, canonicalization, and expiry management. Choose based on generation latency, client control, intermediary path, and threat model.
Rollout plan and evidence
Enable trailers first in an internal SDK and one CDN path, measuring retention and verification outcomes. Provide a manifest fallback and make clients report their verification mode. After HTTP/1.1, HTTP/2, compression, and cache tests pass, expand to uncontrollable clients; if a critical path drops trailers, make the manifest the required path.
RFC 9110 describes trailers for integrity checks, signatures, and post-processing status, while specifying declaration, limitations, and intermediary-loss behavior. Node.js documents the sending conditions for Trailer and addTrailers(). A public REST API interview guide emphasizes contracts, idempotency, errors, and observability. Together they support the protocol choices and verification plan in this question.
Common mistakes and follow-ups
Treating a trailer as a “late response header”
The processing time and intermediary semantics differ. Only metadata whose field definition permits trailers belongs there, and it must be stored and processed separately.
Omitting the Trailer header
Many implementations will not reliably emit or expose trailing fields. Declare the field name first, then test actual retention with clients and proxies.
Checking only that the connection closed
A close can mean truncation. Confirm message completion, trailer presence, and digest match before delivering the file.
Calling a digest a signature
A digest detects accidental corruption but cannot stop an attacker with write access from replacing content. Use a signed manifest and trusted key distribution for authentication.
What if a CDN drops trailers?
Keep the object unverified, switch to a precomputed digest or manifest, and monitor the path’s drop rate. Never silently convert a missing digest into success.