Skip to content

Commit e8dde23

Browse files
Merge branch '4.4' into 5.0
* 4.4: [Mime] Remove unused var [HttpClient] fix monitoring timeouts when other streams are active [PhpUnitBridge] fix syntax on PHP 5.3 [PhpUnitBridge] Fix undefined index when output of "composer show" cannot be parsed properly cascade validation to child forms [PhpUnitBridge] fix undefined var on version 3.4 Move ajax clear event listener initialization on loadToolbar [HttpClient] Throw JsonException instead of TransportException on empty response in Response::toArray() take into account the context when preserving empty array objects [VarExporter] tfix: s/markAsSkipped/markTestSkipped/ bumped Symfony version to 4.4.10 updated VERSION for 4.4.9 updated CHANGELOG for 4.4.9 bumped Symfony version to 3.4.42 updated VERSION for 3.4.41 update CONTRIBUTORS for 3.4.41 updated CHANGELOG for 3.4.41
2 parents 4593ee5 + c44750f commit e8dde23

7 files changed

+35
-25
lines changed

Internal/NativeClientState.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ final class NativeClientState extends ClientState
2828
public $responseCount = 0;
2929
/** @var string[] */
3030
public $dnsCache = [];
31-
/** @var resource[] */
32-
public $handles = [];
3331
/** @var bool */
3432
public $sleep = false;
3533

Response/NativeResponse.php

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -220,11 +220,6 @@ private static function schedule(self $response, array &$runningResponses): void
220220
*/
221221
private static function perform(ClientState $multi, array &$responses = null): void
222222
{
223-
// List of native handles for stream_select()
224-
if (null !== $responses) {
225-
$multi->handles = [];
226-
}
227-
228223
foreach ($multi->openHandles as $i => [$h, $buffer, $onProgress]) {
229224
$hasActivity = false;
230225
$remaining = &$multi->openHandles[$i][3];
@@ -291,8 +286,6 @@ private static function perform(ClientState $multi, array &$responses = null): v
291286
$multi->handlesActivity[$i][] = $e;
292287
unset($multi->openHandles[$i]);
293288
$multi->sleep = false;
294-
} elseif (null !== $responses) {
295-
$multi->handles[] = $h;
296289
}
297290
}
298291

@@ -307,7 +300,7 @@ private static function perform(ClientState $multi, array &$responses = null): v
307300
}
308301
}
309302

310-
if (\count($multi->handles) >= $multi->maxHostConnections) {
303+
if (\count($multi->openHandles) >= $multi->maxHostConnections) {
311304
return;
312305
}
313306

@@ -318,10 +311,6 @@ private static function perform(ClientState $multi, array &$responses = null): v
318311
$multi->sleep = false;
319312
self::perform($multi);
320313

321-
if (null !== $response->handle) {
322-
$multi->handles[] = $response->handle;
323-
}
324-
325314
break;
326315
}
327316
}
@@ -335,7 +324,8 @@ private static function perform(ClientState $multi, array &$responses = null): v
335324
private static function select(ClientState $multi, float $timeout): int
336325
{
337326
$_ = [];
327+
$handles = array_column($multi->openHandles, 0);
338328

339-
return (!$multi->sleep = !$multi->sleep) ? -1 : stream_select($multi->handles, $_, $_, (int) $timeout, (int) (1E6 * ($timeout - (int) $timeout)));
329+
return (!$multi->sleep = !$multi->sleep) ? -1 : stream_select($handles, $_, $_, (int) $timeout, (int) (1E6 * ($timeout - (int) $timeout)));
340330
}
341331
}

Response/ResponseTrait.php

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public function getContent(bool $throw = true): string
137137
public function toArray(bool $throw = true): array
138138
{
139139
if ('' === $content = $this->getContent($throw)) {
140-
throw new TransportException('Response body is empty.');
140+
throw new JsonException('Response body is empty.');
141141
}
142142

143143
if (null !== $this->jsonData) {
@@ -316,7 +316,7 @@ public static function stream(iterable $responses, float $timeout = null): \Gene
316316
}
317317

318318
$lastActivity = microtime(true);
319-
$isTimeout = false;
319+
$enlapsedTimeout = 0;
320320

321321
while (true) {
322322
$hasActivity = false;
@@ -338,15 +338,15 @@ public static function stream(iterable $responses, float $timeout = null): \Gene
338338
} elseif (!isset($multi->openHandles[$j])) {
339339
unset($responses[$j]);
340340
continue;
341-
} elseif ($isTimeout) {
341+
} elseif ($enlapsedTimeout >= $timeoutMax) {
342342
$multi->handlesActivity[$j] = [new ErrorChunk($response->offset, sprintf('Idle timeout reached for "%s".', $response->getInfo('url')))];
343343
} else {
344344
continue;
345345
}
346346

347347
while ($multi->handlesActivity[$j] ?? false) {
348348
$hasActivity = true;
349-
$isTimeout = false;
349+
$enlapsedTimeout = 0;
350350

351351
if (\is_string($chunk = array_shift($multi->handlesActivity[$j]))) {
352352
if (null !== $response->inflate && false === $chunk = @inflate_add($response->inflate, $chunk)) {
@@ -379,7 +379,7 @@ public static function stream(iterable $responses, float $timeout = null): \Gene
379379
}
380380
} elseif ($chunk instanceof ErrorChunk) {
381381
unset($responses[$j]);
382-
$isTimeout = true;
382+
$enlapsedTimeout = $timeoutMax;
383383
} elseif ($chunk instanceof FirstChunk) {
384384
if ($response->logger) {
385385
$info = $response->getInfo();
@@ -447,10 +447,11 @@ public static function stream(iterable $responses, float $timeout = null): \Gene
447447
continue;
448448
}
449449

450-
switch (self::select($multi, $timeoutMin)) {
451-
case -1: usleep(min(500, 1E6 * $timeoutMin)); break;
452-
case 0: $isTimeout = microtime(true) - $lastActivity > $timeoutMax; break;
450+
if (-1 === self::select($multi, min($timeoutMin, $timeoutMax - $enlapsedTimeout))) {
451+
usleep(min(500, 1E6 * $timeoutMin));
453452
}
453+
454+
$enlapsedTimeout = microtime(true) - $lastActivity;
454455
}
455456
}
456457
}

Tests/CurlHttpClientTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,15 @@ public function testHttp2PushVulcainWithUnusedResponse()
112112
$this->assertSame($expected, $logger->logs);
113113
}
114114

115+
public function testTimeoutIsNotAFatalError()
116+
{
117+
if ('\\' === \DIRECTORY_SEPARATOR) {
118+
$this->markTestSkipped('Too transient on Windows');
119+
}
120+
121+
parent::testTimeoutIsNotAFatalError();
122+
}
123+
115124
private function getVulcainClient(): CurlHttpClient
116125
{
117126
if (\PHP_VERSION_ID >= 70300 && \PHP_VERSION_ID < 70304) {

Tests/HttpClientTestCase.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,17 @@ public function testToStream404()
7272
$this->assertSame($response, stream_get_meta_data($stream)['wrapper_data']->getResponse());
7373
$this->assertSame(404, $response->getStatusCode());
7474

75-
$this->expectException(ClientException::class);
7675
$response = $client->request('GET', 'http://localhost:8057/404');
77-
$stream = $response->toStream();
76+
$this->expectException(ClientException::class);
77+
$response->toStream();
7878
}
7979

8080
public function testNonBlockingStream()
8181
{
8282
$client = $this->getHttpClient(__FUNCTION__);
8383
$response = $client->request('GET', 'http://localhost:8057/timeout-body');
8484
$stream = $response->toStream();
85+
usleep(10000);
8586

8687
$this->assertTrue(stream_set_blocking($stream, false));
8788
$this->assertSame('<1>', fread($stream, 8192));
@@ -99,6 +100,7 @@ public function testTimeoutIsNotAFatalError()
99100
$response = $client->request('GET', 'http://localhost:8057/timeout-body', [
100101
'timeout' => 0.25,
101102
]);
103+
$this->assertSame(200, $response->getStatusCode());
102104

103105
try {
104106
$response->getContent();

Tests/MockHttpClientTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ protected function getHttpClient(string $testCase): HttpClientInterface
6969
$this->markTestSkipped("MockHttpClient doesn't unzip");
7070
break;
7171

72+
case 'testTimeoutWithActiveConcurrentStream':
73+
$this->markTestSkipped('Real transport required');
74+
break;
75+
7276
case 'testDestruct':
7377
$this->markTestSkipped("MockHttpClient doesn't timeout on destruct");
7478
break;

Tests/Response/MockResponseTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ public function testToArrayError($content, $responseHeaders, $message)
3535

3636
public function toArrayErrors()
3737
{
38+
yield [
39+
'content' => '',
40+
'responseHeaders' => [],
41+
'message' => 'Response body is empty.',
42+
];
43+
3844
yield [
3945
'content' => '{}',
4046
'responseHeaders' => ['content-type' => 'plain/text'],

0 commit comments

Comments
 (0)