1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-21 15:04:11 -05:00

fix(ext/http): correctly consume response body in Deno.serve (#24811)

Prior to this commit, you could return a `Response` created from a
string or Uint8Array multiple times.

Now you can't do that anymore.
This commit is contained in:
Luca Casonato 2024-08-01 15:46:05 +02:00 committed by GitHub
parent c79cb339ef
commit 4eda9e64e9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 56 additions and 0 deletions

View file

@ -436,6 +436,11 @@ function fastSyncResponseOrStream(
const stream = respBody.streamOrStatic;
const body = stream.body;
if (body !== undefined) {
// We ensure the response has not been consumed yet in the caller of this
// function.
stream.consumed = true;
}
if (TypedArrayPrototypeGetSymbolToStringTag(body) === "Uint8Array") {
innerRequest?.close();
@ -505,6 +510,12 @@ function mapToCallback(context, callback, onError) {
"Return value from serve handler must be a response or a promise resolving to a response",
);
}
if (response.bodyUsed) {
throw TypeError(
"The body of the Response returned from the serve handler has already been consumed.",
);
}
} catch (error) {
try {
response = await onError(error);

View file

@ -631,6 +631,51 @@ Deno.test(
},
);
Deno.test(
{ permissions: { net: true } },
async function httpServerMultipleResponseBodyConsume() {
const ac = new AbortController();
const { promise, resolve } = Promise.withResolvers<void>();
const response = new Response("Hello World");
let hadError = false;
const server = Deno.serve({
handler: () => {
return response;
},
port: servePort,
signal: ac.signal,
onListen: onListen(resolve),
onError: () => {
hadError = true;
return new Response("Internal Server Error", { status: 500 });
},
});
await promise;
assert(!response.bodyUsed);
const resp = await fetch(`http://127.0.0.1:${servePort}/`, {
headers: { "connection": "close" },
});
assertEquals(resp.status, 200);
const text = await resp.text();
assertEquals(text, "Hello World");
assert(response.bodyUsed);
const resp2 = await fetch(`http://127.0.0.1:${servePort}/`, {
headers: { "connection": "close" },
});
assertEquals(resp2.status, 500);
const text2 = await resp2.text();
assertEquals(text2, "Internal Server Error");
assert(hadError);
assert(response.bodyUsed);
ac.abort();
await server.finished;
},
);
Deno.test({ permissions: { net: true } }, async function httpServerOverload1() {
const ac = new AbortController();
const deferred = Promise.withResolvers<void>();