8000 [HttpClient] Fix seeking in not-yet-initialized requests · symfony/symfony@5046e85 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5046e85

Browse files
[HttpClient] Fix seeking in not-yet-initialized requests
1 parent 216b339 commit 5046e85

File tree

3 files changed

+28
-5
lines changed

3 files changed

+28
-5
lines changed

src/Symfony/Component/HttpClient/Response/StreamWrapper.php

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
*/
2323
class StreamWrapper
2424
{
25-
/** @var resource|string|null */
25+
/** @var resource|null */
2626
public $context;
2727

2828
/** @var HttpClientInterface */
@@ -31,7 +31,7 @@ class StreamWrapper
3131
/** @var ResponseInterface */
3232
private $response;
3333

34-
/** @var resource|null */
34+
/** @var resource|string|null */
3535
private $content;
3636

3737
/** @var resource|null */
@@ -81,6 +81,7 @@ public function bindHandles(&$handle, &$content): void
8181
{
8282
$this->handle = &$handle;
8383
$this->content = &$content;
84+
$this->offset = null;
8485
}
8586

8687
public function stream_open(string $path, string $mode, int $options): bool
@@ -125,7 +126,7 @@ public function stream_read(int $count)
125126
}
126127
}
127128

128-
if (0 !== fseek($this->content, $this->offset)) {
129+
if (0 !== fseek($this->content, $this->offset ?? 0)) {
129130
return false;
130131
}
131132

@@ -154,6 +155,11 @@ public function stream_read(int $count)
154155
try {
155156
$this->eof = true;
156157
$this->eof = !$chunk->isTimeout();
158+
159+
if (!$this->eof && !$this->blocking) {
160+
return '';
161+
}
162+
157163
$this->eof = $chunk->isLast();
158164

159165
if ($chunk->isFirst()) {
@@ -196,7 +202,7 @@ public function stream_set_option(int $option, int $arg1, ?int $arg2): bool
196202

197203
public function stream_tell(): int
198204
{
199-
return $this->offset;
205+
return $this->offset ?? 0;
200206
}
201207

202208
public function stream_eof(): bool
@@ -206,14 +212,19 @@ public function stream_eof(): bool
206212

207213
public function stream_seek(int $offset, int $whence = \SEEK_SET): bool
208214
{
215+
if (null === $this->content && null === $this->offset) {
216+
$this->response->getStatusCode();
217+
$this->offset = 0;
218+
}
219+
209220
if (!\is_resource($this->content) || 0 !== fseek($this->content, 0, \SEEK_END)) {
210221
return false;
211222
}
212223

213224
$size = ftell($this->content);
214225

215226
if (\SEEK_CUR === $whence) {
216-
$offset += $this->offset;
227+
$offset += $this->offset ?? 0;
217228
}
218229

219230
if (\SEEK_END === $whence || $size < $offset) {

src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,17 @@ public function testNonBlockingStream()
118118
$this->assertTrue(feof($stream));
119119
}
120120

121+
public function testSeekAsyncStream()
122+
{
123+
$client = $this->getHttpClient(__FUNCTION__);
124+
$response = $client->request('GET', 'http://localhost:8057/timeout-body');
125+
$stream = $response->toStream(false);
126+
127+
$this->assertSame(0, fseek($stream, 0, \SEEK_CUR));
128+
$this->assertSame('<1>', fread($stream, 8192));
129+
$this->assertFalse(feof($stream));
130+
}
131+
121132
public function testTimeoutIsNotAFatalError()
122133
{
123134
$client = $this->getHttpClient(__FUNCTION__);

src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ protected function getHttpClient(string $testCase): HttpClientInterface
311311
return $client;
312312

313313
case 'testNonBlockingStream':
314+
case 'testSeekAsyncStream':
314315
$responses[] = new MockResponse((function () { yield '<1>'; yield ''; yield '<2>'; })(), ['response_headers' => $headers]);
315316
break;
316317

0 commit comments

Comments
 (0)
0