From bf02d04479237bae02eb5156158eb41bba9acd6d Mon Sep 17 00:00:00 2001 From: pfg Date: Tue, 27 May 2025 20:14:21 -0700 Subject: [PATCH] Don't validate cookie strings passed in the CookieMap constructor (#19945) Co-authored-by: pfgithub <6010774+pfgithub@users.noreply.github.com> --- src/bun.js/bindings/CookieMap.cpp | 15 ----------- test/js/bun/cookie/cookie.test.ts | 44 ++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/bun.js/bindings/CookieMap.cpp b/src/bun.js/bindings/CookieMap.cpp index ece4833bdc..aabca2aa4f 100644 --- a/src/bun.js/bindings/CookieMap.cpp +++ b/src/bun.js/bindings/CookieMap.cpp @@ -60,14 +60,6 @@ ExceptionOr> CookieMap::create(std::variant Vector> cookies; for (const auto& pair : pairs) { if (pair.size() == 2) { - if (!pair[1].isEmpty() && !isValidHTTPHeaderValue(pair[1])) { - if (throwOnInvalidCookieString) { - return Exception { TypeError, "Invalid cookie string: cookie value is not valid"_s }; - } else { - continue; - } - } - cookies.append(KeyValuePair(pair[0], pair[1])); } else if (throwOnInvalidCookieString) { return Exception { TypeError, "Invalid cookie string: expected name=value pair"_s }; @@ -78,13 +70,6 @@ ExceptionOr> CookieMap::create(std::variant [&](const HashMap& pairs) -> ExceptionOr> { Vector> cookies; for (const auto& entry : pairs) { - if (!entry.value.isEmpty() && !isValidHTTPHeaderValue(entry.value)) { - if (throwOnInvalidCookieString) { - return Exception { TypeError, "Invalid cookie string: cookie value is not valid"_s }; - } else { - continue; - } - } cookies.append(KeyValuePair(entry.key, entry.value)); } diff --git a/test/js/bun/cookie/cookie.test.ts b/test/js/bun/cookie/cookie.test.ts index e7972faf9b..0f6ea67fef 100644 --- a/test/js/bun/cookie/cookie.test.ts +++ b/test/js/bun/cookie/cookie.test.ts @@ -323,7 +323,7 @@ describe("cookie path option", () => { "/x/y": { GET(r) { r.cookies.set("user", "a", { maxAge: 3600, path: "/" }); - const cookie = r.cookies.toSetCookieHeaders().at(0); + const cookie = r.cookies.toSetCookieHeaders().at(0)!; return new Response("ok", { headers: { "set-cookie": cookie }, }); @@ -371,3 +371,45 @@ test("delete cookie invalid path option", () => { `"Invalid cookie name: contains invalid characters"`, ); }); + +describe("Bun.CookieMap constructor", () => { + test("throws for invalid array", () => { + expect(() => new Bun.CookieMap([["abc defg =fhaingj809读写汉字学中文"]])).toThrowErrorMatchingInlineSnapshot( + `"Expected arrays of exactly two strings"`, + ); + }); + test("accepts unicode cookie value in object", () => { + const map = new Bun.CookieMap({ + "cookie key": "读写汉字学中文", + }); + expect(map.get("cookie key")).toBe("读写汉字学中文"); + }); + test("accepts unicode cookie value in array", () => { + const map = new Bun.CookieMap([["cookie key", "读写汉字学中文"]]); + expect(map.get("cookie key")).toBe("读写汉字学中文"); + }); + test("accepts unicode cookie value in string", () => { + const map = new Bun.CookieMap("cookie key=读写汉字学中文"); + expect(map.get("cookie key")).toBe("读写汉字学中文"); + }); + test("serializes unicode cookie value", () => { + const map = new Bun.CookieMap(); + map.set("cookiekey", "读写汉字学中文"); + expect(map.toSetCookieHeaders()).toMatchInlineSnapshot(` + [ + "cookiekey=%E8%AF%BB%E5%86%99%E6%B1%89%E5%AD%97%E5%AD%A6%E4%B8%AD%E6%96%87; Path=/; SameSite=Lax", + ] + `); + // re-parse + const reparsed = new Bun.CookieMap(map.toSetCookieHeaders()[0].split(";")[0]!); + expect(reparsed.get("cookiekey")).toBe("读写汉字学中文"); + }); + test("doesn't parse percent encoded value in object or array", () => { + const map = new Bun.CookieMap({ + "cookiekey": "%E8%AF%BB%E5%86%99%E6%B1%89%E5%AD%97%E5%AD%A6%E4%B8%AD%E6%96%87", + }); + const map2 = new Bun.CookieMap([["cookiekey", "%E8%AF%BB%E5%86%99%E6%B1%89%E5%AD%97%E5%AD%A6%E4%B8%AD%E6%96%87"]]); + expect(map.get("cookiekey")).toBe("%E8%AF%BB%E5%86%99%E6%B1%89%E5%AD%97%E5%AD%A6%E4%B8%AD%E6%96%87"); + expect(map2.get("cookiekey")).toBe("%E8%AF%BB%E5%86%99%E6%B1%89%E5%AD%97%E5%AD%A6%E4%B8%AD%E6%96%87"); + }); +});