Description
Symfony version(s) affected: 4.3.*
Description
According to the Symfony docs, HttpClientInterface::stream()
is not supposed to throw any errors but it seems like under some circumstances that's still the case.
How to reproduce
It's pretty hard to reproduce because for me it seems to happen when I get a 502
server response but I wasn't able to mock it to create a test case. But maybe the stack trace can already help.
So this is the code I used:
namespace MyProject;
class MyClass
{
public function processResponses(array $responses): void
{
foreach ($this->getClient()->stream($responses) as $response => $chunk) {
try {
// Whatever is not 200 OK is not going to be processed any further
if (200 !== $response->getStatusCode()) {
$response->cancel();
continue; // TODO: is that even needed? Does cancel() always turn into a TransportException?
}
if ($chunk->isLast()) {
// Process
$this->processResponse($response);
}
} catch (TransportExceptionInterface | RedirectionExceptionInterface | ClientExceptionInterface | ServerExceptionInterface $e) {
// I should land here
}
}
}
}
Stacktrace:
PHP Fatal error: Uncaught Symfony\Component\HttpClient\Exception\ServerException: HTTP/2 502 returned for "https://demo-url.com/foobar.html". in /project/vendor/symfony/http-client/Response/ResponseTrait.php:229
Stack trace:
#0 /project/vendor/symfony/http-client/Response/ResponseTrait.php(86): Symfony\Component\HttpClient\Response\CurlResponse->checkStatusCode()
#1 /project/vendor/symfony/http-client/Response/ResponseTrait.php(333): Symfony\Component\HttpClient\Response\CurlResponse->getHeaders(true)
#2 [internal function]: Symfony\Component\HttpClient\Response\CurlResponse::stream(Array, NULL)
#3 /project/vendor/symfony/http-client/Response/ResponseStream.php(44): Generator->next()
#4 /project/src/MyClass.php(262): Symfony\Component\HttpClient\Response\ResponseStream->next()
#5 /project/src/MyClass.php(256): MyProject\MyClass->processResponses(Array)
Possible Solution
Depending on what I do I also get this sometimes during CurlResponse::__destruct()
so I think the issue here is that under some circumstances (I kind of think when just no chunk arrives) stream()
still throws which should not happen. So it's also related to #31187 because as you can see I'm actually trying to catch the ServerExceptionInterface
inside my loop :)