Skip to content

feat: Support __Host- prefixed session cookies for sticky sessions#549

Open
hoffmaen wants to merge 3 commits intocloudfoundry:developfrom
sap-contributions:host-cookie
Open

feat: Support __Host- prefixed session cookies for sticky sessions#549
hoffmaen wants to merge 3 commits intocloudfoundry:developfrom
sap-contributions:host-cookie

Conversation

@hoffmaen
Copy link
Copy Markdown
Contributor

@hoffmaen hoffmaen commented Mar 31, 2026

Summary

  • Gorouter now recognises __Host--prefixed variants of configured sticky session cookie names (e.g. __Host-JSESSIONID), both in application responses and client requests
  • Uses exact prefix matching (__Host-) per RFC 6265bis, which mandates this canonical casing for user agents — no case-insensitive matching needed
  • No additional configuration required; the __Host- prefix is handled automatically for every name in router.sticky_session_cookie_names

Motivation

The __Host- cookie prefix ensures that session cookies are bound to the exact origin host and are never sent to subdomains, preventing session cookie leakage to other applications on shared domains. This prefix also enforces that cookies are only set over HTTPS, without a Domain attribute, and with Path=/ — supporting it in gorouter's sticky session handling allows applications to leverage these stricter security guarantees while retaining session affinity.

Backward Compatibility

Breaking Change? No

Note on AI usage

Parts of this code and tests were developed with assistance from Claude Code (claude-opus-4-20250514).

<img src="images/sticky_sessions_chips_migration.png" alt="Sticky Sessions - CHIPS migration sequence" width="800">

### Does Gorouter support `__Host-` prefixed session cookies?
Yes. [RFC 6265bis](https://www.rfc-editor.org/rfc/draft-ietf-httpbis-rfc6265bis-19.html#name-the-__host-prefix) defines
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.

This link seems broken search doesn't return anything, how about https://datatracker.ietf.org/doc/draft-ietf-httpbis-rfc6265bis/ ?
(though that one will probably also change once it's no longer draft)

Note: if an application were to set a new `__Host-JSESSIONID` alongside a delete (`Max-Age=0`) for
the old `JSESSIONID` in the same response, both would produce a `__VCAP_ID__` in the same cookie
jar partition. Depending on processing order, the browser could apply the delete `__VCAP_ID__`
after the new one, effectively removing it.
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 add what this actually means for a developer, e.g. "This could mean breaking session stickyness for the time of migration from JSESSIONID to _Host-...?"

Comment on lines +94 to +97
name := c.Name
if strings.HasPrefix(name, "__Host-") {
name = name[7:]
}
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.

Suggested change
name := c.Name
if strings.HasPrefix(name, "__Host-") {
name = name[7:]
}
name := strings.TrimPrefix(c.Name, "__Host-")

Wouldn't this be simpler? see also below

Comment on lines +600 to +619
if IsSessionCookie(cookie.Name, stickySessionCookieNames) {
sessionCookies = append(sessionCookies, cookie)
}
}
return sessionCookies, nil
}

// IsSessionCookie reports whether cookieName matches a configured sticky session cookie name,
// either directly or after stripping the "__Host-" prefix (RFC 6265bis).
func IsSessionCookie(cookieName string, stickySessionCookieNames config.StringSet) bool {
if _, ok := stickySessionCookieNames[cookieName]; ok {
return true
}
if strings.HasPrefix(cookieName, "__Host-") {
_, ok := stickySessionCookieNames[cookieName[7:]]
return ok
}
return false
}

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.

Suggested change
if IsSessionCookie(cookie.Name, stickySessionCookieNames) {
sessionCookies = append(sessionCookies, cookie)
}
}
return sessionCookies, nil
}
// IsSessionCookie reports whether cookieName matches a configured sticky session cookie name,
// either directly or after stripping the "__Host-" prefix (RFC 6265bis).
func IsSessionCookie(cookieName string, stickySessionCookieNames config.StringSet) bool {
if _, ok := stickySessionCookieNames[cookieName]; ok {
return true
}
if strings.HasPrefix(cookieName, "__Host-") {
_, ok := stickySessionCookieNames[cookieName[7:]]
return ok
}
return false
}
// also match __Host- prefix
name := strings.TrimPrefix(cookie.Name, "__Host-")
if _, ok := stickySessionCookieNames[name]; ok {
sessionCookies = append(sessionCookies, cookie)
}
}
return sessionCookies, nil
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

2 participants