mirror of
https://github.com/withastro/astro.git
synced 2025-01-22 10:31:53 -05:00
fix: handle requests for double slash in dev (#12733)
* fix: handle requests for double slash in dev * Handle base * Oops * Snapshots * Move redirect out of routing --------- Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
This commit is contained in:
parent
9b0a624c8c
commit
bbf1d8894e
5 changed files with 39 additions and 4 deletions
5
.changeset/twenty-cherries-switch.md
Normal file
5
.changeset/twenty-cherries-switch.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Fixes a bug that caused the dev server to return an error if requesting "//"
|
|
@ -1,5 +1,5 @@
|
|||
export type RedirectTemplate = {
|
||||
from: string;
|
||||
from?: string;
|
||||
location: string | URL;
|
||||
status: number;
|
||||
};
|
||||
|
@ -14,6 +14,6 @@ export function redirectTemplate({ status, location, from }: RedirectTemplate) {
|
|||
<meta name="robots" content="noindex">
|
||||
<link rel="canonical" href="${location}">
|
||||
<body>
|
||||
<a href="${location}">Redirecting from <code>${from}</code> to <code>${location}</code></a>
|
||||
<a href="${location}">Redirecting ${from ? `from <code>${from}</code> ` : ''}to <code>${location}</code></a>
|
||||
</body>`;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,9 @@ import { appendForwardSlash } from '@astrojs/internal-helpers/path';
|
|||
import { bold } from 'kleur/colors';
|
||||
import type { Logger } from '../core/logger/core.js';
|
||||
import notFoundTemplate, { subpathNotUsedTemplate } from '../template/4xx.js';
|
||||
import { writeHtmlResponse } from './response.js';
|
||||
import { writeHtmlResponse, writeRedirectResponse } from './response.js';
|
||||
|
||||
const manySlashes = /\/{2,}$/;
|
||||
|
||||
export function baseMiddleware(
|
||||
settings: AstroSettings,
|
||||
|
@ -21,7 +23,10 @@ export function baseMiddleware(
|
|||
|
||||
return function devBaseMiddleware(req, res, next) {
|
||||
const url = req.url!;
|
||||
|
||||
if (manySlashes.test(url)) {
|
||||
const destination = url.replace(manySlashes, '/');
|
||||
return writeRedirectResponse(res, 301, destination);
|
||||
}
|
||||
let pathname: string;
|
||||
try {
|
||||
pathname = decodeURI(new URL(url, 'http://localhost').pathname);
|
||||
|
|
|
@ -7,6 +7,7 @@ import { Readable } from 'node:stream';
|
|||
import { getSetCookiesFromResponse } from '../core/cookies/index.js';
|
||||
import { getViteErrorPayload } from '../core/errors/dev/index.js';
|
||||
import notFoundTemplate from '../template/4xx.js';
|
||||
import { redirectTemplate } from '../core/routing/3xx.js';
|
||||
|
||||
export async function handle404Response(
|
||||
origin: string,
|
||||
|
@ -53,6 +54,17 @@ export function writeHtmlResponse(res: http.ServerResponse, statusCode: number,
|
|||
res.end();
|
||||
}
|
||||
|
||||
export function writeRedirectResponse(res: http.ServerResponse, statusCode: number, location: string) {
|
||||
const html = redirectTemplate({ status: statusCode, location });
|
||||
res.writeHead(statusCode, {
|
||||
Location: location,
|
||||
'Content-Type': 'text/html',
|
||||
'Content-Length': Buffer.byteLength(html, 'utf-8'),
|
||||
});
|
||||
res.write(html);
|
||||
res.end();
|
||||
}
|
||||
|
||||
export async function writeWebResponse(res: http.ServerResponse, webResponse: Response) {
|
||||
const { status, headers, body, statusText } = webResponse;
|
||||
|
||||
|
|
|
@ -48,6 +48,19 @@ describe('Development Routing', () => {
|
|||
assert.equal(response.status, 200);
|
||||
});
|
||||
|
||||
it('redirects when loading double slash', async () => {
|
||||
const response = await fixture.fetch('//', { redirect: 'manual' });
|
||||
assert.equal(response.status, 301);
|
||||
assert.equal(response.headers.get('Location'), '/');
|
||||
});
|
||||
|
||||
it('redirects when loading multiple slashes', async () => {
|
||||
const response = await fixture.fetch('/////', { redirect: 'manual' });
|
||||
assert.equal(response.status, 301);
|
||||
assert.equal(response.headers.get('Location'), '/');
|
||||
});
|
||||
|
||||
|
||||
it('404 when loading invalid dynamic route', async () => {
|
||||
const response = await fixture.fetch('/2');
|
||||
assert.equal(response.status, 404);
|
||||
|
|
Loading…
Reference in a new issue