Skip to content

Commit

Permalink
bug #35209 [HttpClient] fix support for non-blocking resource streams…
Browse files Browse the repository at this point in the history
… (nicolas-grekas)

This PR was merged into the 4.4 branch.

Discussion
----------

[HttpClient] fix support for non-blocking resource streams

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #35187, Fix #35187
| License       | MIT
| Doc PR        | -

Commits
-------

c651f63 [HttpClient] fix support for non-blocking resource streams
  • Loading branch information
nicolas-grekas committed Jan 4, 2020
2 parents 75c24bb + c651f63 commit 9d4c98e
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 1 deletion.
17 changes: 16 additions & 1 deletion src/Symfony/Component/HttpClient/Response/StreamWrapper.php
Expand Up @@ -37,6 +37,8 @@ class StreamWrapper
/** @var resource|null */
private $handle;

private $blocking = true;
private $timeout;
private $eof = false;
private $offset = 0;

Expand Down Expand Up @@ -150,7 +152,7 @@ public function stream_read(int $count)
return $data;
}

foreach ($this->client->stream([$this->response]) as $chunk) {
foreach ($this->client->stream([$this->response], $this->blocking ? $this->timeout : 0) as $chunk) {
try {
$this->eof = true;
$this->eof = !$chunk->isTimeout();
Expand Down Expand Up @@ -181,6 +183,19 @@ public function stream_read(int $count)
return '';
}

public function stream_set_option(int $option, int $arg1, ?int $arg2): bool
{
if (STREAM_OPTION_BLOCKING === $option) {
$this->blocking = (bool) $arg1;
} elseif (STREAM_OPTION_READ_TIMEOUT === $option) {
$this->timeout = $arg1 + $arg2 / 1e6;
} else {
return false;
}

return true;
}

public function stream_tell(): int
{
return $this->offset;
Expand Down
16 changes: 16 additions & 0 deletions src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php
Expand Up @@ -75,4 +75,20 @@ public function testToStream404()
$response = $client->request('GET', 'http://localhost:8057/404');
$stream = $response->toStream();
}

public function testNonBlockingStream()
{
$client = $this->getHttpClient(__FUNCTION__);
$response = $client->request('GET', 'http://localhost:8057/timeout-body');
$stream = $response->toStream();

$this->assertTrue(stream_set_blocking($stream, false));
$this->assertSame('<1>', fread($stream, 8192));
$this->assertFalse(feof($stream));

$this->assertTrue(stream_set_blocking($stream, true));
$this->assertSame('<2>', fread($stream, 8192));
$this->assertSame('', fread($stream, 8192));
$this->assertTrue(feof($stream));
}
}
4 changes: 4 additions & 0 deletions src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php
Expand Up @@ -171,6 +171,10 @@ protected function getHttpClient(string $testCase): HttpClientInterface

return $client;

case 'testNonBlockingStream':
$responses[] = new MockResponse((function () { yield '<1>'; yield ''; yield '<2>'; })(), ['response_headers' => $headers]);
break;

case 'testMaxDuration':
$mock = $this->getMockBuilder(ResponseInterface::class)->getMock();
$mock->expects($this->any())
Expand Down

0 comments on commit 9d4c98e

Please sign in to comment.