summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIsaiah Gamble <77396670+tsar-boomba@users.noreply.github.com>2023-01-14 23:08:34 -0500
committerGitHub <noreply@github.com>2023-01-15 05:08:34 +0100
commitefcbfd5206fcdfac55c26a7133c04dd330d047b9 (patch)
treed34f0cccd2ffc0cde77e6bcdbc6fa8cf5f64f9b8
parentfd85f840cd707c31d08fa836562127e249c9ff62 (diff)
fix(ext/fetch) Fix request clone error in flash server (#16174)
-rw-r--r--cli/tests/unit/flash_test.ts39
-rw-r--r--ext/fetch/23_request.js50
-rw-r--r--ext/fetch/internal.d.ts2
-rw-r--r--ext/http/01_http.js7
4 files changed, 91 insertions, 7 deletions
diff --git a/cli/tests/unit/flash_test.ts b/cli/tests/unit/flash_test.ts
index 5604f6b5f..706b9f72b 100644
--- a/cli/tests/unit/flash_test.ts
+++ b/cli/tests/unit/flash_test.ts
@@ -2328,6 +2328,45 @@ Deno.test(
},
);
+// https://github.com/denoland/deno/issues/15858
+Deno.test(
+ { permissions: { net: true } },
+ async function httpServerCanCloneRequest() {
+ const ac = new AbortController();
+ const listeningPromise = deferred();
+
+ const server = Deno.serve({
+ handler: async (req) => {
+ const cloned = req.clone();
+ assertEquals(req.headers, cloned.headers);
+
+ // both requests can read body
+ await req.text();
+ await cloned.json();
+
+ return new Response("ok");
+ },
+ signal: ac.signal,
+ onListen: onListen(listeningPromise),
+ onError: createOnErrorCb(ac),
+ });
+
+ try {
+ await listeningPromise;
+ const resp = await fetch("http://localhost:9000/", {
+ headers: { connection: "close" },
+ method: "POST",
+ body: '{"sus":true}',
+ });
+ const text = await resp.text();
+ assertEquals(text, "ok");
+ } finally {
+ ac.abort();
+ await server;
+ }
+ },
+);
+
// Checks large streaming response
// https://github.com/denoland/deno/issues/16567
Deno.test(
diff --git a/ext/fetch/23_request.js b/ext/fetch/23_request.js
index b78cf48aa..e266a7e44 100644
--- a/ext/fetch/23_request.js
+++ b/ext/fetch/23_request.js
@@ -155,9 +155,11 @@
/**
* https://fetch.spec.whatwg.org/#concept-request-clone
* @param {InnerRequest} request
+ * @param {boolean} skipBody
+ * @param {boolean} flash
* @returns {InnerRequest}
*/
- function cloneInnerRequest(request, skipBody = false) {
+ function cloneInnerRequest(request, skipBody = false, flash = false) {
const headerList = ArrayPrototypeMap(
request.headerList,
(x) => [x[0], x[1]],
@@ -168,6 +170,19 @@
body = request.body.clone();
}
+ if (flash) {
+ return {
+ body,
+ methodCb: request.methodCb,
+ urlCb: request.urlCb,
+ headerList: request.headerList,
+ streamRid: request.streamRid,
+ serverId: request.serverId,
+ redirectMode: "follow",
+ redirectCount: 0,
+ };
+ }
+
return {
method: request.method,
headerList,
@@ -487,16 +502,30 @@
}
let newReq;
if (this[_flash]) {
- newReq = cloneInnerRequest(this[_flash]);
+ newReq = cloneInnerRequest(this[_flash], false, true);
} else {
newReq = cloneInnerRequest(this[_request]);
}
const newSignal = abortSignal.newSignal();
- abortSignal.follow(newSignal, this[_signal]);
+
+ if (this[_signal]) {
+ abortSignal.follow(newSignal, this[_signal]);
+ }
+
+ if (this[_flash]) {
+ return fromInnerRequest(
+ newReq,
+ newSignal,
+ guardFromHeaders(this[_headers]),
+ true,
+ );
+ }
+
return fromInnerRequest(
newReq,
newSignal,
guardFromHeaders(this[_headers]),
+ false,
);
}
@@ -573,14 +602,22 @@
/**
* @param {InnerRequest} inner
+ * @param {AbortSignal} signal
* @param {"request" | "immutable" | "request-no-cors" | "response" | "none"} guard
+ * @param {boolean} flash
* @returns {Request}
*/
- function fromInnerRequest(inner, signal, guard) {
+ function fromInnerRequest(inner, signal, guard, flash) {
const request = webidl.createBranded(Request);
- request[_request] = inner;
+ if (flash) {
+ request[_flash] = inner;
+ } else {
+ request[_request] = inner;
+ }
request[_signal] = signal;
- request[_getHeaders] = () => headersFromHeaderList(inner.headerList, guard);
+ request[_getHeaders] = flash
+ ? () => headersFromHeaderList(inner.headerList(), guard)
+ : () => headersFromHeaderList(inner.headerList, guard);
return request;
}
@@ -606,6 +643,7 @@
body: body !== null ? new InnerBody(body) : null,
methodCb,
urlCb,
+ headerList: headersCb,
streamRid,
serverId,
redirectMode: "follow",
diff --git a/ext/fetch/internal.d.ts b/ext/fetch/internal.d.ts
index 242cf44da..13a91d2d0 100644
--- a/ext/fetch/internal.d.ts
+++ b/ext/fetch/internal.d.ts
@@ -83,6 +83,8 @@ declare namespace globalThis {
| "request-no-cors"
| "response"
| "none",
+ skipBody: boolean,
+ flash: boolean,
): Request;
function redirectStatus(status: number): boolean;
function nullBodyStatus(status: number): boolean;
diff --git a/ext/http/01_http.js b/ext/http/01_http.js
index a6c1a06fc..8151d5a74 100644
--- a/ext/http/01_http.js
+++ b/ext/http/01_http.js
@@ -135,7 +135,12 @@
false,
);
const signal = abortSignal.newSignal();
- const request = fromInnerRequest(innerRequest, signal, "immutable");
+ const request = fromInnerRequest(
+ innerRequest,
+ signal,
+ "immutable",
+ false,
+ );
const respondWith = createRespondWith(
this,