diff --git a/src/Symfony/Component/HttpClient/Response/AsyncResponse.php b/src/Symfony/Component/HttpClient/Response/AsyncResponse.php index 69522f7e871f0..dc70ed8ae7e30 100644 --- a/src/Symfony/Component/HttpClient/Response/AsyncResponse.php +++ b/src/Symfony/Component/HttpClient/Response/AsyncResponse.php @@ -34,6 +34,7 @@ final class AsyncResponse implements ResponseInterface, StreamableInterface private $response; private $info = ['canceled' => false]; private $passthru; + private $lastYielded = false; /** * @param ?callable(ChunkInterface, AsyncContext): ?\Iterator $passthru @@ -255,7 +256,10 @@ public static function stream(iterable $responses, float $timeout = null, string } } - if (null === $chunk->getError() && !$chunk->isLast() && $r->response === $response && null !== $r->client) { + if (null === $chunk->getError() && $chunk->isLast()) { + $r->lastYielded = true; + } + if (null === $chunk->getError() && !$r->lastYielded && $r->response === $response && null !== $r->client) { throw new \LogicException('A chunk passthru must yield an "isLast()" chunk before ending a stream.'); } diff --git a/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php b/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php index 82b36e1871259..66701a9f9dee6 100644 --- a/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php +++ b/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php @@ -230,4 +230,27 @@ public function testRetryTimeout() $this->assertSame(200, $response->getStatusCode()); } + + public function testRecurciveStream() + { + $client = new class(parent::getHttpClient(__FUNCTION__)) implements HttpClientInterface { + use AsyncDecoratorTrait; + + public function request(string $method, string $url, array $options = []): ResponseInterface + { + return new AsyncResponse($this->client, $method, $url, $options); + } + }; + + $response = $client->request('GET', 'http://localhost:8057/json'); + $content = ''; + foreach ($client->stream($response) as $chunk) { + $content .= $chunk->getContent(); + foreach ($client->stream($response) as $chunk) { + $content .= $chunk->getContent(); + } + } + + $this->assertSame('{"documents":[{"id":"\/json\/1"},{"id":"\/json\/2"},{"id":"\/json\/3"}]}', $content); + } }
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: