1010
1111type RequestInfo = Request | URL ;
1212
13+ class Fetch {
14+ // TODO: Event
15+ constructor ( ) {
16+ ( this as any ) . dispatcher = { } ;
17+ ( this as any ) . connection = null ;
18+ ( this as any ) . dump = false ;
19+ ( this as any ) . state = "ongoing" ;
20+ }
21+ }
22+
1323/** The fetch(input, init) method steps are: */
1424const fetch = ( input : RequestInfo , init = undefined ) => {
1525 // 1. Let p be a new promise.
@@ -80,9 +90,12 @@ const fetch = (input: RequestInfo, init = undefined) => {
8090 // 3. If response is a network error, then reject p with a TypeError and abort these steps.
8191 // 4. Set responseObject to the result of creating a Response object, given response, "immutable", and relevantRealm.
8292 // 5. Resolve p with responseObject.
93+ controller = fetching ( {
94+ request,
95+ } ) ;
8396
8497 // 13. Return p.
85- return p ;
98+ return p . promise ;
8699} ;
87100
88101( globalThis as unknown as { fetch : typeof fetch } ) . fetch = fetch ;
@@ -97,3 +110,186 @@ function createDeferredPromise() {
97110
98111 return { promise, resolve : res , reject : rej } ;
99112}
113+
114+ /**
115+ * To fetch, given a request request, an optional algorithm processRequestBodyChunkLength, an optional algorithm processRequestEndOfBody,
116+ * an optional algorithm processEarlyHintsResponse, an optional algorithm processResponse, an optional algorithm processResponseEndOfBody,
117+ * an optional algorithm processResponseConsumeBody, and an optional boolean useParallelQueue (default false), run the steps below.
118+ * If given, processRequestBodyChunkLength must be an algorithm accepting an integer representing the number of bytes transmitted.
119+ * If given, processRequestEndOfBody must be an algorithm accepting no arguments. If given, processEarlyHintsResponse must be
120+ * an algorithm accepting a response. If given, processResponse must be an algorithm accepting a response. If given,
121+ * processResponseEndOfBody must be an algorithm accepting a response. If given,
122+ * processResponseConsumeBody must be an algorithm accepting a response and null, failure, or a byte sequence.
123+ *
124+ * The user agent may be asked to suspend the ongoing fetch. The user agent may either accept or ignore the suspension request.
125+ * The suspended fetch can be resumed. The user agent should ignore the suspension request if the ongoing fetch is updating
126+ * the response in the HTTP cache for the request.
127+ *
128+ * @see https://fetch.spec.whatwg.org/#fetching
129+ */
130+ const fetching = (
131+ {
132+ request,
133+ processRequestBodyChunkLength,
134+ processRequestEndOfBody,
135+ processResponse,
136+ processResponseEndOfBody,
137+ processResponseConsumeBody,
138+ processEarlyHintsResponse,
139+ } : {
140+ request : any ;
141+ processRequestBodyChunkLength ?: any ;
142+ processRequestEndOfBody ?: any ;
143+ processResponse ?: any ;
144+ processResponseEndOfBody ?: any ;
145+ processResponseConsumeBody ?: any ;
146+ processEarlyHintsResponse ?: any ;
147+ } ,
148+ ) => {
149+ // 1. Assert: request’s mode is "navigate" or processEarlyHintsResponse is null.
150+ // NOTE: Processing of early hints (responses whose status is 103) is only vetted for navigations.
151+ if ( request . mode === "navigate" ) {
152+ throw new Error ( "error" ) ;
153+ }
154+
155+ // 2. Let taskDestination be null.
156+ let taskDestination = null ;
157+
158+ // 3. Let crossOriginIsolatedCapability be false.
159+ let crossOriginIsolatedCapability = false ;
160+
161+ // 4. Populate request from client given request.
162+ // populateRequest();
163+
164+ // 5. If request’s client is non-null, then:
165+ if ( request . client != null ) {
166+ // 1. Set taskDestination to request’s client’s global object.
167+ taskDestination = request . client . globalObject ;
168+ // 2. Set crossOriginIsolatedCapability to request’s client’s cross-origin isolated capability.
169+ crossOriginIsolatedCapability =
170+ request . client . crossOriginIsolatedCapability ;
171+ }
172+
173+ // TODO
174+ // 6. If useParallelQueue is true, then set taskDestination to the result of starting a new parallel queue.
175+
176+ // TODO
177+ // 7. Let timingInfo be a new fetch timing info whose start time and post-redirect start time are
178+ // the coarsened shared current time given crossOriginIsolatedCapability,
179+ // and render-blocking is set to request’s render-blocking.
180+ let timingInfo = 0 ;
181+
182+ // 8. Let fetchParams be a new fetch params whose
183+ // request is request, timing info is timingInfo,
184+ // process request body chunk length is processRequestBodyChunkLength,
185+ // process request end-of-body is processRequestEndOfBody,
186+ // process early hints response is processEarlyHintsResponse,
187+ // process response is processResponse,
188+ // process response consume body is processResponseConsumeBody,
189+ // process response end-of-body is processResponseEndOfBody,
190+ // task destination is taskDestination,
191+ // and cross-origin isolated capability is crossOriginIsolatedCapability.
192+ const fetchParams = {
193+ controller : new Fetch ( ) ,
194+ timingInfo, // TODO
195+ processRequestBodyChunkLength,
196+ processRequestEndOfBody,
197+ processResponse,
198+ processResponseConsumeBody,
199+ processResponseEndOfBody,
200+ taskDestination,
201+ crossOriginIsolatedCapability,
202+ } ;
203+
204+ // TODO: step9, 10
205+ // 9. If request’s body is a byte sequence, then set request’s body to request’s body as a body.
206+ // 10. If all of the following conditions are true:
207+ // - request’s URL’s scheme is an HTTP(S) scheme
208+ // - request’s mode is "same-origin", "cors", or "no-cors"
209+ // - request’s client is not null, and request’s client’s global object is a Window object
210+ // - request’s method is `GET`
211+ // - request’s unsafe-request flag is not set or request’s header list is empty
212+ // then:
213+ // 1. Assert: request’s origin is same origin with request’s client’s origin.
214+ // 2. Let onPreloadedResponseAvailable be an algorithm that runs the following step given a response response:
215+ // set fetchParams’s preloaded response candidate to response.
216+ // 3. Let foundPreloadedResource be the result of invoking consume a preloaded resource for request’s client,
217+ // given request’s URL, request’s destination, request’s mode, request’s credentials mode, request’s integrity metadata,
218+ // and onPreloadedResponseAvailable.
219+ // 4. If foundPreloadedResource is true and fetchParams’s preloaded response candidate is null, then set fetchParams’s preloaded response candidate to "pending".
220+
221+ // 11. If request’s header list does not contain `Accept`, then:
222+ // if (!request.headersList.contains("accept", true)) {
223+ // 1. Let value be `*/*`.
224+ // const value = "*/*";
225+
226+ // TODO
227+ // 2. If request’s initiator is "prefetch", then set value to the document `Accept` header value.
228+ // 3. Otherwise, the user agent should set value to the first matching statement, if any, switching on request’s destination:
229+ // ↪︎ "document"
230+ // ↪︎ "frame"
231+ // ↪︎ "iframe"
232+ // the document `Accept` header value
233+ // ↪︎ "image"
234+ // `image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5`
235+ // ↪︎ "json"
236+ // `application/json,*/*;q=0.5`
237+ // ↪︎ "style"
238+ // `text/css,*/*;q=0.1`
239+
240+ // 4. Append (`Accept`, value) to request’s header list.
241+ // request.headersList.append("accept", value, true);
242+ // }
243+
244+ // 12. If request’s header list does not contain `Accept-Language`,
245+ // then user agents should append
246+ // (`Accept-Language, an appropriate header value)
247+ // to request’s header list.
248+ // if (!request.headersList.contains("accept-language", true)) {
249+ // request.headersList.append("accept-language", "*", true);
250+ // }
251+
252+ // TODO
253+ // 13. If request’s internal priority is null, then use request’s priority,
254+ // initiator, destination, and render-blocking in an implementation-defined
255+ // manner to set request’s internal priority to an implementation-defined object.
256+
257+ // NOTE: The implementation-defined object could encompass stream weight and dependency for HTTP/2, priorities used
258+ // in Extensible Prioritization Scheme for HTTP for transports where it applies (including HTTP/3),
259+ // and equivalent information used to prioritize dispatch and processing of HTTP/1 fetches. [RFC9218]
260+ // 14. If request is a subresource request, then:
261+ // 1. Let record be a new fetch record whose request is request and controller is fetchParams’s controller.
262+ // 2. Append record to request’s client’s fetch group list of fetch records.
263+
264+ // 15. Run main fetch given fetchParams.
265+ mainFetch ( fetchParams ) ;
266+
267+ // 16. Return fetchParams’s controller.
268+ return fetchParams . controller ;
269+ } ;
270+
271+ /**
272+ * To populate request from client given a request request:
273+ * @see https://fetch.spec.whatwg.org/#populate-request-from-client
274+ */
275+ const populateRequest = ( ) => {
276+ // 1. If request’s traversable for user prompts is "client":
277+ // 1. Set request’s traversable for user prompts to "no-traversable".
278+ // 2. If request’s client is non-null:
279+ // 1. Let global be request’s client’s global object.
280+ // 2. If global is a Window object and global’s navigable is not null, then set request’s traversable for user prompts to global’s navigable’s traversable navigable.
281+ // 2. If request’s origin is "client":
282+ // 1. Assert: request’s client is non-null.
283+ // 2. Set request’s origin to request’s client’s origin.
284+ // 3. If request’s policy container is "client":
285+ // 1. If request’s client is non-null, then set request’s policy container to a clone of request’s client’s policy container. [HTML]
286+ // 2. Otherwise, set request’s policy container to a new policy container.
287+ } ;
288+
289+ /**
290+ * To main fetch, given a fetch params fetchParams and an optional boolean recursive (default false)
291+ * @see https://fetch.spec.whatwg.org/#main-fetch
292+ */
293+ const mainFetch = ( fetchParams : any ) => {
294+ console . log ( fetchParams ) ;
295+ } ;
0 commit comments