mirror of
https://github.com/denoland/deno.git
synced 2024-12-23 15:49:44 -05: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
|
||||
Deno.test(
|
||||
{ permissions: { net: true } },
|
||||
|
|
|
@ -812,3 +812,20 @@ Deno.test(
|
|||
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 {
|
||||
ArrayPrototypeForEach,
|
||||
ArrayPrototypeMap,
|
||||
FunctionPrototypeCall,
|
||||
Map,
|
||||
ObjectDefineProperty,
|
||||
ObjectFreeze,
|
||||
ObjectPrototypeIsPrototypeOf,
|
||||
ObjectSetPrototypeOf,
|
||||
Promise,
|
||||
PromisePrototype,
|
||||
PromisePrototypeThen,
|
||||
Set,
|
||||
SymbolIterator,
|
||||
|
@ -436,6 +439,29 @@
|
|||
primordials.PromisePrototypeCatch = (thisPromise, 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
|
||||
* rejected). The resolved value cannot be modified from the callback.
|
||||
|
|
|
@ -529,14 +529,15 @@
|
|||
// 2.6.
|
||||
// Rather than consuming the body as an ArrayBuffer, this passes each
|
||||
// chunk to the feed as soon as it's available.
|
||||
(async () => {
|
||||
const reader = res.body.getReader();
|
||||
while (true) {
|
||||
const { value: chunk, done } = await reader.read();
|
||||
if (done) break;
|
||||
ops.op_wasm_streaming_feed(rid, chunk);
|
||||
}
|
||||
})().then(
|
||||
PromisePrototypeThen(
|
||||
(async () => {
|
||||
const reader = res.body.getReader();
|
||||
while (true) {
|
||||
const { value: chunk, done } = await reader.read();
|
||||
if (done) break;
|
||||
ops.op_wasm_streaming_feed(rid, chunk);
|
||||
}
|
||||
})(),
|
||||
// 2.7
|
||||
() => core.close(rid),
|
||||
// 2.8
|
||||
|
|
|
@ -29,11 +29,13 @@
|
|||
const {
|
||||
Function,
|
||||
ObjectPrototypeIsPrototypeOf,
|
||||
PromiseAll,
|
||||
Promise,
|
||||
PromisePrototypeCatch,
|
||||
PromisePrototypeThen,
|
||||
SafePromiseAll,
|
||||
TypedArrayPrototypeSubarray,
|
||||
TypeError,
|
||||
Uint8Array,
|
||||
Promise,
|
||||
Uint8ArrayPrototype,
|
||||
} = window.__bootstrap.primordials;
|
||||
|
||||
|
@ -342,24 +344,27 @@
|
|||
}
|
||||
const reader = respBody.getReader(); // Aquire JS lock.
|
||||
try {
|
||||
core.opAsync(
|
||||
"op_flash_write_resource",
|
||||
http1Response(
|
||||
method,
|
||||
innerResp.status ?? 200,
|
||||
innerResp.headerList,
|
||||
0, // Content-Length will be set by the op.
|
||||
null,
|
||||
true,
|
||||
PromisePrototypeThen(
|
||||
core.opAsync(
|
||||
"op_flash_write_resource",
|
||||
http1Response(
|
||||
method,
|
||||
innerResp.status ?? 200,
|
||||
innerResp.headerList,
|
||||
0, // Content-Length will be set by the op.
|
||||
null,
|
||||
true,
|
||||
),
|
||||
serverId,
|
||||
i,
|
||||
resourceBacking.rid,
|
||||
resourceBacking.autoClose,
|
||||
),
|
||||
serverId,
|
||||
i,
|
||||
resourceBacking.rid,
|
||||
resourceBacking.autoClose,
|
||||
).then(() => {
|
||||
// Release JS lock.
|
||||
readableStreamClose(respBody);
|
||||
});
|
||||
() => {
|
||||
// Release JS lock.
|
||||
readableStreamClose(respBody);
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
await reader.cancel(error);
|
||||
throw error;
|
||||
|
@ -486,10 +491,16 @@
|
|||
const serverId = core.ops.op_flash_serve(listenOpts);
|
||||
const serverPromise = core.opAsync("op_flash_drive_server", serverId);
|
||||
|
||||
core.opAsync("op_flash_wait_for_listening", serverId).then((port) => {
|
||||
onListen({ hostname: listenOpts.hostname, port });
|
||||
}).catch(() => {});
|
||||
const finishedPromise = serverPromise.catch(() => {});
|
||||
PromisePrototypeCatch(
|
||||
PromisePrototypeThen(
|
||||
core.opAsync("op_flash_wait_for_listening", serverId),
|
||||
(port) => {
|
||||
onListen({ hostname: listenOpts.hostname, port });
|
||||
},
|
||||
),
|
||||
() => {},
|
||||
);
|
||||
const finishedPromise = PromisePrototypeCatch(serverPromise, () => {});
|
||||
|
||||
const server = {
|
||||
id: serverId,
|
||||
|
@ -554,7 +565,27 @@
|
|||
let resp;
|
||||
try {
|
||||
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) =>
|
||||
handleResponse(
|
||||
req,
|
||||
|
@ -595,7 +626,7 @@
|
|||
|
||||
signal?.addEventListener("abort", () => {
|
||||
clearInterval(dateInterval);
|
||||
server.close().then(() => {}, () => {});
|
||||
PromisePrototypeThen(server.close(), () => {}, () => {});
|
||||
}, {
|
||||
once: true,
|
||||
});
|
||||
|
@ -638,8 +669,8 @@
|
|||
}, 1000);
|
||||
}
|
||||
|
||||
await PromiseAll([
|
||||
server.serve().catch(console.error),
|
||||
await SafePromiseAll([
|
||||
PromisePrototypeCatch(server.serve(), console.error),
|
||||
serverPromise,
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
ObjectPrototypeIsPrototypeOf,
|
||||
ObjectSetPrototypeOf,
|
||||
Promise,
|
||||
PromiseAll,
|
||||
PromisePrototypeCatch,
|
||||
PromisePrototypeThen,
|
||||
PromiseReject,
|
||||
|
@ -43,6 +42,7 @@
|
|||
queueMicrotask,
|
||||
RangeError,
|
||||
ReflectHas,
|
||||
SafePromiseAll,
|
||||
SharedArrayBuffer,
|
||||
Symbol,
|
||||
SymbolAsyncIterator,
|
||||
|
@ -2302,7 +2302,8 @@
|
|||
});
|
||||
}
|
||||
shutdownWithAction(
|
||||
() => PromiseAll(ArrayPrototypeMap(actions, (action) => action())),
|
||||
() =>
|
||||
SafePromiseAll(ArrayPrototypeMap(actions, (action) => action())),
|
||||
true,
|
||||
error,
|
||||
);
|
||||
|
|
|
@ -27,12 +27,12 @@
|
|||
ObjectDefineProperty,
|
||||
ObjectPrototypeIsPrototypeOf,
|
||||
Promise,
|
||||
PromiseAll,
|
||||
PromisePrototypeCatch,
|
||||
PromisePrototypeThen,
|
||||
PromiseReject,
|
||||
PromiseResolve,
|
||||
SafeArrayIterator,
|
||||
SafePromiseAll,
|
||||
Set,
|
||||
SetPrototypeEntries,
|
||||
SetPrototypeForEach,
|
||||
|
@ -1517,7 +1517,7 @@
|
|||
"OperationError",
|
||||
);
|
||||
}
|
||||
const operations = PromiseAll(scope.operations);
|
||||
const operations = SafePromiseAll(scope.operations);
|
||||
return PromisePrototypeThen(
|
||||
operations,
|
||||
() => PromiseResolve(null),
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
String,
|
||||
TypeError,
|
||||
Uint8Array,
|
||||
PromiseAll,
|
||||
PromisePrototypeThen,
|
||||
SafePromiseAll,
|
||||
SymbolFor,
|
||||
} = window.__bootstrap.primordials;
|
||||
const {
|
||||
|
@ -155,7 +156,7 @@
|
|||
|
||||
const waitPromise = core.opAsync("op_spawn_wait", this.#rid);
|
||||
this.#waitPromiseId = waitPromise[promiseIdSymbol];
|
||||
this.#status = waitPromise.then((res) => {
|
||||
this.#status = PromisePrototypeThen(waitPromise, (res) => {
|
||||
this.#rid = null;
|
||||
signal?.[remove](onAbort);
|
||||
return res;
|
||||
|
@ -179,7 +180,7 @@
|
|||
);
|
||||
}
|
||||
|
||||
const [status, stdout, stderr] = await PromiseAll([
|
||||
const [status, stdout, stderr] = await SafePromiseAll([
|
||||
this.#status,
|
||||
collectOutput(this.#stdout),
|
||||
collectOutput(this.#stderr),
|
||||
|
|
Loading…
Reference in a new issue