From 35c08ef395de1e0c621989f19e9dddefe9f4e222 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 3 Jan 2020 14:52:20 +0100 Subject: [PATCH] [HttpClient] fix casting responses to PHP streams --- .../Component/HttpClient/CurlHttpClient.php | 4 ++-- .../Component/HttpClient/NativeHttpClient.php | 2 +- .../HttpClient/Response/ResponseTrait.php | 6 ++++- .../HttpClient/Response/StreamWrapper.php | 23 +++++++++++-------- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index d26b48c19a..a36372c619 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -288,7 +288,7 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface, $pushedResponse = $pushedResponse->response; $pushedResponse->__construct($this->multi, $url, $options, $this->logger); } else { - $this->logger && $this->logger->debug(sprintf('Rejecting pushed response: "%s".', $url)); + $this->logger && $this->logger->debug(sprintf('Rejecting pushed response: "%s"', $url)); $pushedResponse = null; } } @@ -412,7 +412,7 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface, return false; } - foreach (['proxy', 'no_proxy', 'bindto'] as $k) { + foreach (['proxy', 'no_proxy', 'bindto', 'local_cert', 'local_pk'] as $k) { if ($options[$k] !== $pushedResponse->parentOptions[$k]) { return false; } diff --git a/src/Symfony/Component/HttpClient/NativeHttpClient.php b/src/Symfony/Component/HttpClient/NativeHttpClient.php index a500200aba..56405fd6a3 100644 --- a/src/Symfony/Component/HttpClient/NativeHttpClient.php +++ b/src/Symfony/Component/HttpClient/NativeHttpClient.php @@ -169,7 +169,7 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac $this->multi->dnsCache = $options['resolve'] + $this->multi->dnsCache; } - $this->logger && $this->logger->info(sprintf('Request: %s %s', $method, implode('', $url))); + $this->logger && $this->logger->info(sprintf('Request: "%s %s"', $method, implode('', $url))); [$host, $port, $url['authority']] = self::dnsResolve($url, $this->multi, $info, $onProgress); diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php index 0ea434e3a0..71a04f1e8a 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -204,7 +204,11 @@ trait ResponseTrait $this->getHeaders($throw); } - return StreamWrapper::createResource($this, null, $this->content, $this->handle && 'stream' === get_resource_type($this->handle) ? $this->handle : null); + $stream = StreamWrapper::createResource($this); + stream_get_meta_data($stream)['wrapper_data'] + ->bindHandles($this->handle, $this->content); + + return $stream; } /** diff --git a/src/Symfony/Component/HttpClient/Response/StreamWrapper.php b/src/Symfony/Component/HttpClient/Response/StreamWrapper.php index 59fd118e86..4b8566e869 100644 --- a/src/Symfony/Component/HttpClient/Response/StreamWrapper.php +++ b/src/Symfony/Component/HttpClient/Response/StreamWrapper.php @@ -43,13 +43,9 @@ class StreamWrapper /** * Creates a PHP stream resource from a ResponseInterface. * - * @param resource|null $contentBuffer The seekable resource where the response body is buffered - * @param resource|null $selectHandle The resource handle that should be monitored when - * stream_select() is used on the created stream - * * @return resource */ - public static function createResource(ResponseInterface $response, HttpClientInterface $client = null, $contentBuffer = null, $selectHandle = null) + public static function createResource(ResponseInterface $response, HttpClientInterface $client = null) { if (null === $client && !method_exists($response, 'stream')) { throw new \InvalidArgumentException(sprintf('Providing a client to "%s()" is required when the response doesn\'t have any "stream()" method.', __CLASS__)); @@ -63,8 +59,6 @@ class StreamWrapper $context = [ 'client' => $client ?? $response, 'response' => $response, - 'content' => $contentBuffer, - 'handle' => $selectHandle, ]; return fopen('symfony://'.$response->getInfo('url'), 'r', false, stream_context_create(['symfony' => $context])) ?: null; @@ -78,6 +72,17 @@ class StreamWrapper return $this->response; } + /** + * @param resource|null $handle The resource handle that should be monitored when + * stream_select() is used on the created stream + * @param resource|null $content The seekable resource where the response body is buffered + */ + public function bindHandles(&$handle, &$content): void + { + $this->handle = &$handle; + $this->content = &$content; + } + public function stream_open(string $path, string $mode, int $options): bool { if ('r' !== $mode) { @@ -91,8 +96,6 @@ class StreamWrapper $context = stream_context_get_options($this->context)['symfony'] ?? null; $this->client = $context['client'] ?? null; $this->response = $context['response'] ?? null; - $this->content = $context['content'] ?? null; - $this->handle = $context['handle'] ?? null; $this->context = null; if (null !== $this->client && null !== $this->response) { @@ -238,6 +241,8 @@ class StreamWrapper public function stream_cast(int $castAs) { if (STREAM_CAST_FOR_SELECT === $castAs) { + $this->response->getHeaders(false); + return $this->handle ?? false; }