diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 764527ee1b5..b2924892b02 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -2585,12 +2585,16 @@ function _drupal_shutdown_function() { } } catch (Exception $exception) { - // If we are displaying errors, then do so with no possibility of a further - // uncaught exception being thrown. - require_once __DIR__ . '/errors.inc'; - if (error_displayable()) { - print '

Uncaught exception thrown in shutdown function.

'; - print '

' . Error::renderExceptionSafe($exception) . '


'; + // If using PHP-FPM then fastcgi_finish_request() will have been fired + // preventing further output to the browser. + if (!function_exists('fastcgi_finish_request')) { + // If we are displaying errors, then do so with no possibility of a + // further uncaught exception being thrown. + require_once __DIR__ . '/errors.inc'; + if (error_displayable()) { + print '

Uncaught exception thrown in shutdown function.

'; + print '

' . Error::renderExceptionSafe($exception) . '


'; + } } error_log($exception); } diff --git a/core/modules/system/lib/Drupal/system/Tests/System/ShutdownFunctionsTest.php b/core/modules/system/lib/Drupal/system/Tests/System/ShutdownFunctionsTest.php index 96b2f8d5741..2c42bd00dbc 100644 --- a/core/modules/system/lib/Drupal/system/Tests/System/ShutdownFunctionsTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/System/ShutdownFunctionsTest.php @@ -36,11 +36,23 @@ class ShutdownFunctionsTest extends WebTestBase { $arg1 = $this->randomName(); $arg2 = $this->randomName(); $this->drupalGet('system-test/shutdown-functions/' . $arg1 . '/' . $arg2); - $this->assertText(t('First shutdown function, arg1 : @arg1, arg2: @arg2', array('@arg1' => $arg1, '@arg2' => $arg2))); - $this->assertText(t('Second shutdown function, arg1 : @arg1, arg2: @arg2', array('@arg1' => $arg1, '@arg2' => $arg2))); - // Make sure exceptions displayed through - // \Drupal\Core\Utility\Error::renderExceptionSafe() are correctly escaped. - $this->assertRaw('Drupal is <blink>awesome</blink>.'); + // If using PHP-FPM then fastcgi_finish_request() will have been fired + // returning the response before shutdown functions have fired. + // @see \Drupal\system_test\Controller\SystemTestController::shutdownFunctions() + $server_using_fastcgi = strpos($this->drupalGetContent(), 'The function fastcgi_finish_request exists when serving the request.'); + if ($server_using_fastcgi) { + // We need to wait to ensure that the shutdown functions have fired. + sleep(1); + } + $this->assertEqual(\Drupal::state()->get('_system_test_first_shutdown_function'), array($arg1, $arg2)); + $this->assertEqual(\Drupal::state()->get('_system_test_second_shutdown_function'), array($arg1, $arg2)); + + if (!$server_using_fastcgi) { + // Make sure exceptions displayed through + // \Drupal\Core\Utility\Error::renderExceptionSafe() are correctly + // escaped. + $this->assertRaw('Drupal is <blink>awesome</blink>.'); + } } } diff --git a/core/modules/system/tests/modules/system_test/lib/Drupal/system_test/Controller/SystemTestController.php b/core/modules/system/tests/modules/system_test/lib/Drupal/system_test/Controller/SystemTestController.php index 5d7f49ca667..868117aebc2 100644 --- a/core/modules/system/tests/modules/system_test/lib/Drupal/system_test/Controller/SystemTestController.php +++ b/core/modules/system/tests/modules/system_test/lib/Drupal/system_test/Controller/SystemTestController.php @@ -68,6 +68,14 @@ class SystemTestController extends ControllerBase { */ public function shutdownFunctions($arg1, $arg2) { system_test_page_shutdown_functions($arg1, $arg2); + // If using PHP-FPM then fastcgi_finish_request() will have been fired + // preventing further output to the browser which means that the escaping of + // the exception message can not be tested. + // @see _drupal_shutdown_function() + // @see \Drupal\system\Tests\System\ShutdownFunctionsTest + if (function_exists('fastcgi_finish_request')) { + return 'The function fastcgi_finish_request exists when serving the request.'; + } } } diff --git a/core/modules/system/tests/modules/system_test/system_test.module b/core/modules/system/tests/modules/system_test/system_test.module index 040d9f31573..1eda491bca9 100644 --- a/core/modules/system/tests/modules/system_test/system_test.module +++ b/core/modules/system/tests/modules/system_test/system_test.module @@ -140,9 +140,8 @@ function system_test_page_shutdown_functions($arg1, $arg2) { * Dummy shutdown function which registers another shutdown function. */ function _system_test_first_shutdown_function($arg1, $arg2) { - // Output something, page has already been printed and the session stored - // so we can't use drupal_set_message. - print t('First shutdown function, arg1 : @arg1, arg2: @arg2', array('@arg1' => $arg1, '@arg2' => $arg2)); + // Set something to ensure that this function got called. + \Drupal::state()->set('_system_test_first_shutdown_function', array($arg1, $arg2)); drupal_register_shutdown_function('_system_test_second_shutdown_function', $arg1, $arg2); } @@ -150,14 +149,13 @@ function _system_test_first_shutdown_function($arg1, $arg2) { * Dummy shutdown function. */ function _system_test_second_shutdown_function($arg1, $arg2) { - // Output something, page has already been printed and the session stored - // so we can't use drupal_set_message. - print t('Second shutdown function, arg1 : @arg1, arg2: @arg2', array('@arg1' => $arg1, '@arg2' => $arg2)); + // Set something to ensure that this function got called. + \Drupal::state()->set('_system_test_second_shutdown_function', array($arg1, $arg2)); // Throw an exception with an HTML tag. Since this is called in a shutdown // function, it will not bubble up to the default exception handler but will // be caught in _drupal_shutdown_function() and be displayed through - // \Drupal\Core\Utility\Error::renderExceptionSafe(). + // \Drupal\Core\Utility\Error::renderExceptionSafe() if possible. throw new Exception('Drupal is awesome.'); }