From 820a26dde5cdc11b5bf430bc2a1e3b09084ae045 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 6 Jul 2022 20:48:14 -0400 Subject: [PATCH] Fix: Infer content type with charset in dev and prod (#3841) * fix: add text/plain;charset;utf-8 header in dev * test: ensure content type for body shorthand * chore: changeset * feat: infer content type by pathname * feat: add charset to prod build handler * test: update for charset in prod build test --- .changeset/ten-radios-rush.md | 5 +++++ packages/astro/src/core/app/index.ts | 4 +++- packages/astro/src/vite-plugin-astro-server/index.ts | 8 +++++++- packages/astro/test/ssr-api-route.test.js | 9 ++++++++- 4 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 .changeset/ten-radios-rush.md diff --git a/.changeset/ten-radios-rush.md b/.changeset/ten-radios-rush.md new file mode 100644 index 000000000..1162c46e3 --- /dev/null +++ b/.changeset/ten-radios-rush.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fix: add default content type to endpoints with { body } shorthand diff --git a/packages/astro/src/core/app/index.ts b/packages/astro/src/core/app/index.ts index 6fcb51717..e407adea2 100644 --- a/packages/astro/src/core/app/index.ts +++ b/packages/astro/src/core/app/index.ts @@ -149,7 +149,9 @@ export class App { const headers = new Headers(); const mimeType = mime.getType(url.pathname); if (mimeType) { - headers.set('Content-Type', mimeType); + headers.set('Content-Type', `${mimeType};charset=utf-8`); + } else { + headers.set('Content-Type', 'text/plain;charset=utf-8'); } const bytes = this.#encoder.encode(body); headers.set('Content-Length', bytes.byteLength.toString()); diff --git a/packages/astro/src/vite-plugin-astro-server/index.ts b/packages/astro/src/vite-plugin-astro-server/index.ts index a628247ec..3e8fec074 100644 --- a/packages/astro/src/vite-plugin-astro-server/index.ts +++ b/packages/astro/src/vite-plugin-astro-server/index.ts @@ -1,5 +1,6 @@ import type http from 'http'; import type * as vite from 'vite'; +import mime from 'mime'; import type { AstroConfig, ManifestData } from '../@types/astro'; import type { SSROptions } from '../core/render/dev/index'; @@ -315,7 +316,12 @@ async function handleRequest( if (result.type === 'response') { await writeWebResponse(res, result.response); } else { - res.writeHead(200); + let contentType = 'text/plain'; + const computedMimeType = route.pathname ? mime.getType(route.pathname) : null; + if (computedMimeType) { + contentType = computedMimeType; + } + res.writeHead(200, { 'Content-Type': `${contentType};charset=utf-8` }); res.end(result.body); } } else { diff --git a/packages/astro/test/ssr-api-route.test.js b/packages/astro/test/ssr-api-route.test.js index e4758f10e..ec6e65641 100644 --- a/packages/astro/test/ssr-api-route.test.js +++ b/packages/astro/test/ssr-api-route.test.js @@ -30,7 +30,7 @@ describe('API routes in SSR', () => { const request = new Request('http://example.com/food.json'); const response = await app.render(request); expect(response.status).to.equal(200); - expect(response.headers.get('Content-Type')).to.equal('application/json'); + expect(response.headers.get('Content-Type')).to.equal('application/json;charset=utf-8'); expect(response.headers.get('Content-Length')).to.not.be.empty; const body = await response.json(); expect(body.length).to.equal(3); @@ -56,6 +56,13 @@ describe('API routes in SSR', () => { expect(text).to.equal(`ok`); }); + it('Infer content type with charset for { body } shorthand', async () => { + const response = await fixture.fetch('/food.json', { + method: 'GET', + }); + expect(response.headers.get('Content-Type')).to.equal('application/json;charset=utf-8'); + }); + it('Can set multiple headers of the same type', async () => { const response = await fixture.fetch('/login', { method: 'POST',