From 1fb2e23a6747a4f774e63639eb522cb34aadbf42 Mon Sep 17 00:00:00 2001 From: Luca Casonato Date: Sun, 6 Jun 2021 15:37:17 +0200 Subject: feat(fetch): implement abort (#10863) This commit introduces fetch aborting via an AbortSignal. --- extensions/fetch/23_request.js | 51 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) (limited to 'extensions/fetch/23_request.js') diff --git a/extensions/fetch/23_request.js b/extensions/fetch/23_request.js index ac38ce552..29eddcf22 100644 --- a/extensions/fetch/23_request.js +++ b/extensions/fetch/23_request.js @@ -26,9 +26,11 @@ getDecodeSplitHeader, } = window.__bootstrap.headers; const { HttpClient } = window.__bootstrap.fetch; + const abortSignal = window.__bootstrap.abortSignal; const _request = Symbol("request"); const _headers = Symbol("headers"); + const _signal = Symbol("signal"); const _mimeType = Symbol("mime type"); const _body = Symbol("body"); @@ -145,6 +147,8 @@ [_request]; /** @type {Headers} */ [_headers]; + /** @type {AbortSignal} */ + [_signal]; get [_mimeType]() { let charset = null; let essence = null; @@ -206,6 +210,9 @@ let request; const baseURL = getLocationHref(); + // 4. + let signal = null; + // 5. if (typeof input === "string") { const parsedURL = new URL(input, baseURL); @@ -213,8 +220,12 @@ } else { // 6. if (!(input instanceof Request)) throw new TypeError("Unreachable"); request = input[_request]; + signal = input[_signal]; } + // 12. + // TODO(lucacasonato): create a copy of `request` + // 22. if (init.redirect !== undefined) { request.redirectMode = init.redirect; @@ -227,6 +238,11 @@ request.method = method; } + // 26. + if (init.signal !== undefined) { + signal = init.signal; + } + // NOTE: non standard extension. This handles Deno.HttpClient parameter if (init.client !== undefined) { if (init.client !== null && !(init.client instanceof HttpClient)) { @@ -242,6 +258,12 @@ // 27. this[_request] = request; + // 28. + this[_signal] = abortSignal.newSignal(); + if (signal !== null) { + abortSignal.follow(this[_signal], signal); + } + // 29. this[_headers] = headersFromHeaderList(request.headerList, "request"); @@ -299,6 +321,9 @@ // 40. request.body = finalBody; + + // 41. + // TODO(lucacasonato): Extranious? https://github.com/whatwg/fetch/issues/1249 } get method() { @@ -321,13 +346,24 @@ return this[_request].redirectMode; } + get signal() { + webidl.assertBranded(this, Request); + return this[_signal]; + } + clone() { webidl.assertBranded(this, Request); if (this[_body] && this[_body].unusable()) { throw new TypeError("Body is unusable."); } const newReq = cloneInnerRequest(this[_request]); - return fromInnerRequest(newReq, guardFromHeaders(this[_headers])); + const newSignal = abortSignal.newSignal(); + abortSignal.follow(newSignal, this[_signal]); + return fromInnerRequest( + newReq, + newSignal, + guardFromHeaders(this[_headers]), + ); } get [Symbol.toStringTag]() { @@ -364,6 +400,10 @@ enumerable: true, configurable: true, }); + Object.defineProperty(Request.prototype, "signal", { + enumerable: true, + configurable: true, + }); Object.defineProperty(Request.prototype, "clone", { enumerable: true, writable: true, @@ -403,6 +443,12 @@ ), }, { key: "redirect", converter: webidl.converters["RequestRedirect"] }, + { + key: "signal", + converter: webidl.createNullableConverter( + webidl.converters["AbortSignal"], + ), + }, { key: "client", converter: webidl.converters.any }, ], ); @@ -420,9 +466,10 @@ * @param {"request" | "immutable" | "request-no-cors" | "response" | "none"} guard * @returns {Request} */ - function fromInnerRequest(inner, guard) { + function fromInnerRequest(inner, signal, guard) { const request = webidl.createBranded(Request); request[_request] = inner; + request[_signal] = signal; request[_headers] = headersFromHeaderList(inner.headerList, guard); return request; } -- cgit v1.2.3