0
0
mirror of https://github.com/honojs/hono.git synced 2024-11-21 18:18:57 +01:00

fix(serve-static):supports directory contains . and not ends / (#3256)

This commit is contained in:
Yusuke Wada 2024-08-11 13:01:29 +09:00 committed by GitHub
parent ac069d1696
commit 7a254bc0c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 73 additions and 1 deletions

View File

@ -145,6 +145,18 @@ describe('Serve Static Middleware', () => {
expect(res.status).toBe(200)
expect(await res.text()).toBe('Bun!!')
})
it('Should return 200 response - /static/helloworld', async () => {
const res = await app.request('http://localhost/static/helloworld')
expect(res.status).toBe(200)
expect(await res.text()).toBe('Hi\n')
})
it('Should return 200 response - /static/hello.world', async () => {
const res = await app.request('http://localhost/static/hello.world')
expect(res.status).toBe(200)
expect(await res.text()).toBe('Hi\n')
})
})
// Bun support WebCrypto since v0.2.2

View File

@ -0,0 +1 @@
Hi

View File

@ -0,0 +1 @@
Hi

View File

@ -123,6 +123,14 @@ Deno.test('Serve Static middleware', async () => {
} as Request)
assertEquals(res.status, 404)
assertEquals(await res.text(), '404 Not Found')
res = await app.request('http://localhost/static/helloworld')
assertEquals(res.status, 200)
assertEquals(await res.text(), 'Hi\n')
res = await app.request('http://localhost/static/hello.world')
assertEquals(res.status, 200)
assertEquals(await res.text(), 'Hi\n')
})
Deno.test('JWT Authentication middleware', async () => {

View File

@ -0,0 +1 @@
Hi

View File

@ -0,0 +1 @@
Hi

View File

@ -2,6 +2,7 @@
import { serveStatic as baseServeStatic } from '../../middleware/serve-static'
import type { ServeStaticOptions } from '../../middleware/serve-static'
import type { Env, MiddlewareHandler } from '../../types'
import { stat } from 'node:fs/promises'
export const serveStatic = <E extends Env = Env>(
options: ServeStaticOptions<E>
@ -16,10 +17,19 @@ export const serveStatic = <E extends Env = Env>(
const pathResolve = (path: string) => {
return `./${path}`
}
const isDir = async (path: string) => {
let isDir
try {
const stats = await stat(path)
isDir = stats.isDirectory()
} catch {}
return isDir
}
return baseServeStatic({
...options,
getContent,
pathResolve,
isDir,
})(c, next)
}
}

View File

@ -4,7 +4,7 @@ import type { Env, MiddlewareHandler } from '../../types'
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const { open } = Deno
const { open, lstatSync } = Deno
export const serveStatic = <E extends Env = Env>(
options: ServeStaticOptions<E>
@ -22,10 +22,19 @@ export const serveStatic = <E extends Env = Env>(
const pathResolve = (path: string) => {
return `./${path}`
}
const isDir = (path: string) => {
let isDir
try {
const stat = lstatSync(path)
isDir = stat.isDirectory
} catch {}
return isDir
}
return baseServeStatic({
...options,
getContent,
pathResolve,
isDir,
})(c, next)
}
}

View File

@ -15,6 +15,9 @@ describe('Serve Static Middleware', () => {
pathResolve: (path) => {
return `./${path}`
},
isDir: (path) => {
return path === 'static/hello.world'
},
})
app.get('/static/*', serveStatic)
@ -37,6 +40,20 @@ describe('Serve Static Middleware', () => {
expect(await res.text()).toBe('Hello in ./static/sub/index.html')
})
it('Should return 200 response - /static/helloworld', async () => {
const res = await app.request('/static/helloworld')
expect(res.status).toBe(200)
expect(res.headers.get('Content-Type')).toMatch(/^text\/html/)
expect(await res.text()).toBe('Hello in ./static/helloworld/index.html')
})
it('Should return 200 response - /static/hello.world', async () => {
const res = await app.request('/static/hello.world')
expect(res.status).toBe(200)
expect(res.headers.get('Content-Type')).toMatch(/^text\/html/)
expect(await res.text()).toBe('Hello in ./static/hello.world/index.html')
})
it('Should decode URI strings - /static/%E7%82%8E.txt', async () => {
const res = await app.request('/static/%E7%82%8E.txt')
expect(res.status).toBe(200)

View File

@ -26,6 +26,7 @@ export const serveStatic = <E extends Env = Env>(
options: ServeStaticOptions<E> & {
getContent: (path: string, c: Context<E>) => Promise<Data | Response | null>
pathResolve?: (path: string) => string
isDir?: (path: string) => boolean | undefined | Promise<boolean | undefined>
}
): MiddlewareHandler => {
return async (c, next) => {
@ -39,6 +40,17 @@ export const serveStatic = <E extends Env = Env>(
filename = options.rewriteRequestPath ? options.rewriteRequestPath(filename) : filename
const root = options.root
// If it was Directory, force `/` on the end.
if (!filename.endsWith('/') && options.isDir) {
const path = getFilePathWithoutDefaultDocument({
filename,
root,
})
if (path && (await options.isDir(path))) {
filename = filename + '/'
}
}
let path = getFilePath({
filename,
root,