Skip to content
File

Blob: test/util/d1Bookmark.ts

typescript51 lines
1import {
2 D1_BOOKMARK_COOKIE_MAX_AGE_SECONDS,
3 D1_BOOKMARK_COOKIE_NAME,
4 D1_BOOKMARK_HEADER,
5} from "@/worker/routes/d1Bookmark";
6 
7export { D1_BOOKMARK_HEADER, D1_BOOKMARK_COOKIE_NAME, D1_BOOKMARK_COOKIE_MAX_AGE_SECONDS };
8export const D1_BOOKMARK_COOKIE_HEADER_NAME = `__Host-${D1_BOOKMARK_COOKIE_NAME}`;
9 
10// Parses `Set-Cookie` headers and pulls out the bookmark cookie. Tests
11// drive the worker through `workerExports.default.fetch`, which surfaces
12// a single combined `Set-Cookie` header even when the worker appended
13// several cookies; we split on the conventional comma-newline pattern
14// and look for our entry by name. Attribute values are the raw strings
15// the worker emitted (after URL-decoding the cookie value itself).
16export type ParsedBookmarkCookie = {
17 value: string;
18 attributes: Record<string, string | true>;
19};
20 
21export function parseBookmarkCookie(setCookieHeader: string | null): ParsedBookmarkCookie | null {
22 if (!setCookieHeader) return null;
23 // Multiple cookies in a combined header are separated by `, ` in
24 // workerd's surface; entries can themselves contain commas inside
25 // `Expires=...`, but the bookmark cookie only carries `Max-Age`, so
26 // splitting on `,` followed by a space is safe here.
27 const entries = setCookieHeader.split(/, (?=[^ ]+=)/);
28 for (const entry of entries) {
29 const [head, ...rest] = entry.split(";");
30 if (!head) continue;
31 const eq = head.indexOf("=");
32 if (eq === -1) continue;
33 const name = head.slice(0, eq).trim();
34 if (name !== D1_BOOKMARK_COOKIE_HEADER_NAME) continue;
35 const rawValue = head.slice(eq + 1).trim();
36 const attributes: Record<string, string | true> = {};
37 for (const attr of rest) {
38 const trimmed = attr.trim();
39 if (!trimmed) continue;
40 const aeq = trimmed.indexOf("=");
41 if (aeq === -1) {
42 attributes[trimmed] = true;
43 } else {
44 attributes[trimmed.slice(0, aeq)] = trimmed.slice(aeq + 1);
45 }
46 }
47 return { value: decodeURIComponent(rawValue), attributes };
48 }
49 return null;
50}