From 93e3b30535ed0807781c43d86296818f55ab1b68 Mon Sep 17 00:00:00 2001 From: Kevin Payravi Date: Sat, 9 May 2026 04:35:09 +0200 Subject: [PATCH 1/2] Fix: Headers not forwarded to clients --- src/ResponseHelper.ts | 20 ++++++++------------ test/unit/ResponseHelper.test.ts | 6 +++--- test/unit/ThumbnailApi.test.ts | 8 ++++---- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/ResponseHelper.ts b/src/ResponseHelper.ts index e34c763..290a057 100644 --- a/src/ResponseHelper.ts +++ b/src/ResponseHelper.ts @@ -40,23 +40,19 @@ export class ResponseHelper { } //providers/s3 could set all sorts of weird headers, but we only want to pass along a few - getHeadersFromTarget(headers: Headers): Map { - const result = new Map(); + getHeadersFromTarget(headers: Headers): Record { + const result: Record = {}; - const addHeader = ( - result: Map, - headers: Headers, - header: string, - ) => { + const addHeader = (header: string) => { const value = headers.get(header); - if (value) { - result.set(header, value); + + if (value !== null) { + result[header] = value; } }; - // Reduce headers to just those that we want to pass through - addHeader(result, headers, "Content-Type"); - addHeader(result, headers, "Last-Modified"); + addHeader("Content-Type"); + addHeader("Last-Modified"); return result; } diff --git a/test/unit/ResponseHelper.test.ts b/test/unit/ResponseHelper.test.ts index 0583d45..a48d1f6 100644 --- a/test/unit/ResponseHelper.test.ts +++ b/test/unit/ResponseHelper.test.ts @@ -16,9 +16,9 @@ describe("ResponseHelper", () => { ["foo", "bar"], ]); const result = responseHelper.getHeadersFromTarget(headers); - expect(result.get("Content-Type")).toBe("image/jpeg"); - expect(result.get("Last-Modified")).toBe("2"); - expect(result.get("foo")).toBeUndefined(); + expect(result["Content-Type"]).toBe("image/jpeg"); + expect(result["Last-Modified"]).toBe("2"); + expect(result["foo"]).toBeUndefined(); }); test.each([ diff --git a/test/unit/ThumbnailApi.test.ts b/test/unit/ThumbnailApi.test.ts index 1058510..4e68e68 100644 --- a/test/unit/ThumbnailApi.test.ts +++ b/test/unit/ThumbnailApi.test.ts @@ -119,7 +119,7 @@ describe("ThumbnailApi async tests", () => { responseHelper.getHeadersFromTarget = (headers: Headers) => { expect(headers).toBeDefined(); - return new Map([["content-type", "image/jpeg"]]); + return { "content-type": "image/jpeg" }; }; const mockPipe = jest.fn(); @@ -160,7 +160,7 @@ describe("ThumbnailApi async tests", () => { status: 200, } as Response), ); - responseHelper.getHeadersFromTarget = jest.fn(() => new Map()); + responseHelper.getHeadersFromTarget = jest.fn(() => ({})); responseHelper.translateStatusCode = jest.fn(() => 200); responseHelper.okBody = okBody; @@ -206,7 +206,7 @@ describe("ThumbnailApi async tests", () => { } as Response), ); responseHelper.getHeadersFromTarget = jest.fn( - () => new Map([["content-type", "image/jpeg"]]), + () => ({ "content-type": "image/jpeg" }), ); responseHelper.translateStatusCode = jest.fn(() => 200); responseHelper.okBody = okBody; @@ -396,7 +396,7 @@ describe("ThumbnailApi async tests", () => { responseHelper.getHeadersFromTarget = (headers: Headers) => { expect(headers).toBeDefined(); - return new Map([["content-type", "image/jpeg"]]); + return { "content-type": "image/jpeg" }; }; const okStatus = jest.fn(() => false); From e6bf29fc5a43e1a1f61f31c9e16f2de87324d72c Mon Sep 17 00:00:00 2001 From: Kevin Payravi Date: Sat, 9 May 2026 05:06:22 +0200 Subject: [PATCH 2/2] Override Content-Type All thumbnails in S3 are stored as .jpg, but may not be stored with the correct content type, causing S3 to return application/octet-stream as the default value. This overrides the Content-Type to ensure clients always receive type image/jpeg. --- src/ThumbnailApi.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/ThumbnailApi.ts b/src/ThumbnailApi.ts index 811488e..7fecaf5 100644 --- a/src/ThumbnailApi.ts +++ b/src/ThumbnailApi.ts @@ -156,9 +156,13 @@ export class ThumbnailApi { } try { - expressResponse.set( - this.responseHelper.getHeadersFromTarget(response.headers), - ); + const headers = this.responseHelper.getHeadersFromTarget(response.headers); + // All thumbnails in S3 are stored as .jpg, + // but may not be stored with the correct content type, + // causing S3 to return application/octet-stream as the default value. + // This overrides the Content-Type to ensure clients always receive type image/jpeg. + headers["Content-Type"] = "image/jpeg"; + expressResponse.set(headers); } catch (err) { this.releaseUpstreamBody(response); const error = err instanceof Error