Skip to content

Commit be834db

Browse files
authored
Reject non-HTTP schemes in StreamHandler (#2989)
* 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.
1 parent cc80b00 commit be834db

File tree

2 files changed

+20
-1
lines changed

2 files changed

+20
-1
lines changed

src/Handler/StreamHandler.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,10 @@ private function createStream(RequestInterface $request, array $options)
266266
$methods = \array_flip(\get_class_methods(__CLASS__));
267267
}
268268

269+
if (!\in_array($request->getUri()->getScheme(), ['http', 'https'])) {
270+
throw new RequestException(\sprintf("The scheme '%s' is not supported.", $request->getUri()->getScheme()), $request);
271+
}
272+
269273
// HTTP/1.1 streams using the PHP stream wrapper require a
270274
// Connection: close header
271275
if ($request->getProtocolVersion() == '1.1'
@@ -318,7 +322,7 @@ static function () use ($context, $params) {
318322
return $this->createResource(
319323
function () use ($uri, &$http_response_header, $contextResource, $context, $options, $request) {
320324
$resource = @\fopen((string) $uri, 'r', false, $contextResource);
321-
$this->lastHeaders = $http_response_header;
325+
$this->lastHeaders = $http_response_header ?? [];
322326

323327
if (false === $resource) {
324328
throw new ConnectException(sprintf('Connection refused for URI %s', $uri), $request, null, $context);

tests/Handler/StreamHandlerTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,4 +738,19 @@ public function testHandlesInvalidStatusCodeGracefully()
738738
]
739739
)->wait();
740740
}
741+
742+
public function testRejectsNonHttpSchemes()
743+
{
744+
$handler = new StreamHandler();
745+
746+
$this->expectException(RequestException::class);
747+
$this->expectExceptionMessage("The scheme 'file' is not supported.");
748+
749+
$handler(
750+
new Request('GET', 'file:///etc/passwd'),
751+
[
752+
RequestOptions::STREAM => true,
753+
]
754+
)->wait();
755+
}
741756
}

0 commit comments

Comments
 (0)