Cookie Jar: domain/path matching, Set-Cookie parsing, SameSite, Expiry #3

Closed
opened 2026-06-17 13:37:43 +00:00 by Artur · 1 comment
Owner

Goal

Implement a browser-like cookie jar per RFC 6265:

  • Set-Cookie header parsing
  • Domain matching (exact + suffix)
  • Path matching (prefix)
  • Secure enforcement (HTTPS only)
  • HttpOnly (inaccessible via document.cookie)
  • SameSite (Strict/Lax/None)
  • Expiry/Max-Age TTL
  • Cookie request header generation
  • document.cookie getter/setter

What to Build

src/network/cookies.ts

export interface Cookie {
  name: string;
  value: string;
  domain: string;
  path: string;
  secure: boolean;
  httpOnly: boolean;
  sameSite: 'Strict' | 'Lax' | 'None';
  expires: Date | null;        // null = session cookie
  creationTime: Date;
  lastAccessTime: Date;
}

export class CookieJar {
  // Parse Set-Cookie header and store cookie
  setFromHeader(setCookieHeader: string, requestUrl: string): void;

  // Set cookie directly (for document.cookie)
  set(name: string, value: string, options?: Partial<CookieOptions>): void;

  // Match cookies for a URL (returns Cookie objects)
  match(url: string): Cookie[];

  // Generate "name=value; name2=value2" header string
  getCookieHeader(url: string): string;

  // document.cookie getter (only !httpOnly cookies)
  getDocumentCookie(url: string): string;

  // document.cookie setter
  setDocumentCookie(cookieString: string, url: string): void;

  // Remove expired cookies
  purgeExpired(): void;

  // Dump all cookies (for output)
  dump(): Cookie[];

  // Clear all cookies
  clear(): void;
}
  • Name/Value: no CTLs or whitespace (except = for separator)
  • Value may be in DQUOTES
  • Domain: leading dot allowed; matches exact + subdomains
  • Path: prefix-match against request path
  • Expires: HTTP-date format (RFC 1123, RFC 850, asctime)
  • Max-Age: seconds (positive/negative/zero)
  • Secure: only on HTTPS requests
  • HttpOnly: not readable via document.cookie
  • SameSite: Strict/Lax/None, default = Lax (Chromium since 2020)
  1. Domain matching: request-domain must equal cookie-domain or be subdomain
  2. Path matching: request-path must start with cookie-path
  3. Secure check: Secure cookies only on HTTPS
  4. HttpOnly check: not included in document.cookie
  5. Expiry check: expired cookies not matched
  6. SameSite check: Strict only same-site; Lax allows top-level GET; None always

Tests

Unit Tests

Test Verifies
cookies.parse-simple.test.ts name=value -> Cookie(name='name', value='value')
cookies.parse-full.test.ts Full Set-Cookie header with all attributes
cookies.parse-multiple.test.ts Set-Cookie with two cookies
cookies.parse-invalid.test.ts Invalid cookie ignored (no crash)
cookies.domain-match.test.ts .example.com matches sub.example.com but not other.com
cookies.path-match.test.ts Path=/foo matches /foo/bar but not /bar
cookies.secure.test.ts Secure cookie only on HTTPS
cookies.httpOnly.test.ts HttpOnly not in document.cookie
cookies.expiry.test.ts Expired cookie not matched
cookies.max-age.test.ts Max-Age calculated correctly
cookies.same-site-strict.test.ts SameSite=Strict blocked on cross-site
cookies.same-site-lax.test.ts SameSite=Lax allows top-level GET
cookies.cookie-header.test.ts getCookieHeader returns correct string

Edge Cases

Test Verifies
cookies.empty-value.test.ts name= -> value=''
cookies.overwrite.test.ts Same name/domain/path overwrites
cookies.remove-by-expiry.test.ts Expiry in past removes cookie
cookies.remove-by-max-age-0.test.ts Max-Age=0 removes cookie
cookies.purge-expired.test.ts purgeExpired removes all expired
cookies.same-site-none-insecure.test.ts SameSite=None requires Secure
cookies.domain-public-suffix.test.ts No cookie for TLD-only domain

Definition of Done

  • CookieJar class implemented
  • Set-Cookie parser (RFC 6265)
  • Cookie matching (Domain, Path, Secure, HttpOnly, Expiry, SameSite)
  • document.cookie getter/setter
  • dump() for output
  • All tests pass
  • 100% line + branch coverage
## Goal Implement a browser-like cookie jar per RFC 6265: - Set-Cookie header parsing - Domain matching (exact + suffix) - Path matching (prefix) - Secure enforcement (HTTPS only) - HttpOnly (inaccessible via document.cookie) - SameSite (Strict/Lax/None) - Expiry/Max-Age TTL - Cookie request header generation - document.cookie getter/setter ## What to Build ### src/network/cookies.ts ``` export interface Cookie { name: string; value: string; domain: string; path: string; secure: boolean; httpOnly: boolean; sameSite: 'Strict' | 'Lax' | 'None'; expires: Date | null; // null = session cookie creationTime: Date; lastAccessTime: Date; } export class CookieJar { // Parse Set-Cookie header and store cookie setFromHeader(setCookieHeader: string, requestUrl: string): void; // Set cookie directly (for document.cookie) set(name: string, value: string, options?: Partial<CookieOptions>): void; // Match cookies for a URL (returns Cookie objects) match(url: string): Cookie[]; // Generate "name=value; name2=value2" header string getCookieHeader(url: string): string; // document.cookie getter (only !httpOnly cookies) getDocumentCookie(url: string): string; // document.cookie setter setDocumentCookie(cookieString: string, url: string): void; // Remove expired cookies purgeExpired(): void; // Dump all cookies (for output) dump(): Cookie[]; // Clear all cookies clear(): void; } ``` ### Cookie Parsing Rules (RFC 6265) - Name/Value: no CTLs or whitespace (except = for separator) - Value may be in DQUOTES - Domain: leading dot allowed; matches exact + subdomains - Path: prefix-match against request path - Expires: HTTP-date format (RFC 1123, RFC 850, asctime) - Max-Age: seconds (positive/negative/zero) - Secure: only on HTTPS requests - HttpOnly: not readable via document.cookie - SameSite: Strict/Lax/None, default = Lax (Chromium since 2020) ### Cookie Matching (RFC 6265 Section 5.1.4) 1. Domain matching: request-domain must equal cookie-domain or be subdomain 2. Path matching: request-path must start with cookie-path 3. Secure check: Secure cookies only on HTTPS 4. HttpOnly check: not included in document.cookie 5. Expiry check: expired cookies not matched 6. SameSite check: Strict only same-site; Lax allows top-level GET; None always ## Tests ### Unit Tests | Test | Verifies | |------|----------| | cookies.parse-simple.test.ts | `name=value` -> Cookie(name='name', value='value') | | cookies.parse-full.test.ts | Full Set-Cookie header with all attributes | | cookies.parse-multiple.test.ts | Set-Cookie with two cookies | | cookies.parse-invalid.test.ts | Invalid cookie ignored (no crash) | | cookies.domain-match.test.ts | .example.com matches sub.example.com but not other.com | | cookies.path-match.test.ts | Path=/foo matches /foo/bar but not /bar | | cookies.secure.test.ts | Secure cookie only on HTTPS | | cookies.httpOnly.test.ts | HttpOnly not in document.cookie | | cookies.expiry.test.ts | Expired cookie not matched | | cookies.max-age.test.ts | Max-Age calculated correctly | | cookies.same-site-strict.test.ts | SameSite=Strict blocked on cross-site | | cookies.same-site-lax.test.ts | SameSite=Lax allows top-level GET | | cookies.cookie-header.test.ts | getCookieHeader returns correct string | ### Edge Cases | Test | Verifies | |------|----------| | cookies.empty-value.test.ts | `name=` -> value='' | | cookies.overwrite.test.ts | Same name/domain/path overwrites | | cookies.remove-by-expiry.test.ts | Expiry in past removes cookie | | cookies.remove-by-max-age-0.test.ts | Max-Age=0 removes cookie | | cookies.purge-expired.test.ts | purgeExpired removes all expired | | cookies.same-site-none-insecure.test.ts | SameSite=None requires Secure | | cookies.domain-public-suffix.test.ts | No cookie for TLD-only domain | ## Definition of Done - [ ] CookieJar class implemented - [ ] Set-Cookie parser (RFC 6265) - [ ] Cookie matching (Domain, Path, Secure, HttpOnly, Expiry, SameSite) - [ ] document.cookie getter/setter - [ ] dump() for output - [ ] All tests pass - [ ] 100% line + branch coverage
Author
Owner

Cookie Jar — domain/path matching, Set-Cookie parsing, SameSite, Expiry. Implementiert in src/network/cookies.ts. Tests: cookies.test.ts.

Cookie Jar — domain/path matching, Set-Cookie parsing, SameSite, Expiry. ✅ Implementiert in src/network/cookies.ts. Tests: cookies.test.ts.
Artur closed this issue 2026-06-18 06:28:02 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
glow-all/true-headless-browser#3
No description provided.