Skip to content

Commit 27deb06

Browse files
committed
Response: setCookie() supports the Partitioned (CHIPS) attribute
Adds a $partitioned argument to setCookie(). When enabled it appends the Partitioned attribute and forces Secure, which the browser requires for a partitioned cookie. Like $sameSite, the argument lives only on Response, not on the IResponse interface.
1 parent 23ef54a commit 27deb06

2 files changed

Lines changed: 14 additions & 3 deletions

File tree

src/Http/Response.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ public function setCookie(
237237
?bool $secure = null,
238238
?bool $httpOnly = null,
239239
?string $sameSite = null,
240+
bool $partitioned = false,
240241
): static
241242
{
242243
self::checkHeaders();
@@ -254,8 +255,9 @@ public function setCookie(
254255

255256
$seconds = Helpers::expirationToSeconds($expire);
256257
$sameSite ??= self::SameSiteLax;
257-
$secure = $sameSite === self::SameSiteNone
258-
? true // SameSite=None requires the Secure attribute, otherwise the browser rejects the cookie
258+
// both SameSite=None and Partitioned are rejected by the browser without the Secure attribute
259+
$secure = $sameSite === self::SameSiteNone || $partitioned
260+
? true
259261
: $secure ?? $this->cookieSecure;
260262
// the value is raw-url-encoded the same way PHP reads it back from $_COOKIE;
261263
// Max-Age takes precedence over expires (RFC 6265), expires is sent too for ancient clients
@@ -265,7 +267,8 @@ public function setCookie(
265267
. (($domain = $domain ?? ($path ? '' : $this->cookieDomain)) === '' ? '' : '; domain=' . $domain)
266268
. ($secure ? '; secure' : '')
267269
. (($httpOnly ?? true) ? '; HttpOnly' : '')
268-
. '; SameSite=' . $sameSite;
270+
. '; SameSite=' . $sameSite
271+
. ($partitioned ? '; Partitioned' : '');
269272
header('Set-Cookie: ' . $cookie, replace: false);
270273
return $this;
271274
}

tests/Http/Response.setCookie.phpt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ $headers = array_values(array_diff(headers_list(), $old, ['Set-Cookie:']));
135135
Assert::same(['Set-Cookie: test=value; path=/; secure; HttpOnly; SameSite=None'], $headers);
136136

137137

138+
// Partitioned (CHIPS) adds the attribute and forces Secure
139+
$response = new Http\Response;
140+
$old = headers_list();
141+
$response->setCookie('test', 'value', null, sameSite: Http\IResponse::SameSiteNone, partitioned: true);
142+
$headers = array_values(array_diff(headers_list(), $old, ['Set-Cookie:']));
143+
Assert::same(['Set-Cookie: test=value; path=/; secure; HttpOnly; SameSite=None; Partitioned'], $headers);
144+
145+
138146
// integer 0 is deprecated, but kept as a session cookie for BC
139147
$response = new Http\Response;
140148
$old = headers_list();

0 commit comments

Comments
 (0)