diff --git a/src/serve-static.ts b/src/serve-static.ts index f72d425..d28ded4 100644 --- a/src/serve-static.ts +++ b/src/serve-static.ts @@ -105,7 +105,6 @@ export const serveStatic = ( await options.onNotFound?.(path, c) return next() } - await options.onFound?.(path, c) const mimeType = getMimeType(path) c.header('Content-Type', mimeType || 'application/octet-stream') @@ -133,37 +132,38 @@ export const serveStatic = ( } } + let result const size = stats.size + const range = c.req.header('range') || '' if (c.req.method == 'HEAD' || c.req.method == 'OPTIONS') { c.header('Content-Length', size.toString()) c.status(200) - return c.body(null) - } - - const range = c.req.header('range') || '' - - if (!range) { + result = c.body(null) + } else if (!range) { c.header('Content-Length', size.toString()) - return c.body(createStreamBody(createReadStream(path)), 200) - } - - c.header('Accept-Ranges', 'bytes') - c.header('Date', stats.birthtime.toUTCString()) + result = c.body(createStreamBody(createReadStream(path)), 200) + } else { + c.header('Accept-Ranges', 'bytes') + c.header('Date', stats.birthtime.toUTCString()) + + const parts = range.replace(/bytes=/, '').split('-', 2) + const start = parseInt(parts[0], 10) || 0 + let end = parseInt(parts[1], 10) || size - 1 + if (size < end - start + 1) { + end = size - 1 + } - const parts = range.replace(/bytes=/, '').split('-', 2) - const start = parseInt(parts[0], 10) || 0 - let end = parseInt(parts[1], 10) || size - 1 - if (size < end - start + 1) { - end = size - 1 - } + const chunksize = end - start + 1 + const stream = createReadStream(path, { start, end }) - const chunksize = end - start + 1 - const stream = createReadStream(path, { start, end }) + c.header('Content-Length', chunksize.toString()) + c.header('Content-Range', `bytes ${start}-${end}/${stats.size}`) - c.header('Content-Length', chunksize.toString()) - c.header('Content-Range', `bytes ${start}-${end}/${stats.size}`) + result = c.body(createStreamBody(stream), 206) + } - return c.body(createStreamBody(stream), 206) + await options.onFound?.(path, c) + return result } } diff --git a/test/serve-static.test.ts b/test/serve-static.test.ts index d35f751..d2d3692 100644 --- a/test/serve-static.test.ts +++ b/test/serve-static.test.ts @@ -18,6 +18,9 @@ describe('Serve Static Middleware', () => { root: './test/assets', onFound: (path, c) => { c.header('X-Custom', `Found the file at ${path}`) + if (c.req.query('type')) { + c.header('Content-Type', c.req.query('type')) + } }, }) ) @@ -182,6 +185,14 @@ describe('Serve Static Middleware', () => { ) }) + it('Should handle the `onFound` option', async () => { + const res = await request(server).get( + '/static/data.json?type=application/json;%20charset=utf-8' + ) + expect(res.status).toBe(200) + expect(res.headers['content-type']).toBe('application/json; charset=utf-8') + }) + it('Should handle double dots in URL', async () => { const res = await request(server).get('/static/../secret.txt') expect(res.status).toBe(404)