From 450c3c4998d24bdc1912756114d3b42493b1ae99 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 24 Sep 2019 19:56:24 +0200 Subject: [PATCH] [HttpClient] fix race condition when reading response with informational status --- src/Symfony/Component/HttpClient/CurlHttpClient.php | 2 +- .../Component/HttpClient/Response/CurlResponse.php | 8 +++++--- .../Component/HttpClient/Response/NativeResponse.php | 6 +++++- .../Contracts/HttpClient/Test/Fixtures/web/index.php | 2 ++ 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index a1d850f94d..d2110d4132 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -355,7 +355,7 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface */ private static function acceptPushForRequest(string $method, array $options, PushedResponse $pushedResponse): bool { - if ($options['body'] || $method !== $pushedResponse->requestHeaders[':method'][0]) { + if ('' !== $options['body'] || $method !== $pushedResponse->requestHeaders[':method'][0]) { return false; } diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index 0b044630f6..532f413086 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -121,15 +121,17 @@ final class CurlResponse implements ResponseInterface if (\in_array($waitFor, ['headers', 'destruct'], true)) { try { - self::stream([$response])->current(); + foreach (self::stream([$response]) as $chunk) { + if ($chunk->isFirst()) { + break; + } + } } catch (\Throwable $e) { // Persist timeouts thrown during initialization $response->info['error'] = $e->getMessage(); $response->close(); throw $e; } - } elseif ('content' === $waitFor && ($response->multi->handlesActivity[$response->id][0] ?? null) instanceof FirstChunk) { - self::stream([$response])->current(); } curl_setopt($ch, CURLOPT_HEADERFUNCTION, null); diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php index 7aa2d8022d..2f414e3ba2 100644 --- a/src/Symfony/Component/HttpClient/Response/NativeResponse.php +++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php @@ -65,7 +65,11 @@ final class NativeResponse implements ResponseInterface } if (null === $response->remaining) { - self::stream([$response])->current(); + foreach (self::stream([$response]) as $chunk) { + if ($chunk->isFirst()) { + break; + } + } } }; } diff --git a/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php b/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php index bc613868f2..ec03bb61c2 100644 --- a/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php +++ b/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php @@ -45,6 +45,8 @@ switch ($vars['REQUEST_URI']) { header('HTTP/1.1 103 Early Hints'); header('Link: ; rel=preload; as=style', false); header('Link: ; rel=preload; as=script', false); + flush(); + usleep(1000); 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";