diff options
author | Isaiah Gamble <77396670+tsar-boomba@users.noreply.github.com> | 2023-01-14 23:08:34 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-15 05:08:34 +0100 |
commit | efcbfd5206fcdfac55c26a7133c04dd330d047b9 (patch) | |
tree | d34f0cccd2ffc0cde77e6bcdbc6fa8cf5f64f9b8 | |
parent | fd85f840cd707c31d08fa836562127e249c9ff62 (diff) |
fix(ext/fetch) Fix request clone error in flash server (#16174)
-rw-r--r-- | cli/tests/unit/flash_test.ts | 39 | ||||
-rw-r--r-- | ext/fetch/23_request.js | 50 | ||||
-rw-r--r-- | ext/fetch/internal.d.ts | 2 | ||||
-rw-r--r-- | ext/http/01_http.js | 7 |
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, |