Skip to content

Commit 1fdc800

Browse files
authored
fix: deduplicate HEAD entry in 405 response allow header (#14564)
* deduplicate items in allow header * changeset * add test * clarify comment * format
1 parent d4dd214 commit 1fdc800

File tree

4 files changed

+29
-1
lines changed

4 files changed

+29
-1
lines changed

.changeset/salty-candles-chew.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': patch
3+
---
4+
5+
fix: avoid including `HEAD` twice when an unhandled HTTP method is used in a request to a `+server` handler that has both a `GET` handler and a `HEAD` handler

packages/kit/src/runtime/server/utils.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,11 @@ export function method_not_allowed(mod, method) {
3939
export function allowed_methods(mod) {
4040
const allowed = ENDPOINT_METHODS.filter((method) => method in mod);
4141

42-
if ('GET' in mod || 'HEAD' in mod) allowed.push('HEAD');
42+
// if there's no HEAD handler, but we have a GET handler, we respond to
43+
// HEAD requests using the GET handler and omit the response body.
44+
if ('GET' in mod && !('HEAD' in mod)) {
45+
allowed.push('HEAD');
46+
}
4347

4448
return allowed;
4549
}

packages/kit/test/apps/basics/src/routes/endpoint-output/head-handler/+server.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
// The GET handler is included alongside the HEAD handler to test that HEAD
2+
// is not included twice in the `allow` header list of allowed methods.
3+
// This is because HEAD is always allowed if GET is allowed too
4+
export function GET() {
5+
return new Response('Hello world!');
6+
}
7+
18
/** @type {import('@sveltejs/kit').RequestHandler} */
29
export function HEAD() {
310
return new Response('', {

packages/kit/test/apps/basics/test/server.test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,18 @@ test.describe('Endpoints', () => {
281281
expect(allow_header).toMatch(/\bHEAD\b/);
282282
});
283283

284+
test('405 allow header has no duplicate methods listed', async ({ request }) => {
285+
const response = await request.post('/endpoint-output/head-handler');
286+
287+
expect(response.status()).toBe(405);
288+
289+
const allow_header = response.headers()['allow'];
290+
const methods = allow_header.split(',').map((m) => m.trim());
291+
const unique_methods = [...new Set(methods)];
292+
293+
expect(methods).toEqual(unique_methods);
294+
});
295+
284296
// TODO all the remaining tests in this section are really only testing
285297
// setResponse, since we're not otherwise changing anything on the response.
286298
// might be worth making these unit tests instead

0 commit comments

Comments
 (0)