diff --git a/.changeset/khaki-bears-enjoy.md b/.changeset/khaki-bears-enjoy.md new file mode 100644 index 000000000000..364644706f2d --- /dev/null +++ b/.changeset/khaki-bears-enjoy.md @@ -0,0 +1,5 @@ +--- +"astro": patch +--- + +Fixes an issue where configured redirects could not include certain characters in the target path. diff --git a/packages/astro/src/core/redirects/render.ts b/packages/astro/src/core/redirects/render.ts index 120fab26e4c8..24361fde471f 100644 --- a/packages/astro/src/core/redirects/render.ts +++ b/packages/astro/src/core/redirects/render.ts @@ -8,7 +8,7 @@ export async function renderRedirect(renderContext: RenderContext) { const { redirect, redirectRoute } = routeData; const status = redirectRoute && typeof redirect === 'object' ? redirect.status : method === 'GET' ? 301 : 308; - const headers = { location: redirectRouteGenerate(renderContext) }; + const headers = { location: encodeURI(redirectRouteGenerate(renderContext)) }; return new Response(null, { status, headers }); } diff --git a/packages/astro/test/redirects.test.js b/packages/astro/test/redirects.test.js index ab3a3eb37ed9..ffb7b242e821 100644 --- a/packages/astro/test/redirects.test.js +++ b/packages/astro/test/redirects.test.js @@ -98,6 +98,16 @@ describe('Astro.redirect', () => { const response = await app.render(request); assert.equal(response.headers.get('Location'), '/not-verbatim/target3/x/y/z'); }); + + it('Forwards params to the target path - special characters', async () => { + const app = await fixture.loadTestAdapterApp(); + const request = new Request('http://example.com/source/Las Vegas’'); + const response = await app.render(request); + assert.equal( + response.headers.get('Location'), + '/not-verbatim/target1/Las%20Vegas%E2%80%99' + ); + }); }); }); @@ -232,9 +242,17 @@ describe('Astro.redirect', () => { it('performs dynamic redirects', async () => { const response = await fixture.fetch('/more/old/hello', { redirect: 'manual' }); + assert.equal(response.status, 301); assert.equal(response.headers.get('Location'), '/more/hello'); }); + it('performs dynamic redirects with special characters', async () => { + // encodeURI("/more/old/’") + const response = await fixture.fetch("/more/old/%E2%80%99", { redirect: 'manual' }); + assert.equal(response.status, 301); + assert.equal(response.headers.get('Location'), "/more/%E2%80%99"); + }); + it('performs dynamic redirects with multiple params', async () => { const response = await fixture.fetch('/more/old/hello/world', { redirect: 'manual' }); assert.equal(response.headers.get('Location'), '/more/hello/world');