From b21cc761c632bd9533d08abd33e5f9fd715d2e92 Mon Sep 17 00:00:00 2001 From: miyamonz Date: Tue, 1 Aug 2023 15:17:39 +0900 Subject: [PATCH 1/2] support absolute root path --- src/getFilePathforAbsRoot.test.ts | 8 +++++++ src/getFilePathforAbsRoot.ts | 23 ++++++++++++++++++ src/serve-static.ts | 39 ++++++++++++++++++------------- 3 files changed, 54 insertions(+), 16 deletions(-) create mode 100644 src/getFilePathforAbsRoot.test.ts create mode 100644 src/getFilePathforAbsRoot.ts diff --git a/src/getFilePathforAbsRoot.test.ts b/src/getFilePathforAbsRoot.test.ts new file mode 100644 index 0000000..2d1901b --- /dev/null +++ b/src/getFilePathforAbsRoot.test.ts @@ -0,0 +1,8 @@ +import { getFilePathforAbsRoot } from './getFilePathforAbsRoot' + +describe('getFilePathforAbsRoot', () => { + it('Should return file path correctly', async () => { + expect(getFilePathforAbsRoot({ filename: 'foo', root: '/bar' })).toBe('/bar/foo/index.html') + expect(getFilePathforAbsRoot({ filename: 'foo.txt', root: '/bar' })).toBe('/bar/foo.txt') + }) +}) diff --git a/src/getFilePathforAbsRoot.ts b/src/getFilePathforAbsRoot.ts new file mode 100644 index 0000000..7dfdefc --- /dev/null +++ b/src/getFilePathforAbsRoot.ts @@ -0,0 +1,23 @@ +import { getFilePath } from 'hono/utils/filepath' + +/** + * wrapper for getFilePath, with absolute root path + */ +export function getFilePathforAbsRoot(options: { + root: string + filename: string + defaultDocument?: string +}) { + if (!options.root.startsWith('/')) { + throw new Error('root must be absolute path') + } + + const path = getFilePath({ + filename: options.filename, + defaultDocument: options.defaultDocument, + }) + if (!path) return undefined + + const root = options.root + (options.root?.endsWith('/') ? '' : '/') + return root + path +} diff --git a/src/serve-static.ts b/src/serve-static.ts index 7f59276..ffab9d1 100644 --- a/src/serve-static.ts +++ b/src/serve-static.ts @@ -1,6 +1,7 @@ import type { MiddlewareHandler } from 'hono' import { ReadStream, createReadStream, existsSync, lstatSync } from 'fs' import { getFilePath } from 'hono/utils/filepath' +import { getFilePathforAbsRoot } from './getFilePathforAbsRoot' import { getMimeType } from 'hono/utils/mime' export type ServeStaticOptions = { @@ -38,27 +39,33 @@ export const serveStatic = (options: ServeStaticOptions = { root: '' }): Middlew const url = new URL(c.req.url) - const filename = options.path ?? decodeURIComponent(url.pathname) - let path = getFilePath({ - filename: options.rewriteRequestPath ? options.rewriteRequestPath(filename) : filename, - root: options.root, - defaultDocument: options.index ?? 'index.html', - }) - - if (!path) return next() - - path = `./${path}` - - if (!existsSync(path)) { + const path = options.path ?? decodeURIComponent(url.pathname) + const filename = options.rewriteRequestPath?.(path) ?? path + const defaultDocument = options.index ?? 'index.html' + + const filePath = options.root?.startsWith('/') + ? getFilePathforAbsRoot({ + filename, + root: options.root, + defaultDocument, + }) + : './' + + getFilePath({ + filename, + root: options.root, + defaultDocument, + }) + + if (!filePath || !existsSync(filePath)) { return next() } - const mimeType = getMimeType(path) + const mimeType = getMimeType(filePath) if (mimeType) { c.header('Content-Type', mimeType) } - const stat = lstatSync(path) + const stat = lstatSync(filePath) const size = stat.size if (c.req.method == 'HEAD' || c.req.method == 'OPTIONS') { @@ -71,7 +78,7 @@ export const serveStatic = (options: ServeStaticOptions = { root: '' }): Middlew if (!range) { c.header('Content-Length', size.toString()) - return c.body(createStreamBody(createReadStream(path)), 200) + return c.body(createStreamBody(createReadStream(filePath)), 200) } c.header('Accept-Ranges', 'bytes') @@ -88,7 +95,7 @@ export const serveStatic = (options: ServeStaticOptions = { root: '' }): Middlew } const chunksize = end - start + 1 - const stream = createReadStream(path, { start, end }) + const stream = createReadStream(filePath, { start, end }) c.header('Content-Length', chunksize.toString()) c.header('Content-Range', `bytes ${start}-${end}/${stat.size}`) From 89b81043fa9f2a24269f177040ad39f8e7abf930 Mon Sep 17 00:00:00 2001 From: miyamonz Date: Tue, 1 Aug 2023 15:21:36 +0900 Subject: [PATCH 2/2] fix comment --- src/serve-static.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serve-static.ts b/src/serve-static.ts index ffab9d1..ead1e49 100644 --- a/src/serve-static.ts +++ b/src/serve-static.ts @@ -6,7 +6,7 @@ import { getMimeType } from 'hono/utils/mime' export type ServeStaticOptions = { /** - * Root path, relative to current working directory. (absolute paths are not supported) + * Root path, relative to current working directory or absolte path. */ root?: string path?: string