mirror of
https://github.com/denoland/deno.git
synced 2025-09-26 12:19:12 +00:00
fix(core): fix APIs not to be affected by Promise.prototype.then
modification (#16326)
This commit is contained in:
parent
edaceecec7
commit
59ac110edd
8 changed files with 145 additions and 42 deletions
|
@ -2227,6 +2227,32 @@ Deno.test(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Deno.test(
|
||||||
|
{ permissions: { net: true } },
|
||||||
|
async function serveWithPromisePrototypeThenOverride() {
|
||||||
|
const originalThen = Promise.prototype.then;
|
||||||
|
try {
|
||||||
|
Promise.prototype.then = () => {
|
||||||
|
throw new Error();
|
||||||
|
};
|
||||||
|
const ac = new AbortController();
|
||||||
|
const listeningPromise = deferred();
|
||||||
|
const server = Deno.serve({
|
||||||
|
handler: (_req) => new Response("ok"),
|
||||||
|
hostname: "localhost",
|
||||||
|
port: 4501,
|
||||||
|
signal: ac.signal,
|
||||||
|
onListen: onListen(listeningPromise),
|
||||||
|
onError: createOnErrorCb(ac),
|
||||||
|
});
|
||||||
|
ac.abort();
|
||||||
|
await server;
|
||||||
|
} finally {
|
||||||
|
Promise.prototype.then = originalThen;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// https://github.com/denoland/deno/issues/15549
|
// https://github.com/denoland/deno/issues/15549
|
||||||
Deno.test(
|
Deno.test(
|
||||||
{ permissions: { net: true } },
|
{ permissions: { net: true } },
|
||||||
|
|
|
@ -812,3 +812,20 @@ Deno.test(
|
||||||
assertStringIncludes(stdoutText, "typescript");
|
assertStringIncludes(stdoutText, "typescript");
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Deno.test(
|
||||||
|
{ permissions: { read: true, run: true } },
|
||||||
|
async function spawnWithPromisePrototypeThenOverride() {
|
||||||
|
const originalThen = Promise.prototype.then;
|
||||||
|
try {
|
||||||
|
Promise.prototype.then = () => {
|
||||||
|
throw new Error();
|
||||||
|
};
|
||||||
|
await Deno.spawn(Deno.execPath(), {
|
||||||
|
args: ["eval", "console.log('hello world')"],
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
Promise.prototype.then = originalThen;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
|
@ -275,12 +275,15 @@
|
||||||
|
|
||||||
const {
|
const {
|
||||||
ArrayPrototypeForEach,
|
ArrayPrototypeForEach,
|
||||||
|
ArrayPrototypeMap,
|
||||||
FunctionPrototypeCall,
|
FunctionPrototypeCall,
|
||||||
Map,
|
Map,
|
||||||
ObjectDefineProperty,
|
ObjectDefineProperty,
|
||||||
ObjectFreeze,
|
ObjectFreeze,
|
||||||
|
ObjectPrototypeIsPrototypeOf,
|
||||||
ObjectSetPrototypeOf,
|
ObjectSetPrototypeOf,
|
||||||
Promise,
|
Promise,
|
||||||
|
PromisePrototype,
|
||||||
PromisePrototypeThen,
|
PromisePrototypeThen,
|
||||||
Set,
|
Set,
|
||||||
SymbolIterator,
|
SymbolIterator,
|
||||||
|
@ -436,6 +439,29 @@
|
||||||
primordials.PromisePrototypeCatch = (thisPromise, onRejected) =>
|
primordials.PromisePrototypeCatch = (thisPromise, onRejected) =>
|
||||||
PromisePrototypeThen(thisPromise, undefined, onRejected);
|
PromisePrototypeThen(thisPromise, undefined, onRejected);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Promise that is resolved with an array of results when all of the
|
||||||
|
* provided Promises resolve, or rejected when any Promise is rejected.
|
||||||
|
* @param {unknown[]} values An array of Promises.
|
||||||
|
* @returns A new Promise.
|
||||||
|
*/
|
||||||
|
primordials.SafePromiseAll = (values) =>
|
||||||
|
// Wrapping on a new Promise is necessary to not expose the SafePromise
|
||||||
|
// prototype to user-land.
|
||||||
|
new Promise((a, b) =>
|
||||||
|
SafePromise.all(
|
||||||
|
ArrayPrototypeMap(
|
||||||
|
values,
|
||||||
|
(p) => {
|
||||||
|
if (ObjectPrototypeIsPrototypeOf(PromisePrototype, p)) {
|
||||||
|
return new SafePromise((c, d) => PromisePrototypeThen(p, c, d));
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
).then(a, b)
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attaches a callback that is invoked when the Promise is settled (fulfilled or
|
* Attaches a callback that is invoked when the Promise is settled (fulfilled or
|
||||||
* rejected). The resolved value cannot be modified from the callback.
|
* rejected). The resolved value cannot be modified from the callback.
|
||||||
|
|
|
@ -529,14 +529,15 @@
|
||||||
// 2.6.
|
// 2.6.
|
||||||
// Rather than consuming the body as an ArrayBuffer, this passes each
|
// Rather than consuming the body as an ArrayBuffer, this passes each
|
||||||
// chunk to the feed as soon as it's available.
|
// chunk to the feed as soon as it's available.
|
||||||
(async () => {
|
PromisePrototypeThen(
|
||||||
const reader = res.body.getReader();
|
(async () => {
|
||||||
while (true) {
|
const reader = res.body.getReader();
|
||||||
const { value: chunk, done } = await reader.read();
|
while (true) {
|
||||||
if (done) break;
|
const { value: chunk, done } = await reader.read();
|
||||||
ops.op_wasm_streaming_feed(rid, chunk);
|
if (done) break;
|
||||||
}
|
ops.op_wasm_streaming_feed(rid, chunk);
|
||||||
})().then(
|
}
|
||||||
|
})(),
|
||||||
// 2.7
|
// 2.7
|
||||||
() => core.close(rid),
|
() => core.close(rid),
|
||||||
// 2.8
|
// 2.8
|
||||||
|
|
|
@ -29,11 +29,13 @@
|
||||||
const {
|
const {
|
||||||
Function,
|
Function,
|
||||||
ObjectPrototypeIsPrototypeOf,
|
ObjectPrototypeIsPrototypeOf,
|
||||||
PromiseAll,
|
Promise,
|
||||||
|
PromisePrototypeCatch,
|
||||||
|
PromisePrototypeThen,
|
||||||
|
SafePromiseAll,
|
||||||
TypedArrayPrototypeSubarray,
|
TypedArrayPrototypeSubarray,
|
||||||
TypeError,
|
TypeError,
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
Promise,
|
|
||||||
Uint8ArrayPrototype,
|
Uint8ArrayPrototype,
|
||||||
} = window.__bootstrap.primordials;
|
} = window.__bootstrap.primordials;
|
||||||
|
|
||||||
|
@ -342,24 +344,27 @@
|
||||||
}
|
}
|
||||||
const reader = respBody.getReader(); // Aquire JS lock.
|
const reader = respBody.getReader(); // Aquire JS lock.
|
||||||
try {
|
try {
|
||||||
core.opAsync(
|
PromisePrototypeThen(
|
||||||
"op_flash_write_resource",
|
core.opAsync(
|
||||||
http1Response(
|
"op_flash_write_resource",
|
||||||
method,
|
http1Response(
|
||||||
innerResp.status ?? 200,
|
method,
|
||||||
innerResp.headerList,
|
innerResp.status ?? 200,
|
||||||
0, // Content-Length will be set by the op.
|
innerResp.headerList,
|
||||||
null,
|
0, // Content-Length will be set by the op.
|
||||||
true,
|
null,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
serverId,
|
||||||
|
i,
|
||||||
|
resourceBacking.rid,
|
||||||
|
resourceBacking.autoClose,
|
||||||
),
|
),
|
||||||
serverId,
|
() => {
|
||||||
i,
|
// Release JS lock.
|
||||||
resourceBacking.rid,
|
readableStreamClose(respBody);
|
||||||
resourceBacking.autoClose,
|
},
|
||||||
).then(() => {
|
);
|
||||||
// Release JS lock.
|
|
||||||
readableStreamClose(respBody);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
await reader.cancel(error);
|
await reader.cancel(error);
|
||||||
throw error;
|
throw error;
|
||||||
|
@ -486,10 +491,16 @@
|
||||||
const serverId = core.ops.op_flash_serve(listenOpts);
|
const serverId = core.ops.op_flash_serve(listenOpts);
|
||||||
const serverPromise = core.opAsync("op_flash_drive_server", serverId);
|
const serverPromise = core.opAsync("op_flash_drive_server", serverId);
|
||||||
|
|
||||||
core.opAsync("op_flash_wait_for_listening", serverId).then((port) => {
|
PromisePrototypeCatch(
|
||||||
onListen({ hostname: listenOpts.hostname, port });
|
PromisePrototypeThen(
|
||||||
}).catch(() => {});
|
core.opAsync("op_flash_wait_for_listening", serverId),
|
||||||
const finishedPromise = serverPromise.catch(() => {});
|
(port) => {
|
||||||
|
onListen({ hostname: listenOpts.hostname, port });
|
||||||
|
},
|
||||||
|
),
|
||||||
|
() => {},
|
||||||
|
);
|
||||||
|
const finishedPromise = PromisePrototypeCatch(serverPromise, () => {});
|
||||||
|
|
||||||
const server = {
|
const server = {
|
||||||
id: serverId,
|
id: serverId,
|
||||||
|
@ -554,7 +565,27 @@
|
||||||
let resp;
|
let resp;
|
||||||
try {
|
try {
|
||||||
resp = handler(req);
|
resp = handler(req);
|
||||||
if (resp instanceof Promise || typeof resp?.then === "function") {
|
if (resp instanceof Promise) {
|
||||||
|
PromisePrototypeCatch(
|
||||||
|
PromisePrototypeThen(
|
||||||
|
resp,
|
||||||
|
(resp) =>
|
||||||
|
handleResponse(
|
||||||
|
req,
|
||||||
|
resp,
|
||||||
|
body,
|
||||||
|
hasBody,
|
||||||
|
method,
|
||||||
|
serverId,
|
||||||
|
i,
|
||||||
|
respondFast,
|
||||||
|
respondChunked,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onError,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
} else if (typeof resp?.then === "function") {
|
||||||
resp.then((resp) =>
|
resp.then((resp) =>
|
||||||
handleResponse(
|
handleResponse(
|
||||||
req,
|
req,
|
||||||
|
@ -595,7 +626,7 @@
|
||||||
|
|
||||||
signal?.addEventListener("abort", () => {
|
signal?.addEventListener("abort", () => {
|
||||||
clearInterval(dateInterval);
|
clearInterval(dateInterval);
|
||||||
server.close().then(() => {}, () => {});
|
PromisePrototypeThen(server.close(), () => {}, () => {});
|
||||||
}, {
|
}, {
|
||||||
once: true,
|
once: true,
|
||||||
});
|
});
|
||||||
|
@ -638,8 +669,8 @@
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
await PromiseAll([
|
await SafePromiseAll([
|
||||||
server.serve().catch(console.error),
|
PromisePrototypeCatch(server.serve(), console.error),
|
||||||
serverPromise,
|
serverPromise,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
ObjectPrototypeIsPrototypeOf,
|
ObjectPrototypeIsPrototypeOf,
|
||||||
ObjectSetPrototypeOf,
|
ObjectSetPrototypeOf,
|
||||||
Promise,
|
Promise,
|
||||||
PromiseAll,
|
|
||||||
PromisePrototypeCatch,
|
PromisePrototypeCatch,
|
||||||
PromisePrototypeThen,
|
PromisePrototypeThen,
|
||||||
PromiseReject,
|
PromiseReject,
|
||||||
|
@ -43,6 +42,7 @@
|
||||||
queueMicrotask,
|
queueMicrotask,
|
||||||
RangeError,
|
RangeError,
|
||||||
ReflectHas,
|
ReflectHas,
|
||||||
|
SafePromiseAll,
|
||||||
SharedArrayBuffer,
|
SharedArrayBuffer,
|
||||||
Symbol,
|
Symbol,
|
||||||
SymbolAsyncIterator,
|
SymbolAsyncIterator,
|
||||||
|
@ -2302,7 +2302,8 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
shutdownWithAction(
|
shutdownWithAction(
|
||||||
() => PromiseAll(ArrayPrototypeMap(actions, (action) => action())),
|
() =>
|
||||||
|
SafePromiseAll(ArrayPrototypeMap(actions, (action) => action())),
|
||||||
true,
|
true,
|
||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
|
|
|
@ -27,12 +27,12 @@
|
||||||
ObjectDefineProperty,
|
ObjectDefineProperty,
|
||||||
ObjectPrototypeIsPrototypeOf,
|
ObjectPrototypeIsPrototypeOf,
|
||||||
Promise,
|
Promise,
|
||||||
PromiseAll,
|
|
||||||
PromisePrototypeCatch,
|
PromisePrototypeCatch,
|
||||||
PromisePrototypeThen,
|
PromisePrototypeThen,
|
||||||
PromiseReject,
|
PromiseReject,
|
||||||
PromiseResolve,
|
PromiseResolve,
|
||||||
SafeArrayIterator,
|
SafeArrayIterator,
|
||||||
|
SafePromiseAll,
|
||||||
Set,
|
Set,
|
||||||
SetPrototypeEntries,
|
SetPrototypeEntries,
|
||||||
SetPrototypeForEach,
|
SetPrototypeForEach,
|
||||||
|
@ -1517,7 +1517,7 @@
|
||||||
"OperationError",
|
"OperationError",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const operations = PromiseAll(scope.operations);
|
const operations = SafePromiseAll(scope.operations);
|
||||||
return PromisePrototypeThen(
|
return PromisePrototypeThen(
|
||||||
operations,
|
operations,
|
||||||
() => PromiseResolve(null),
|
() => PromiseResolve(null),
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
String,
|
String,
|
||||||
TypeError,
|
TypeError,
|
||||||
Uint8Array,
|
Uint8Array,
|
||||||
PromiseAll,
|
PromisePrototypeThen,
|
||||||
|
SafePromiseAll,
|
||||||
SymbolFor,
|
SymbolFor,
|
||||||
} = window.__bootstrap.primordials;
|
} = window.__bootstrap.primordials;
|
||||||
const {
|
const {
|
||||||
|
@ -155,7 +156,7 @@
|
||||||
|
|
||||||
const waitPromise = core.opAsync("op_spawn_wait", this.#rid);
|
const waitPromise = core.opAsync("op_spawn_wait", this.#rid);
|
||||||
this.#waitPromiseId = waitPromise[promiseIdSymbol];
|
this.#waitPromiseId = waitPromise[promiseIdSymbol];
|
||||||
this.#status = waitPromise.then((res) => {
|
this.#status = PromisePrototypeThen(waitPromise, (res) => {
|
||||||
this.#rid = null;
|
this.#rid = null;
|
||||||
signal?.[remove](onAbort);
|
signal?.[remove](onAbort);
|
||||||
return res;
|
return res;
|
||||||
|
@ -179,7 +180,7 @@
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [status, stdout, stderr] = await PromiseAll([
|
const [status, stdout, stderr] = await SafePromiseAll([
|
||||||
this.#status,
|
this.#status,
|
||||||
collectOutput(this.#stdout),
|
collectOutput(this.#stdout),
|
||||||
collectOutput(this.#stderr),
|
collectOutput(this.#stderr),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue