Skip to content

Commit

Permalink
fix(rerouting): check that the new route is different (#8648)
Browse files Browse the repository at this point in the history
* fix(rerouting): check that the new route is different

* add tests

* changeset grammar
  • Loading branch information
lilnasy authored Sep 28, 2023
1 parent eada8ab commit cfd895d
Show file tree
Hide file tree
Showing 22 changed files with 152 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/wild-bees-sneeze.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fixed an issue where a response with status code 404 led to an endless loop of implicit rerouting in dev mode.
5 changes: 3 additions & 2 deletions packages/astro/src/vite-plugin-astro-server/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ export async function handleRoute({
let response = await pipeline.renderRoute(renderContext, mod);
if (response.status === 404 && has404Route(manifestData)) {
const fourOhFourRoute = await matchRoute('/404', manifestData, pipeline);
if (fourOhFourRoute?.route !== options.route)
return handleRoute({
...options,
matchedRoute: fourOhFourRoute,
Expand Down Expand Up @@ -342,6 +343,6 @@ function getStatus(matchedRoute?: MatchedRoute): 404 | 500 | undefined {
if (matchedRoute.route.route === '/500') return 500;
}

function has404Route(manifest: ManifestData): RouteData | undefined {
return manifest.routes.find((route) => route.route === '/404');
function has404Route(manifest: ManifestData): boolean {
return manifest.routes.some((route) => route.route === '/404');
}
57 changes: 57 additions & 0 deletions packages/astro/test/custom-404-implicit-rerouting.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { expect } from 'chai';
import { loadFixture } from './test-utils.js';

for (const caseNumber of [ 1, 2, 3, 4 ]) {
describe(`Custom 404 with implicit rerouting - Case #${caseNumber}`, () => {
/** @type Awaited<ReturnType<typeof loadFixture>> */
let fixture;
/** @type Awaited<ReturnType<typeof fixture['startDevServer']>> */
let devServer

before(async () => {
fixture = await loadFixture({
root: `./fixtures/custom-404-loop-case-${caseNumber}/`,
site: 'http://example.com'
});

devServer = await fixture.startDevServer();
});

// sanity check
it('dev server handles normal requests', async () => {
const resPromise = fixture.fetch('/');
const result = await withTimeout(resPromise, 1000);
expect(result).to.not.equal(timeout);
expect(result.status).to.equal(200);
});

it('dev server stays responsive', async () => {
const resPromise = fixture.fetch('/alvsibdlvjks');
const result = await withTimeout(resPromise, 1000);
expect(result).to.not.equal(timeout);
expect(result.status).to.equal(404);
});

after(async () => {
await devServer.stop();
});
});
}


/***** UTILITY FUNCTIONS *****/

const timeout = Symbol("timeout")

/** @template Res */
function withTimeout(
/** @type Promise<Res> */
responsePromise,
/** @type number */
timeLimit
) {
/** @type Promise<typeof timeout> */
const timeoutPromise = new Promise(resolve => setTimeout(() => resolve(timeout), timeLimit))

return Promise.race([ responsePromise, timeoutPromise ]);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "@test/custom-404-loop-case-1",
"version": "0.0.0",
"private": true,
"dependencies": {
"astro": "workspace:*"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
Astro.response.status = 404
---
<p>four oh four route</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p>all good here... or is it?</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "@test/custom-404-loop-case-2",
"version": "0.0.0",
"private": true,
"dependencies": {
"astro": "workspace:*"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
return new Response(null, { status: 404 })
---
<p>four oh four route</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p>all good here... or is it?</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "@test/custom-404-loop-case-3",
"version": "0.0.0",
"private": true,
"dependencies": {
"astro": "workspace:*"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export async function onRequest(ctx, next) {
if (ctx.url.pathname !== '/') {
const response = await next()
return new Response(response.body, { ...response, status: 404 })
}
return next();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p>four oh four route</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p>all good here... or is it?</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "@test/custom-404-loop-case-4",
"version": "0.0.0",
"private": true,
"dependencies": {
"astro": "workspace:*"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export function onRequest(ctx, next) {
if (ctx.url.pathname !== '/') {
return new Response(null, { status: 404 });
}
return next();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p>four oh four route</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p>all good here... or is it?</p>
24 changes: 24 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit cfd895d

Please sign in to comment.