Repository navigation
Add the fetch object model: Headers, Request and Response - #3101
Merged
Merged
Conversation
The offline half of fetch — everything a host can adopt without granting outbound network access. Behind the new WebApiFeatures.Fetch flag, which UseWebApis() never sets and Default will never include. Headers is the whole class: append/delete/get/getSetCookie/has/set, the iterable declaration's entries/keys/values/forEach/@@iterator over sort-and- combine (distinct lowercased names in byte order, values joined by ", ", Set-Cookie the one name never combined), RFC 9110 token names and header values that may carry no NUL, CR or LF — the request-splitting defence. The list itself is engine-free, so the HTTP half can build one off-thread. Request is the minimal request of the plan's surface v1: method (normalized for the six standard methods, forbidden methods refused), url, headers, redirect, signal, the Body mixin and clone. Response is status/ok/statusText/ headers/url/redirected/type/bodyUsed, text/json/arrayBuffer/bytes/blob/clone and the three statics error/redirect/json. Bodies are byte[]-buffered rather than streamed: every consumer answers an already-resolved promise, bodyUsed flips on the first read, a second read rejects with a TypeError, clone-after-read throws one, and a clone shares the bytes while carrying its own flag. body is therefore always null and says so. A FormData body is a TypeError naming the missing multipart serializer rather than a silently stringified object. Enabling Fetch implies Events, Url and Files, whose interfaces are part of fetch's own surface; the closure is computed in WebApiRegistration so that a host assigning Options.WebApi.Features directly gets it too, and so that the option keeps reading back what the host asked for. Options.FetchOptions arrives with the flag — HttpClient/HttpClientFactory, AllowedSchemes, UrlFilter, MaxResponseBytes, MaxRedirects, Timeout and MaxConcurrentRequests — so the policy surface is reviewable before anything uses it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Merged
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.
Part of the opt-in web API series (#3079): the fetch object model —
Headers,RequestandResponsebehindWebApiFeatures.Fetch— with no networking in this PR. The algorithm (transport, redirect policy, the actualfetch()global doing I/O) follows as the next PR; splitting them keeps this one fully offline-testable and reviewable as pure object semantics.Headersper https://fetch.spec.whatwg.org/#headers-class: pair-sequence/record init,append/delete/get/getSetCookie/has/set, iteration as the spec's sort-and-combine recomputed live per step (mutation-pinned: snapshotting the sort once failsIterationIsLive), multi-value backing soSet-Cookienever folds, RFC 9110 token validation for names and NUL/CR/LF refusal for values — the request-splicing defense is mutation-pinned too.Request(minimal per the plan): normalized method with the forbidden-method list enforced (CONNECT/TRACE/TRACK— unlike the browser's forbidden-header list, which is deliberately not enforced server-side, the Node/Deno posture; both decisions documented on the types), URL resolved by the in-tree WHATWG parser with no base (an embedded engine has no document, so relative input is aTypeError; URLs with credentials refused per spec),signal,redirect, body mixin,clone().Response: constructor withinitialize a responsein the spec's exact step order (body extracted before the range checks —Response.json(null, {status: 204})is aTypeError, initially implemented wrong and caught by the pinned test), staticserror()/json()(via Jint's own JSON serializer)/redirect(),text()/json()/arrayBuffer()/bytes()/blob(),clone(),typeasbasic/default/error(no origin → nocors/opaque). Bodies are bufferedbyte[]in this PR;bodyanswersnull(a meaningful spec value —if (response.body)degrades sanely) and the streaming integration lands separately on top of the streams feature.FormDatabodies are aTypeErrornaming the missing multipart serializer, which also arrives separately.WebApiFeatures.Fetch = 1 << 10impliesEvents | Url | Files(closure computed at install, pinned) and is never part ofDefault—UseWebApis()still yields an engine with nofetch-anything;UseFetch()is the explicit opt-in and arrives with the algorithm PR.Verified: all-TFM build, both suites both frameworks, both host-contract-verification configurations; seven mutation-verified pins across this and the algorithm commit (the ones in this PR: live iteration, header-value splicing,
Response.jsonnull-body ordering).🤖 Generated with Claude Code