From aeed0e14a04e22adb8c46049605b87319d9c5e04 Mon Sep 17 00:00:00 2001 From: Cezar Augusto Date: Sun, 20 Sep 2026 09:57:16 -0300 Subject: [PATCH] fix: send a one-byte asset with its byte instead of Content-Length 0 --- src/middleware.js | 2 ++ src/utils/compatibleAPI.js | 7 +++++-- test/middleware.test.js | 23 +++++++++++++++++++++++ types/utils/compatibleAPI.d.ts | 2 ++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/middleware.js b/src/middleware.js index 45cce79..55fa0bf 100644 --- a/src/middleware.js +++ b/src/middleware.js @@ -703,6 +703,7 @@ function wrapper(context) { extra.outputFileSystem, start, end, + len, ); ({ bufferOrStream, byteLength } = result); @@ -848,6 +849,7 @@ function wrapper(context) { extra.outputFileSystem, start, end, + len, )); } catch (error) { await errorHandler(/** @type {NodeJS.ErrnoException} */ (error)); diff --git a/src/utils/compatibleAPI.js b/src/utils/compatibleAPI.js index 2800981..0175315 100644 --- a/src/utils/compatibleAPI.js +++ b/src/utils/compatibleAPI.js @@ -218,6 +218,7 @@ function finish(res, data) { * @param {OutputFileSystem} outputFileSystem output file system * @param {number} start start * @param {number} end end + * @param {number} len byte length of the range, or of the whole file * @returns {{ bufferOrStream: (Buffer | import("fs").ReadStream), byteLength: number }} result with buffer or stream and byte length */ function createReadStreamOrReadFileSync( @@ -225,6 +226,7 @@ function createReadStreamOrReadFileSync( outputFileSystem, start, end, + len, ) { /** @type {Buffer | import("fs").ReadStream} */ let bufferOrStream; @@ -243,8 +245,9 @@ function createReadStreamOrReadFileSync( end, }); - // Handle files with zero bytes - byteLength = end === 0 ? 0 : end - start + 1; + // An empty file and a one-byte file both end at offset 0, so the length + // is the caller's byte count. A stat without a size keeps the arithmetic + byteLength = Number.isFinite(len) ? len : end - start + 1; } else { bufferOrStream = outputFileSystem.readFileSync(filename); ({ byteLength } = bufferOrStream); diff --git a/test/middleware.test.js b/test/middleware.test.js index 52d24c1..5cb5898 100644 --- a/test/middleware.test.js +++ b/test/middleware.test.js @@ -1053,6 +1053,10 @@ describe.each([ path.resolve(outputPath, "empty-file.txt"), "", ); + instance.context.outputFileSystem.writeFileSync( + path.resolve(outputPath, "one-byte.txt"), + "a", + ); }); afterAll(async () => { @@ -1463,6 +1467,25 @@ describe.each([ ); }); + it('should return "200" code for the "GET" request and "Content-Length" of "1" when file has one byte', async () => { + const response = await req.get("/one-byte.txt"); + + expect(response.statusCode).toBe(200); + expect(response.headers["content-length"]).toBe("1"); + expect(response.text).toBe("a"); + }); + + it('should return "206" code for the "GET" request with a one-byte range', async () => { + const response = await req + .get("/one-byte.txt") + .set("Range", "bytes=0-0"); + + expect(response.statusCode).toBe(206); + expect(response.headers["content-range"]).toBe("bytes 0-0/1"); + expect(response.headers["content-length"]).toBe("1"); + expect(response.text).toBe("a"); + }); + it('should return the "200" code for the "GET" request to the "image image.svg" file', async () => { const fileData = instance.context.outputFileSystem.readFileSync( path.resolve(outputPath, "image image.svg"), diff --git a/types/utils/compatibleAPI.d.ts b/types/utils/compatibleAPI.d.ts index 01c077e..1cf7b13 100644 --- a/types/utils/compatibleAPI.d.ts +++ b/types/utils/compatibleAPI.d.ts @@ -218,6 +218,7 @@ declare function finish< * @param {OutputFileSystem} outputFileSystem output file system * @param {number} start start * @param {number} end end + * @param {number} len byte length of the range, or of the whole file * @returns {{ bufferOrStream: (Buffer | import("fs").ReadStream), byteLength: number }} result with buffer or stream and byte length */ declare function createReadStreamOrReadFileSync( @@ -225,6 +226,7 @@ declare function createReadStreamOrReadFileSync( outputFileSystem: OutputFileSystem, start: number, end: number, + len: number, ): { bufferOrStream: Buffer | import("fs").ReadStream; byteLength: number;