Add .trailers to Response/Request - #1940
Open
jasnell wants to merge 1 commit into
Open
Conversation
jasnell
commented
Jul 11, 2026
| <p>A <dfn export>trailer state</dfn> is a <a for=/>struct</a> used to represent | ||
| HTTP trailer fields received after a response body | ||
| ([[HTTP]], <a href="https://httpwg.org/specs/rfc9110.html#trailers">Section 6.5</a>). | ||
| It has: |
Author
There was a problem hiding this comment.
The struct here is really only to deal with cloning... wasn't sure if it would be better to go more specific / concrete or to describe things in a more generic / hand wavy way... went with more specific.
Adds `Promise<Headers>` `trailers` properties to `Request` and `Response` When sending... `trailers` resolves to an empty, immutable `Headers` since we're not dealing with sending trailers in this change. When receiving... `trailers` resolves to an immutable, populated/filtered `Headers` resolved after the body is completed. This means the trailers promise will not resolve if the body is not consumed.
jasnell
force-pushed
the
jasnell/trailers
branch
from
July 11, 2026 17:08
aca5d2b to
3cbc607
Compare
passcod
added a commit
to passcod/faith
that referenced
this pull request
Aug 5, 2026
These names started as internal identifiers and ended up in the README, where "controllable-h1" and "encoding" mean nothing to a reader. The rows: controllable-h1 and controllable-h2 are node-h1 and node-h2. It is Node's own server, and SCRIPTABLE already carries the it-can-misbehave-on-request idea that "controllable" was there for. The dimensions say what they check: framing becomes "chunked bodies", encoding becomes "gzip", conditional becomes "conditional GET", alpn becomes "protocol negotiation", keepalive becomes "connection reuse", header-limits becomes "oversized headers", goaway becomes "h2 GOAWAY", altsvc becomes "HTTP/3 upgrade", and h3 becomes "HTTP/3". One name each, used in the table, the TAP output and matrix.json, rather than a display label beside an identifier -- two names for one thing is how they drift. Files and exports follow, so the module you open matches the row you read. Also rewords the trailers dimension's note about consuming the body first. It described faith's implementation, down to the state it polls; what a reader needs is that trailers arrive after the body ends, which the fetch spec's trailers proposal requires (whatwg/fetch#1940). The implementation detail was also about to be wrong. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
passcod
added a commit
to passcod/faith
that referenced
this pull request
Aug 5, 2026
…means Closes #31, but not the way that issue proposed. Waiting for the body first is correct: the fetch spec's trailers proposal (whatwg/fetch#1940) says the promise resolves after the body is completed, and so "will not resolve if the body is not consumed". So the ordering stays; what was wrong is how the waiting was done and that nothing said so. The wait was a `yield_now` loop over a lock, for a wait the spec makes unbounded by design. Half a second of waiting cost half a second of CPU, kept Node's event loop alive, and survived a test framework's own timeout -- in the conformance harness this presented as a job that hung with no diagnosis. It is now a watch channel: trailers that already arrived return without yielding, a waiter parks until the body ends, and the future can be cancelled while it waits. Measured at 1ms of CPU across 500ms of waiting, against ~500ms before. discard() now settles the question as "none" instead of leaving it pending forever. On a multiplexed connection it cancels the stream before trailers could arrive, and draining an HTTP/1 body there bypasses the stream that would have collected them -- either way no trailers are coming, and a caller who discarded the body and then awaited trailers used to wait forever. The ordering is documented where a caller would look: the getter, wrapper.d.ts and the README's Response.trailers section, each pointing at the spec so it reads as the specified behaviour rather than a quirk. Nothing said it before, which is what made the wedge easy to hit. The test pins both halves: that the promise stays pending until the body is consumed, that it costs no CPU while pending, that a promise held from before the read resolves when the body ends, and that a discarded body answers null. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
Promise<Headers>trailersproperties toRequestandResponseWhen sending...
trailersresolves to an empty, immutableHeaderssince we're not dealing with sending trailers in this change.When receiving...
trailersresolves to an immutable, populated/filteredHeadersresolved after the body is completed. This means the trailers promise will not resolve if the body is not consumed.The minimal conformance requirement here is the presence of the
.trailersproperty. An implementation which chooses not to actually support trailers would need only return a resolved promise with an immutable emptyHeaders. Nothing in this should be interpreted as requiring any implementation to actually implement trailers support.Refs: #981
(See WHATWG Working Mode: Changes for more details.)
💥 Error: 422 Unprocessable Entity 💥
PR Preview failed to build. (Last tried on Jul 11, 2026, 5:40 PM UTC).
More
PR Preview relies on a number of web services to run. There seems to be an issue with the following one:
🚨 Spec Generator - Spec Generator is the web service used to build bikeshed/ReSpec specs
🔗 Related URL
Error output:
[ { "lineNum": "1675:17", "messageType": "link", "text": "Multiple possible 'dfn' local refs for 'trailer state'.\nRandomly chose one of them; other instances might get a different random choice." }, { "lineNum": "1679:51", "messageType": "link", "text": "Multiple possible 'dfn' local refs for 'trailer state'.\nRandomly chose one of them; other instances might get a different random choice." }, { "lineNum": "1699:48", "messageType": "link", "text": "Multiple possible 'dfn' local refs for 'trailer state'.\nRandomly chose one of them; other instances might get a different random choice." }, { "lineNum": "2652:4", "messageType": "link", "text": "Multiple possible 'dfn' local refs for 'trailer state'.\nRandomly chose one of them; other instances might get a different random choice." }, { "lineNum": "2652:63", "messageType": "link", "text": "Multiple possible 'dfn' local refs for 'trailer state'.\nRandomly chose one of them; other instances might get a different random choice." }, { "lineNum": null, "messageType": "failure", "text": "Did not generate, due to errors exceeding the allowed error level." } ]This seems to be an issue with the Spec Generator service. PR Preview doesn't manage this service and so has no control over it. If you've identified an issue with it, you can report the issue to the maintainers of Spec Generator directly. Please be courteous. Thank you!
If you don't have enough information above to solve the error by yourself or if the issue doesn't seem related to Spec Generator, you can file an issue with PR Preview.