Skip to content

Commit

Permalink
Cast header values when using set/replaceHeaders()
Browse files Browse the repository at this point in the history
Closes #22.
  • Loading branch information
trowski committed Mar 9, 2023
1 parent f9e3849 commit 0dc8069
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 18 deletions.
6 changes: 6 additions & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
</projectFiles>

<issueHandlers>
<DocblockTypeContradiction>
<errorLevel type="suppress">
<directory name="src" />
</errorLevel>
</DocblockTypeContradiction>

<MissingClosureReturnType>
<errorLevel type="suppress">
<directory name="src" />
Expand Down
47 changes: 30 additions & 17 deletions src/HttpMessage.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,7 @@ protected function setHeaders(array $headers): void
$this->headerCase = [];

try {
foreach ($headers as $name => $value) {
$this->setHeader($name, $value);
}
$this->setHeadersFromArray($headers);
} catch (\Throwable $e) {
$this->headers = $before;
$this->headerCase = $beforeCase;
Expand All @@ -112,9 +110,7 @@ protected function replaceHeaders(array $headers): void
$beforeCase = $this->headerCase;

try {
foreach ($headers as $name => $value) {
$this->setHeader($name, $value);
}
$this->setHeadersFromArray($headers);
} catch (\Throwable $e) {
$this->headers = $before;
$this->headerCase = $beforeCase;
Expand All @@ -123,6 +119,20 @@ protected function replaceHeaders(array $headers): void
}
}

/**
* @param HeaderParamArrayType $headers
*/
private function setHeadersFromArray(array $headers): void
{
foreach ($headers as $name => $value) {
if (!\is_string($value) && !\is_array($value)) {
$value = self::castHeaderValue($value);
}

$this->setHeader($name, $value);
}
}

/**
* Sets the named header to the given value.
*
Expand Down Expand Up @@ -210,9 +220,16 @@ public function hasHeader(string $name): bool
return isset($this->headers[HEADER_LOWERCASE_MAP[$name] ?? \strtolower($name)]);
}

private function isNameValid(string $name): bool
private static function castHeaderValue(mixed $value): string
{
return (bool) \preg_match('/^[A-Za-z0-9`~!#$%^&_|\'\-*+.]+$/', $name);
return match (true) {
\is_string($value) => $value,
\is_int($value), \is_float($value), $value instanceof \Stringable => (string) $value,
default => throw new \TypeError(\sprintf(
'Header array may contain only types which may be cast to a string; got "%s"',
\get_debug_type($value),
)),
};
}

/**
Expand All @@ -223,16 +240,12 @@ private static function castHeaderArrayValues(array $values): array
{
static $mapper;

$mapper ??= static fn (mixed $value) => match (true) {
\is_string($value) => $value,
\is_int($value), \is_float($value), $value instanceof \Stringable => (string) $value,
default => throw new \TypeError(\sprintf(
'Header array may contain only types which may be cast to a string; got "%s"',
\get_debug_type($value),
)),
};
return \array_map($mapper ??= self::castHeaderValue(...), \array_values($values));
}

return \array_map($mapper, \array_values($values));
private function isNameValid(string $name): bool
{
return (bool) \preg_match('/^[A-Za-z0-9`~!#$%^&_|\'\-*+.]+$/', $name);
}

/**
Expand Down
4 changes: 3 additions & 1 deletion test/HttpMessageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,14 @@ public function testSetAndReplaceHeaders(): void
$this->assertTrue($message->hasHeader('baz'));
$this->assertSame(['baz'], $message->getHeaderArray('baz'));

$message->setHeaders(['foo' => ['new']]);
$message->setHeaders(['foo' => ['new'], 'qux' => 1]);
$this->assertSame(['new'], $message->getHeaderArray('foo'));
$this->assertFalse($message->hasHeader('bar'));
$this->assertSame([], $message->getHeaderArray('bar'));
$this->assertFalse($message->hasHeader('baz'));
$this->assertSame([], $message->getHeaderArray('baz'));
$this->assertTrue($message->hasHeader('qux'));
$this->assertSame(['1'], $message->getHeaderArray('qux'));

$message->setHeader('bar', ['biz', 'baz']);
$this->assertSame(['biz', 'baz'], $message->getHeaderArray('bar'));
Expand Down

0 comments on commit 0dc8069

Please sign in to comment.