Skip to content

Commit

Permalink
Reject non-HTTP schemes in StreamHandler (#2989)
Browse files Browse the repository at this point in the history
* Handle non-HTTP schemes gracefully in StreamHandler

If an URI that does not use the HTTP stream wrapper is passed to the
StreamHandler then the magic `$http_response_header` variable will not be
filled, thus remaining `null`.

This ultimately results in a `TypeError`, because `null` is passed to
HeaderProcessor::parseHeaders(), which expects an `array`.

* Reject non-HTTP schemes in StreamHandler

Non-HTTP schemes are effectively not supported, because the HTTP response
headers will only be filled for the `http` and `https` stream wrappers. Also
Guzzle is an HTTP client after all.

Reject non-HTTP schemes early on to improve error messages and to prevent
possible exploits using odd stream wrappers in case an non-fully-trusted URL is
passed to Guzzle.
  • Loading branch information
TimWolla authored Mar 13, 2022
1 parent cc80b00 commit be834db
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 1 deletion.
6 changes: 5 additions & 1 deletion src/Handler/StreamHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,10 @@ private function createStream(RequestInterface $request, array $options)
$methods = \array_flip(\get_class_methods(__CLASS__));
}

if (!\in_array($request->getUri()->getScheme(), ['http', 'https'])) {
throw new RequestException(\sprintf("The scheme '%s' is not supported.", $request->getUri()->getScheme()), $request);
}

// HTTP/1.1 streams using the PHP stream wrapper require a
// Connection: close header
if ($request->getProtocolVersion() == '1.1'
Expand Down Expand Up @@ -318,7 +322,7 @@ static function () use ($context, $params) {
return $this->createResource(
function () use ($uri, &$http_response_header, $contextResource, $context, $options, $request) {
$resource = @\fopen((string) $uri, 'r', false, $contextResource);
$this->lastHeaders = $http_response_header;
$this->lastHeaders = $http_response_header ?? [];

if (false === $resource) {
throw new ConnectException(sprintf('Connection refused for URI %s', $uri), $request, null, $context);
Expand Down
15 changes: 15 additions & 0 deletions tests/Handler/StreamHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -738,4 +738,19 @@ public function testHandlesInvalidStatusCodeGracefully()
]
)->wait();
}

public function testRejectsNonHttpSchemes()
{
$handler = new StreamHandler();

$this->expectException(RequestException::class);
$this->expectExceptionMessage("The scheme 'file' is not supported.");

$handler(
new Request('GET', 'file:///etc/passwd'),
[
RequestOptions::STREAM => true,
]
)->wait();
}
}

0 comments on commit be834db

Please sign in to comment.