From f1c6449266835711d0cb1191e178e2269f6257e8 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Tue, 2 May 2023 16:25:07 -0500 Subject: [PATCH] fix: allow numeric header names RFC 7230 allows for numeric header names, both integers and floats, though the expectation is that they are provided as string values. Since PHP casts integer strings into integers for purposes of array keys, this can lead to a scenario where `HeaderSecurity` was then flagging the value as invalid - despite the fact that the regex used on strings clearly allows the value. This patch modifies `HeaderSecurity::assertValidName()` to allow for numeric names, and casts them to a string when performing validations. Fixes #11 Signed-off-by: Matthew Weier O'Phinney --- src/HeaderSecurity.php | 8 ++++---- test/HeaderSecurityTest.php | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/HeaderSecurity.php b/src/HeaderSecurity.php index d12486ae..b3495f49 100644 --- a/src/HeaderSecurity.php +++ b/src/HeaderSecurity.php @@ -148,16 +148,16 @@ public static function assertValid(mixed $value): void */ public static function assertValidName(mixed $name): void { - if (! is_string($name)) { + if (! is_string($name) && ! is_numeric($name)) { throw new Exception\InvalidArgumentException(sprintf( - 'Invalid header name type; expected string; received %s', + 'Invalid header name type; expected string or numeric value; received %s', is_object($name) ? $name::class : gettype($name) )); } - if (! preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/D', $name)) { + if (! preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/D', (string) $name)) { throw new Exception\InvalidArgumentException(sprintf( '"%s" is not valid header name', - $name + (string) $name )); } } diff --git a/test/HeaderSecurityTest.php b/test/HeaderSecurityTest.php index ca7c49d9..53acf6ce 100644 --- a/test/HeaderSecurityTest.php +++ b/test/HeaderSecurityTest.php @@ -130,4 +130,21 @@ public function testAssertValidNameRaisesExceptionForInvalidName(string $value): HeaderSecurity::assertValidName($value); } + + /** @psalm-return non-empty-array */ + public function provideValidNumericHeaderNameValues(): array + { + return [ + 'zero' => [0], + 'int' => [1], + 'zero-float' => [0.0], + 'float' => [1.1], + ]; + } + + /** @dataProvider provideValidNumericHeaderNameValues */ + public function testAssertValidNameDoesNotRaiseExceptionForValidNumericValues(int|float $value): void + { + $this->assertNull(HeaderSecurity::assertValidName($value)); + } }