Skip to content

Commit a879fe0

Browse files
dario-piotrowiczyuripaveEnchan1207vicb
authored
V3 backport for #9454 and #10683 (#10716)
* fix(miniflare): api proxy preserve multiple Set-Cookie headers * [miniflare] custom serialization for RegExp object (#9454) * feat: encode pattern when serialize RegExp object * test: check if test suites can be filtered by pattern includes non-ascii string * chore: remove unneeded comment * test: serialize RegExp object * docs: add changeset for vitest-pool-workers to describe fix --------- Co-authored-by: Calvin Tsang <[email protected]> Co-authored-by: Enchan <[email protected]> Co-authored-by: Victor Berchet <[email protected]>
1 parent cb7ace5 commit a879fe0

File tree

3 files changed

+72
-2
lines changed

3 files changed

+72
-2
lines changed

.changeset/hungry-crews-tap.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"miniflare": patch
3+
---
4+
5+
fix: api proxy preserve multiple Set-Cookie headers

packages/miniflare/src/workers/core/devalue.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ export const structuredSerializableReducers: ReducersRevivers = {
6060
];
6161
}
6262
},
63+
RegExp(value) {
64+
if (value instanceof RegExp) {
65+
const { source, flags } = value;
66+
const encoded = Buffer.from(source).toString("base64");
67+
return flags ? ["RegExp", encoded, flags] : ["RegExp", encoded];
68+
}
69+
},
6370
Error(value) {
6471
for (const ctor of ALLOWED_ERROR_CONSTRUCTORS) {
6572
if (value instanceof ctor && value.name === ctor.name) {
@@ -97,6 +104,14 @@ export const structuredSerializableRevivers: ReducersRevivers = {
97104
if ("BYTES_PER_ELEMENT" in ctor) length /= ctor.BYTES_PER_ELEMENT;
98105
return new ctor(buffer as ArrayBuffer, byteOffset, length);
99106
},
107+
RegExp(value) {
108+
assert(Array.isArray(value));
109+
const [name, encoded, flags] = value;
110+
assert(typeof name === "string");
111+
assert(typeof encoded === "string");
112+
const source = Buffer.from(encoded, "base64").toString("utf-8");
113+
return new RegExp(source, flags);
114+
},
100115
Error(value) {
101116
assert(Array.isArray(value));
102117
const [name, message, stack, cause] = value as unknown[];
@@ -134,7 +149,7 @@ export function createHTTPReducers(
134149
): ReducersRevivers {
135150
return {
136151
Headers(val) {
137-
if (val instanceof impl.Headers) return Object.fromEntries(val);
152+
if (val instanceof impl.Headers) return [...val.entries()];
138153
},
139154
Request(val) {
140155
if (val instanceof impl.Request) {
@@ -154,7 +169,7 @@ export function createHTTPRevivers<RS>(
154169
return {
155170
Headers(value) {
156171
assert(typeof value === "object" && value !== null);
157-
return new impl.Headers(value as Record<string, string>);
172+
return new impl.Headers(value as string[][]);
158173
},
159174
Request(value) {
160175
assert(Array.isArray(value));
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import test from "ava";
2+
import { parse, stringify } from "devalue";
3+
import {
4+
createHTTPReducers,
5+
createHTTPRevivers,
6+
structuredSerializableReducers,
7+
structuredSerializableRevivers,
8+
} from "miniflare";
9+
import { NODE_PLATFORM_IMPL } from "../../../src/plugins/core/proxy/types";
10+
11+
test("serialize Headers object consisting of multiple Set-Cookie headers", (t) => {
12+
const impl = NODE_PLATFORM_IMPL;
13+
14+
const headers = new impl.Headers([
15+
["content-type", "application/json"],
16+
["authorization", "Bearer token"],
17+
]);
18+
headers.append("Set-Cookie", "cookie1=value_for_cookie_1; Path=/; HttpOnly;");
19+
headers.append("Set-Cookie", "cookie2=value_for_cookie_2; Path=/; HttpOnly;");
20+
21+
const serialized = stringify(headers, createHTTPReducers(impl));
22+
const deserialized = parse(serialized, createHTTPRevivers(impl));
23+
t.true(deserialized instanceof impl.Headers);
24+
t.is(deserialized.get("content-type"), "application/json");
25+
t.is(deserialized.get("authorization"), "Bearer token");
26+
t.deepEqual(deserialized.getSetCookie(), [
27+
"cookie1=value_for_cookie_1; Path=/; HttpOnly;",
28+
"cookie2=value_for_cookie_2; Path=/; HttpOnly;",
29+
]);
30+
});
31+
32+
test("serialize RegExp object consisting of only ascii chars", (t) => {
33+
const input = new RegExp(/HelloWorld/);
34+
35+
const serialized = stringify(input, structuredSerializableReducers);
36+
t.is(serialized, '[["RegExp",1],[2,3],"RegExp","SGVsbG9Xb3JsZA=="]');
37+
38+
const deserialized = parse(serialized, structuredSerializableRevivers);
39+
t.deepEqual(deserialized, input);
40+
});
41+
42+
test("serialize RegExp object containing non-ascii chars", (t) => {
43+
const input = new RegExp(//);
44+
45+
const serialized = stringify(input, structuredSerializableReducers);
46+
t.is(serialized, '[["RegExp",1],[2,3],"RegExp","44GT44KT44Gr44Gh44Gv"]');
47+
48+
const deserialized = parse(serialized, structuredSerializableRevivers);
49+
t.deepEqual(deserialized, input);
50+
});

0 commit comments

Comments
 (0)