Skip to content

Commit 006fe7e

Browse files
committed
🔧 fix: normalize path when necessary
1 parent a6dc9bf commit 006fe7e

File tree

4 files changed

+34
-23
lines changed

4 files changed

+34
-23
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
# 1.4.6 - 3 Nov 2025
2+
Bug fix:
3+
- normalize path only when unsafe
4+
- cache `crypto` package import
5+
16
# 1.4.5 - 1 Nov 2025
27
Bug fix:
38
- [#52](https://github.com/elysiajs/elysia-static/pull/52) resolve static paths correctly on Windows

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@elysiajs/static",
3-
"version": "1.4.5",
3+
"version": "1.4.6",
44
"license": "MIT",
55
"scripts": {
66
"dev": "bun run --watch example/index.ts",

src/index.ts

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ export async function staticPlugin<const Prefix extends string = '/prefix'>({
4949
if (!builtinModule) return new Elysia()
5050

5151
const [fs, path] = builtinModule
52+
const isUnsafeSep = path.sep !== '/'
53+
54+
const normalizePath = isUnsafeSep
55+
? (p: string) => p.replace(/\\/g, '/')
56+
: (p: string) => p
5257

5358
const fileCache = new LRUCache<string, Response>()
5459

@@ -79,24 +84,25 @@ export async function staticPlugin<const Prefix extends string = '/prefix'>({
7984
if (decodeURI)
8085
relativePath = fastDecodeURI(relativePath) ?? relativePath
8186

82-
let pathName = path.join(prefix, relativePath)
87+
let pathName = normalizePath(path.join(prefix, relativePath))
8388

8489
if (isBun && absolutePath.endsWith('.html')) {
8590
const htmlBundle = await import(absolutePath)
86-
const normalizedPath = pathName.replace(/\\/g, '/')
8791

88-
app.get(normalizedPath, htmlBundle.default)
89-
if (indexHTML && normalizedPath.endsWith('/index.html'))
92+
app.get(pathName, htmlBundle.default)
93+
if (indexHTML && pathName.endsWith('/index.html'))
9094
app.get(
91-
normalizedPath.replace('/index.html', ''),
95+
pathName.replace('/index.html', ''),
9296
htmlBundle.default
9397
)
9498

9599
continue
96100
}
97101

98102
if (!extension)
99-
pathName = pathName.slice(0, pathName.lastIndexOf('.'))
103+
pathName = normalizePath(
104+
pathName.slice(0, pathName.lastIndexOf('.'))
105+
)
100106

101107
const file: Awaited<ReturnType<typeof getFile>> = isBun
102108
? getFile(absolutePath)
@@ -182,9 +188,8 @@ export async function staticPlugin<const Prefix extends string = '/prefix'>({
182188

183189
return response.clone()
184190
}
185-
const normalizedPath = pathName.replace(/\\/g, '/')
186191
app.get(
187-
normalizedPath,
192+
pathName,
188193
useETag
189194
? (handleCache as any)
190195
: new Response(
@@ -197,9 +202,9 @@ export async function staticPlugin<const Prefix extends string = '/prefix'>({
197202
)
198203
)
199204

200-
if (indexHTML && normalizedPath.endsWith('/index.html'))
205+
if (indexHTML && pathName.endsWith('/index.html'))
201206
app.get(
202-
normalizedPath.replace('/index.html', ''),
207+
pathName.replace('/index.html', ''),
203208
useETag
204209
? (handleCache as any)
205210
: new Response(
@@ -227,14 +232,13 @@ export async function staticPlugin<const Prefix extends string = '/prefix'>({
227232
if (!absolutePath || shouldIgnore(absolutePath)) continue
228233

229234
let relativePath = absolutePath.replace(assetsDir, '')
230-
const pathName = path.join(prefix, relativePath)
231-
const normalizedPath = pathName.replace(/\\/g, '/')
235+
const pathName = normalizePath(path.join(prefix, relativePath))
232236
const htmlBundle = await import(absolutePath)
233237

234-
app.get(normalizedPath, htmlBundle.default)
235-
if (indexHTML && normalizedPath.endsWith('/index.html'))
238+
app.get(pathName, htmlBundle.default)
239+
if (indexHTML && pathName.endsWith('/index.html'))
236240
app.get(
237-
normalizedPath.replace('/index.html', ''),
241+
pathName.replace('/index.html', ''),
238242
htmlBundle.default
239243
)
240244
}
@@ -243,11 +247,13 @@ export async function staticPlugin<const Prefix extends string = '/prefix'>({
243247
app.onError(() => {}).get(
244248
`${prefix}/*`,
245249
async ({ params, headers: requestHeaders }) => {
246-
const pathName = path.join(
247-
assets,
248-
decodeURI
249-
? fastDecodeURI(params['*']) ?? params['*']
250-
: params['*']
250+
const pathName = normalizePath(
251+
path.join(
252+
assets,
253+
decodeURI
254+
? (fastDecodeURI(params['*']) ?? params['*'])
255+
: params['*']
256+
)
251257
)
252258

253259
if (shouldIgnore(pathName)) throw new NotFoundError()

src/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,8 @@ export async function generateETag(file: BunFile | Buffer<ArrayBufferLike>) {
204204
.update(await (file as BunFile).arrayBuffer())
205205
.digest('base64')
206206

207-
if (!crypto) Crypto = process.getBuiltinModule('crypto')
208-
if (!crypto)
207+
if (!Crypto) Crypto = process.getBuiltinModule('crypto')
208+
if (!Crypto)
209209
return void console.warn(
210210
'[@elysiajs/static] crypto is required to generate etag.'
211211
)

0 commit comments

Comments
 (0)