Skip to content

Commit 82a95df

Browse files
committed
bug #25348 [HttpFoundation] Send cookies using header() to fix "SameSite" ones (nicolas-grekas, cvilleger)
This PR was merged into the 3.4 branch. Discussion ---------- [HttpFoundation] Send cookies using header() to fix "SameSite" ones | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #25344 | License | MIT | Doc PR | - Commits ------- 73fec23 [HttpFoundation] Add functional tests for Response::sendHeaders() e350ea0 [HttpFoundation] Send cookies using header() to fix "SameSite" ones
2 parents 9a0422c + 73fec23 commit 82a95df

19 files changed

+231
-30
lines changed

src/Symfony/Component/HttpFoundation/Cookie.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,12 @@ public function __toString()
145145
$str = ($this->isRaw() ? $this->getName() : urlencode($this->getName())).'=';
146146

147147
if ('' === (string) $this->getValue()) {
148-
$str .= 'deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; max-age=-31536001';
148+
$str .= 'deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; Max-Age=0';
149149
} else {
150150
$str .= $this->isRaw() ? $this->getValue() : rawurlencode($this->getValue());
151151

152152
if (0 !== $this->getExpiresTime()) {
153-
$str .= '; expires='.gmdate('D, d-M-Y H:i:s T', $this->getExpiresTime()).'; max-age='.$this->getMaxAge();
153+
$str .= '; expires='.gmdate('D, d-M-Y H:i:s T', $this->getExpiresTime()).'; Max-Age='.$this->getMaxAge();
154154
}
155155
}
156156

@@ -224,7 +224,9 @@ public function getExpiresTime()
224224
*/
225225
public function getMaxAge()
226226
{
227-
return 0 !== $this->expire ? $this->expire - time() : 0;
227+
$maxAge = $this->expire - time();
228+
229+
return 0 >= $maxAge ? 0 : $maxAge;
228230
}
229231

230232
/**

src/Symfony/Component/HttpFoundation/Response.php

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ public function sendHeaders()
327327
}
328328

329329
// headers
330-
foreach ($this->headers->allPreserveCaseWithoutCookies() as $name => $values) {
330+
foreach ($this->headers->allPreserveCase() as $name => $values) {
331331
foreach ($values as $value) {
332332
header($name.': '.$value, false, $this->statusCode);
333333
}
@@ -336,15 +336,6 @@ public function sendHeaders()
336336
// status
337337
header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText), true, $this->statusCode);
338338

339-
// cookies
340-
foreach ($this->headers->getCookies() as $cookie) {
341-
if ($cookie->isRaw()) {
342-
setrawcookie($cookie->getName(), $cookie->getValue(), $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly());
343-
} else {
344-
setcookie($cookie->getName(), $cookie->getValue(), $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly());
345-
}
346-
}
347-
348339
return $this;
349340
}
350341

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,13 @@ public function testCookieIsCleared()
162162
public function testToString()
163163
{
164164
$cookie = new Cookie('foo', 'bar', $expire = strtotime('Fri, 20-May-2011 15:25:52 GMT'), '/', '.myfoodomain.com', true);
165-
$this->assertEquals('foo=bar; expires=Fri, 20-May-2011 15:25:52 GMT; max-age='.($expire - time()).'; path=/; domain=.myfoodomain.com; secure; httponly', (string) $cookie, '->__toString() returns string representation of the cookie');
165+
$this->assertEquals('foo=bar; expires=Fri, 20-May-2011 15:25:52 GMT; Max-Age=0; path=/; domain=.myfoodomain.com; secure; httponly', (string) $cookie, '->__toString() returns string representation of the cookie');
166166

167167
$cookie = new Cookie('foo', 'bar with white spaces', strtotime('Fri, 20-May-2011 15:25:52 GMT'), '/', '.myfoodomain.com', true);
168-
$this->assertEquals('foo=bar%20with%20white%20spaces; expires=Fri, 20-May-2011 15:25:52 GMT; max-age='.($expire - time()).'; path=/; domain=.myfoodomain.com; secure; httponly', (string) $cookie, '->__toString() encodes the value of the cookie according to RFC 3986 (white space = %20)');
168+
$this->assertEquals('foo=bar%20with%20white%20spaces; expires=Fri, 20-May-2011 15:25:52 GMT; Max-Age=0; path=/; domain=.myfoodomain.com; secure; httponly', (string) $cookie, '->__toString() encodes the value of the cookie according to RFC 3986 (white space = %20)');
169169

170170
$cookie = new Cookie('foo', null, 1, '/admin/', '.myfoodomain.com');
171-
$this->assertEquals('foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', $expire = time() - 31536001).'; max-age='.($expire - time()).'; path=/admin/; domain=.myfoodomain.com; httponly', (string) $cookie, '->__toString() returns string representation of a cleared cookie if value is NULL');
171+
$this->assertEquals('foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', $expire = time() - 31536001).'; Max-Age=0; path=/admin/; domain=.myfoodomain.com; httponly', (string) $cookie, '->__toString() returns string representation of a cleared cookie if value is NULL');
172172

173173
$cookie = new Cookie('foo', 'bar', 0, '/', '');
174174
$this->assertEquals('foo=bar; path=/; httponly', (string) $cookie);
@@ -194,7 +194,7 @@ public function testGetMaxAge()
194194
$this->assertEquals($expire - time(), $cookie->getMaxAge());
195195

196196
$cookie = new Cookie('foo', 'bar', $expire = time() - 100);
197-
$this->assertEquals($expire - time(), $cookie->getMaxAge());
197+
$this->assertEquals(0, $cookie->getMaxAge());
198198
}
199199

200200
public function testFromString()
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
use Symfony\Component\HttpFoundation\Response;
4+
5+
$parent = __DIR__;
6+
while (!@file_exists($parent.'/vendor/autoload.php')) {
7+
if (!@file_exists($parent)) {
8+
// open_basedir restriction in effect
9+
break;
10+
}
11+
if ($parent === dirname($parent)) {
12+
echo "vendor/autoload.php not found\n";
13+
exit(1);
14+
}
15+
16+
$parent = dirname($parent);
17+
}
18+
19+
require $parent.'/vendor/autoload.php';
20+
21+
error_reporting(-1);
22+
ini_set('html_errors', 0);
23+
ini_set('display_errors', 1);
24+
25+
header_remove('X-Powered-By');
26+
header('Content-Type: text/plain; charset=utf-8');
27+
28+
register_shutdown_function(function () {
29+
echo "\n";
30+
session_write_close();
31+
print_r(headers_list());
32+
echo "shutdown\n";
33+
});
34+
ob_start();
35+
36+
$r = new Response();
37+
$r->headers->set('Date', 'Sat, 12 Nov 1955 20:04:00 GMT');
38+
39+
return $r;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
Warning: Expiry date cannot have a year greater than 9999 in %scookie_max_age.php on line 10
3+
4+
Array
5+
(
6+
[0] => Content-Type: text/plain; charset=utf-8
7+
[1] => Cache-Control: no-cache, private
8+
[2] => Date: Sat, 12 Nov 1955 20:04:00 GMT
9+
[3] => Set-Cookie: foo=bar; expires=Sat, 01-Jan-10000 02:46:40 GMT; Max-Age=%d; path=/
10+
)
11+
shutdown
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
use Symfony\Component\HttpFoundation\Cookie;
4+
5+
$r = require __DIR__.'/common.inc';
6+
7+
$r->headers->setCookie(new Cookie('foo', 'bar', 253402310800, '', null, false, false));
8+
$r->sendHeaders();
9+
10+
setcookie('foo2', 'bar', 253402310800, '/');
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
Array
3+
(
4+
[0] => Content-Type: text/plain; charset=utf-8
5+
[1] => Cache-Control: no-cache, private
6+
[2] => Date: Sat, 12 Nov 1955 20:04:00 GMT
7+
[3] => Set-Cookie: ?*():@&+$/%#[]=?*():@&+$/%#[]; path=/
8+
[4] => Set-Cookie: ?*():@&+$/%#[]=?*():@&+$/%#[]; path=/
9+
)
10+
shutdown
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
use Symfony\Component\HttpFoundation\Cookie;
4+
5+
$r = require __DIR__.'/common.inc';
6+
7+
$str = '?*():@&+$/%#[]';
8+
9+
$r->headers->setCookie(new Cookie($str, $str, 0, '/', null, false, false, true));
10+
$r->sendHeaders();
11+
12+
setrawcookie($str, $str, 0, '/', null, false, false);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
Array
3+
(
4+
[0] => Content-Type: text/plain; charset=utf-8
5+
[1] => Cache-Control: no-cache, private
6+
[2] => Date: Sat, 12 Nov 1955 20:04:00 GMT
7+
[3] => Set-Cookie: CookieSamesiteLaxTest=LaxValue; path=/; httponly; samesite=lax
8+
)
9+
shutdown
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
use Symfony\Component\HttpFoundation\Cookie;
4+
5+
$r = require __DIR__.'/common.inc';
6+
7+
$r->headers->setCookie(new Cookie('CookieSamesiteLaxTest', 'LaxValue', 0, '/', null, false, true, false, Cookie::SAMESITE_LAX));
8+
$r->sendHeaders();

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy