8000 Merge branch '6.4' into 7.0 · symfony/symfony@c9753aa · GitHub
[go: up one dir, main page]

Skip to content

Commit c9753aa

Browse files
committed
Merge branch '6.4' into 7.0
* 6.4: [HttpFoundation] Cookies Having Independent Partitioned State (CHIPS) Proofread UPGRADE guide
2 parents dfc3b3d + 569573a commit c9753aa

File tree

4 files changed

+79
-8
lines changed

4 files changed

+79
-8
lines changed

UPGRADE-7.0.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
UPGRADE FROM 6.4 to 7.0
22
=======================
33

4-
Symfony 6.4 and Symfony 7.0 will be released simultaneously at the end of November 2023. According to the Symfony
5-
release process, both versions will have the same features, but Symfony 7.0 won't include any deprecated features.
4+
Symfony 6.4 and Symfony 7.0 are released simultaneously at the end of November 2023. According to the Symfony
5+
release process, both versions have the same features, but Symfony 7.0 doesn't include any deprecated features.
66
To upgrade, make sure to resolve all deprecation notices.
77
Read more about this in the [Symfony documentation](https://symfony.com/doc/current/setup/upgrade_major.html).
88

src/Symfony/Component/HttpFoundation/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ CHANGELOG
1818
* Make `HeaderBag::getDate()`, `Response::getDate()`, `getExpires()` and `getLastModified()` return a `DateTimeImmutable`
1919
* Support root-level `Generator` in `StreamedJsonResponse`
2020
* Add `UriSigner` from the HttpKernel component
21+
* Add `partitioned` flag to `Cookie` (CHIPS Cookie)
2122

2223
6.3
2324
---

src/Symfony/Component/HttpFoundation/Cookie.php

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class Cookie
3232

3333
private bool $raw;
3434
private ?string $sameSite = null;
35+
private bool $partitioned = false;
3536
private bool $secureDefault = false;
3637

3738
private const RESERVED_CHARS_LIST = "=,; \t\r\n\v\f";
@@ -51,6 +52,7 @@ public static function fromString(string $cookie, bool $decode = false): static
5152
'httponly' => false,
5253
'raw' => !$decode,
5354
'samesite' => null,
55+
'partitioned' => false,
5456
];
5557

5658
$parts = HeaderUtils::split($cookie, ';=');
@@ -66,17 +68,20 @@ public static function fromString(string $cookie, bool $decode = false): static
6668
$data['expires'] = time() + (int) $data['max-age'];
6769
}
6870

69-
return new static($name, $value, $data['expires'], $data['path'], $data['domain'], $data['secure'], $data['httponly'], $data['raw'], $data['samesite']);
71+
return new static($name, $value, $data['expires'], $data['path'], $data['domain'], $data['secure'], $data['httponly'], $data['raw'], $data['samesite'], $data['partitioned']);
7072
}
7173

7274
/**
7375
* @see self::__construct
7476
*
7577
* @param self::SAMESITE_*|''|null $sameSite
78+
* @param bool $partitioned
7679
*/
77-
public static function create(string $name, string $value = null, int|string|\DateTimeInterface $expire = 0, ?string $path = '/', string $domain = null, bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = self::SAMESITE_LAX): self
80+
public static function create(string $name, string $value = null, int|string|\DateTimeInterface $expire = 0, ?string $path = '/', string $domain = null, bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = self::SAMESITE_LAX /* , bool $partitioned = false */): self
7881
{
79-
return new self($name, $value, $expire, $path, $domain, $secure, $httpOnly, $raw, $sameSite);
82+
$partitioned = 9 < \func_num_args() ? func_get_arg(9) : false;
83+
84+
return new self($name, $value, $expire, $path, $domain, $secure, $httpOnly, $raw, $sameSite, $partitioned);
8085
}
8186

8287
/**
@@ -92,7 +97,7 @@ public static function create(string $name, string $value = null, int|string|\Da
9297
*
9398
* @throws \InvalidArgumentException
9499
*/
95-
public function __construct(string $name, string $value = null, int|string|\DateTimeInterface $expire = 0, ?string $path = '/', string $domain = null, bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = self::SAMESITE_LAX)
100+
public function __construct(string $name, string $value = null, int|string|\DateTimeInterface $expire = 0, ?string $path = '/', string $domain = null, bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = self::SAMESITE_LAX, bool $partitioned = false)
96101
{
97102
// from PHP source code
98103
if ($raw && false !== strpbrk($name, self::RESERVED_CHARS_LIST)) {
@@ -112,6 +117,7 @@ public function __construct(string $name, string $value = null, int|string|\Date
112117
$this->httpOnly = $httpOnly;
113118
$this->raw = $raw;
114119
$this->sameSite = $this->withSameSite($sameSite)->sameSite;
120+
$this->partitioned = $partitioned;
115121
}
116122

117123
/**
@@ -237,6 +243,17 @@ public function withSameSite(?string $sameSite): static
237243
return $cookie;
238244
}
239245

246+
/**
247+
* Creates a cookie copy that is tied to the top-level site in cross-site context.
248+
*/
249+
public function withPartitioned(bool $partitioned = true): static
250+
{
251+
$cookie = clone $this;
252+
$cookie->partitioned = $partitioned;
253+
254+
return $cookie;
255+
}
256+
240257
/**
241258
* Returns the cookie as a string.
242259
*/
@@ -268,18 +285,22 @@ public function __toString(): string
268285
$str .= '; domain='.$this->getDomain();
269286
}
270287

271-
if (true === $this->isSecure()) {
288+
if ($this->isSecure()) {
272289
$str .= '; secure';
273290
}
274291

275-
if (true === $this->isHttpOnly()) {
292+
if ($this->isHttpOnly()) {
276293
$str .= '; httponly';
277294
}
278295

279296
if (null !== $this->getSameSite()) {
280297
$str .= '; samesite='.$this->getSameSite();
281298
}
282299

300+
if ($this->isPartitioned()) {
301+
$str .= '; partitioned';
302+
}
303+
283304
return $str;
284305
}
285306

@@ -365,6 +386,14 @@ public function isRaw(): bool
365386
return $this->raw;
366387
}
367388

389+
/**
390+
* Checks whether the cookie should be tied to the top-level site in cross-site context.
391+
*/
392+
public function isPartitioned(): bool
393+
{
394+
return $this->partitioned;
395+
}
396+
368397
/**
369398
* @return self::SAMESITE_*|null
370399
*/

src/Symfony/Component/HttpFoundation/Tests/CookieTest.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,19 @@ public function testNegativeExpirationIsNotPossible()
8787
$this->assertSame(0, $cookie->getExpiresTime());
8888
}
8989

90+
public function testMinimalParameters()
91+
{
92+
$constructedCookie = new Cookie('foo');
93+
94+
$createdCookie = Cookie::create('foo');
95+
96+
$cookie = new Cookie('foo', null, 0, '/', null, null, true, false, 'lax');
97+
98+
$this->assertEquals($constructedCookie, $cookie);
99+
100+
$this->assertEquals($createdCookie, $cookie);
101+
}
102+
90103
public function testGetValue()
91104
{
92105
$value = 'MyValue';
@@ -187,6 +200,17 @@ public function testIsHttpOnly()
187200
$this->assertTrue($cookie->isHttpOnly(), '->isHttpOnly() returns whether the cookie is only transmitted over HTTP');
188201
}
189202

203+
public function testIsPartitioned()
204+
{
205+
$cookie = new Cookie('foo', 'bar', 0, '/', '.myfoodomain.com', true, true, false, 'Lax', true);
206+
207+
$this->assertTrue($cookie->isPartitioned());
208+
209+
$cookie = Cookie::create('foo')->withPartitioned(true);
210+
211+
$this->assertTrue($cookie->isPartitioned());
212+
}
213+
190214
public function testCookieIsNotCleared()
191215
{
192216
$cookie = Cookie::create('foo', 'bar', time() + 3600 * 24);
@@ -262,6 +286,20 @@ public function testToString()
262286
->withSameSite(null);
263287
$this->assertEquals($expected, (string) $cookie, '->__toString() returns string representation of a cleared cookie if value is NULL');
264288

289+
$expected = 'foo=deleted; expires='.gmdate('D, d M Y H:i:s T', $expire = time() - 31536001).'; Max-Age=0; path=/admin/; domain=.myfoodomain.com; secure; httponly; samesite=none; partitioned';
290+
$cookie = new Cookie('foo', null, 1, '/admin/', '.myfoodomain.com', true, true, false, 'none', true);
291+
$this->assertEquals($expected, (string) $cookie, '->__toString() returns string representation of a cleared cookie if value is NULL');
292+
293+
$cookie = Cookie::create('foo')
294+
->withExpires(1)
295+
->withPath('/admin/')
296+
->withDomain('.myfoodomain.com')
297+
->withSecure(true)
298+
->withHttpOnly(true)
299+
->withSameSite('none')
300+
->withPartitioned(true);
301+
$this->assertEquals($expected, (string) $cookie, '->__toString() returns string representation of a cleared cookie if value is NULL');
302+
265303
$expected = 'foo=bar; path=/; httponly; samesite=lax';
266304
$cookie = Cookie::create('foo', 'bar');
267305
$this->assertEquals($expected, (string) $cookie);
@@ -321,6 +359,9 @@ public function testFromString()
321359

322360
$cookie = Cookie::fromString('foo_cookie=foo==; expires=Tue, 22 Sep 2020 06:27:09 GMT; path=/');
323361
$this->assertEquals(Cookie::create('foo_cookie', 'foo==', strtotime('Tue, 22 Sep 2020 06:27:09 GMT'), '/', null, false, false, true, null), $cookie);
362+
363+
$cookie = Cookie::fromString('foo_cookie=foo==; expires=Tue, 22 Sep 2020 06:27:09 GMT; path=/; secure; httponly; samesite=none; partitioned');
364+
$this->assertEquals(new Cookie('foo_cookie', 'foo==', strtotime('Tue, 22 Sep 2020 06:27:09 GMT'), '/', null, true, true, true, 'none', true), $cookie);
324365
}
325366

326367
public function testFromStringWithHttpOnly()

0 commit comments

Comments
 (0)
0