Skip to content

KTOR-9805 use in cookies a custom expires parser - #5878

Open
Evgeny Usorov (eusorov) wants to merge 2 commits into
ktorio:mainfrom
eusorov:feat/KTOR-9805-cookie-custom-expires-parser
Open

Evgeny Usorov (eusorov) wants to merge 2 commits into
ktorio:mainfrom
eusorov:feat/KTOR-9805-cookie-custom-expires-parser

Conversation

@eusorov

Copy link
Copy Markdown

KTOR-9805 HttpCookies: Allow configuring a custom Expires parser

Subsystem
Client, ktor-client-core, ktor-http

Motivation
Some servers send nonstandard Set-Cookie dates — commonly Expires=0, meaning "delete this cookie now". Ktor can't parse those and leaves expires = null. With no Max-Age, storage derives no lifetime and treats the cookie as a session cookie, holding it and resending it for the rest of the session — the opposite of what the server asked.

HttpCookies.Config offers no date hook, and widening the built-in parser isn't safe: 0 means epoch-delete to one server and is invalid to another, so the interpretation belongs to the application.

Solution
Let the application supply the parser:

install(HttpCookies) { expiresParser { if (it == "0") GMTDate(0L) else null } }
  • Replaces built-in parsing with no fallback: selection is by configuration, not by result, so a null return can't silently reinstate a date the application rejected.
  • Returning null or throwing leaves expires unset and keeps the cookie, preserving the KTOR-9235 contract that a bad date never fails the response; Max-Age still takes precedence and storage is unchanged.
  • Adds HttpCookies.Config.expiresParser, plus parseServerSetCookieHeader(header, parser) and HttpMessage.setCookie(parser) in ktor-http for use without the plugin.
  • Existing signatures stay as real declarations that delegate, so binary compatibility holds and there is one implementation.
  • 13 new tests in common source sets, covering parser replacement, absence of fallback, Max-Age precedence, and receive/store/resend.

@eusorov Evgeny Usorov (eusorov) changed the title Fix KTOR-9805 use custom expires parser in cookies KTOR-9805 use custom expires parser in cookies Sep 14, 2026
@eusorov
Evgeny Usorov (eusorov) marked this pull request as ready for review September 14, 2026 19:58
@eusorov

Copy link
Copy Markdown
Author

CI failures are unrelated flakes in ktor-client-tests and 'Read timed out' on JS build. Pls rerun the affected builds

@eusorov Evgeny Usorov (eusorov) changed the title KTOR-9805 use custom expires parser in cookies KTOR-9805 use in cookies a custom expires parser Sep 14, 2026

@bjhham Bruce Hamilton (bjhham) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe in addition, it would make sense to include the "0" case in the default parser, since this is fairly common convention, and the parser already has quite a bit of leniency built in.

@eusorov

Evgeny Usorov (eusorov) commented Sep 15, 2026 •

Copy link
Copy Markdown
Author

Happy to add it — 0 as "delete now" is common enough that users shouldn't have to configure it.

One scoping question first: should it go in fromCookieToGmtDate(), or only in the default Expires path of parseServerSetCookieHeader? The former is the more natural home given the existing leniency, but it's shared with server-side cookie parsing and with anyone calling the function directly, so it's a wider behaviour change than this PR currently makes.

Two things worth flagging either way:

  • It changes existing outcomes. Expires=0 currently leaves expires = null, so the cookie is kept as a session cookie; afterwards it becomes epoch and storage drops it as already expired. That's the server's intent, but it is a deliberate deviation from RFC 6265 §5.1.1, which says to ignore an unparseable date.
  • The expiresParser KDoc uses Expires=0 as its worked example, so I'd swap in something the default parser still won't handle.

and also worth to mention that here KTOR-7964 the same was requested but then ticket was closed with a bulk closing action.

@bjhham

Copy link
Copy Markdown
Contributor

It should go under fromCookieToGmtDate().

@eusorov

Evgeny Usorov (eusorov) commented Sep 20, 2026 •

Copy link
Copy Markdown
Author

It should go under fromCookieToGmtDate().

added that behaviour

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.

2 participants