Skip to content

Commit

Permalink
fix: add header value validation (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
msmakouz authored Apr 26, 2024
1 parent f5c329b commit 213cd0d
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 1 deletion.
6 changes: 5 additions & 1 deletion src/HttpWorker.php
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,11 @@ private function arrayToHeaderValue(array $headers = []): array
* @var array<array-key, string> $value
*/
foreach ($headers as $key => $value) {
$result[$key] = new HeaderValue(['value' => $value]);
/** @psalm-suppress DocblockTypeContradiction */
$value = \array_filter(\is_array($value) ? $value : [$value], static fn (mixed $v): bool => \is_string($v));
if ($value !== []) {
$result[$key] = new HeaderValue(['value' => $value]);
}
}

return $result;
Expand Down
49 changes: 49 additions & 0 deletions tests/Unit/HttpWorkerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,22 @@ public function testRespondWithProtoCodec(): void
$worker->respond(200, 'foo', ['Content-Type' => ['application/x-www-form-urlencoded']]);
}

#[DataProvider('headersDataProvider')]
public function testRespondWithProtoCodecWithHeaders(array $headers, array $expected): void
{
$expectedHeader = new Response(['status' => 200, 'headers' => $expected]);

$worker = $this->createMock(WorkerInterface::class);
$worker->expects($this->once())
->method('respond')
->with(new Payload('foo', $expectedHeader->serializeToString()), Frame::CODEC_PROTO);

(new \ReflectionProperty(HttpWorker::class, 'codec'))->setValue(Frame::CODEC_PROTO);
$worker = new HttpWorker($worker);

$worker->respond(200, 'foo', $headers);
}

public function testRespondWithJsonCodec(): void
{
$worker = $this->createMock(WorkerInterface::class);
Expand Down Expand Up @@ -262,6 +278,39 @@ public static function emptyRequestDataProvider(): \Traversable
yield [new Payload(null, null)];
}

public static function headersDataProvider(): \Traversable
{
yield [
['Content-Type' => ['application/x-www-form-urlencoded']],
['Content-Type' => new HeaderValue(['value' => ['application/x-www-form-urlencoded']])]
];
yield [
['Content-Type' => ['application/x-www-form-urlencoded'], 'X-Test' => ['foo', 'bar']],
[
'Content-Type' => new HeaderValue(['value' => ['application/x-www-form-urlencoded']]),
'X-Test' => new HeaderValue(['value' => ['foo', 'bar']]),
]
];
yield [['Content-Type' => [null]], []];
yield [['Content-Type' => [1]], []];
yield [['Content-Type' => [true]], []];
yield [['Content-Type' => [false]], []];
yield [['Content-Type' => [new \stdClass()]], []];
yield [['Content-Type' => [1.5]], []];
yield [
['X-Test' => ['foo', 'bar'], 'X-Test2' => ['foo', null], 'X-Test3' => [null, 1]],
[
'X-Test' => new HeaderValue(['value' => ['foo', 'bar']]),
'X-Test2' => new HeaderValue(['value' => ['foo']]),
]
];
yield [
['Content-Type' => 'application/x-www-form-urlencoded'],
['Content-Type' => new HeaderValue(['value' => ['application/x-www-form-urlencoded']])]
];
yield [['Content-Type' => new \stdClass()], []];
}

private static function createProtoRequest(array $values): \RoadRunner\HTTP\DTO\V1\Request
{
$toHeaderValue = static function (string $key, bool $wrap = true) use (&$values): void {
Expand Down

0 comments on commit 213cd0d

Please sign in to comment.