Skip to content

Commit

Permalink
Merge pull request #87 from WoltLab/normalize-line-folding
Browse files Browse the repository at this point in the history
Normalize line-folded headers values to not contain newlines
  • Loading branch information
weierophinney authored May 4, 2022
2 parents 7556371 + da685b9 commit a3f03b3
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 3 deletions.
8 changes: 7 additions & 1 deletion src/MessageTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use function is_string;
use function preg_match;
use function sprintf;
use function str_replace;
use function strtolower;
use function trim;

Expand Down Expand Up @@ -399,8 +400,13 @@ private function filterHeaderValue($values) : array
return array_map(function ($value) {
HeaderSecurity::assertValid($value);

$value = (string)$value;

// Normalize line folding to a single space (RFC 7230#3.2.4).
$value = str_replace(["\r\n\t", "\r\n "], ' ', $value);

// Remove optional whitespace (OWS, RFC 7230#3.2.3) around the header value.
return trim((string) $value, "\t ");
return trim($value, "\t ");
}, array_values($values));
}

Expand Down
26 changes: 24 additions & 2 deletions test/MessageTraitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -327,13 +327,13 @@ public function testDoesNotAllowCRLFInjectionWhenCallingWithAddedHeader($name, $
public function testWithHeaderAllowsHeaderContinuations(): void
{
$message = $this->message->withHeader('X-Foo-Bar', "value,\r\n second value");
$this->assertSame("value,\r\n second value", $message->getHeaderLine('X-Foo-Bar'));
$this->assertSame("value, second value", $message->getHeaderLine('X-Foo-Bar'));
}

public function testWithAddedHeaderAllowsHeaderContinuations(): void
{
$message = $this->message->withAddedHeader('X-Foo-Bar', "value,\r\n second value");
$this->assertSame("value,\r\n second value", $message->getHeaderLine('X-Foo-Bar'));
$this->assertSame("value, second value", $message->getHeaderLine('X-Foo-Bar'));
}

/** @return non-empty-array<non-empty-string, array{non-empty-string}> */
Expand All @@ -357,6 +357,28 @@ public function testWithHeaderTrimsWhitespace(string $value): void
$this->assertSame(trim($value, "\t "), $message->getHeaderLine('X-Foo-Bar'));
}

/** @return non-empty-array<non-empty-string, array{non-empty-string}> */
public function headersWithContinuation(): array
{
return [
'space' => ["foo\r\n bar"],
'tab' => ["foo\r\n\tbar"],
];
}

/**
* @dataProvider headersWithContinuation
*/
public function testWithHeaderNormalizesContinuationToNotContainNewlines(string $value): void
{
$message = $this->message->withHeader('X-Foo-Bar', $value);
// Newlines must no longer appear.
$this->assertStringNotContainsString("\r", $message->getHeaderLine('X-Foo-Bar'));
$this->assertStringNotContainsString("\n", $message->getHeaderLine('X-Foo-Bar'));
// But there must be at least one space.
$this->assertStringContainsString(' ', $message->getHeaderLine('X-Foo-Bar'));
}

/** @return non-empty-array<non-empty-string, array{int|float}> */
public function numericHeaderValuesProvider(): array
{
Expand Down

0 comments on commit a3f03b3

Please sign in to comment.