Skip to content

Commit ae404a8

Browse files
authored
Fix #101: Don't duplicate Host header values when getallheaders() returns non-canonical casing
1 parent 1b84708 commit ae404a8

4 files changed

Lines changed: 65 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## 3.2.2 under development
44

5+
- Bug #101: Don't duplicate `Host` header values when `getallheaders()` returns non-canonical casing (@samdark)
56
- Bug #100: Don't route emitter failures through `ErrorCatcher` in `HttpApplicationRunner` (@samdark)
67
- Enh #104: Apply PHP CS Fixer (@Tigrov)
78
- Enh #103: Refactor `RequestFactory` (@Tigrov)

src/RequestFactory.php

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
use function fopen;
1616
use function function_exists;
17-
use function getallheaders;
1817
use function is_array;
1918
use function preg_match;
2019
use function str_replace;
@@ -56,7 +55,7 @@ public function create(mixed $body = null): ServerRequestInterface
5655

5756
// Add headers
5857
foreach ($this->getHeaders() as $name => $value) {
59-
if ($name === 'Host' && $request->hasHeader('Host')) {
58+
if (strtolower($name) === 'host' && $request->hasHeader('Host')) {
6059
continue;
6160
}
6261
$request = $request->withAddedHeader($name, $value);
@@ -151,8 +150,7 @@ private function getHeaders(): array
151150
{
152151
/** @psalm-var array<string, string> $_SERVER */
153152

154-
if (function_exists('getallheaders') && ($headers = getallheaders()) !== false) {
155-
/** @psalm-var array<string, string> $headers */
153+
if (($headers = $this->getAllHeaders()) !== false) {
156154
return $headers;
157155
}
158156

@@ -180,6 +178,24 @@ private function getHeaders(): array
180178
return $headers;
181179
}
182180

181+
/**
182+
* @psalm-return array<string, string>|false
183+
*/
184+
private function getAllHeaders(): array|false
185+
{
186+
if (function_exists(__NAMESPACE__ . '\getallheaders')) {
187+
/** @psalm-var array<string, string>|false */
188+
return getallheaders();
189+
}
190+
191+
if (function_exists('getallheaders')) {
192+
/** @psalm-var array<string, string>|false */
193+
return getallheaders();
194+
}
195+
196+
return false;
197+
}
198+
183199
private function normalizeHeaderName(string $name): string
184200
{
185201
return str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $name))));

tests/RequestFactory/RequestFactoryTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,23 @@
1818

1919
final class RequestFactoryTest extends TestCase
2020
{
21+
public static array|false $getAllHeadersResult = false;
22+
2123
private array $globalServer = [];
2224
private array $globalPost = [];
2325
private array $globalFiles = [];
2426

27+
public static function setUpBeforeClass(): void
28+
{
29+
require_once __DIR__ . '/getallheaders_stub.php';
30+
}
31+
2532
protected function setUp(): void
2633
{
2734
$this->globalServer = $_SERVER;
2835
$this->globalPost = $_POST;
2936
$this->globalFiles = $_FILES;
37+
self::$getAllHeadersResult = false;
3038
}
3139

3240
protected function tearDown(): void
@@ -36,6 +44,11 @@ protected function tearDown(): void
3644
$_FILES = $this->globalFiles;
3745
}
3846

47+
public static function getAllHeadersStubResult(): array|false
48+
{
49+
return self::$getAllHeadersResult;
50+
}
51+
3952
public function testUploadedFiles(): void
4053
{
4154
$_SERVER = [
@@ -93,6 +106,23 @@ public function testHeadersParsing(): void
93106
$this->assertSame($expected, $request->getHeaders());
94107
}
95108

109+
public function testHeadersFromGetAllHeadersDoNotDuplicateHost(): void
110+
{
111+
self::$getAllHeadersResult = [
112+
'host' => 'example.com',
113+
'X-Test' => 'header-value',
114+
];
115+
$_SERVER = [
116+
'HTTP_HOST' => 'example.com',
117+
'REQUEST_METHOD' => 'GET',
118+
];
119+
120+
$request = $this->createRequestFactory()->create();
121+
122+
$this->assertSame(['example.com'], $request->getHeader('Host'));
123+
$this->assertSame(['header-value'], $request->getHeader('X-Test'));
124+
}
125+
96126
public function testInvalidMethodException(): void
97127
{
98128
$_SERVER = [];
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yiisoft\Yii\Runner\Http;
6+
7+
use function function_exists;
8+
9+
if (!function_exists(__NAMESPACE__ . '\getallheaders')) {
10+
function getallheaders(): array|false
11+
{
12+
return Tests\RequestFactory\RequestFactoryTest::getAllHeadersStubResult();
13+
}
14+
}

0 commit comments

Comments
 (0)