fix(ext/fetch) Fix request clone error in flash server (#16174)

This commit is contained in:
Isaiah Gamble 2023-01-14 23:08:34 -05:00 committed by GitHub
parent fd85f840cd
commit efcbfd5206
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 91 additions and 7 deletions

View file

@ -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(

View file

@ -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",

View file

@ -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;

View file

@ -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,