Skip to content

Commit 456d3e0

Browse files
[HttpClient] fix management of shorter-than-requested timeouts with AmpHttpClient
1 parent bc35419 commit 456d3e0

File tree

2 files changed

+33
-21
lines changed

2 files changed

+33
-21
lines changed

Response/AmpResponse.php

+29-14
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ final class AmpResponse implements ResponseInterface
4242
private $canceller;
4343
private $onProgress;
4444

45+
private static $delay;
46+
4547
/**
4648
* @internal
4749
*/
@@ -171,18 +173,21 @@ private static function perform(ClientState $multi, array &$responses = null): v
171173
*/
172174
private static function select(ClientState $multi, float $timeout): int
173175
{
174-
$selected = 1;
175-
$delay = Loop::delay(1000 * $timeout, static function () use (&$selected) {
176-
$selected = 0;
177-
Loop::stop();
178-
});
179-
Loop::run();
176+
$start = microtime(true);
177+
$remaining = $timeout;
180178

181-
if ($selected) {
182-
Loop::cancel($delay);
183-
}
179+
while (true) {
180+
self::$delay = Loop::delay(1000 * $remaining, [Loop::class, 'stop']);
181+
Loop::run();
184182

185-
return $selected;
183+
if (null === self::$delay) {
184+
return 1;
185+
}
186+
187+
if (0 >= $remaining = $timeout - microtime(true) + $start) {
188+
return 0;
189+
}
190+
}
186191
}
187192

188193
private static function generateResponse(Request $request, AmpClientState $multi, string $id, array &$info, array &$headers, CancellationTokenSource $canceller, array &$options, \Closure $onProgress, &$handle, ?LoggerInterface $logger)
@@ -192,7 +197,7 @@ private static function generateResponse(Request $request, AmpClientState $multi
192197
$request->setInformationalResponseHandler(static function (Response $response) use (&$activity, $id, &$info, &$headers) {
193198
self::addResponseHeaders($response, $info, $headers);
194199
$activity[$id][] = new InformationalChunk($response->getStatus(), $response->getHeaders());
195-
Loop::defer([Loop::class, 'stop']);
200+
self::stopLoop();
196201
});
197202

198203
try {
@@ -210,7 +215,7 @@ private static function generateResponse(Request $request, AmpClientState $multi
210215
if ('HEAD' === $response->getRequest()->getMethod() || \in_array($info['http_code'], [204, 304], true)) {
211216
$activity[$id][] = null;
212217
$activity[$id][] = null;
213-
Loop::defer([Loop::class, 'stop']);
218+
self::stopLoop();
214219

215220
return;
216221
}
@@ -222,7 +227,7 @@ private static function generateResponse(Request $request, AmpClientState $multi
222227
$body = $response->getBody();
223228

224229
while (true) {
225-
Loop::defer([Loop::class, 'stop']);
230+
self::stopLoop();
226231

227232
if (null === $data = yield $body->read()) {
228233
break;
@@ -241,7 +246,7 @@ private static function generateResponse(Request $request, AmpClientState $multi
241246
$info['download_content_length'] = $info['size_download'];
242247
}
243248

244-
Loop::defer([Loop::class, 'stop']);
249+
self::stopLoop();
245250
}
246251

247252
private static function followRedirects(Request $originRequest, AmpClientState $multi, array &$info, array &$headers, CancellationTokenSource $canceller, array $options, \Closure $onProgress, &$handle, ?LoggerInterface $logger)
@@ -402,4 +407,14 @@ private static function getPushedResponse(Request $request, AmpClientState $mult
402407
return $response;
403408
}
404409
}
410+
411+
private static function stopLoop(): void
412+
{
413+
if (null !== self::$delay) {
414+
Loop::cancel(self::$delay);
415+
self::$delay = null;
416+
}
417+
418+
Loop::defer([Loop::class, 'stop']);
419+
}
405420
}

Tests/HttpClientTest.php

+4-7
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,15 @@
1212
namespace Symfony\Component\HttpClient\Tests;
1313

1414
use PHPUnit\Framework\TestCase;
15-
use Symfony\Component\HttpClient\AmpHttpClient;
16-
use Symfony\Component\HttpClient\CurlHttpClient;
1715
use Symfony\Component\HttpClient\HttpClient;
16+
use Symfony\Component\HttpClient\NativeHttpClient;
17+
use Symfony\Contracts\HttpClient\HttpClientInterface;
1818

1919
class HttpClientTest extends TestCase
2020
{
2121
public function testCreateClient()
2222
{
23-
if (\extension_loaded('curl') && ('\\' !== \DIRECTORY_SEPARATOR || ini_get('curl.cainfo') || ini_get('openssl.cafile') || ini_get('openssl.capath')) && 0x073d00 <= curl_version()['version_number']) {
24-
$this->assertInstanceOf(CurlHttpClient::class, HttpClient::create());
25-
} else {
26-
$this->assertInstanceOf(AmpHttpClient::class, HttpClient::create());
27-
}
23+
$this->assertInstanceOf(HttpClientInterface::class, HttpClient::create());
24+
$this->assertNotInstanceOf(NativeHttpClient::class, HttpClient::create());
2825
}
2926
}

0 commit comments

Comments
 (0)