Skip to content

Commit 3acc28f

Browse files
committed
bug #36766 [HttpClient] add TimeoutExceptionInterface (nicolas-grekas)
This PR was merged into the 5.1-dev branch. Discussion ---------- [HttpClient] add TimeoutExceptionInterface | Q | A | ------------- | --- | Branch? | master | Bug fix? | yes | New feature? | yes | Deprecations? | no | Tickets | - | License | MIT | Doc PR | - This is fixing a design issue: unlike any other `TransportExceptionInterface`, timeouts are not fatal transport errors. For this reason, we must allow one to identify them. ~This PR also marks exception classes as `@internal`, to encourage ppl to catch them using their interface and not their class name.~ this would revert #30549 Commits ------- ab8eca0 [HttpClient] add TimeoutExceptionInterface
2 parents 2ed6a0d + ab8eca0 commit 3acc28f

File tree

8 files changed

+79
-36
lines changed

8 files changed

+79
-36
lines changed

src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\HttpClient\Chunk;
1313

14+
use Symfony\Component\HttpClient\Exception\TimeoutException;
1415
use Symfony\Component\HttpClient\Exception\TransportException;
1516
use Symfony\Contracts\HttpClient\ChunkInterface;
1617

@@ -61,7 +62,7 @@ public function isTimeout(): bool
6162
public function isFirst(): bool
6263
{
6364
$this->didThrow = true;
64-
throw new TransportException($this->errorMessage, 0, $this->error);
65+
throw null !== $this->error ? new TransportException($this->errorMessage, 0, $this->error) : new TimeoutException($this->errorMessage);
6566
}
6667

6768
/**
@@ -70,7 +71,7 @@ public function isFirst(): bool
7071
public function isLast(): bool
7172
{
7273
$this->didThrow = true;
73-
throw new TransportException($this->errorMessage, 0, $this->error);
74+
throw null !== $this->error ? new TransportException($this->errorMessage, 0, $this->error) : new TimeoutException($this->errorMessage);
7475
}
7576

7677
/**
@@ -79,7 +80,7 @@ public function isLast(): bool
7980
public function getInformationalStatus(): ?array
8081
{
8182
$this->didThrow = true;
82-
throw new TransportException($this->errorMessage, 0, $this->error);
83+
throw null !== $this->error ? new TransportException($this->errorMessage, 0, $this->error) : new TimeoutException($this->errorMessage);
8384
}
8485

8586
/**
@@ -88,7 +89,7 @@ public function getInformationalStatus(): ?array
8889
public function getContent(): string
8990
{
9091
$this->didThrow = true;
91-
throw new TransportException($this->errorMessage, 0, $this->error);
92+
throw null !== $this->error ? new TransportException($this->errorMessage, 0, $this->error) : new TimeoutException($this->errorMessage);
9293
}
9394

9495
/**
@@ -119,7 +120,7 @@ public function __destruct()
119120
{
120121
if (!$this->didThrow) {
121122
$this->didThrow = true;
122-
throw new TransportException($this->errorMessage, 0, $this->error);
123+
throw null !== $this->error ? new TransportException($this->errorMessage, 0, $this->error) : new TimeoutException($this->errorMessage);
123124
}
124125
}
125126
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\HttpClient\Exception;
13+
14+
use Symfony\Contracts\HttpClient\Exception\TimeoutExceptionInterface;
15+
16+
/**
17+
* @author Nicolas Grekas <p@tchwork.com>
18+
*/
19+
final class TimeoutException extends TransportException implements TimeoutExceptionInterface
20+
{
21+
}

src/Symfony/Component/HttpClient/Exception/TransportException.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@
1616
/**
1717
* @author Nicolas Grekas <p@tchwork.com>
1818
*/
19-
final class TransportException extends \RuntimeException implements TransportExceptionInterface
19+
class TransportException extends \RuntimeException implements TransportExceptionInterface
2020
{
2121
}

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

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
namespace Symfony\Component\HttpClient\Tests;
1313

1414
use Symfony\Component\HttpClient\Exception\ClientException;
15-
use Symfony\Component\HttpClient\Exception\TransportException;
1615
use Symfony\Component\HttpClient\Response\StreamWrapper;
1716
use Symfony\Component\Process\Exception\ProcessFailedException;
1817
use Symfony\Component\Process\Process;
@@ -105,32 +104,6 @@ public function testNonBlockingStream()
105104
$this->assertTrue(feof($stream));
106105
}
107106

108-
public function testTimeoutIsNotAFatalError()
109-
{
110-
$client = $this->getHttpClient(__FUNCTION__);
111-
$response = $client->request('GET', 'http://localhost:8057/timeout-body', [
112-
'timeout' => 0.25,
113-
]);
114-
115-
try {
116-
$response->getContent();
117-
$this->fail(TransportException::class.' expected');
118-
} catch (TransportException $e) {
119-
}
120-
121-
for ($i = 0; $i < 10; ++$i) {
122-
try {
123-
$this->assertSame('<1><2>', $response->getContent());
124-
break;
125-
} catch (TransportException $e) {
126-
}
127-
}
128-
129-
if (10 === $i) {
130-
throw $e;
131-
}
132-
}
133-
134107
public function testResponseStreamRewind()
135108
{
136109
$client = $this->getHttpClient(__FUNCTION__);

src/Symfony/Component/HttpClient/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"require": {
2424
"php": "^7.2.5",
2525
"psr/log": "^1.0",
26-
"symfony/http-client-contracts": "^1.1.8|^2",
26+
"symfony/http-client-contracts": "^2.1.1",
2727
"symfony/polyfill-php73": "^1.11",
2828
"symfony/polyfill-php80": "^1.15",
2929
"symfony/service-contracts": "^1.0|^2"
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Contracts\HttpClient\Exception;
13+
14+
/**
15+
* When an idle timeout occurs.
16+
*
17+
* @author Nicolas Grekas <p@tchwork.com>
18+
*/
19+
interface TimeoutExceptionInterface extends TransportExceptionInterface
20+
{
21+
}

src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@
116116
echo '<1>';
117117
@ob_flush();
118118
flush();
119-
usleep(500000);
119+
usleep(600000);
120120
echo '<2>';
121121
exit;
122122

src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
1616
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
17+
use Symfony\Contracts\HttpClient\Exception\TimeoutExceptionInterface;
1718
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
1819
use Symfony\Contracts\HttpClient\HttpClientInterface;
1920

@@ -739,9 +740,35 @@ public function testTimeoutOnAccess()
739740
$response->getHeaders();
740741
}
741742

742-
public function testTimeoutOnStream()
743+
public function testTimeoutIsNotAFatalError()
743744
{
744745
usleep(300000); // wait for the previous test to release the server
746+
$client = $this->getHttpClient(__FUNCTION__);
747+
$response = $client->request('GET', 'http://localhost:8057/timeout-body', [
748+
'timeout' => 0.3,
749+
]);
750+
751+
try {
752+
$response->getContent();
753+
$this->fail(TimeoutExceptionInterface::class.' expected');
754+
} catch (TimeoutExceptionInterface $e) {
755+
}
756+
757+
for ($i = 0; $i < 10; ++$i) {
758+
try {
759+
$this->assertSame('<1><2>', $response->getContent());
760+
break;
761+
} catch (TimeoutExceptionInterface $e) {
762+
}
763+
}
764+
765+
if (10 === $i) {
766+
throw $e;
767+
}
768+
}
769+
770+
public function testTimeoutOnStream()
771+
{
745772
$client = $this->getHttpClient(__FUNCTION__);
746773
$response = $client->request('GET', 'http://localhost:8057/timeout-body');
747774

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy