Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitcaa54c1

Browse files
[HttpClient] Fix handling timeouts when responses are destructed
1 parent7b54c60 commitcaa54c1

File tree

12 files changed

+88
-10
lines changed

12 files changed

+88
-10
lines changed

‎src/Symfony/Component/HttpClient/Internal/ClientState.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ class ClientState
2222
{
2323
public$handlesActivity = [];
2424
public$openHandles = [];
25+
public$lastTimeout;
2526
}

‎src/Symfony/Component/HttpClient/Response/AmpResponse.php‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ final class AmpResponse implements ResponseInterface, StreamableInterface
4545

4646
privatestatic$nextId ='a';
4747

48-
private$multi;
4948
private$options;
5049
private$canceller;
5150
private$onProgress;

‎src/Symfony/Component/HttpClient/Response/AsyncResponse.php‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,13 @@ public function __construct(HttpClientInterface $client, string $method, string
5757
}
5858
$this->response =$client->request($method,$url, ['buffer' =>false] +$options);
5959
$this->passthru =$passthru;
60-
$this->initializer =staticfunction (self$response) {
60+
$this->initializer =staticfunction (self$response,float$timeout =null) {
6161
if (null ===$response->shouldBuffer) {
6262
returnfalse;
6363
}
6464

6565
while (true) {
66-
foreach (self::stream([$response])as$chunk) {
66+
foreach (self::stream([$response],$timeout)as$chunk) {
6767
if ($chunk->isTimeout() &&$response->passthru) {
6868
foreach (self::passthru($response->client,$response,newErrorChunk($response->offset,newTransportException($chunk->getError())))as$chunk) {
6969
if ($chunk->isFirst()) {
@@ -179,6 +179,7 @@ public function __destruct()
179179

180180
if ($this->initializer &&null ===$this->getInfo('error')) {
181181
try {
182+
self::initialize($this, -0.0);
182183
$this->getHeaders(true);
183184
}catch (HttpExceptionInterface$httpException) {
184185
// no-op

‎src/Symfony/Component/HttpClient/Response/CommonResponseTrait.php‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,15 +145,15 @@ public function __wakeup()
145145
*/
146146
abstractprotectedfunctionclose():void;
147147

148-
privatestaticfunctioninitialize(self$response):void
148+
privatestaticfunctioninitialize(self$response,float$timeout =null):void
149149
{
150150
if (null !==$response->getInfo('error')) {
151151
thrownewTransportException($response->getInfo('error'));
152152
}
153153

154154
try {
155-
if (($response->initializer)($response)) {
156-
foreach (self::stream([$response])as$chunk) {
155+
if (($response->initializer)($response,$timeout)) {
156+
foreach (self::stream([$response],$timeout)as$chunk) {
157157
if ($chunk->isFirst()) {
158158
break;
159159
}

‎src/Symfony/Component/HttpClient/Response/CurlResponse.php‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ final class CurlResponse implements ResponseInterface, StreamableInterface
3333
use TransportResponseTrait;
3434

3535
privatestatic$performing =false;
36-
private$multi;
3736
private$debugBuffer;
3837

3938
/**

‎src/Symfony/Component/HttpClient/Response/NativeResponse.php‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ final class NativeResponse implements ResponseInterface, StreamableInterface
3535
private$onProgress;
3636
private$remaining;
3737
private$buffer;
38-
private$multi;
3938
private$debugBuffer;
4039
private$shouldBuffer;
4140
private$pauseExpiry =0;

‎src/Symfony/Component/HttpClient/Response/TransportResponseTrait.php‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ trait TransportResponseTrait
4343
private$finalInfo;
4444
private$canary;
4545
private$logger;
46+
/** @var ClientState|null */
47+
private$multi =null;
4648

4749
/**
4850
* {@inheritdoc}
@@ -138,7 +140,7 @@ private function doDestruct()
138140
$this->shouldBuffer =true;
139141

140142
if ($this->initializer &&null ===$this->info['error']) {
141-
self::initialize($this);
143+
self::initialize($this, -0.0);
142144
$this->checkStatusCode();
143145
}
144146
}
@@ -159,6 +161,12 @@ public static function stream(iterable $responses, float $timeout = null): \Gene
159161
$lastActivity =microtime(true);
160162
$elapsedTimeout =0;
161163

164+
if ($fromLastTimeout =0.0 ===$timeout &&'-0' === (string)$timeout) {
165+
$timeout =null;
166+
}elseif ($fromLastTimeout =0 >$timeout) {
167+
$timeout = -$timeout;
168+
}
169+
162170
while (true) {
163171
$hasActivity =false;
164172
$timeoutMax =0;
@@ -172,15 +180,21 @@ public static function stream(iterable $responses, float $timeout = null): \Gene
172180
foreach ($responsesas$j =>$response) {
173181
$timeoutMax =$timeout ??max($timeoutMax,$response->timeout);
174182
$timeoutMin =min($timeoutMin,$response->timeout,1);
183+
184+
if ($fromLastTimeout &&null !==$multi->lastTimeout) {
185+
$elapsedTimeout =microtime(true) -$multi->lastTimeout;
186+
}
187+
175188
$chunk =false;
176189

177190
if (isset($multi->handlesActivity[$j])) {
178-
// no-op
191+
$multi->lastTimeout =null;
179192
}elseif (!isset($multi->openHandles[$j])) {
180193
unset($responses[$j]);
181194
continue;
182195
}elseif ($elapsedTimeout >=$timeoutMax) {
183196
$multi->handlesActivity[$j] = [newErrorChunk($response->offset,sprintf('Idle timeout reached for "%s".',$response->getInfo('url')))];
197+
$multi->lastTimeout ??$multi->lastTimeout =$lastActivity;
184198
}else {
185199
continue;
186200
}

‎src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
namespaceSymfony\Component\HttpClient\Tests;
1313

1414
useSymfony\Component\HttpClient\AsyncDecoratorTrait;
15+
useSymfony\Component\HttpClient\CurlHttpClient;
1516
useSymfony\Component\HttpClient\DecoratorTrait;
17+
useSymfony\Component\HttpClient\HttpClient;
1618
useSymfony\Component\HttpClient\Response\AsyncContext;
1719
useSymfony\Component\HttpClient\Response\AsyncResponse;
1820
useSymfony\Contracts\HttpClient\ChunkInterface;
@@ -29,6 +31,10 @@ protected function getHttpClient(string $testCase, \Closure $chunkFilter = null,
2931
$this->markTestSkipped("AsyncDecoratorTrait doesn't cache handles");
3032
}
3133

34+
if ('testTimeoutOnDestruct' ===$testCase) {
35+
returnnewCurlHttpClient();
36+
}
37+
3238
$chunkFilter =$chunkFilter ??staticfunction (ChunkInterface$chunk,AsyncContext$context) {yield$chunk; };
3339

3440
returnnewclass($decoratedClient ??parent::getHttpClient($testCase),$chunkFilter)implements HttpClientInterface {
@@ -49,6 +55,15 @@ public function request(string $method, string $url, array $options = []): Respo
4955
};
5056
}
5157

58+
publicfunctiontestTimeoutOnDestruct()
59+
{
60+
if (HttpClient::create()instanceof NativeHttpClient) {
61+
parent::testTimeoutOnDestruct();
62+
}else {
63+
HttpClientTestCase::testTimeoutOnDestruct();
64+
}
65+
}
66+
5267
publicfunctiontestRetry404()
5368
{
5469
$client =$this->getHttpClient(__FUNCTION__,function (ChunkInterface$chunk,AsyncContext$context) {

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ abstract class HttpClientTestCase extends BaseHttpClientTestCase
3232
{
3333
privatestatic$vulcainStarted =false;
3434

35+
publicfunctiontestTimeoutOnDestruct()
36+
{
37+
if (!method_exists(parent::class,'testTimeoutOnDestruct')) {
38+
$this->markTestSkipped('BaseHttpClientTestCase doesn\'t have testTimeoutOnDestruct().');
39+
}
40+
41+
parent::testTimeoutOnDestruct();
42+
}
43+
3544
publicfunctiontestAcceptHeader()
3645
{
3746
$client =$this->getHttpClient(__FUNCTION__);

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,10 @@ protected function getHttpClient(string $testCase): HttpClientInterface
236236
$this->markTestSkipped('Real transport required');
237237
break;
238238

239+
case'testTimeoutOnDestruct':
240+
$this->markTestSkipped('Real transport required');
241+
break;
242+
239243
case'testDestruct':
240244
$this->markTestSkipped("MockHttpClient doesn't timeout on destruct");
241245
break;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp