From d9266c4467ca0faa1213c1a5995164e5655ab375 Mon Sep 17 00:00:00 2001 From: Ming-jun Lu <40516784+mingjunlu@users.noreply.github.com> Date: Tue, 13 Feb 2024 19:28:14 +0800 Subject: [PATCH] Fix an issue where ReadableStream wasn't canceled in dev mode (#9971) * Fix an issue where ReadableStream wasn't canceled in dev mode * Add changeset * add test --------- Co-authored-by: lilnasy <69170106+lilnasy@users.noreply.github.com> --- .changeset/thin-kangaroos-exist.md | 5 +++ .../src/vite-plugin-astro-server/response.ts | 6 +++ .../vite-plugin-astro-server/response.test.js | 41 +++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 .changeset/thin-kangaroos-exist.md diff --git a/.changeset/thin-kangaroos-exist.md b/.changeset/thin-kangaroos-exist.md new file mode 100644 index 000000000000..5563e5638fbc --- /dev/null +++ b/.changeset/thin-kangaroos-exist.md @@ -0,0 +1,5 @@ +--- +"astro": patch +--- + +Fixes an issue where ReadableStream wasn't canceled in dev mode diff --git a/packages/astro/src/vite-plugin-astro-server/response.ts b/packages/astro/src/vite-plugin-astro-server/response.ts index 75649a714482..54cf6ef3ab90 100644 --- a/packages/astro/src/vite-plugin-astro-server/response.ts +++ b/packages/astro/src/vite-plugin-astro-server/response.ts @@ -82,6 +82,12 @@ export async function writeWebResponse(res: http.ServerResponse, webResponse: Re res.write(body); } else { const reader = body.getReader(); + res.on('close', () => { + reader.cancel().catch((error: unknown) => { + // eslint-disable-next-line no-console + console.error('An unexpected error occurred in the middle of the stream.', error); + }); + }); while (true) { const { done, value } = await reader.read(); if (done) break; diff --git a/packages/astro/test/units/vite-plugin-astro-server/response.test.js b/packages/astro/test/units/vite-plugin-astro-server/response.test.js index a47769556e40..a9c06fd266f2 100644 --- a/packages/astro/test/units/vite-plugin-astro-server/response.test.js +++ b/packages/astro/test/units/vite-plugin-astro-server/response.test.js @@ -21,6 +21,28 @@ const fileSystem = { headers.append('Set-Cookie', 'world'); return new Response(null, { headers }); }`, + '/src/pages/streaming.js': `export const GET = ({ locals }) => { + let sentChunks = 0; + + const readableStream = new ReadableStream({ + async pull(controller) { + if (sentChunks === 3) return controller.close(); + else sentChunks++; + + await new Promise(resolve => setTimeout(resolve, 1000)); + controller.enqueue(new TextEncoder().encode('hello')); + }, + cancel() { + locals.cancelledByTheServer = true; + } + }); + + return new Response(readableStream, { + headers: { + "Content-Type": "text/event-stream" + } + }) + }`, }; describe('endpoints', () => { @@ -60,4 +82,23 @@ describe('endpoints', () => { 'set-cookie': ['hello', 'world'], }); }); + + it('Headers with multisple values (set-cookie special case)', async () => { + const { req, res, done } = createRequestAndResponse({ + method: 'GET', + url: '/streaming', + }); + + const locals = { cancelledByTheServer: false } + req[Symbol.for("astro.locals")] = locals + + container.handle(req, res); + + await new Promise(resolve => setTimeout(resolve, 500)); + res.emit('close'); + + await done; + + expect(locals).to.deep.equal({ cancelledByTheServer: true }); + }); });