Skip to content

feat(serve-static): support absolute path#257

Merged
yusukebe merged 16 commits into
mainfrom
feat/serve-static-absolute-path
Jul 19, 2025
Merged

feat(serve-static): support absolute path#257
yusukebe merged 16 commits into
mainfrom
feat/serve-static-absolute-path

Conversation

@yusukebe

@yusukebe yusukebe commented Jul 14, 2025

Copy link
Copy Markdown
Member

Fixies #187
Related to #203 #238

This PR enables serve-static to support absolute paths, but both root and path options.

I considered that we should move the serve-static feature to the main honojs/hono core related to #203 honojs/hono#3483. However, if so, we need to update the peer dependencies for hono so that we can add this feature to this project separately from honojs/hono.

Comment thread package.json
},
"scripts": {
"test": "node --expose-gc ./node_modules/.bin/jest",
"test": "node --expose-gc node_modules/jest/bin/jest.js",

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To support Windows on CI.

@yusukebe
yusukebe marked this pull request as ready for review July 14, 2025 23:08
@yusukebe

Copy link
Copy Markdown
Member Author

Hi @usualoma

Can you review this, please?

@usualoma usualoma left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @yusukebe

Thanks for creating the pull request.
I've added a comment, so please check it out.

Comment thread src/serve-static.ts Outdated
Comment thread src/serve-static.ts Outdated
Comment thread test/serve-static.test.ts Outdated
Comment thread test/serve-static.test.ts
Comment thread test/serve-static.test.ts
expect(res.text).toBe('<h1>Hello Hono</h1>')
expect(res.headers['content-type']).toBe('text/html; charset=utf-8')
expect(res.headers['x-custom']).toBe('Found the file at ./test/assets/static/index.html')
expect(res.headers['x-custom']).toMatch(

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To simplify implementation, make the path passed to onFound an absolute path.

app.use(
  '/static/*',
  serveStatic({
    root: './test/assets',
    onFound: (path, c) => {
      // path is an absolute path
      c.header('X-Custom', `Found the file at ${path}`)
    },
  })
)

@yusukebe

Copy link
Copy Markdown
Member Author

@usualoma

Thank you for reviewing. I made it simple using Node.js API. What do you think of this?

Comment thread src/serve-static.ts Outdated
path = addCurrentDirPrefix(path)
} else {
// Security check: prevent path traversal attacks
if (!optionPath && !path.startsWith(rootResolved)) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

path.startsWith(rootResolved)

Comment thread src/serve-static.ts Outdated
Comment thread src/serve-static.ts Outdated
path = addCurrentDirPrefix(path)
if (optionPath) {
// Use path option directly if specified
path = resolve(optionPath)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the current main branch, I think "root" is also used here.

Suggested change
path = resolve(optionPath)
path = resolve(join(optionRoot, optionPath))

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@usualoma Thanks.

I think join is not needed, so it should beresolve(optionRoot, optionPath).

I aslo added the tests and the change is here:

f6f5b90

What do you think of this?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yusukebe Thank you!

The behavior when specifying an absolute path in path will change from before.

app.use('*', serveStatic({
    root: 'public',
    path: '/file.html',
}))

Previously, it behaved as if it joined to root. If this is an intentional change in behavior, I think it's OK.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@usualoma

Thank you for pointing that out! It's better to keep the current behavior. I updated the code: d26e6ee

Please review it!

yusukebe and others added 2 commits July 17, 2025 07:34
Co-authored-by: Taku Amano <taku@taaas.jp>
Co-authored-by: Taku Amano <taku@taaas.jp>
@yusukebe
yusukebe force-pushed the feat/serve-static-absolute-path branch from 18ebc11 to 8f15053 Compare July 16, 2025 22:39

@usualoma usualoma left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. LGTM!

@yusukebe

Copy link
Copy Markdown
Member Author

@usualoma Thank you for reviewing!

Landing it.

@yusukebe
yusukebe merged commit a0be2f4 into main Jul 19, 2025
4 checks passed
@yusukebe
yusukebe deleted the feat/serve-static-absolute-path branch July 19, 2025 00:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants