From 412411d795d8c264d6b902b95b1db5dba4bfb04d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 23 Jun 2019 19:28:28 +0200 Subject: [PATCH] [HttpClient] fix dealing with 1xx informational responses --- .../HttpClient/Response/CurlResponse.php | 27 ++++++++++++------- .../HttpClient/Test/Fixtures/web/index.php | 11 ++++++++ .../HttpClient/Test/HttpClientTestCase.php | 9 +++++++ 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index 14d3f935e0..0c2130241d 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -289,7 +289,19 @@ final class CurlResponse implements ResponseInterface // Regular header line: add it to the list self::addResponseHeaders([substr($data, 0, -2)], $info, $headers); - if (0 === strpos($data, 'HTTP') && 300 <= $info['http_code'] && $info['http_code'] < 400) { + if (0 !== strpos($data, 'HTTP/')) { + if (0 === stripos($data, 'Location:')) { + $location = trim(substr($data, 9, -2)); + } + + return \strlen($data); + } + + if (\function_exists('openssl_x509_read') && $certinfo = curl_getinfo($ch, CURLINFO_CERTINFO)) { + $info['peer_certificate_chain'] = array_map('openssl_x509_read', array_column($certinfo, 'Cert')); + } + + if (300 <= $info['http_code'] && $info['http_code'] < 400) { if (curl_getinfo($ch, CURLINFO_REDIRECT_COUNT) === $options['max_redirects']) { curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); } elseif (303 === $info['http_code'] || ('POST' === $info['http_method'] && \in_array($info['http_code'], [301, 302], true))) { @@ -298,15 +310,14 @@ final class CurlResponse implements ResponseInterface } } - if (0 === stripos($data, 'Location:')) { - $location = trim(substr($data, 9, -2)); - } - return \strlen($data); } // End of headers: handle redirects and add to the activity list - $statusCode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE); + if (200 > $statusCode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE)) { + return \strlen($data); + } + $info['redirect_url'] = null; if (300 <= $statusCode && $statusCode < 400 && null !== $location) { @@ -336,10 +347,6 @@ final class CurlResponse implements ResponseInterface return 0; } - if (\function_exists('openssl_x509_read') && $certinfo = curl_getinfo($ch, CURLINFO_CERTINFO)) { - $info['peer_certificate_chain'] = array_map('openssl_x509_read', array_column($certinfo, 'Cert')); - } - curl_setopt($ch, CURLOPT_PRIVATE, 'content'); } elseif (null !== $info['redirect_url'] && $logger) { $logger->info(sprintf('Redirecting: "%s %s"', $info['http_code'], $info['redirect_url'])); diff --git a/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php b/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php index 8d1762913c..bc613868f2 100644 --- a/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php +++ b/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php @@ -41,6 +41,17 @@ switch ($vars['REQUEST_URI']) { ob_start('ob_gzhandler'); break; + case '/103': + header('HTTP/1.1 103 Early Hints'); + header('Link: ; rel=preload; as=style', false); + header('Link: ; rel=preload; as=script', false); + echo "HTTP/1.1 200 OK\r\n"; + echo "Date: Fri, 26 May 2017 10:02:11 GMT\r\n"; + echo "Content-Length: 13\r\n"; + echo "\r\n"; + echo 'Here the body'; + exit; + case '/404': header('Content-Type: application/json', true, 404); break; diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php index c995bc26fc..c0acd55cea 100644 --- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php +++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php @@ -721,6 +721,15 @@ abstract class HttpClientTestCase extends TestCase $this->assertSame('/?a=a&b=b', $body['REQUEST_URI']); } + public function testInformationalResponse() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/103'); + + $this->assertSame('Here the body', $response->getContent()); + $this->assertSame(200, $response->getStatusCode()); + } + /** * @requires extension zlib */