diff --git a/src/FpmRuntime/FpmHandler.php b/src/FpmRuntime/FpmHandler.php index 4156bb595..ccdaf045d 100644 --- a/src/FpmRuntime/FpmHandler.php +++ b/src/FpmRuntime/FpmHandler.php @@ -187,6 +187,11 @@ public function handleRequest(HttpRequestEvent $event, Context $context): HttpRe throw new FastCgiCommunicationFailed; } + // PHP-FPM sends no output when it fails to start the request, such as running out of memory parsing the body + if ($response->getOutput() === '') { + throw new FastCgiCommunicationFailed('PHP-FPM failed to start the request, the PHP-FPM logs contain the error'); + } + $responseHeaders = $this->getResponseHeaders($response); // The status code is returned separately, it is not an HTTP header unset($responseHeaders['status']); diff --git a/tests/FpmRuntime/FpmHandlerTest.php b/tests/FpmRuntime/FpmHandlerTest.php index 97e511d7d..dca2f8f30 100644 --- a/tests/FpmRuntime/FpmHandlerTest.php +++ b/tests/FpmRuntime/FpmHandlerTest.php @@ -3,6 +3,7 @@ namespace Bref\Test\FpmRuntime; use Bref\Context\Context; +use Bref\FpmRuntime\FastCgi\FastCgiCommunicationFailed; use Bref\FpmRuntime\FastCgi\Timeout; use Bref\FpmRuntime\FpmHandler; use Bref\Test\HttpRequestProxyTest; @@ -1257,6 +1258,33 @@ public function test worker logs are still written in case of a timeou } } + public function test requests that FPM fails to start are reported as errors() + { + $this->fpm = new FpmHandler(__DIR__ . '/fixtures/request.php', __DIR__ . '/fixtures/php-fpm-low-memory.conf'); + $this->fpm->start(); + + try { + $this->fpm->handle([ + 'version' => '1.0', + 'httpMethod' => 'POST', + 'headers' => [ + 'Content-Type' => 'application/x-www-form-urlencoded', + ], + 'body' => implode('&', array_map(fn (int $i) => "a{$i}[]=1", range(1, 50000))), + ], $this->fakeContext); + $this->fail('No exception was thrown'); + } catch (FastCgiCommunicationFailed $e) { + self::assertSame('PHP-FPM failed to start the request, the PHP-FPM logs contain the error', $e->getMessage()); + + // PHP-FPM should work after that + $statusCode = $this->fpm->handle([ + 'version' => '1.0', + 'httpMethod' => 'GET', + ], $this->fakeContext)['statusCode']; + self::assertEquals(200, $statusCode); + } + } + /** * @see https://github.com/brefphp/bref/issues/316 */ diff --git a/tests/FpmRuntime/fixtures/php-fpm-low-memory.conf b/tests/FpmRuntime/fixtures/php-fpm-low-memory.conf new file mode 100644 index 000000000..397af77ac --- /dev/null +++ b/tests/FpmRuntime/fixtures/php-fpm-low-memory.conf @@ -0,0 +1,10 @@ +error_log = /dev/null + +[default] +pm = static +pm.max_children = 1 +listen = /tmp/.bref/php-fpm.sock +; Run out of memory parsing the test's request body, without displaying the error +php_admin_value[memory_limit] = 8M +php_admin_value[max_input_vars] = 100000 +php_admin_value[display_errors] = Off