Skip to content

fix: #9407

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed

fix: #9407

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 48 additions & 1 deletion system/HTTP/Header.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace CodeIgniter\HTTP;

use InvalidArgumentException;
use Stringable;

/**
Expand Down Expand Up @@ -54,7 +55,7 @@ class Header implements Stringable
*/
public function __construct(string $name, $value = null)
{
$this->name = $name;
$this->setName($name);
$this->setValue($value);
}

Expand All @@ -81,9 +82,13 @@ public function getValue()
* Sets the name of the header, overwriting any previous value.
*
* @return $this
*
* @throws InvalidArgumentException
*/
public function setName(string $name)
{
$this->validateName($name);

$this->name = $name;

return $this;
Expand All @@ -95,11 +100,15 @@ public function setName(string $name)
* @param array<int|string, array<string, string>|string>|string|null $value
*
* @return $this
*
* @throws InvalidArgumentException
*/
public function setValue($value = null)
{
$this->value = is_array($value) ? $value : (string) $value;

$this->validateValue($value);

return $this;
}

Expand All @@ -110,13 +119,17 @@ public function setValue($value = null)
* @param array<string, string>|string|null $value
*
* @return $this
*
* @throws InvalidArgumentException
*/
public function appendValue($value = null)
{
if ($value === null) {
return $this;
}

$this->validateValue($value);

if (! is_array($this->value)) {
$this->value = [$this->value];
}
Expand All @@ -135,9 +148,13 @@ public function appendValue($value = null)
* @param array<string, string>|string|null $value
*
* @return $this
*
* @throws InvalidArgumentException
*/
public function prependValue($value = null)
{
$this->validateValue($value);

if ($value === null) {
return $this;
}
Expand Down Expand Up @@ -193,4 +210,34 @@ public function __toString(): string
{
return $this->name . ': ' . $this->getValueLine();
}

/**
* @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2
*
* @throws InvalidArgumentException
*/
private function validateName(string $name): void
{
if (preg_match("@^[!#$%&'*+.^_`|~0-9A-Za-z-]+$@D", $name) !== 1) {
throw new InvalidArgumentException('Header name must be an RFC 7230 compatible string.');
}
}

/**
* @param array<string, string>|string|null $value
*
* @throws InvalidArgumentException
*/
private function validateValue($value): void
{
if (is_string($value) && preg_match("@^[ \t\x21-\x7E\x80-\xFF]*$@D", $value) !== 1) {
throw new InvalidArgumentException('Header values must be RFC 7230 compatible strings.');
}

if (is_array($value)) {
array_map(function ($v): void {
$this->validateValue($v);
}, $value);
}
}
}
68 changes: 68 additions & 0 deletions tests/system/HTTP/HeaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

use CodeIgniter\Test\CIUnitTestCase;
use Error;
use InvalidArgumentException;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Group;
use stdClass;

Expand Down Expand Up @@ -234,4 +236,70 @@ public function testHeaderToStringShowsEntireHeader(): void

$this->assertSame($expected, (string) $header);
}

/**
* @param string $name
*/
#[DataProvider('invalidNamesProvider')]
public function testInvalidHeaderNames($name): void
{
$this->expectException(InvalidArgumentException::class);

new Header($name, 'text/html');
}

/**
* @return list<list<string>>
*/
public static function invalidNamesProvider(): array
{
return [
["Content-Type\r\n\r\n"],
["Content-Type\r\n"],
["Content-Type\n"],
["\tContent-Type\t"],
["\n\nContent-Type\n\n"],
["\r\nContent-Type"],
["\nContent-Type"],
["Content\r\n-Type"],
["\n"],
["\r\n"],
["\t"],
[' Content-Type '],
['Content - Type'],
[''],
];
}

/**
* @param array<int|string, array<string, string>|string>|string|null $value
*/
#[DataProvider('invalidValuesProvider')]
public function testInvalidHeaderValues($value): void
{
$this->expectException(InvalidArgumentException::class);

new Header('X-Test-Header', $value);
}

/**
* @return list<list<list<string>|string>>
*/
public static function invalidValuesProvider(): array
{
return [
["Header\n Value"],
["Header\r\n Value"],
["Header\r Value"],
["Header Value\n"],
["\nHeader Value"],
["Header Value\r\n"],
["\n\rHeader Value"],
["\n\nHeader Value\n\n"],
[
["Header\n Value"],
["Header\r\n Value"],
],
];
}
}
6 changes: 6 additions & 0 deletions user_guide_src/source/changelogs/v4.5.8.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ Release Date: Unreleased
BREAKING
********

Header
======

Added validation of the name and value for ``CodeIgniter\HTTP\Header``. Some specific headers can cause the system to crash.

***************
Message Changes
***************
Expand All @@ -31,6 +36,7 @@ Bugs Fixed
**********

- **Database:** Fixed a bug where ``Builder::affectedRows()`` threw an error when the previous query call failed in ``Postgre`` and ``SQLSRV`` drivers.
- **Header:** Improper headers parsing. Line breaks and other incorrect characters in headers (``CodeIgniter\HTTP\Header``) may break the HTTP request. See https://datatracker.ietf.org/doc/html/rfc7230 for more details.

See the repo's
`CHANGELOG.md <https://github.com/codeigniter4/CodeIgniter4/blob/develop/CHANGELOG.md>`_
Expand Down
Loading