From 4db140277038f16eb4b6af9477a6b152966de7c2 Mon Sep 17 00:00:00 2001 From: marie <15118505+marie@users.noreply.github.com> Date: Fri, 20 Sep 2019 15:03:12 +0500 Subject: [PATCH 1/2] [HttpFoundation] allow additinal characters in not raw cookies --- .../Component/HttpFoundation/Cookie.php | 21 +++++++++++++---- .../Component/HttpFoundation/Response.php | 2 +- .../HttpFoundation/Tests/CookieTest.php | 23 +++++++++++++++---- .../cookie_urlencode.expected | 3 ++- .../response-functional/cookie_urlencode.php | 9 +++++--- .../invalid_cookie_name.php | 2 +- 6 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Cookie.php b/src/Symfony/Component/HttpFoundation/Cookie.php index 83a97087f1..98a5ef00a8 100644 --- a/src/Symfony/Component/HttpFoundation/Cookie.php +++ b/src/Symfony/Component/HttpFoundation/Cookie.php @@ -18,6 +18,10 @@ namespace Symfony\Component\HttpFoundation; */ class Cookie { + const SAMESITE_NONE = 'none'; + const SAMESITE_LAX = 'lax'; + const SAMESITE_STRICT = 'strict'; + protected $name; protected $value; protected $domain; @@ -25,12 +29,13 @@ class Cookie protected $path; protected $secure; protected $httpOnly; + private $raw; private $sameSite; - const SAMESITE_NONE = 'none'; - const SAMESITE_LAX = 'lax'; - const SAMESITE_STRICT = 'strict'; + private static $reservedCharsList = "=,; \t\r\n\v\f"; + private static $reservedCharsFrom = ['=', ',', ';', ' ', "\t", "\r", "\n", "\v", "\f"]; + private static $reservedCharsTo = ['%3D', '%2C', '%3B', '%20', '%09', '%0D', '%0A', '%0B', '%0C']; /** * Creates cookie from raw header string. @@ -97,7 +102,7 @@ class Cookie public function __construct($name, $value = null, $expire = 0, $path = '/', $domain = null, $secure = false, $httpOnly = true, $raw = false, $sameSite = null) { // from PHP source code - if (preg_match("/[=,; \t\r\n\013\014]/", $name)) { + if ($raw && false !== strpbrk($name, self::$reservedCharsList)) { throw new \InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $name)); } @@ -143,7 +148,13 @@ class Cookie */ public function __toString() { - $str = ($this->isRaw() ? $this->getName() : urlencode($this->getName())).'='; + if ($this->isRaw()) { + $str = $this->getName(); + } else { + $str = str_replace(self::$reservedCharsFrom, self::$reservedCharsTo, $this->getName()); + } + + $str .= '='; if ('' === (string) $this->getValue()) { $str .= 'deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; Max-Age=0'; diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php index 8a17acdd5f..26e3a3378e 100644 --- a/src/Symfony/Component/HttpFoundation/Response.php +++ b/src/Symfony/Component/HttpFoundation/Response.php @@ -342,7 +342,7 @@ class Response // cookies foreach ($this->headers->getCookies() as $cookie) { - header('Set-Cookie: '.$cookie->getName().strstr($cookie, '='), false, $this->statusCode); + header('Set-Cookie: '.$cookie, false, $this->statusCode); } // status diff --git a/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php b/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php index 38c195df36..169f917875 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php @@ -24,10 +24,9 @@ use Symfony\Component\HttpFoundation\Cookie; */ class CookieTest extends TestCase { - public function invalidNames() + public function namesWithSpecialCharacters() { return [ - [''], [',MyName'], [';MyName'], [' MyName'], @@ -40,12 +39,26 @@ class CookieTest extends TestCase } /** - * @dataProvider invalidNames + * @dataProvider namesWithSpecialCharacters */ - public function testInstantiationThrowsExceptionIfCookieNameContainsInvalidCharacters($name) + public function testInstantiationThrowsExceptionIfRawCookieNameContainsSpecialCharacters($name) { $this->expectException('InvalidArgumentException'); - new Cookie($name); + new Cookie($name, null, 0, null, null, null, false, true); + } + + /** + * @dataProvider namesWithSpecialCharacters + */ + public function testInstantiationSucceedNonRawCookieNameContainsSpecialCharacters($name) + { + $this->assertInstanceOf(Cookie::class, new Cookie($name)); + } + + public function testInstantiationThrowsExceptionIfCookieNameIsEmpty() + { + $this->expectException('InvalidArgumentException'); + new Cookie(''); } public function testInvalidExpiration() diff --git a/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/cookie_urlencode.expected b/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/cookie_urlencode.expected index 14e44a398a..17a9efc669 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/cookie_urlencode.expected +++ b/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/cookie_urlencode.expected @@ -4,7 +4,8 @@ Array [0] => Content-Type: text/plain; charset=utf-8 [1] => Cache-Control: no-cache, private [2] => Date: Sat, 12 Nov 1955 20:04:00 GMT - [3] => Set-Cookie: ?*():@&+$/%#[]=%3F%2A%28%29%3A%40%26%2B%24%2F%25%23%5B%5D; path=/ + [3] => Set-Cookie: %3D%2C%3B%20%09%0D%0A%0B%0C=%3D%2C%3B%20%09%0D%0A%0B%0C; path=/ [4] => Set-Cookie: ?*():@&+$/%#[]=%3F%2A%28%29%3A%40%26%2B%24%2F%25%23%5B%5D; path=/ + [5] => Set-Cookie: ?*():@&+$/%#[]=%3F%2A%28%29%3A%40%26%2B%24%2F%25%23%5B%5D; path=/ ) shutdown diff --git a/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/cookie_urlencode.php b/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/cookie_urlencode.php index 05b9af30d5..9ffb0dfec8 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/cookie_urlencode.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/cookie_urlencode.php @@ -4,9 +4,12 @@ use Symfony\Component\HttpFoundation\Cookie; $r = require __DIR__.'/common.inc'; -$str = '?*():@&+$/%#[]'; +$str1 = "=,; \t\r\n\v\f"; +$r->headers->setCookie(new Cookie($str1, $str1, 0, '', null, false, false, false, null)); -$r->headers->setCookie(new Cookie($str, $str, 0, '', null, false, false)); +$str2 = '?*():@&+$/%#[]'; + +$r->headers->setCookie(new Cookie($str2, $str2, 0, '', null, false, false, false, null)); $r->sendHeaders(); -setcookie($str, $str, 0, '/'); +setcookie($str2, $str2, 0, '/'); diff --git a/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/invalid_cookie_name.php b/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/invalid_cookie_name.php index 3fe1571845..3acf86039d 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/invalid_cookie_name.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/invalid_cookie_name.php @@ -5,7 +5,7 @@ use Symfony\Component\HttpFoundation\Cookie; $r = require __DIR__.'/common.inc'; try { - $r->headers->setCookie(new Cookie('Hello + world', 'hodor')); + $r->headers->setCookie(new Cookie('Hello + world', 'hodor', 0, null, null, null, false, true)); } catch (\InvalidArgumentException $e) { echo $e->getMessage(); } From fda5b20c3974bb6269d2ff9e29dd61a495af1cf4 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 28 Sep 2019 18:12:11 +0200 Subject: [PATCH 2/2] sync phpunit script with master --- phpunit | 3 +++ 1 file changed, 3 insertions(+) diff --git a/phpunit b/phpunit index d334dc0720..b07ca07d06 100755 --- a/phpunit +++ b/phpunit @@ -17,5 +17,8 @@ if (!getenv('SYMFONY_PHPUNIT_VERSION')) { putenv('SYMFONY_PHPUNIT_VERSION=6.5'); } } +if (!getenv('SYMFONY_PATCH_TYPE_DECLARATIONS')) { + putenv('SYMFONY_PATCH_TYPE_DECLARATIONS=deprecations=1'); +} putenv('SYMFONY_PHPUNIT_DIR='.__DIR__.'/.phpunit'); require __DIR__.'/vendor/symfony/phpunit-bridge/bin/simple-phpunit';