summaryrefslogtreecommitdiff
path: root/ext/fetch/26_fetch.js
diff options
context:
space:
mode:
authorLuca Casonato <hello@lcas.dev>2022-12-19 12:49:00 +0100
committerGitHub <noreply@github.com>2022-12-19 12:49:00 +0100
commit43b6390629ad62edbeca3b884ccee53422876a1a (patch)
treee72fb0808b5abb636e29c41c5fa5a7ee2a547435 /ext/fetch/26_fetch.js
parent84b70dd2fb780a779930342d21c27e4e368070f1 (diff)
fix(ext/fetch): handle errors in req body stream (#17081)
Right now an error in a request body stream causes an uncatchable global promise rejection. This PR fixes this to instead propagate the error correctly into the promise returned from `fetch`. It additionally fixes errored readable stream bodies being treated as successfully completed bodies by Rust.
Diffstat (limited to 'ext/fetch/26_fetch.js')
-rw-r--r--ext/fetch/26_fetch.js73
1 files changed, 50 insertions, 23 deletions
diff --git a/ext/fetch/26_fetch.js b/ext/fetch/26_fetch.js
index e522079bf..4a18e73f2 100644
--- a/ext/fetch/26_fetch.js
+++ b/ext/fetch/26_fetch.js
@@ -200,6 +200,8 @@
}
terminator[abortSignal.add](onAbort);
+ let requestSendError;
+ let requestSendErrorSet = false;
if (requestBodyRid !== null) {
if (
reqBody === null ||
@@ -210,44 +212,69 @@
const reader = reqBody.getReader();
WeakMapPrototypeSet(requestBodyReaders, req, reader);
(async () => {
- while (true) {
- const { value, done } = await PromisePrototypeCatch(
- reader.read(),
- (err) => {
- if (terminator.aborted) return { done: true, value: undefined };
- throw err;
- },
- );
+ let done = false;
+ while (!done) {
+ let val;
+ try {
+ const res = await reader.read();
+ done = res.done;
+ val = res.value;
+ } catch (err) {
+ if (terminator.aborted) break;
+ // TODO(lucacasonato): propagate error into response body stream
+ requestSendError = err;
+ requestSendErrorSet = true;
+ break;
+ }
if (done) break;
- if (!ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, value)) {
- await reader.cancel("value not a Uint8Array");
+ if (!ObjectPrototypeIsPrototypeOf(Uint8ArrayPrototype, val)) {
+ const error = new TypeError(
+ "Item in request body ReadableStream is not a Uint8Array",
+ );
+ await reader.cancel(error);
+ // TODO(lucacasonato): propagate error into response body stream
+ requestSendError = error;
+ requestSendErrorSet = true;
break;
}
try {
- await PromisePrototypeCatch(
- core.writeAll(requestBodyRid, value),
- (err) => {
- if (terminator.aborted) return;
- throw err;
- },
- );
- if (terminator.aborted) break;
+ await core.writeAll(requestBodyRid, val);
} catch (err) {
+ if (terminator.aborted) break;
await reader.cancel(err);
+ // TODO(lucacasonato): propagate error into response body stream
+ requestSendError = err;
+ requestSendErrorSet = true;
break;
}
}
+ if (done && !terminator.aborted) {
+ try {
+ await core.shutdown(requestBodyRid);
+ } catch (err) {
+ if (!terminator.aborted) {
+ requestSendError = err;
+ requestSendErrorSet = true;
+ }
+ }
+ }
WeakMapPrototypeDelete(requestBodyReaders, req);
core.tryClose(requestBodyRid);
})();
}
-
let resp;
try {
- resp = await PromisePrototypeCatch(opFetchSend(requestRid), (err) => {
- if (terminator.aborted) return;
- throw err;
- });
+ resp = await opFetchSend(requestRid);
+ } catch (err) {
+ if (terminator.aborted) return;
+ if (requestSendErrorSet) {
+ // if the request body stream errored, we want to propagate that error
+ // instead of the original error from opFetchSend
+ throw new TypeError("Failed to fetch: request body stream errored", {
+ cause: requestSendError,
+ });
+ }
+ throw err;
} finally {
if (cancelHandleRid !== null) {
core.tryClose(cancelHandleRid);