From 2e3faf14773d42dd0ae3fc73d7943e131e6a40ff Mon Sep 17 00:00:00 2001 From: cboar Date: Wed, 10 Sep 2025 15:06:28 -0700 Subject: [PATCH] fix: prevent unnecessary flattening of headers during convertRes --- packages/open-next/src/core/routing/util.ts | 3 ++- .../open-next/src/http/openNextResponse.ts | 4 +-- packages/open-next/src/http/util.ts | 27 +++++++++++++------ 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/packages/open-next/src/core/routing/util.ts b/packages/open-next/src/core/routing/util.ts index 99aa45850..abc7e14a9 100644 --- a/packages/open-next/src/core/routing/util.ts +++ b/packages/open-next/src/core/routing/util.ts @@ -102,8 +102,9 @@ export function convertRes(res: OpenNextNodeResponse): InternalResult { // When using HEAD requests, it seems that flushHeaders is not called, not sure why // Probably some kind of race condition const headers = parseHeaders(res.getFixedHeaders()); + const contentType = headers["content-type"]; const isBase64Encoded = - isBinaryContentType(headers["content-type"]) || + (typeof contentType === "string" && isBinaryContentType(contentType)) || !!headers["content-encoding"]; // We cannot convert the OpenNextNodeResponse to a ReadableStream directly // You can look in the `aws-lambda.ts` file for some context diff --git a/packages/open-next/src/http/openNextResponse.ts b/packages/open-next/src/http/openNextResponse.ts index 7e814856b..821f59225 100644 --- a/packages/open-next/src/http/openNextResponse.ts +++ b/packages/open-next/src/http/openNextResponse.ts @@ -10,7 +10,7 @@ import { Transform } from "node:stream"; import type { StreamCreator } from "types/open-next"; import { debug } from "../adapters/logger"; -import { parseHeaders, parseSetCookieHeader } from "./util"; +import { flattenHeaders, parseSetCookieHeader } from "./util"; const SET_COOKIE_HEADER = "set-cookie"; const CANNOT_BE_USED = "This cannot be used in OpenNext"; @@ -184,7 +184,7 @@ export class OpenNextNodeResponse extends Transform implements ServerResponse { // We need to fix the set-cookie header here this.headers[SET_COOKIE_HEADER] = this._cookies; - const parsedHeaders = parseHeaders(this.headers); + const parsedHeaders = flattenHeaders(this.headers); // We need to remove the set-cookie header from the parsed headers because // it does not handle multiple set-cookie headers properly diff --git a/packages/open-next/src/http/util.ts b/packages/open-next/src/http/util.ts index d5b29768d..4194616bc 100644 --- a/packages/open-next/src/http/util.ts +++ b/packages/open-next/src/http/util.ts @@ -3,7 +3,7 @@ import type http from "node:http"; export const parseHeaders = ( headers?: http.OutgoingHttpHeader[] | http.OutgoingHttpHeaders, ) => { - const result: Record = {}; + const result: Record = {}; if (!headers) { return result; } @@ -12,20 +12,31 @@ export const parseHeaders = ( if (value === undefined) { continue; } - result[key.toLowerCase()] = convertHeader(value); + result[key.toLowerCase()] = + typeof value === "number" ? String(value) : value; } return result; }; -export const convertHeader = (header: http.OutgoingHttpHeader) => { - if (typeof header === "string") { - return header; +export const flattenHeaders = ( + headers?: http.OutgoingHttpHeader[] | http.OutgoingHttpHeaders, +) => { + const result: Record = {}; + if (!headers) { + return result; } - if (Array.isArray(header)) { - return header.join(","); + + for (const [key, value] of Object.entries(headers)) { + if (value === undefined) { + continue; + } + result[key.toLowerCase()] = Array.isArray(value) + ? value.join(",") + : String(value); } - return String(header); + + return result; }; /**