Skip to content

Commit fb4082d

Browse files
authored
fix: handle HTTP/2 responses without a reason phrase in CURLRequest (#10050)
* fix: handle HTTP/2 responses without a reason phrase in CURLRequest * add changelog * fix changelog * fix changelog
1 parent e7bf630 commit fb4082d

File tree

4 files changed

+22
-4
lines changed

4 files changed

+22
-4
lines changed

system/HTTP/CURLRequest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -504,14 +504,14 @@ protected function setResponseHeaders(array $headers = [])
504504
$this->response->setHeader($title, $value);
505505
}
506506
} elseif (str_starts_with($header, 'HTTP')) {
507-
preg_match('#^HTTP\/([12](?:\.[01])?) (\d+) (.+)#', $header, $matches);
507+
preg_match('#^HTTP\/([12](?:\.[01])?) (\d+)(?: (.+))?#', $header, $matches);
508508

509509
if (isset($matches[1])) {
510510
$this->response->setProtocolVersion($matches[1]);
511511
}
512512

513513
if (isset($matches[2])) {
514-
$this->response->setStatusCode((int) $matches[2], $matches[3] ?? null);
514+
$this->response->setStatusCode((int) $matches[2], $matches[3] ?? '');
515515
}
516516
}
517517
}

tests/system/Cookie/CookieTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ public function testArrayAccessOfCookie(): void
301301
$this->assertSame($cookie['path'], $cookie->getPath());
302302

303303
$this->expectException('InvalidArgumentException');
304-
$cookie['expiry']; // @phpstan-ignore expr.resultUnused
304+
$cookie['expiry'];
305305
}
306306

307307
public function testCannotSetPropertyViaArrayAccess(): void

tests/system/HTTP/CURLRequestTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,6 +1041,23 @@ public function testResponseHeadersShortProtocol(): void
10411041
$this->assertSame(235, $response->getStatusCode());
10421042
}
10431043

1044+
public function testResponseHeadersWithoutReasonPhrase(): void
1045+
{
1046+
// HTTP/2 does not include a reason phrase per RFC 7540.
1047+
// curl synthesizes the status line as "HTTP/2 200" with no trailing reason.
1048+
$request = $this->getRequest([
1049+
'baseURI' => 'http://www.foo.com/api/v1/',
1050+
'delay' => 100,
1051+
]);
1052+
1053+
$request->setOutput("HTTP/2 200\x0d\x0aContent-Type: text/html\x0d\x0a\x0d\x0aHi there");
1054+
$response = $request->get('bogus');
1055+
1056+
$this->assertSame('2.0', $response->getProtocolVersion());
1057+
$this->assertSame(200, $response->getStatusCode());
1058+
$this->assertSame('OK', $response->getReasonPhrase());
1059+
}
1060+
10441061
public function testPostFormEncoded(): void
10451062
{
10461063
$params = [

user_guide_src/source/changelogs/v4.7.1.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,15 @@ Bugs Fixed
5151
- **ContentSecurityPolicy:** Fixed a bug where custom CSP tags were not removed from generated HTML when CSP was disabled. The method now ensures that all custom CSP tags are removed from the generated HTML.
5252
- **ContentSecurityPolicy:** Fixed a bug where ``generateNonces()`` produces corrupted JSON responses by replacing CSP nonce placeholders with unescaped double quotes. The method now automatically JSON-escapes nonce attributes when the response Content-Type is JSON.
5353
- **ContentSecurityPolicy:** Fixed a bug where nonces generated by ``getScriptNonce()`` and ``getStyleNonce()`` were not added to the ``script-src-elem`` and ``style-src-elem`` directives, causing nonces to be silently ignored by browsers when those directives were present.
54+
- **CURLRequest:** Fixed a bug where HTTP/2 responses without a reason phrase (e.g., ``HTTP/2 200``) were not parsed correctly, causing the status code and protocol version to be ignored.
5455
- **Database:** Fixed a bug where ``BaseConnection::callFunction()`` could double-prefix already-prefixed function names.
5556
- **Database:** Fixed a bug where ``BasePreparedQuery::prepare()`` could mis-handle SQL containing colon syntax by over-broad named-placeholder replacement. It now preserves PostgreSQL cast syntax like ``::timestamp``.
5657
- **Model:** Fixed a bug where ``BaseModel::updateBatch()`` threw an exception when ``updateOnlyChanged`` was ``true`` and the index field value did not change.
5758
- **Model:** Fixed a bug where ``Model::chunk()`` ran an unnecessary extra database query at the end of iteration. ``chunk()`` now also throws ``InvalidArgumentException`` when called with a non-positive chunk size.
5859
- **Session:** Fixed a bug in ``MemcachedHandler`` where the constructor incorrectly threw an exception when ``savePath`` was not empty.
60+
- **Testing:** Fixed a bug in ``FeatureTestTrait::withRoutes()`` where invalid HTTP methods were not properly validated, thus passing them all to ``RouteCollection``.
5961
- **Toolbar:** Fixed a bug where the standalone toolbar page loaded from ``?debugbar_time=...`` was not interactive.
6062
- **Toolbar:** Fixed a bug in the Routes panel where only the first route parameter was converted to an input field on hover.
61-
- **Testing:** Fixed a bug in ``FeatureTestTrait::withRoutes()`` where invalid HTTP methods were not properly validated, thus passing them all to ``RouteCollection``.
6263
- **Validation:** Rule ``valid_cc_number`` now has the correct translation.
6364
- **Validation:** Fixed a bug where rules did not fire for array elements missing a key when using wildcard fields (e.g., ``contacts.friends.*.name``).
6465
- **View:** Fixed a bug where ``View`` would throw an error if the ``appOverridesFolder`` config property was not defined.

0 commit comments

Comments
 (0)