Skip to content

Commit a0a9782

Browse files
committed
feat: trailing slash middleware handles HEAD request
1 parent 808e520 commit a0a9782

File tree

2 files changed

+92
-2
lines changed

2 files changed

+92
-2
lines changed

src/middleware/trailing-slash/index.test.ts

+86
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,46 @@ describe('Resolve trailing slash', () => {
4545
expect(loc.pathname).toBe('/the/example/endpoint/without/trailing/slash')
4646
expect(loc.searchParams.get('exampleParam')).toBe('1')
4747
})
48+
49+
it('should handle HEAD request for root path correctly', async () => {
50+
const resp = await app.request('/', { method: 'HEAD' })
51+
52+
expect(resp).not.toBeNull()
53+
expect(resp.status).toBe(200)
54+
})
55+
56+
it('should handle HEAD request for path without trailing slash correctly', async () => {
57+
const resp = await app.request('/the/example/endpoint/without/trailing/slash', {
58+
method: 'HEAD',
59+
})
60+
61+
expect(resp).not.toBeNull()
62+
expect(resp.status).toBe(200)
63+
})
64+
65+
it('should handle HEAD request for path with trailing slash correctly', async () => {
66+
const resp = await app.request('/the/example/endpoint/without/trailing/slash/', {
67+
method: 'HEAD',
68+
})
69+
const loc = new URL(resp.headers.get('location')!)
70+
71+
expect(resp).not.toBeNull()
72+
expect(resp.status).toBe(301)
73+
expect(loc.pathname).toBe('/the/example/endpoint/without/trailing/slash')
74+
})
75+
76+
it('should preserve query parameters when redirecting HEAD requests', async () => {
77+
const resp = await app.request(
78+
'/the/example/endpoint/without/trailing/slash/?exampleParam=1',
79+
{ method: 'HEAD' }
80+
)
81+
const loc = new URL(resp.headers.get('location')!)
82+
83+
expect(resp).not.toBeNull()
84+
expect(resp.status).toBe(301)
85+
expect(loc.pathname).toBe('/the/example/endpoint/without/trailing/slash')
86+
expect(loc.searchParams.get('exampleParam')).toBe('1')
87+
})
4888
})
4989

5090
describe('appendTrailingSlash middleware', () => {
@@ -100,5 +140,51 @@ describe('Resolve trailing slash', () => {
100140
expect(loc.pathname).toBe('/the/example/endpoint/with/trailing/slash/')
101141
expect(loc.searchParams.get('exampleParam')).toBe('1')
102142
})
143+
144+
it('should handle HEAD request for root path correctly', async () => {
145+
const resp = await app.request('/', { method: 'HEAD' })
146+
147+
expect(resp).not.toBeNull()
148+
expect(resp.status).toBe(200)
149+
})
150+
151+
it('should handle HEAD request for file-like paths correctly', async () => {
152+
const resp = await app.request('/the/example/simulate/a.file', { method: 'HEAD' })
153+
154+
expect(resp).not.toBeNull()
155+
expect(resp.status).toBe(200)
156+
})
157+
158+
it('should handle HEAD request for path with trailing slash correctly', async () => {
159+
const resp = await app.request('/the/example/endpoint/with/trailing/slash/', {
160+
method: 'HEAD',
161+
})
162+
163+
expect(resp).not.toBeNull()
164+
expect(resp.status).toBe(200)
165+
})
166+
167+
it('should redirect HEAD request for path without trailing slash to one with it', async () => {
168+
const resp = await app.request('/the/example/endpoint/with/trailing/slash', {
169+
method: 'HEAD',
170+
})
171+
const loc = new URL(resp.headers.get('location')!)
172+
173+
expect(resp).not.toBeNull()
174+
expect(resp.status).toBe(301)
175+
expect(loc.pathname).toBe('/the/example/endpoint/with/trailing/slash/')
176+
})
177+
178+
it('should preserve query parameters when redirecting HEAD requests', async () => {
179+
const resp = await app.request('/the/example/endpoint/with/trailing/slash?exampleParam=1', {
180+
method: 'HEAD',
181+
})
182+
const loc = new URL(resp.headers.get('location')!)
183+
184+
expect(resp).not.toBeNull()
185+
expect(resp.status).toBe(301)
186+
expect(loc.pathname).toBe('/the/example/endpoint/with/trailing/slash/')
187+
expect(loc.searchParams.get('exampleParam')).toBe('1')
188+
})
103189
})
104190
})

src/middleware/trailing-slash/index.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const trimTrailingSlash = (): MiddlewareHandler => {
2626

2727
if (
2828
c.res.status === 404 &&
29-
c.req.method === 'GET' &&
29+
(c.req.method === 'GET' || c.req.method === 'HEAD') &&
3030
c.req.path !== '/' &&
3131
c.req.path.at(-1) === '/'
3232
) {
@@ -57,7 +57,11 @@ export const appendTrailingSlash = (): MiddlewareHandler => {
5757
return async function appendTrailingSlash(c, next) {
5858
await next()
5959

60-
if (c.res.status === 404 && c.req.method === 'GET' && c.req.path.at(-1) !== '/') {
60+
if (
61+
c.res.status === 404 &&
62+
(c.req.method === 'GET' || c.req.method === 'HEAD') &&
63+
c.req.path.at(-1) !== '/'
64+
) {
6165
const url = new URL(c.req.url)
6266
url.pathname += '/'
6367

0 commit comments

Comments
 (0)