[HttpClient] fix canceling responses in a streaming loop

This commit is contained in:
Nicolas Grekas 2019-07-24 09:56:35 +02:00
parent 560dc8b9f7
commit c5c67d913d
3 changed files with 31 additions and 4 deletions

View File

@ -78,6 +78,15 @@ class MockResponse implements ResponseInterface
return null !== $type ? $this->info[$type] ?? null : $this->info;
}
/**
* {@inheritdoc}
*/
public function cancel(): void
{
$this->info['error'] = 'Response has been canceled.';
$this->body = null;
}
/**
* {@inheritdoc}
*/
@ -150,8 +159,11 @@ class MockResponse implements ResponseInterface
foreach ($responses as $response) {
$id = $response->id;
if (!$response->body) {
// Last chunk
if (null === $response->body) {
// Canceled response
$response->body = [];
} elseif ([] === $response->body) {
// Error chunk
$multi->handlesActivity[$id][] = null;
$multi->handlesActivity[$id][] = null !== $response->info['error'] ? new TransportException($response->info['error']) : null;
} elseif (null === $chunk = array_shift($response->body)) {
@ -242,7 +254,7 @@ class MockResponse implements ResponseInterface
// populate info related to headers
$info = $mock->getInfo() ?: [];
$response->info['http_code'] = ($info['http_code'] ?? 0) ?: $mock->getStatusCode(false) ?: 200;
$response->info['http_code'] = ($info['http_code'] ?? 0) ?: $mock->getStatusCode() ?: 200;
$response->addResponseHeaders($info['response_headers'] ?? [], $response->info, $response->headers);
$dlSize = isset($response->headers['content-encoding']) ? 0 : (int) ($response->headers['content-length'][0] ?? 0);

View File

@ -327,7 +327,7 @@ trait ResponseTrait
unset($multi->handlesActivity[$j]);
if ($chunk instanceof FirstChunk && null === $response->initializer) {
if ($chunk instanceof FirstChunk && null === $response->initializer && null === $response->info['error']) {
// Ensure the HTTP status code is always checked
$response->getHeaders(true);
} elseif ($chunk instanceof ErrorChunk && !$chunk->didThrow()) {

View File

@ -505,6 +505,21 @@ abstract class HttpClientTestCase extends TestCase
$response->getHeaders();
}
public function testCancelInStream()
{
$client = $this->getHttpClient(__FUNCTION__);
$response = $client->request('GET', 'http://localhost:8057/404');
foreach ($client->stream($response) as $chunk) {
$response->cancel();
}
$this->expectException(TransportExceptionInterface::class);
foreach ($client->stream($response) as $chunk) {
}
}
public function testOnProgressCancel()
{
$client = $this->getHttpClient(__FUNCTION__);