fix(cover): include Cache-Control and ETag in 304 responses

This commit is contained in:
neon
2026-04-04 04:11:36 -06:00
parent bab3813ff8
commit 585da64312
2 changed files with 8 additions and 6 deletions
@@ -159,13 +159,15 @@ describe('BookController', () => {
it('returns 304 when cover etag matches', async () => {
const { controller, bookService } = makeController();
const { reply } = makeReply();
const { reply, headers } = makeReply();
bookService.getCoverPath.mockResolvedValue('/tmp/cover.jpg');
mockStat.mockResolvedValue({ mtimeMs: 1234 } as never);
await controller.getCover(7, makeUser(), reply, '"1234"');
expect(reply.status).toHaveBeenCalledWith(304);
expect(headers['Cache-Control']).toBe('private, max-age=86400');
expect(headers['ETag']).toBe('"1234"');
expect(reply.send).toHaveBeenCalled();
expect(mockCreateReadStream).not.toHaveBeenCalled();
});
@@ -178,7 +180,7 @@ describe('BookController', () => {
await controller.getCover(7, makeUser(), reply, undefined);
expect(headers['Cache-Control']).toBe('no-cache');
expect(headers['Cache-Control']).toBe('private, max-age=86400');
expect(headers['ETag']).toBe('"4321"');
expect(reply.type).toHaveBeenCalledWith('image/png');
expect(mockCreateReadStream).toHaveBeenCalledWith('/tmp/cover.png');
+4 -4
View File
@@ -228,13 +228,13 @@ export class BookController {
const { mtimeMs } = await stat(coverPath);
const etag = `"${Math.floor(mtimeMs)}"`;
if (ifNoneMatch === etag) {
reply.status(304).send();
reply.status(304).header('Cache-Control', 'private, max-age=86400').header('ETag', etag).send();
return;
}
const ext = coverPath.split('.').pop()?.toLowerCase();
const contentType = ext === 'png' ? 'image/png' : 'image/jpeg';
reply.header('Cache-Control', 'no-cache');
reply.header('Cache-Control', 'private, max-age=86400');
reply.header('ETag', etag);
reply.type(contentType);
reply.send(createReadStream(coverPath));
@@ -253,11 +253,11 @@ export class BookController {
const { mtimeMs } = await stat(thumbnailPath);
const etag = `"${Math.floor(mtimeMs)}"`;
if (ifNoneMatch === etag) {
reply.status(304).send();
reply.status(304).header('Cache-Control', 'private, max-age=86400').header('ETag', etag).send();
return;
}
reply.header('Cache-Control', 'no-cache');
reply.header('Cache-Control', 'private, max-age=86400');
reply.header('ETag', etag);
reply.type('image/jpeg');
reply.send(createReadStream(thumbnailPath));