From c90d258bf55a39c9c20ea84de70291033a8d4cf4 Mon Sep 17 00:00:00 2001 From: Aral Roca Gomez Date: Fri, 6 Dec 2024 16:06:29 +0100 Subject: [PATCH] fix(render): fix uncoded ReadableStream in HTTP Responses (#668) --- .../response-rendered-page/index.test.ts | 31 +++++++++++++++---- .../src/utils/response-rendered-page/index.ts | 5 ++- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/packages/brisa/src/utils/response-rendered-page/index.test.ts b/packages/brisa/src/utils/response-rendered-page/index.test.ts index 2de0aaae..301ee0b7 100644 --- a/packages/brisa/src/utils/response-rendered-page/index.test.ts +++ b/packages/brisa/src/utils/response-rendered-page/index.test.ts @@ -55,7 +55,8 @@ describe('utils', () => { 'X-Mode': 'reactivity', }, }); - const html = await response.text(); + + const html = await getTextFromResponse(response); expect(response.status).toBe(200); expect(response.headers.get('X-Mode')).toBe('reactivity'); @@ -77,7 +78,7 @@ describe('utils', () => { 'X-Mode': 'reactivity', }, }); - const html = await response.text(); + const html = await getTextFromResponse(response); expect(response.status).toBe(200); expect(response.headers.get('X-Mode')).toBe('reactivity'); @@ -105,7 +106,7 @@ describe('utils', () => { 'X-Mode': 'reactivity', }, }); - const html = await response.text(); + const html = await getTextFromResponse(response); expect(response.status).toBe(200); expect(response.headers.get('X-Mode')).toBe('reactivity'); @@ -134,7 +135,8 @@ describe('utils', () => { 'X-Mode': 'reactivity', }, }); - const html = await response.text(); + + const html = await getTextFromResponse(response); expect(response.status).toBe(200); expect(response.headers.get('X-Mode')).toBe('reactivity'); @@ -169,7 +171,8 @@ describe('utils', () => { 'X-Mode': 'reactivity', }, }); - const html = await response.text(); + + const html = await getTextFromResponse(response); expect(response.status).toBe(200); expect(response.headers.get('X-Mode')).toBe('reactivity'); @@ -194,7 +197,9 @@ describe('utils', () => { filePath: path.join(PAGES_DIR, 'somepage.tsx'), } as MatchedBrisaRoute, }); - const html = await response.text(); + + const html = await getTextFromResponse(response); + expect(response.status).toBe(200); expect(html).toStartWith(''); expect(html).toContain(''); @@ -330,3 +335,17 @@ describe('utils', () => { }); }); }); + +async function getTextFromResponse(response: Response) { + try { + const text = await response.text(); + if (text.startsWith('\u0000') || text.includes(',')) { + const byteArray = new Uint8Array(text.split(',').map(Number)); + return new TextDecoder('utf-8').decode(byteArray); + } + return text; + } catch { + const buffer = await response.arrayBuffer(); + return new TextDecoder('utf-8').decode(buffer); + } +} diff --git a/packages/brisa/src/utils/response-rendered-page/index.ts b/packages/brisa/src/utils/response-rendered-page/index.ts index 52b3f952..7d2e9b69 100644 --- a/packages/brisa/src/utils/response-rendered-page/index.ts +++ b/packages/brisa/src/utils/response-rendered-page/index.ts @@ -52,7 +52,10 @@ export default async function responseRenderedPage({ status, }; - return new Response(htmlStream, responseOptions); + return new Response( + htmlStream.pipeThrough(new TextEncoderStream()), + responseOptions, + ); } export function routeToPrerenderedPagePath(route: MatchedBrisaRoute) {