*
- * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Exception\ErrorException instead.
+ * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Error\FatalError instead.
*/
class FatalErrorException extends \ErrorException
{
diff --git a/src/Symfony/Component/Debug/Exception/FatalThrowableError.php b/src/Symfony/Component/Debug/Exception/FatalThrowableError.php
index 53c410b014b1d..e13b0172f0588 100644
--- a/src/Symfony/Component/Debug/Exception/FatalThrowableError.php
+++ b/src/Symfony/Component/Debug/Exception/FatalThrowableError.php
@@ -11,14 +11,14 @@
namespace Symfony\Component\Debug\Exception;
-@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', FatalThrowableError::class, \Symfony\Component\ErrorHandler\Exception\ErrorException::class), E_USER_DEPRECATED);
+@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4.', FatalThrowableError::class), E_USER_DEPRECATED);
/**
* Fatal Throwable Error.
*
* @author Nicolas Grekas
*
- * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Exception\ErrorException instead.
+ * @deprecated since Symfony 4.4
*/
class FatalThrowableError extends FatalErrorException
{
diff --git a/src/Symfony/Component/ErrorHandler/Exception/ErrorException.php b/src/Symfony/Component/ErrorHandler/Exception/ErrorException.php
deleted file mode 100644
index 759d3fdc47a3f..0000000000000
--- a/src/Symfony/Component/ErrorHandler/Exception/ErrorException.php
+++ /dev/null
@@ -1,42 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\ErrorHandler\Exception;
-
-use Symfony\Component\ErrorHandler\ThrowableUtils;
-
-class ErrorException extends \ErrorException
-{
- private $originalClassName;
-
- public function __construct(\Throwable $e)
- {
- $this->originalClassName = \get_class($e);
-
- parent::__construct(
- $e->getMessage(),
- $e->getCode(),
- ThrowableUtils::getSeverity($e),
- $e->getFile(),
- $e->getLine(),
- $e->getPrevious()
- );
-
- $refl = new \ReflectionProperty(\Exception::class, 'trace');
- $refl->setAccessible(true);
- $refl->setValue($this, $e->getTrace());
- }
-
- public function getOriginalClassName(): string
- {
- return $this->originalClassName;
- }
-}
diff --git a/src/Symfony/Component/ErrorRenderer/Exception/FlattenException.php b/src/Symfony/Component/ErrorRenderer/Exception/FlattenException.php
index da3454e05eb04..dd86f5b74bb07 100644
--- a/src/Symfony/Component/ErrorRenderer/Exception/FlattenException.php
+++ b/src/Symfony/Component/ErrorRenderer/Exception/FlattenException.php
@@ -12,7 +12,6 @@
namespace Symfony\Component\ErrorRenderer\Exception;
use Symfony\Component\Debug\Exception\FlattenException as LegacyFlattenException;
-use Symfony\Component\ErrorHandler\Exception\ErrorException;
use Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
@@ -70,7 +69,7 @@ public static function createFromThrowable(\Throwable $exception, int $statusCod
$e->setStatusCode($statusCode);
$e->setHeaders($headers);
$e->setTraceFromThrowable($exception);
- $e->setClass($exception instanceof ErrorException ? $exception->getOriginalClassName() : \get_class($exception));
+ $e->setClass(\get_class($exception));
$e->setFile($exception->getFile());
$e->setLine($exception->getLine());
diff --git a/src/Symfony/Component/ErrorRenderer/Tests/Exception/FlattenExceptionTest.php b/src/Symfony/Component/ErrorRenderer/Tests/Exception/FlattenExceptionTest.php
index dc2678be8158a..dad78d152540d 100644
--- a/src/Symfony/Component/ErrorRenderer/Tests/Exception/FlattenExceptionTest.php
+++ b/src/Symfony/Component/ErrorRenderer/Tests/Exception/FlattenExceptionTest.php
@@ -12,7 +12,6 @@
namespace Symfony\Component\ErrorRenderer\Tests\Exception;
use PHPUnit\Framework\TestCase;
-use Symfony\Component\ErrorHandler\Exception\ErrorException;
use Symfony\Component\ErrorRenderer\Exception\FlattenException;
use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
@@ -130,16 +129,6 @@ public function testFlattenHttpException(\Throwable $exception)
$this->assertInstanceOf($flattened->getClass(), $exception, 'The class is set to the class of the original exception');
}
- public function testWrappedThrowable()
- {
- $exception = new ErrorException(new \DivisionByZeroError('Ouch', 42));
- $flattened = FlattenException::createFromThrowable($exception);
-
- $this->assertSame('Ouch', $flattened->getMessage(), 'The message is copied from the original error.');
- $this->assertSame(42, $flattened->getCode(), 'The code is copied from the original error.');
- $this->assertSame('DivisionByZeroError', $flattened->getClass(), 'The class is set to the class of the original error');
- }
-
public function testThrowable()
{
$error = new \DivisionByZeroError('Ouch', 42);
diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md
index 28af7d7fc0a92..08a8cfddd7332 100644
--- a/src/Symfony/Component/HttpKernel/CHANGELOG.md
+++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md
@@ -21,6 +21,8 @@ CHANGELOG
* Marked the `RouterDataCollector::collect()` method as `@final`.
* The `DataCollectorInterface::collect()` and `Profiler::collect()` methods third parameter signature
will be `\Throwable $exception = null` instead of `\Exception $exception = null` in Symfony 5.0.
+ * Deprecated methods `ExceptionEvent::get/setException()`, use `get/setThrowable()` instead
+ * Deprecated class `ExceptionListener`, use `ErrorListener` instead
4.3.0
-----
diff --git a/src/Symfony/Component/HttpKernel/Controller/ErrorController.php b/src/Symfony/Component/HttpKernel/Controller/ErrorController.php
index 4d58a61120cd0..a86fa5c5cf391 100644
--- a/src/Symfony/Component/HttpKernel/Controller/ErrorController.php
+++ b/src/Symfony/Component/HttpKernel/Controller/ErrorController.php
@@ -52,7 +52,7 @@ public function preview(Request $request, int $code): Response
/*
* This Request mimics the parameters set by
- * \Symfony\Component\HttpKernel\EventListener\ExceptionListener::duplicateRequest, with
+ * \Symfony\Component\HttpKernel\EventListener\ErrorListener::duplicateRequest, with
* the additional "showException" flag.
*/
$subRequest = $request->duplicate(null, null, [
diff --git a/src/Symfony/Component/HttpKernel/Event/GetResponseForExceptionEvent.php b/src/Symfony/Component/HttpKernel/Event/GetResponseForExceptionEvent.php
index 3476c7e62a0cc..8b238f0db94dc 100644
--- a/src/Symfony/Component/HttpKernel/Event/GetResponseForExceptionEvent.php
+++ b/src/Symfony/Component/HttpKernel/Event/GetResponseForExceptionEvent.php
@@ -19,45 +19,55 @@
*/
class GetResponseForExceptionEvent extends RequestEvent
{
- /**
- * The exception object.
- *
- * @var \Exception
- */
+ private $throwable;
private $exception;
-
- /**
- * @var bool
- */
private $allowCustomResponseCode = false;
- public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, \Exception $e)
+ public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, \Throwable $e)
{
parent::__construct($kernel, $request, $requestType);
- $this->setException($e);
+ $this->setThrowable($e);
+ }
+
+ public function getThrowable(): \Throwable
+ {
+ return $this->throwable;
+ }
+
+ /**
+ * Replaces the thrown exception.
+ *
+ * This exception will be thrown if no response is set in the event.
+ */
+ public function setThrowable(\Throwable $exception): void
+ {
+ $this->exception = null;
+ $this->throwable = $exception;
}
/**
- * Returns the thrown exception.
+ * @deprecated since Symfony 4.4, use getThrowable instead
*
* @return \Exception The thrown exception
*/
public function getException()
{
- return $this->exception;
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.4, use "getThrowable()" instead.', __METHOD__), E_USER_DEPRECATED);
+
+ return $this->exception ?? $this->exception = $this->throwable instanceof \Exception ? $this->throwable : new FatalThrowableError($this->throwable);
}
/**
- * Replaces the thrown exception.
- *
- * This exception will be thrown if no response is set in the event.
+ * @deprecated since Symfony 4.4, use setThrowable instead
*
* @param \Exception $exception The thrown exception
*/
public function setException(\Exception $exception)
{
- $this->exception = $exception;
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.4, use "setThrowable()" instead.', __METHOD__), E_USER_DEPRECATED);
+
+ $this->throwable = $this->exception = $exception;
}
/**
diff --git a/src/Symfony/Component/HttpKernel/EventListener/DebugHandlersListener.php b/src/Symfony/Component/HttpKernel/EventListener/DebugHandlersListener.php
index 9779431eb9d03..8ed6a10e528a1 100644
--- a/src/Symfony/Component/HttpKernel/EventListener/DebugHandlersListener.php
+++ b/src/Symfony/Component/HttpKernel/EventListener/DebugHandlersListener.php
@@ -15,8 +15,8 @@
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\Console\Event\ConsoleEvent;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
+use Symfony\Component\Debug\Exception\FatalThrowableError;
use Symfony\Component\ErrorHandler\ErrorHandler;
-use Symfony\Component\ErrorHandler\Exception\ErrorException;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
@@ -112,10 +112,6 @@ public function configure(Event $event = null)
throw $e;
}
- if (!$e instanceof \Exception) {
- $e = new ErrorException($e);
- }
-
$hasRun = true;
$kernel->terminateWithException($e, $request);
};
@@ -130,7 +126,7 @@ public function configure(Event $event = null)
$app->renderThrowable($e, $output);
} else {
if (!$e instanceof \Exception) {
- $e = new ErrorException($e);
+ $e = new FatalThrowableError($e);
}
$app->renderException($e, $output);
diff --git a/src/Symfony/Component/HttpKernel/EventListener/ErrorListener.php b/src/Symfony/Component/HttpKernel/EventListener/ErrorListener.php
new file mode 100644
index 0000000000000..9a16cde741432
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/EventListener/ErrorListener.php
@@ -0,0 +1,134 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\EventListener;
+
+use Psr\Log\LoggerInterface;
+use Symfony\Component\ErrorRenderer\Exception\FlattenException;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Event\ExceptionEvent;
+use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
+
+/**
+ * @author Fabien Potencier
+ */
+class ErrorListener implements EventSubscriberInterface
+{
+ protected $controller;
+ protected $logger;
+ protected $debug;
+
+ public function __construct($controller, LoggerInterface $logger = null, $debug = false)
+ {
+ $this->controller = $controller;
+ $this->logger = $logger;
+ $this->debug = $debug;
+ }
+
+ public function logKernelException(ExceptionEvent $event)
+ {
+ $e = FlattenException::createFromThrowable($event->getThrowable());
+
+ $this->logException($event->getThrowable(), sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', $e->getClass(), $e->getMessage(), $e->getFile(), $e->getLine()));
+ }
+
+ public function onKernelException(ExceptionEvent $event)
+ {
+ if (null === $this->controller) {
+ return;
+ }
+
+ $exception = $event->getThrowable();
+ $request = $this->duplicateRequest($exception, $event->getRequest());
+ $eventDispatcher = \func_num_args() > 2 ? func_get_arg(2) : null;
+
+ try {
+ $response = $event->getKernel()->handle($request, HttpKernelInterface::SUB_REQUEST, false);
+ } catch (\Exception $e) {
+ $f = FlattenException::createFromThrowable($e);
+
+ $this->logException($e, sprintf('Exception thrown when handling an exception (%s: %s at %s line %s)', $f->getClass(), $f->getMessage(), $e->getFile(), $e->getLine()));
+
+ $prev = $e;
+ do {
+ if ($exception === $wrapper = $prev) {
+ throw $e;
+ }
+ } while ($prev = $wrapper->getPrevious());
+
+ $prev = new \ReflectionProperty($wrapper instanceof \Exception ? \Exception::class : \Error::class, 'previous');
+ $prev->setAccessible(true);
+ $prev->setValue($wrapper, $exception);
+
+ throw $e;
+ }
+
+ $event->setResponse($response);
+
+ if ($this->debug && $eventDispatcher instanceof EventDispatcherInterface) {
+ $cspRemovalListener = function ($event) use (&$cspRemovalListener, $eventDispatcher) {
+ $event->getResponse()->headers->remove('Content-Security-Policy');
+ $eventDispatcher->removeListener(KernelEvents::RESPONSE, $cspRemovalListener);
+ };
+ $eventDispatcher->addListener(KernelEvents::RESPONSE, $cspRemovalListener, -128);
+ }
+ }
+
+ public static function getSubscribedEvents()
+ {
+ return [
+ KernelEvents::EXCEPTION => [
+ ['logKernelException', 0],
+ ['onKernelException', -128],
+ ],
+ ];
+ }
+
+ /**
+ * Logs an exception.
+ *
+ * @param \Exception $exception The \Exception instance
+ * @param string $message The error message to log
+ */
+ protected function logException(\Exception $exception, $message)
+ {
+ if (null !== $this->logger) {
+ if (!$exception instanceof HttpExceptionInterface || $exception->getStatusCode() >= 500) {
+ $this->logger->critical($message, ['exception' => $exception]);
+ } else {
+ $this->logger->error($message, ['exception' => $exception]);
+ }
+ }
+ }
+
+ /**
+ * Clones the request for the exception.
+ *
+ * @return Request The cloned request
+ */
+ protected function duplicateRequest(\Exception $exception, Request $request)
+ {
+ $attributes = [
+ '_controller' => $this->controller,
+ 'exception' => FlattenException::createFromThrowable($exception),
+ 'logger' => $this->logger instanceof DebugLoggerInterface ? $this->logger : null,
+ ];
+ $request = $request->duplicate(null, null, $attributes);
+ $request->setMethod('GET');
+
+ return $request;
+ }
+}
diff --git a/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php b/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php
index ae64374c6efb4..dc2fd818ce93a 100644
--- a/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php
+++ b/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php
@@ -22,10 +22,10 @@
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
+@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "ErrorListener" instead.', ExceptionListener::class), E_USER_DEPRECATED);
+
/**
- * @author Fabien Potencier
- *
- * @final since Symfony 4.3
+ * @deprecated since Symfony 4.4, use ErrorListener instead
*/
class ExceptionListener implements EventSubscriberInterface
{
diff --git a/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php b/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php
index f9db55211ea83..b8464f1627353 100644
--- a/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php
+++ b/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php
@@ -62,7 +62,7 @@ public function onKernelException(GetResponseForExceptionEvent $event)
return;
}
- $this->exception = $event->getException();
+ $this->exception = $event->getThrowable();
}
/**
diff --git a/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php b/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php
index 9d8e83bc71e08..ee88debae45e8 100644
--- a/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php
+++ b/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php
@@ -143,7 +143,7 @@ public function onKernelRequest(GetResponseEvent $event)
public function onKernelException(GetResponseForExceptionEvent $event)
{
- if (!$this->debug || !($e = $event->getException()) instanceof NotFoundHttpException) {
+ if (!$this->debug || !($e = $event->getThrowable()) instanceof NotFoundHttpException) {
return;
}
diff --git a/src/Symfony/Component/HttpKernel/HttpKernel.php b/src/Symfony/Component/HttpKernel/HttpKernel.php
index 02b35e31ec510..c4cc3a3cc41c5 100644
--- a/src/Symfony/Component/HttpKernel/HttpKernel.php
+++ b/src/Symfony/Component/HttpKernel/HttpKernel.php
@@ -207,7 +207,7 @@ private function handleThrowable(\Throwable $e, Request $request, int $type): Re
$this->dispatcher->dispatch($event, KernelEvents::EXCEPTION);
// a listener might have replaced the exception
- $e = $event->getException();
+ $e = $event->getThrowable();
if (!$event->hasResponse()) {
$this->finishRequest($request, $type);
diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/ErrorListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/ErrorListenerTest.php
new file mode 100644
index 0000000000000..3707f3c4c920e
--- /dev/null
+++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/ErrorListenerTest.php
@@ -0,0 +1,180 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpKernel\Tests\EventListener;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\EventDispatcher\EventDispatcher;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Event\ExceptionEvent;
+use Symfony\Component\HttpKernel\Event\ResponseEvent;
+use Symfony\Component\HttpKernel\EventListener\ErrorListener;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
+use Symfony\Component\HttpKernel\Tests\Logger;
+
+/**
+ * @author Robert Schönthal
+ *
+ * @group time-sensitive
+ */
+class ErrorListenerTest extends TestCase
+{
+ public function testConstruct()
+ {
+ $logger = new TestLogger();
+ $l = new ErrorListener('foo', $logger);
+
+ $_logger = new \ReflectionProperty(\get_class($l), 'logger');
+ $_logger->setAccessible(true);
+ $_controller = new \ReflectionProperty(\get_class($l), 'controller');
+ $_controller->setAccessible(true);
+
+ $this->assertSame($logger, $_logger->getValue($l));
+ $this->assertSame('foo', $_controller->getValue($l));
+ }
+
+ /**
+ * @dataProvider provider
+ */
+ public function testHandleWithoutLogger($event, $event2)
+ {
+ $this->iniSet('error_log', file_exists('/dev/null') ? '/dev/null' : 'nul');
+
+ $l = new ErrorListener('foo');
+ $l->logKernelException($event);
+ $l->onKernelException($event);
+
+ $this->assertEquals(new Response('foo'), $event->getResponse());
+
+ try {
+ $l->logKernelException($event2);
+ $l->onKernelException($event2);
+ $this->fail('RuntimeException expected');
+ } catch (\RuntimeException $e) {
+ $this->assertSame('bar', $e->getMessage());
+ $this->assertSame('foo', $e->getPrevious()->getMessage());
+ }
+ }
+
+ /**
+ * @dataProvider provider
+ */
+ public function testHandleWithLogger($event, $event2)
+ {
+ $logger = new TestLogger();
+
+ $l = new ErrorListener('foo', $logger);
+ $l->logKernelException($event);
+ $l->onKernelException($event);
+
+ $this->assertEquals(new Response('foo'), $event->getResponse());
+
+ try {
+ $l->logKernelException($event2);
+ $l->onKernelException($event2);
+ $this->fail('RuntimeException expected');
+ } catch (\RuntimeException $e) {
+ $this->assertSame('bar', $e->getMessage());
+ $this->assertSame('foo', $e->getPrevious()->getMessage());
+ }
+
+ $this->assertEquals(3, $logger->countErrors());
+ $this->assertCount(3, $logger->getLogs('critical'));
+ }
+
+ public function provider()
+ {
+ if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
+ return [[null, null]];
+ }
+
+ $request = new Request();
+ $exception = new \Exception('foo');
+ $event = new ExceptionEvent(new TestKernel(), $request, HttpKernelInterface::MASTER_REQUEST, $exception);
+ $event2 = new ExceptionEvent(new TestKernelThatThrowsException(), $request, HttpKernelInterface::MASTER_REQUEST, $exception);
+
+ return [
+ [$event, $event2],
+ ];
+ }
+
+ public function testSubRequestFormat()
+ {
+ $listener = new ErrorListener('foo', $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock());
+
+ $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
+ $kernel->expects($this->once())->method('handle')->willReturnCallback(function (Request $request) {
+ return new Response($request->getRequestFormat());
+ });
+
+ $request = Request::create('/');
+ $request->setRequestFormat('xml');
+
+ $event = new ExceptionEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, new \Exception('foo'));
+ $listener->onKernelException($event);
+
+ $response = $event->getResponse();
+ $this->assertEquals('xml', $response->getContent());
+ }
+
+ public function testCSPHeaderIsRemoved()
+ {
+ $dispatcher = new EventDispatcher();
+ $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
+ $kernel->expects($this->once())->method('handle')->willReturnCallback(function (Request $request) {
+ return new Response($request->getRequestFormat());
+ });
+
+ $listener = new ErrorListener('foo', $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(), true);
+
+ $dispatcher->addSubscriber($listener);
+
+ $request = Request::create('/');
+ $event = new ExceptionEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, new \Exception('foo'));
+ $dispatcher->dispatch($event, KernelEvents::EXCEPTION);
+
+ $response = new Response('', 200, ['content-security-policy' => "style-src 'self'"]);
+ $this->assertTrue($response->headers->has('content-security-policy'));
+
+ $event = new ResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, $response);
+ $dispatcher->dispatch($event, KernelEvents::RESPONSE);
+
+ $this->assertFalse($response->headers->has('content-security-policy'), 'CSP header has been removed');
+ $this->assertFalse($dispatcher->hasListeners(KernelEvents::RESPONSE), 'CSP removal listener has been removed');
+ }
+}
+
+class TestLogger extends Logger implements DebugLoggerInterface
+{
+ public function countErrors(Request $request = null): int
+ {
+ return \count($this->logs['critical']);
+ }
+}
+
+class TestKernel implements HttpKernelInterface
+{
+ public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true): Response
+ {
+ return new Response('foo');
+ }
+}
+
+class TestKernelThatThrowsException implements HttpKernelInterface
+{
+ public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true): Response
+ {
+ throw new \RuntimeException('bar');
+ }
+}
diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/ExceptionListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/ExceptionListenerTest.php
index 38966edf2ccbb..28113c14afaba 100644
--- a/src/Symfony/Component/HttpKernel/Tests/EventListener/ExceptionListenerTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/ExceptionListenerTest.php
@@ -20,8 +20,6 @@
use Symfony\Component\HttpKernel\EventListener\ExceptionListener;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
-use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
-use Symfony\Component\HttpKernel\Tests\Logger;
/**
* ExceptionListenerTest.
@@ -29,6 +27,7 @@
* @author Robert Schönthal
*
* @group time-sensitive
+ * @group legacy
*/
class ExceptionListenerTest extends TestCase
{
@@ -157,26 +156,4 @@ public function testCSPHeaderIsRemoved()
}
}
-class TestLogger extends Logger implements DebugLoggerInterface
-{
- public function countErrors(Request $request = null): int
- {
- return \count($this->logs['critical']);
- }
-}
-
-class TestKernel implements HttpKernelInterface
-{
- public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true): Response
- {
- return new Response('foo');
- }
-}
-
-class TestKernelThatThrowsException implements HttpKernelInterface
-{
- public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true): Response
- {
- throw new \RuntimeException('bar');
- }
-}
+class_exists(ErrorListenerTest::class);
diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php
index ea88d4b34fa31..2c1e7721b4fa1 100644
--- a/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php
@@ -19,7 +19,7 @@
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpKernel\Controller\ControllerResolver;
use Symfony\Component\HttpKernel\Event\RequestEvent;
-use Symfony\Component\HttpKernel\EventListener\ExceptionListener;
+use Symfony\Component\HttpKernel\EventListener\ErrorListener;
use Symfony\Component\HttpKernel\EventListener\RouterListener;
use Symfony\Component\HttpKernel\EventListener\ValidateRequestListener;
use Symfony\Component\HttpKernel\HttpKernel;
@@ -168,7 +168,7 @@ public function testWithBadRequest()
$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber(new ValidateRequestListener());
$dispatcher->addSubscriber(new RouterListener($requestMatcher, $requestStack, new RequestContext()));
- $dispatcher->addSubscriber(new ExceptionListener(function () {
+ $dispatcher->addSubscriber(new ErrorListener(function () {
return new Response('Exception handled', 400);
}));
diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php
index 9a6170c086d35..14a84b6752e34 100644
--- a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php
@@ -49,7 +49,7 @@ public function testHandleWhenControllerThrowsAnExceptionAndCatchIsTrueWithAHand
{
$dispatcher = new EventDispatcher();
$dispatcher->addListener(KernelEvents::EXCEPTION, function ($event) {
- $event->setResponse(new Response($event->getException()->getMessage()));
+ $event->setResponse(new Response($event->getThrowable()->getMessage()));
});
$kernel = $this->getHttpKernel($dispatcher, function () { throw new \RuntimeException('foo'); });
@@ -96,7 +96,7 @@ public function testHandleHttpException()
{
$dispatcher = new EventDispatcher();
$dispatcher->addListener(KernelEvents::EXCEPTION, function ($event) {
- $event->setResponse(new Response($event->getException()->getMessage()));
+ $event->setResponse(new Response($event->getThrowable()->getMessage()));
});
$kernel = $this->getHttpKernel($dispatcher, function () { throw new MethodNotAllowedHttpException(['POST']); });
diff --git a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php
index 549543e3efb17..2f97c7e04cc66 100644
--- a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php
+++ b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php
@@ -90,7 +90,7 @@ public function unregister(EventDispatcherInterface $dispatcher)
*/
public function onKernelException(GetResponseForExceptionEvent $event)
{
- $exception = $event->getException();
+ $exception = $event->getThrowable();
do {
if ($exception instanceof AuthenticationException) {
$this->handleAuthenticationException($event, $exception);
@@ -128,13 +128,13 @@ private function handleAuthenticationException(GetResponseForExceptionEvent $eve
$event->setResponse($this->startAuthentication($event->getRequest(), $exception));
$event->allowCustomResponseCode();
} catch (\Exception $e) {
- $event->setException($e);
+ $event->setThrowable($e);
}
}
private function handleAccessDeniedException(GetResponseForExceptionEvent $event, AccessDeniedException $exception)
{
- $event->setException(new AccessDeniedHttpException($exception->getMessage(), $exception));
+ $event->setThrowable(new AccessDeniedHttpException($exception->getMessage(), $exception));
$token = $this->tokenStorage->getToken();
if (!$this->authenticationTrustResolver->isFullFledged($token)) {
@@ -148,7 +148,7 @@ private function handleAccessDeniedException(GetResponseForExceptionEvent $event
$event->setResponse($this->startAuthentication($event->getRequest(), $insufficientAuthenticationException));
} catch (\Exception $e) {
- $event->setException($e);
+ $event->setThrowable($e);
}
return;
@@ -177,7 +177,7 @@ private function handleAccessDeniedException(GetResponseForExceptionEvent $event
$this->logger->error('An exception was thrown when handling an AccessDeniedException.', ['exception' => $e]);
}
- $event->setException(new \RuntimeException('Exception thrown when handling an exception.', 0, $e));
+ $event->setThrowable(new \RuntimeException('Exception thrown when handling an exception.', 0, $e));
}
}
diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php
index f02a52894df1c..fb1db914286fb 100644
--- a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php
+++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php
@@ -15,7 +15,6 @@
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
-use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
@@ -40,7 +39,7 @@ public function testAuthenticationExceptionWithoutEntryPoint(\Exception $excepti
$listener->onKernelException($event);
$this->assertNull($event->getResponse());
- $this->assertEquals($eventException, $event->getException());
+ $this->assertEquals($eventException, $event->getThrowable());
}
/**
@@ -59,7 +58,7 @@ public function testAuthenticationExceptionWithEntryPoint(\Exception $exception)
$this->assertEquals('Forbidden', $event->getResponse()->getContent());
$this->assertEquals(403, $event->getResponse()->getStatusCode());
- $this->assertSame($exception, $event->getException());
+ $this->assertSame($exception, $event->getThrowable());
}
public function getAuthenticationExceptionProvider()
@@ -86,8 +85,8 @@ public function testExceptionWhenEntryPointReturnsBadValue()
$listener = $this->createExceptionListener(null, null, null, $entryPoint);
$listener->onKernelException($event);
// the exception has been replaced by our LogicException
- $this->assertInstanceOf('LogicException', $event->getException());
- $this->assertStringEndsWith('start() method must return a Response object (string returned)', $event->getException()->getMessage());
+ $this->assertInstanceOf('LogicException', $event->getThrowable());
+ $this->assertStringEndsWith('start() method must return a Response object (string returned)', $event->getThrowable()->getMessage());
}
/**
@@ -101,7 +100,7 @@ public function testAccessDeniedExceptionFullFledgedAndWithoutAccessDeniedHandle
$listener->onKernelException($event);
$this->assertNull($event->getResponse());
- $this->assertSame(null === $eventException ? $exception : $eventException, $event->getException()->getPrevious());
+ $this->assertSame(null === $eventException ? $exception : $eventException, $event->getThrowable()->getPrevious());
}
/**
@@ -124,7 +123,7 @@ public function testAccessDeniedExceptionFullFledgedAndWithoutAccessDeniedHandle
$this->assertEquals('Unauthorized', $event->getResponse()->getContent());
$this->assertEquals(401, $event->getResponse()->getStatusCode());
- $this->assertSame(null === $eventException ? $exception : $eventException, $event->getException()->getPrevious());
+ $this->assertSame(null === $eventException ? $exception : $eventException, $event->getThrowable()->getPrevious());
}
/**
@@ -141,7 +140,7 @@ public function testAccessDeniedExceptionFullFledgedAndWithAccessDeniedHandlerAn
$listener->onKernelException($event);
$this->assertEquals('error', $event->getResponse()->getContent());
- $this->assertSame(null === $eventException ? $exception : $eventException, $event->getException()->getPrevious());
+ $this->assertSame(null === $eventException ? $exception : $eventException, $event->getThrowable()->getPrevious());
}
/**
@@ -158,7 +157,7 @@ public function testAccessDeniedExceptionNotFullFledged(\Exception $exception, \
$listener->onKernelException($event);
$this->assertEquals('OK', $event->getResponse()->getContent());
- $this->assertSame(null === $eventException ? $exception : $eventException, $event->getException()->getPrevious());
+ $this->assertSame(null === $eventException ? $exception : $eventException, $event->getThrowable()->getPrevious());
}
public function getAccessDeniedExceptionProvider()
@@ -194,11 +193,7 @@ private function createEvent(\Exception $exception, $kernel = null)
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
}
- if (class_exists(ExceptionEvent::class)) {
- return new ExceptionEvent($kernel, Request::create('/'), HttpKernelInterface::MASTER_REQUEST, $exception);
- }
-
- return new GetResponseForExceptionEvent($kernel, Request::create('/'), HttpKernelInterface::MASTER_REQUEST, $exception);
+ return new ExceptionEvent($kernel, Request::create('/'), HttpKernelInterface::MASTER_REQUEST, $exception);
}
private function createExceptionListener(TokenStorageInterface $tokenStorage = null, AuthenticationTrustResolverInterface $trustResolver = null, HttpUtils $httpUtils = null, AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, AccessDeniedHandlerInterface $accessDeniedHandler = null)
diff --git a/src/Symfony/Component/Security/Http/composer.json b/src/Symfony/Component/Security/Http/composer.json
index d51c9d77e438f..686b2b9f1ec54 100644
--- a/src/Symfony/Component/Security/Http/composer.json
+++ b/src/Symfony/Component/Security/Http/composer.json
@@ -19,7 +19,7 @@
"php": "^7.1.3",
"symfony/security-core": "^4.4",
"symfony/http-foundation": "^3.4|^4.0|^5.0",
- "symfony/http-kernel": "^4.3",
+ "symfony/http-kernel": "^4.4",
"symfony/property-access": "^3.4|^4.0|^5.0"
},
"require-dev": {
diff --git a/src/Symfony/Component/Security/composer.json b/src/Symfony/Component/Security/composer.json
index fb5fd768c1265..5251cd8f005fb 100644
--- a/src/Symfony/Component/Security/composer.json
+++ b/src/Symfony/Component/Security/composer.json
@@ -19,7 +19,7 @@
"php": "^7.1.3",
"symfony/event-dispatcher-contracts": "^1.1|^2",
"symfony/http-foundation": "^3.4|^4.0|^5.0",
- "symfony/http-kernel": "^4.3",
+ "symfony/http-kernel": "^4.4",
"symfony/property-access": "^3.4|^4.0|^5.0",
"symfony/service-contracts": "^1.1|^2"
},