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:
parent
c79cb339ef
commit
4eda9e64e9
2 changed files with 56 additions and 0 deletions
|
@ -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);
|
||||
|
|
|
@ -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>();
|
||||
|
|
Loading…
Reference in a new issue