diff --git a/.changeset/hungry-crews-tap.md b/.changeset/hungry-crews-tap.md new file mode 100644 index 000000000000..c4376be1653f --- /dev/null +++ b/.changeset/hungry-crews-tap.md @@ -0,0 +1,5 @@ +--- +"miniflare": patch +--- + +fix: api proxy preserve multiple Set-Cookie headers diff --git a/packages/miniflare/src/workers/core/devalue.ts b/packages/miniflare/src/workers/core/devalue.ts index a27e6f624765..4255e36e54fd 100644 --- a/packages/miniflare/src/workers/core/devalue.ts +++ b/packages/miniflare/src/workers/core/devalue.ts @@ -149,7 +149,7 @@ export function createHTTPReducers( ): ReducersRevivers { return { Headers(val) { - if (val instanceof impl.Headers) return Object.fromEntries(val); + if (val instanceof impl.Headers) return [...val.entries()]; }, Request(val) { if (val instanceof impl.Request) { @@ -169,7 +169,7 @@ export function createHTTPRevivers( return { Headers(value) { assert(typeof value === "object" && value !== null); - return new impl.Headers(value as Record); + return new impl.Headers(value as string[][]); }, Request(value) { assert(Array.isArray(value)); diff --git a/packages/miniflare/test/workers/core/serialize.spec.ts b/packages/miniflare/test/workers/core/serialize.spec.ts index 2c8528b0bfe6..b4e1bba0dacc 100644 --- a/packages/miniflare/test/workers/core/serialize.spec.ts +++ b/packages/miniflare/test/workers/core/serialize.spec.ts @@ -1,9 +1,12 @@ import test from "ava"; import { parse, stringify } from "devalue"; import { + createHTTPReducers, + createHTTPRevivers, structuredSerializableReducers, structuredSerializableRevivers, } from "miniflare"; +import { NODE_PLATFORM_IMPL } from "../../../src/plugins/core/proxy/types"; test("serialize RegExp object consisting of only ascii chars", (t) => { const input = new RegExp(/HelloWorld/); @@ -24,3 +27,24 @@ test("serialize RegExp object containing non-ascii chars", (t) => { const deserialized = parse(serialized, structuredSerializableRevivers); t.deepEqual(deserialized, input); }); + +test("serialize Headers object consisting of multiple Set-Cookie headers", (t) => { + const impl = NODE_PLATFORM_IMPL; + + const headers = new impl.Headers([ + ["content-type", "application/json"], + ["authorization", "Bearer token"], + ]); + headers.append("Set-Cookie", "cookie1=value_for_cookie_1; Path=/; HttpOnly;"); + headers.append("Set-Cookie", "cookie2=value_for_cookie_2; Path=/; HttpOnly;"); + + const serialized = stringify(headers, createHTTPReducers(impl)); + const deserialized = parse(serialized, createHTTPRevivers(impl)); + t.true(deserialized instanceof impl.Headers); + t.is(deserialized.get("content-type"), "application/json"); + t.is(deserialized.get("authorization"), "Bearer token"); + t.deepEqual(deserialized.getSetCookie(), [ + "cookie1=value_for_cookie_1; Path=/; HttpOnly;", + "cookie2=value_for_cookie_2; Path=/; HttpOnly;", + ]); +});