Visitar URL original
[4.x] Parse the status line of responses strictly by Hackwar · Pull Request #93 · joomla-framework/http · GitHub
Skip to content

[4.x] Parse the status line of responses strictly - #93

Open
Hackwar wants to merge 1 commit into
joomla-framework:4.x-devfrom
Hackwar:4.x-status-line-parsing
Open

Hackwar wants to merge 1 commit into
joomla-framework:4.x-devfrom
Hackwar:4.x-status-line-parsing

Conversation

@Hackwar

@Hackwar Hackwar commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary of Changes

All three transports read the status code with preg_match('/[0-9]{3}/', array_shift($headers), $matches):

  • the pattern is unanchored, so it takes the first three digits anywhere in the first line: a response that starts with Content-Length: 12345 got the status code 123, and HTTP/1.1 2000 OK became 200;
  • the stream and socket transports used $matches[0] without checking the match. With no headers at all array_shift() returns null, so PHP 8.1+ raised a preg_match() null deprecation and then "Undefined array key 0", before the intended InvalidResponseCodeException.

A new protected AbstractTransport::parseStatusCode() matches ^HTTP/<version> <3 digits> (also HTTP/2 200) and throws InvalidResponseCodeException('No HTTP response code found.') when the line does not match. The three transports use it.

Testing Instructions

Tests/Transport/StatusLineTest.php (new, no server needed) calls each transport's getResponse():

  • HTTP/1.1 404 Not Found, HTTP/1.0 200 OK and HTTP/2 201 give 404, 200 and 201;
  • a header instead of a status line, digits after the reason phrase, a four-digit code and (stream) no headers at all throw InvalidResponseCodeException without any PHP warning or deprecation. Before the change all ten cases fail: a made-up code is returned, or PHP errors are raised first.

Documentation Changes Required

docs/classes/TransportInterface.md: a paragraph on parseStatusCode() and the exception.

Related to #82 (stream redirects) and #86 (another AbstractTransport helper); they touch other lines of the same files.

🤖 Generated with Claude Code

The transports took the first run of three digits anywhere in the first
header line as the status code, so a response without a status line got a
code made up from its first header, and the stream and socket transports
read $matches[0] without checking the match, which raised PHP deprecations
and "Undefined array key" warnings before the intended
InvalidResponseCodeException.

Parse the status line with an anchored pattern in a shared
AbstractTransport::parseStatusCode() and throw when it does not match.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant