summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/fetch/23_request.js65
-rw-r--r--ext/fetch/internal.d.ts1
-rw-r--r--ext/http/00_serve.ts32
-rw-r--r--ext/http/01_http.js10
-rw-r--r--ext/web/03_abort_signal.js33
5 files changed, 79 insertions, 62 deletions
diff --git a/ext/fetch/23_request.js b/ext/fetch/23_request.js
index 61c3b3f5d..70e00a874 100644
--- a/ext/fetch/23_request.js
+++ b/ext/fetch/23_request.js
@@ -14,6 +14,7 @@ const {
ArrayPrototypeMap,
ArrayPrototypeSlice,
ArrayPrototypeSplice,
+ ObjectFreeze,
ObjectKeys,
ObjectPrototypeIsPrototypeOf,
RegExpPrototypeExec,
@@ -24,7 +25,6 @@ const {
} = primordials;
import * as webidl from "ext:deno_webidl/00_webidl.js";
-import { assert } from "ext:deno_web/00_infra.js";
import { createFilteredInspectProxy } from "ext:deno_console/01_console.js";
import {
byteUpperCase,
@@ -43,8 +43,12 @@ import {
headersFromHeaderList,
} from "ext:deno_fetch/20_headers.js";
import { HttpClientPrototype } from "ext:deno_fetch/22_http_client.js";
-import * as abortSignal from "ext:deno_web/03_abort_signal.js";
-
+import {
+ createDependentAbortSignal,
+ newSignal,
+ signalAbort,
+} from "ext:deno_web/03_abort_signal.js";
+import { DOMException } from "ext:deno_web/01_dom_exception.js";
const { internalRidSymbol } = core;
const _request = Symbol("request");
@@ -52,6 +56,7 @@ const _headers = Symbol("headers");
const _getHeaders = Symbol("get headers");
const _headersCache = Symbol("headers cache");
const _signal = Symbol("signal");
+const _signalCache = Symbol("signalCache");
const _mimeType = Symbol("mime type");
const _body = Symbol("body");
const _url = Symbol("url");
@@ -262,7 +267,13 @@ class Request {
}
/** @type {AbortSignal} */
- [_signal];
+ get [_signal]() {
+ const signal = this[_signalCache];
+ if (signal !== undefined) {
+ return signal;
+ }
+ return (this[_signalCache] = newSignal());
+ }
get [_mimeType]() {
const values = getDecodeSplitHeader(
headerListFromHeaders(this[_headers]),
@@ -363,11 +374,10 @@ class Request {
// 28.
this[_request] = request;
- // 29.
- const signals = signal !== null ? [signal] : [];
-
- // 30.
- this[_signal] = abortSignal.createDependentAbortSignal(signals, prefix);
+ // 29 & 30.
+ if (signal !== null) {
+ this[_signalCache] = createDependentAbortSignal([signal], prefix);
+ }
// 31.
this[_headers] = headersFromHeaderList(request.headerList, "request");
@@ -473,17 +483,21 @@ class Request {
}
const clonedReq = cloneInnerRequest(this[_request]);
- assert(this[_signal] !== null);
- const clonedSignal = abortSignal.createDependentAbortSignal(
- [this[_signal]],
+ const materializedSignal = this[_signal];
+ const clonedSignal = createDependentAbortSignal(
+ [materializedSignal],
prefix,
);
- return fromInnerRequest(
- clonedReq,
- clonedSignal,
- guardFromHeaders(this[_headers]),
- );
+ const request = new Request(_brand);
+ request[_request] = clonedReq;
+ request[_signalCache] = clonedSignal;
+ request[_getHeaders] = () =>
+ headersFromHeaderList(
+ clonedReq.headerList,
+ guardFromHeaders(this[_headers]),
+ );
+ return request;
}
[SymbolFor("Deno.privateCustomInspect")](inspect, inspectOptions) {
@@ -562,19 +576,30 @@ function toInnerRequest(request) {
/**
* @param {InnerRequest} inner
- * @param {AbortSignal} signal
* @param {"request" | "immutable" | "request-no-cors" | "response" | "none"} guard
* @returns {Request}
*/
-function fromInnerRequest(inner, signal, guard) {
+function fromInnerRequest(inner, guard) {
const request = new Request(_brand);
request[_request] = inner;
- request[_signal] = signal;
request[_getHeaders] = () => headersFromHeaderList(inner.headerList, guard);
return request;
}
+const signalAbortError = new DOMException(
+ "The request has been cancelled.",
+ "AbortError",
+);
+ObjectFreeze(signalAbortError);
+
+function abortRequest(request) {
+ if (request[_signal]) {
+ request[_signal][signalAbort](signalAbortError);
+ }
+}
+
export {
+ abortRequest,
fromInnerRequest,
newInnerRequest,
processUrlList,
diff --git a/ext/fetch/internal.d.ts b/ext/fetch/internal.d.ts
index e0137c59d..17565992f 100644
--- a/ext/fetch/internal.d.ts
+++ b/ext/fetch/internal.d.ts
@@ -70,7 +70,6 @@ declare module "ext:deno_fetch/26_fetch.js" {
function toInnerRequest(request: Request): InnerRequest;
function fromInnerRequest(
inner: InnerRequest,
- signal: AbortSignal | null,
guard:
| "request"
| "immutable"
diff --git a/ext/http/00_serve.ts b/ext/http/00_serve.ts
index afcc16f38..b12a87390 100644
--- a/ext/http/00_serve.ts
+++ b/ext/http/00_serve.ts
@@ -49,7 +49,11 @@ import {
ResponsePrototype,
toInnerResponse,
} from "ext:deno_fetch/23_response.js";
-import { fromInnerRequest, toInnerRequest } from "ext:deno_fetch/23_request.js";
+import {
+ abortRequest,
+ fromInnerRequest,
+ toInnerRequest,
+} from "ext:deno_fetch/23_request.js";
import { AbortController } from "ext:deno_web/03_abort_signal.js";
import {
_eventLoop,
@@ -126,8 +130,6 @@ function addTrailers(resp, headerList) {
op_http_set_response_trailers(inner.external, headerList);
}
-let signalAbortError;
-
class InnerRequest {
#external;
#context;
@@ -137,14 +139,13 @@ class InnerRequest {
#upgraded;
#urlValue;
#completed;
- #abortController;
+ request;
- constructor(external, context, abortController) {
+ constructor(external, context) {
this.#external = external;
this.#context = context;
this.#upgraded = false;
this.#completed = undefined;
- this.#abortController = abortController;
}
close(success = true) {
@@ -158,15 +159,7 @@ class InnerRequest {
);
}
}
- if (!signalAbortError) {
- signalAbortError = new DOMException(
- "The request has been cancelled.",
- "AbortError",
- );
- }
- // Unconditionally abort the request signal. Note that we don't use
- // an error here.
- this.#abortController.abort(signalAbortError);
+ abortRequest(this.request);
this.#external = null;
}
@@ -492,17 +485,16 @@ function fastSyncResponseOrStream(
*/
function mapToCallback(context, callback, onError) {
return async function (req) {
- const abortController = new AbortController();
- const signal = abortController.signal;
-
// Get the response from the user-provided callback. If that fails, use onError. If that fails, return a fallback
// 500 error.
let innerRequest;
let response;
try {
- innerRequest = new InnerRequest(req, context, abortController);
+ innerRequest = new InnerRequest(req, context);
+ const request = fromInnerRequest(innerRequest, "immutable");
+ innerRequest.request = request;
response = await callback(
- fromInnerRequest(innerRequest, signal, "immutable"),
+ request,
new ServeHandlerInfo(innerRequest),
);
diff --git a/ext/http/01_http.js b/ext/http/01_http.js
index 580ba1166..b54768289 100644
--- a/ext/http/01_http.js
+++ b/ext/http/01_http.js
@@ -38,10 +38,10 @@ import {
toInnerResponse,
} from "ext:deno_fetch/23_response.js";
import {
+ abortRequest,
fromInnerRequest,
newInnerRequest,
} from "ext:deno_fetch/23_request.js";
-import { AbortController } from "ext:deno_web/03_abort_signal.js";
import {
_eventLoop,
_idleTimeoutDuration,
@@ -147,19 +147,17 @@ class HttpConn {
body !== null ? new InnerBody(body) : null,
false,
);
- const abortController = new AbortController();
const request = fromInnerRequest(
innerRequest,
- abortController.signal,
"immutable",
false,
);
const respondWith = createRespondWith(
this,
+ request,
readStreamRid,
writeStreamRid,
- abortController,
);
return { request, respondWith };
@@ -200,9 +198,9 @@ class HttpConn {
function createRespondWith(
httpConn,
+ request,
readStreamRid,
writeStreamRid,
- abortController,
) {
return async function respondWith(resp) {
try {
@@ -384,7 +382,7 @@ function createRespondWith(
ws[_serverHandleIdleTimeout]();
}
} catch (error) {
- abortController.abort(error);
+ abortRequest(request);
throw error;
} finally {
if (deleteManagedResource(httpConn, readStreamRid)) {
diff --git a/ext/web/03_abort_signal.js b/ext/web/03_abort_signal.js
index 4971fa418..053b89bdf 100644
--- a/ext/web/03_abort_signal.js
+++ b/ext/web/03_abort_signal.js
@@ -7,8 +7,8 @@ import { primordials } from "ext:core/mod.js";
const {
ArrayPrototypeEvery,
ArrayPrototypePush,
+ FunctionPrototypeApply,
ObjectPrototypeIsPrototypeOf,
- SafeArrayIterator,
SafeSet,
SafeSetIterator,
SafeWeakRef,
@@ -82,6 +82,14 @@ const timerId = Symbol("[[timerId]]");
const illegalConstructorKey = Symbol("illegalConstructorKey");
class AbortSignal extends EventTarget {
+ [abortReason] = undefined;
+ [abortAlgos] = null;
+ [dependent] = false;
+ [sourceSignals] = null;
+ [dependentSignals] = null;
+ [timerId] = null;
+ [webidl.brand] = webidl.brand;
+
static any(signals) {
const prefix = "Failed to execute 'AbortSignal.any'";
webidl.requiredArguments(arguments.length, 1, prefix);
@@ -141,9 +149,11 @@ class AbortSignal extends EventTarget {
const algos = this[abortAlgos];
this[abortAlgos] = null;
- const event = new Event("abort");
- setIsTrusted(event, true);
- super.dispatchEvent(event);
+ if (listenerCount(this, "abort") > 0) {
+ const event = new Event("abort");
+ setIsTrusted(event, true);
+ super.dispatchEvent(event);
+ }
if (algos !== null) {
for (const algorithm of new SafeSetIterator(algos)) {
algorithm();
@@ -168,13 +178,6 @@ class AbortSignal extends EventTarget {
throw new TypeError("Illegal constructor.");
}
super();
- this[abortReason] = undefined;
- this[abortAlgos] = null;
- this[dependent] = false;
- this[sourceSignals] = null;
- this[dependentSignals] = null;
- this[timerId] = null;
- this[webidl.brand] = webidl.brand;
}
get aborted() {
@@ -199,8 +202,8 @@ class AbortSignal extends EventTarget {
// `[add]` and `[remove]` don't ref and unref the timer because they can
// only be used by Deno internals, which use it to essentially cancel async
// ops which would block the event loop.
- addEventListener(...args) {
- super.addEventListener(...new SafeArrayIterator(args));
+ addEventListener() {
+ FunctionPrototypeApply(super.addEventListener, this, arguments);
if (listenerCount(this, "abort") > 0) {
if (this[timerId] !== null) {
refTimer(this[timerId]);
@@ -216,8 +219,8 @@ class AbortSignal extends EventTarget {
}
}
- removeEventListener(...args) {
- super.removeEventListener(...new SafeArrayIterator(args));
+ removeEventListener() {
+ FunctionPrototypeApply(super.removeEventListener, this, arguments);
if (listenerCount(this, "abort") === 0) {
if (this[timerId] !== null) {
unrefTimer(this[timerId]);