Skip to content

Save and load session cookies in Netscape format#81

Open
oalders wants to merge 1 commit into
masterfrom
oalders/netscape-session-cookies
Open

Save and load session cookies in Netscape format#81
oalders wants to merge 1 commit into
masterfrom
oalders/netscape-session-cookies

Conversation

@oalders

@oalders oalders commented Jun 23, 2026

Copy link
Copy Markdown
Member

Summary

HTTP::Cookies::Netscape silently dropped session cookies (cookies with no expiration) in both directions:

  • save: $expires defaulted to 0, so the return if $now > $expires guard always fired and the cookie was never written.
  • load: a 0 expiry was turned into $expires - $now (a large negative max-age), which set_cookie() treats as already-expired and discards.

This change handles an expiry of 0 as a session cookie, matching how curl — and tools built on it like yt-dlp — read and write the cookies.txt format:

  • on save, a session cookie is written with an expiry of 0 and kept;
  • on load, a 0 expiry is read back as a session cookie (undef max-age) rather than an expired one;
  • cookies with a real, past expiry are still dropped, as before.

Per RFC 6265 §5.3, a cookie with neither Max-Age nor Expires is a session cookie that should be retained for the session — which is the behavior this restores for the Netscape format.

Tests

  • New t/netscape.t round-trips a session cookie and a persistent cookie through save/load, asserts the 0 expiry is written, and guards that an already-expired cookie is still not saved.
  • Updated the existing Netscape assertion in t/cookies.t: the no-expiry foo3 cookie is a genuine session cookie (discard=0) and is now correctly retained, so the saved count is 2 (only the explicit Discard cookie is dropped).

Full suite passes (7 files, 128 tests).

Replaces #5

This reimplements the fix originally proposed in #5 against the current codebase. #5 can be closed once this lands. Many thanks to @gottreu (Brian Gottreu) for the original contribution and for surfacing the bug — the approach here follows their lead.

🤖 Generated with Claude Code

A cookie with no expiration (a session cookie) was silently dropped by
HTTP::Cookies::Netscape: on save the `$now > $expires` guard always fired
because $expires defaulted to 0, and on load `$expires - $now` turned a 0
expiry into a large-negative max-age that set_cookie() treated as already
expired and discarded.

Handle an expiry of 0 as a session cookie, matching how curl (and tools
built on it, such as yt-dlp) read and write the cookies.txt format: write
it with an expiry of 0 and keep it, and read a 0 expiry back as a session
cookie rather than an expired one. Cookies with a real, past expiry are
still dropped.

This reimplements the fix originally proposed by Brian Gottreu in #5
against the current codebase, and adds round-trip test coverage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@oalders oalders force-pushed the oalders/netscape-session-cookies branch from e65c1e8 to 066144f Compare June 27, 2026 16:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant