Skip to content

Commit

Permalink
Skip invalid cookies
Browse files Browse the repository at this point in the history
Previously, an invalid cookie would return an empty array.
  • Loading branch information
trowski committed Dec 29, 2023
1 parent 9f3500b commit a9bfd3a
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 18 deletions.
23 changes: 13 additions & 10 deletions src/Cookie/RequestCookie.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
*/
final class RequestCookie implements \Stringable
{
private const NAME_REGEX = /** @lang RegExp */ '(^[^()<>@,;:\\\"/[\]?={}\x01-\x20\x7F]*+$)';
private const VALUE_REGEX = /** @lang RegExp */ '(^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]*+$)';

/**
* Parses the cookies from a 'cookie' header.
*
Expand All @@ -26,8 +29,8 @@ public static function fromHeader(string $string): array
$cookies = \explode(";", $string);
$result = [];

try {
foreach ($cookies as $cookie) {
foreach ($cookies as $cookie) {
try {
// Ignore zero-length cookie.
if (\trim($cookie) === '') {
continue;
Expand All @@ -36,21 +39,21 @@ public static function fromHeader(string $string): array
$parts = \explode('=', $cookie, 2);

if (\count($parts) !== 2) {
return [];
continue;
}

[$name, $value] = $parts;

$name = \trim($name);
if ($name === '') {
return [];
continue;
}

// We can safely trim quotes, as they're not allowed within cookie values
$result[] = new self($name, \trim($value, " \t\""));
} catch (InvalidCookieException) {
// Skip invalid cookie.
}
} catch (InvalidCookieException) {
return [];
}

return $result;
Expand All @@ -64,11 +67,11 @@ public static function fromHeader(string $string): array
*/
public function __construct(private string $name, private string $value = '')
{
if (!\preg_match('(^[^()<>@,;:\\\"/[\]?={}\x01-\x20\x7F]*+$)', $name)) {
if (!\preg_match(self::NAME_REGEX, $name)) {
throw new InvalidCookieException("Invalid cookie name: '{$name}'");
}

if (!\preg_match('(^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]*+$)', $value)) {
if (!\preg_match(self::VALUE_REGEX, $value)) {
throw new InvalidCookieException("Invalid cookie value: '{$value}'");
}
}
Expand All @@ -86,7 +89,7 @@ public function getName(): string
*/
public function withName(string $name): self
{
if (!\preg_match('(^[^()<>@,;:\\\"/[\]?={}\x01-\x20\x7F]++$)', $name)) {
if (!\preg_match(self::NAME_REGEX, $name)) {
throw new InvalidCookieException("Invalid cookie name: '{$name}'");
}

Expand All @@ -106,7 +109,7 @@ public function getValue(): string

public function withValue(string $value): self
{
if (!\preg_match('(^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]*+$)', $value)) {
if (!\preg_match(self::VALUE_REGEX, $value)) {
throw new InvalidCookieException("Invalid cookie value: '{$value}'");
}

Expand Down
11 changes: 7 additions & 4 deletions src/Cookie/ResponseCookie.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
*/
final class ResponseCookie implements \Stringable
{
private const NAME_REGEX = /** @lang RegExp */ '(^[^()<>@,;:\\\"/[\]?={}\x01-\x20\x7F]*+$)';
private const VALUE_REGEX = /** @lang RegExp */ '(^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]*+$)';

private static array $dateFormats = [
'D, d M Y H:i:s T',
'D, d-M-y H:i:s T',
Expand Down Expand Up @@ -164,11 +167,11 @@ public function __construct(
private string $value = '',
CookieAttributes $attributes = null,
) {
if (!\preg_match('(^[^()<>@,;:\\\"/[\]?={}\x01-\x20\x7F]++$)', $name)) {
if (!\preg_match(self::NAME_REGEX, $name)) {
throw new InvalidCookieException("Invalid cookie name: '{$name}'");
}

if (!\preg_match('(^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]*+$)', $value)) {
if (!\preg_match(self::VALUE_REGEX, $value)) {
throw new InvalidCookieException("Invalid cookie value: '{$value}'");
}

Expand All @@ -188,7 +191,7 @@ public function getName(): string
*/
public function withName(string $name): self
{
if (!\preg_match('(^[^()<>@,;:\\\"/[\]?={}\x01-\x20\x7F]++$)', $name)) {
if (!\preg_match(self::NAME_REGEX, $name)) {
throw new InvalidCookieException("Invalid cookie name: '{$name}'");
}

Expand All @@ -208,7 +211,7 @@ public function getValue(): string

public function withValue(string $value): self
{
if (!\preg_match('(^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]*+$)', $value)) {
if (!\preg_match(self::VALUE_REGEX, $value)) {
throw new InvalidCookieException("Invalid cookie value: '{$value}'");
}

Expand Down
7 changes: 3 additions & 4 deletions test/Cookie/RequestCookieTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ public function testParsing()
$this->assertEquals([new RequestCookie("a", "1"), new RequestCookie("b", "2")], RequestCookie::fromHeader("a=1; b=2"));
$this->assertEquals([new RequestCookie("a", "1"), new RequestCookie("b", "2")], RequestCookie::fromHeader("a=1 ;b=2"));
$this->assertEquals([new RequestCookie("a", "1"), new RequestCookie("b", "-2")], RequestCookie::fromHeader("a=1; b = -2"));
$this->assertSame([], RequestCookie::fromHeader("a=1; b=2 2"));

// Any missing = MUST discard the full cookie header
$this->assertSame([], RequestCookie::fromHeader("a=1; b"));
$this->assertEquals([new RequestCookie("a", "1")], RequestCookie::fromHeader("a=1; b=2,2"));
$this->assertEquals([new RequestCookie("a", "1")], RequestCookie::fromHeader("a=1; b=2 2"));
$this->assertEquals([new RequestCookie("a", "1")], RequestCookie::fromHeader("a=1; b"));
}

/**
Expand Down

0 comments on commit a9bfd3a

Please sign in to comment.