Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 59d6acf

Browse filesBrowse files
OskarStarknicolas-grekas
authored andcommitted
[HttpFoundation] Do not swallow trailing = in cookie value
1 parent 878393e commit 59d6acf
Copy full SHA for 59d6acf

File tree

3 files changed

+39
-33
lines changed
Filter options

3 files changed

+39
-33
lines changed

‎src/Symfony/Component/HttpFoundation/HeaderUtils.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/HeaderUtils.php
+32-31Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,21 @@ private function __construct()
3333
*
3434
* Example:
3535
*
36-
* HeaderUtils::split("da, en-gb;q=0.8", ",;")
36+
* HeaderUtils::split('da, en-gb;q=0.8', ',;')
3737
* // => ['da'], ['en-gb', 'q=0.8']]
3838
*
3939
* @param string $separators List of characters to split on, ordered by
40-
* precedence, e.g. ",", ";=", or ",;="
40+
* precedence, e.g. ',', ';=', or ',;='
4141
*
4242
* @return array Nested array with as many levels as there are characters in
4343
* $separators
4444
*/
4545
public static function split(string $header, string $separators): array
4646
{
47+
if ('' === $separators) {
48+
throw new \InvalidArgumentException('At least one separator must be specified.');
49+
}
50+
4751
$quotedSeparators = preg_quote($separators, '/');
4852

4953
preg_match_all('
@@ -77,8 +81,8 @@ public static function split(string $header, string $separators): array
7781
*
7882
* Example:
7983
*
80-
* HeaderUtils::combine([["foo", "abc"], ["bar"]])
81-
* // => ["foo" => "abc", "bar" => true]
84+
* HeaderUtils::combine([['foo', 'abc'], ['bar']])
85+
* // => ['foo' => 'abc', 'bar' => true]
8286
*/
8387
public static function combine(array $parts): array
8488
{
@@ -95,13 +99,13 @@ public static function combine(array $parts): array
9599
/**
96100
* Joins an associative array into a string for use in an HTTP header.
97101
*
98-
* The key and value of each entry are joined with "=", and all entries
102+
* The key and value of each entry are joined with '=', and all entries
99103
* are joined with the specified separator and an additional space (for
100104
* readability). Values are quoted if necessary.
101105
*
102106
* Example:
103107
*
104-
* HeaderUtils::toString(["foo" => "abc", "bar" => true, "baz" => "a b c"], ",")
108+
* HeaderUtils::toString(['foo' => 'abc', 'bar' => true, 'baz' => 'a b c'], ',')
105109
* // => 'foo=abc, bar, baz="a b c"'
106110
*/
107111
public static function toString(array $assoc, string $separator): string
@@ -252,40 +256,37 @@ public static function parseQuery(string $query, bool $ignoreBrackets = false, s
252256
private static function groupParts(array $matches, string $separators, bool $first = true): array
253257
{
254258
$separator = $separators[0];
255-
$partSeparators = substr($separators, 1);
256-
259+
$separators = substr($separators, 1);
257260
$i = 0;
261+
262+
if ('' === $separators && !$first) {
263+
$parts = [''];
264+
265+
foreach ($matches as $match) {
266+
if (!$i && isset($match['separator'])) {
267+
$i = 1;
268+
$parts[1] = '';
269+
} else {
270+
$parts[$i] .= self::unquote($match[0]);
271+
}
272+
}
273+
274+
return $parts;
275+
}
276+
277+
$parts = [];
258278
$partMatches = [];
259-
$previousMatchWasSeparator = false;
279+
260280
foreach ($matches as $match) {
261-
if (!$first && $previousMatchWasSeparator && isset($match['separator']) && $match['separator'] === $separator) {
262-
$previousMatchWasSeparator = true;
263-
$partMatches[$i][] = $match;
264-
} elseif (isset($match['separator']) && $match['separator'] === $separator) {
265-
$previousMatchWasSeparator = true;
281+
if (($match['separator'] ?? null ) === $separator) {
266282
++$i;
267283
} else {
268-
$previousMatchWasSeparator = false;
269284
$partMatches[$i][] = $match;
270285
}
271286
}
272287

273-
$parts = [];
274-
if ($partSeparators) {
275-
foreach ($partMatches as $matches) {
276-
$parts[] = self::groupParts($matches, $partSeparators, false);
277-
}
278-
} else {
279-
foreach ($partMatches as $matches) {
280-
$parts[] = self::unquote($matches[0][0]);
281-
}
282-
283-
if (!$first && 2 < \count($parts)) {
284-
$parts = [
285-
$parts[0],
286-
implode($separator, \array_slice($parts, 1)),
287-
];
288-
}
288+
foreach ($partMatches as $matches) {
289+
$parts[] = '' === $separators ? self::unquote($matches[0][0]) : self::groupParts($matches, $separators, false);
289290
}
290291

291292
return $parts;

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/Tests/CookieTest.php
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,9 @@ public function testFromString()
324324
$cookie = Cookie::fromString('foo=bar', true);
325325
$this->assertEquals(Cookie::create('foo', 'bar', 0, '/', null, false, false, false, null), $cookie);
326326

327+
$cookie = Cookie::fromString('foo=bar=', true);
328+
$this->assertEquals(Cookie::create('foo', 'bar=', 0, '/', null, false, false, false, null), $cookie);
329+
327330
$cookie = Cookie::fromString('foo', true);
328331
$this->assertEquals(Cookie::create('foo', null, 0, '/', null, false, false, false, null), $cookie);
329332

‎src/Symfony/Component/HttpFoundation/Tests/HeaderUtilsTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/Tests/HeaderUtilsTest.php
+4-2Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public static function provideHeaderToSplit(): array
3434
[['foo', '123, bar'], 'foo=123, bar', '='],
3535
[['foo', '123, bar'], ' foo = 123, bar ', '='],
3636
[[['foo', '123'], ['bar']], 'foo=123, bar', ',='],
37-
[[[['foo', '123']], [['bar'], ['foo', '456']]], 'foo=123, bar; foo=456', ',;='],
37+
[[[['foo', '123']], [['bar'], ['foo', '456']]], 'foo=123, bar;; foo=456', ',;='],
3838
[[[['foo', 'a,b;c=d']]], 'foo="a,b;c=d"', ',;='],
3939

4040
[['foo', 'bar'], 'foo,,,, bar', ','],
@@ -46,13 +46,15 @@ public static function provideHeaderToSplit(): array
4646

4747
[[['foo_cookie', 'foo=1&bar=2&baz=3'], ['expires', 'Tue, 22-Sep-2020 06:27:09 GMT'], ['path', '/']], 'foo_cookie=foo=1&bar=2&baz=3; expires=Tue, 22-Sep-2020 06:27:09 GMT; path=/', ';='],
4848
[[['foo_cookie', 'foo=='], ['expires', 'Tue, 22-Sep-2020 06:27:09 GMT'], ['path', '/']], 'foo_cookie=foo==; expires=Tue, 22-Sep-2020 06:27:09 GMT; path=/', ';='],
49+
[[['foo_cookie', 'foo='], ['expires', 'Tue, 22-Sep-2020 06:27:09 GMT'], ['path', '/']], 'foo_cookie=foo=; expires=Tue, 22-Sep-2020 06:27:09 GMT; path=/', ';='],
4950
[[['foo_cookie', 'foo=a=b'], ['expires', 'Tue, 22-Sep-2020 06:27:09 GMT'], ['path', '/']], 'foo_cookie=foo="a=b"; expires=Tue, 22-Sep-2020 06:27:09 GMT; path=/', ';='],
5051

5152
// These are not a valid header values. We test that they parse anyway,
5253
// and that both the valid and invalid parts are returned.
5354
[[], '', ','],
5455
[[], ',,,', ','],
55-
[['foo', 'bar', 'baz'], 'foo, "bar", "baz', ','],
56+
[[['', 'foo'], ['bar', '']], '=foo,bar=', ',='],
57+
[['foo', 'foobar', 'baz'], 'foo, foo"bar", "baz', ','],
5658
[['foo', 'bar, baz'], 'foo, "bar, baz', ','],
5759
[['foo', 'bar, baz\\'], 'foo, "bar, baz\\', ','],
5860
[['foo', 'bar, baz\\'], 'foo, "bar, baz\\\\', ','],

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.