Skip to content

Commit 3d3d8ee

Browse files
authored
feat(ext/fetch): fetching (#83)
* wip * update
1 parent 7373829 commit 3d3d8ee

File tree

2 files changed

+198
-2
lines changed

2 files changed

+198
-2
lines changed

examples/fetch.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const foo = async () => {
33
const res = await fetch("https://developer.mozilla.org");
44
console.log(res);
55
} catch (e) {
6-
console.error(e);
6+
console.error("error", e);
77
}
88
};
99

runtime/src/ext/fetch/fetch/mod.ts

Lines changed: 197 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@
1010

1111
type 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: */
1424
const 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

Comments
 (0)