[HttpKernel][FrameworkBundle] Turn HTTP exceptions to HTTP status codes by default
This commit is contained in:
parent
0c57f00ccd
commit
80b0739fc2
@ -67,6 +67,16 @@
|
||||
<argument type="service" id="router" on-invalid="ignore" />
|
||||
</service>
|
||||
|
||||
<service id="http_exception_listener" class="Symfony\Component\HttpKernel\EventListener\ExceptionListener">
|
||||
<tag name="kernel.event_listener" event="kernel.exception" method="onKernelException" priority="-2048" />
|
||||
<tag name="kernel.reset" method="reset" />
|
||||
<argument>null</argument>
|
||||
<argument>null</argument>
|
||||
<argument>%kernel.debug%</argument>
|
||||
<argument>%kernel.charset%</argument>
|
||||
<argument>%debug.file_link_format%</argument>
|
||||
</service>
|
||||
|
||||
<service id="validate_request_listener" class="Symfony\Component\HttpKernel\EventListener\ValidateRequestListener">
|
||||
<tag name="kernel.event_subscriber" />
|
||||
</service>
|
||||
|
@ -13,8 +13,10 @@ namespace Symfony\Component\HttpKernel\EventListener;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Debug\Exception\FlattenException;
|
||||
use Symfony\Component\Debug\ExceptionHandler;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
|
||||
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
|
||||
@ -33,12 +35,17 @@ class ExceptionListener implements EventSubscriberInterface
|
||||
protected $controller;
|
||||
protected $logger;
|
||||
protected $debug;
|
||||
private $charset;
|
||||
private $fileLinkFormat;
|
||||
private $isTerminating = false;
|
||||
|
||||
public function __construct($controller, LoggerInterface $logger = null, $debug = false)
|
||||
public function __construct($controller, LoggerInterface $logger = null, $debug = false, string $charset = null, $fileLinkFormat = null)
|
||||
{
|
||||
$this->controller = $controller;
|
||||
$this->logger = $logger;
|
||||
$this->debug = $debug;
|
||||
$this->charset = $charset;
|
||||
$this->fileLinkFormat = $fileLinkFormat;
|
||||
}
|
||||
|
||||
public function logKernelException(GetResponseForExceptionEvent $event)
|
||||
@ -50,6 +57,17 @@ class ExceptionListener implements EventSubscriberInterface
|
||||
|
||||
public function onKernelException(GetResponseForExceptionEvent $event)
|
||||
{
|
||||
if (null === $this->controller) {
|
||||
if (!$event->isMasterRequest()) {
|
||||
return;
|
||||
}
|
||||
if (!$this->isTerminating) {
|
||||
$this->isTerminating = true;
|
||||
|
||||
return;
|
||||
}
|
||||
$this->isTerminating = false;
|
||||
}
|
||||
$exception = $event->getException();
|
||||
$request = $this->duplicateRequest($exception, $event->getRequest());
|
||||
$eventDispatcher = func_num_args() > 2 ? func_get_arg(2) : null;
|
||||
@ -85,6 +103,11 @@ class ExceptionListener implements EventSubscriberInterface
|
||||
}
|
||||
}
|
||||
|
||||
public function reset()
|
||||
{
|
||||
$this->isTerminating = false;
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
@ -123,8 +146,12 @@ class ExceptionListener implements EventSubscriberInterface
|
||||
protected function duplicateRequest(\Exception $exception, Request $request)
|
||||
{
|
||||
$attributes = array(
|
||||
'_controller' => $this->controller,
|
||||
'exception' => FlattenException::create($exception),
|
||||
'exception' => $exception = FlattenException::create($exception),
|
||||
'_controller' => $this->controller ?: function () use ($exception) {
|
||||
$handler = new ExceptionHandler($this->debug, $this->charset, $this->fileLinkFormat);
|
||||
|
||||
return new Response($handler->getHtml($exception), $exception->getStatusCode(), $exception->getHeaders());
|
||||
},
|
||||
'logger' => $this->logger instanceof DebugLoggerInterface ? $this->logger : null,
|
||||
);
|
||||
$request = $request->duplicate(null, null, $attributes);
|
||||
|
@ -155,6 +155,25 @@ class ExceptionListenerTest extends TestCase
|
||||
$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');
|
||||
}
|
||||
|
||||
public function testNullController()
|
||||
{
|
||||
$listener = new ExceptionListener(null);
|
||||
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
|
||||
$kernel->expects($this->once())->method('handle')->will($this->returnCallback(function (Request $request) {
|
||||
$controller = $request->attributes->get('_controller');
|
||||
|
||||
return $controller();
|
||||
}));
|
||||
$request = Request::create('/');
|
||||
$event = new GetResponseForExceptionEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, new \Exception('foo'));
|
||||
|
||||
$listener->onKernelException($event);
|
||||
$this->assertNull($event->getResponse());
|
||||
|
||||
$listener->onKernelException($event);
|
||||
$this->assertContains('Whoops, looks like something went wrong.', $event->getResponse()->getContent());
|
||||
}
|
||||
}
|
||||
|
||||
class TestLogger extends Logger implements DebugLoggerInterface
|
||||
|
Reference in New Issue
Block a user