Fix nesteed stream in AsyncResponse

This commit is contained in:
Jérémy Derussé 2020-10-11 18:45:06 +02:00 committed by Nicolas Grekas
parent 62d40d5866
commit 8ba54c17be
2 changed files with 28 additions and 1 deletions

View File

@ -34,6 +34,7 @@ final class AsyncResponse implements ResponseInterface, StreamableInterface
private $response; private $response;
private $info = ['canceled' => false]; private $info = ['canceled' => false];
private $passthru; private $passthru;
private $lastYielded = false;
/** /**
* @param ?callable(ChunkInterface, AsyncContext): ?\Iterator $passthru * @param ?callable(ChunkInterface, AsyncContext): ?\Iterator $passthru
@ -255,7 +256,10 @@ final class AsyncResponse implements ResponseInterface, StreamableInterface
} }
} }
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.'); throw new \LogicException('A chunk passthru must yield an "isLast()" chunk before ending a stream.');
} }

View File

@ -230,4 +230,27 @@ class AsyncDecoratorTraitTest extends NativeHttpClientTest
$this->assertSame(200, $response->getStatusCode()); $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);
}
} }