Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f9ce498

Browse files
James Halsalljameshalsall
James Halsall
authored andcommitted
[HttpKernel] Deprecate X-Status-Code for better alternative
This marks the X-Status-Code header method of setting a custom response status code in exception listeners as deprecated. Instead there is now a new method on the GetResponseForExceptionEvent that allows successful status codes in the response sent to the client.
1 parent 3e9b8f3 commit f9ce498

10 files changed

+113
-12
lines changed

UPGRADE-3.3.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ HttpKernel
7676

7777
* The `Psr6CacheClearer::addPool()` method has been deprecated. Pass an array of pools indexed
7878
by name to the constructor instead.
79+
80+
* The `X-Status-Code` header method of setting a custom status code in the response
81+
when handling exceptions has been removed. There is now a new
82+
`GetResponseForExceptionEvent::allowCustomResponseCode()` method instead, which
83+
will tell the Kernel to use the response code set on the event's response object.
7984

8085
Process
8186
-------

UPGRADE-4.0.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,11 @@ HttpKernel
236236

237237
* The `Psr6CacheClearer::addPool()` method has been removed. Pass an array of pools indexed
238238
by name to the constructor instead.
239+
240+
* The `X-Status-Code` header method of setting a custom status code in the response
241+
when handling exceptions has been removed. There is now a new
242+
`GetResponseForExceptionEvent::allowCustomResponseCode()` method instead, which
243+
will tell the Kernel to use the response code set on the event's response object.
239244

240245
Process
241246
-------

src/Symfony/Component/HttpKernel/Event/GetResponseForExceptionEvent.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ class GetResponseForExceptionEvent extends GetResponseEvent
3636
*/
3737
private $exception;
3838

39+
/**
40+
* @var bool
41+
*/
42+
private $allowCustomResponseCode = false;
43+
3944
public function __construct(HttpKernelInterface $kernel, Request $request, $requestType, \Exception $e)
4045
{
4146
parent::__construct($kernel, $request, $requestType);
@@ -64,4 +69,22 @@ public function setException(\Exception $exception)
6469
{
6570
$this->exception = $exception;
6671
}
72+
73+
/**
74+
* Mark the event as allowing a custom response code.
75+
*/
76+
public function allowCustomResponseCode()
77+
{
78+
$this->allowCustomResponseCode = true;
79+
}
80+
81+
/**
82+
* Returns true if the event allows a custom response code.
83+
*
84+
* @return bool
85+
*/
86+
public function isAllowingCustomResponseCode()
87+
{
88+
return $this->allowCustomResponseCode;
89+
}
6790
}

src/Symfony/Component/HttpKernel/HttpKernel.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,10 +242,12 @@ private function handleException(\Exception $e, $request, $type)
242242

243243
// the developer asked for a specific status code
244244
if ($response->headers->has('X-Status-Code')) {
245+
@trigger_error(sprintf('Using the X-Status-Code header is deprecated, use %s::allowCustomResponseCode() instead.', GetResponseForExceptionEvent::class), E_USER_DEPRECATED);
246+
245247
$response->setStatusCode($response->headers->get('X-Status-Code'));
246248

247249
$response->headers->remove('X-Status-Code');
248-
} elseif (!$response->isClientError() && !$response->isServerError() && !$response->isRedirect()) {
250+
} elseif (!$event->isAllowingCustomResponseCode() && !$response->isClientError() && !$response->isServerError() && !$response->isRedirect()) {
249251
// ensure that we actually have an error response
250252
if ($e instanceof HttpExceptionInterface) {
251253
// keep the HTTP status code and headers
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\HttpKernel\Tests\Event;
13+
14+
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
16+
use Symfony\Component\HttpKernel\Tests\TestHttpKernel;
17+
18+
class GetResponseForExceptionEventTest extends \PHPUnit_Framework_TestCase
19+
{
20+
public function testAllowSuccessfulResponseIsFalseByDefault()
21+
{
22+
$event = new GetResponseForExceptionEvent(new TestHttpKernel(), new Request(), 1, new \Exception());
23+
24+
$this->assertFalse($event->isAllowingCustomResponseCode());
25+
}
26+
}

src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
1818
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
1919
use Symfony\Component\HttpKernel\Event\FilterControllerArgumentsEvent;
20+
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
2021
use Symfony\Component\HttpKernel\HttpKernel;
2122
use Symfony\Component\HttpKernel\HttpKernelInterface;
2223
use Symfony\Component\HttpKernel\KernelEvents;
@@ -111,9 +112,10 @@ public function testHandleHttpException()
111112
}
112113

113114
/**
115+
* @group legacy
114116
* @dataProvider getStatusCodes
115117
*/
116-
public function testHandleWhenAnExceptionIsHandledWithASpecificStatusCode($responseStatusCode, $expectedStatusCode)
118+
public function testLegacyHandleWhenAnExceptionIsHandledWithASpecificStatusCode($responseStatusCode, $expectedStatusCode)
117119
{
118120
$dispatcher = new EventDispatcher();
119121
$dispatcher->addListener(KernelEvents::EXCEPTION, function ($event) use ($responseStatusCode, $expectedStatusCode) {
@@ -137,6 +139,32 @@ public function getStatusCodes()
137139
);
138140
}
139141

142+
/**
143+
* @dataProvider getSpecificStatusCodes
144+
*/
145+
public function testHandleWhenAnExceptionIsHandledWithASpecificStatusCode($expectedStatusCode)
146+
{
147+
$dispatcher = new EventDispatcher();
148+
$dispatcher->addListener(KernelEvents::EXCEPTION, function (GetResponseForExceptionEvent $event) use ($expectedStatusCode) {
149+
$event->allowCustomResponseCode();
150+
$event->setResponse(new Response('', $expectedStatusCode));
151+
});
152+
153+
$kernel = $this->getHttpKernel($dispatcher, function () { throw new \RuntimeException(); });
154+
$response = $kernel->handle(new Request());
155+
156+
$this->assertEquals($expectedStatusCode, $response->getStatusCode());
157+
}
158+
159+
public function getSpecificStatusCodes()
160+
{
161+
return array(
162+
array(200),
163+
array(302),
164+
array(403),
165+
);
166+
}
167+
140168
public function testHandleWhenAListenerReturnsAResponse()
141169
{
142170
$dispatcher = new EventDispatcher();

src/Symfony/Component/Security/Http/EntryPoint/FormAuthenticationEntryPoint.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public function start(Request $request, AuthenticationException $authException =
5454

5555
$response = $this->httpKernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
5656
if (200 === $response->getStatusCode()) {
57-
$response->headers->set('X-Status-Code', 401);
57+
$response->setStatusCode(401);
5858
}
5959

6060
return $response;

src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ private function handleAuthenticationException(GetResponseForExceptionEvent $eve
112112

113113
try {
114114
$event->setResponse($this->startAuthentication($event->getRequest(), $exception));
115+
if (method_exists($event, 'allowCustomResponseCode')) {
116+
$event->allowCustomResponseCode();
117+
}
115118
} catch (\Exception $e) {
116119
$event->setException($e);
117120
}
@@ -155,6 +158,9 @@ private function handleAccessDeniedException(GetResponseForExceptionEvent $event
155158
$subRequest->attributes->set(Security::ACCESS_DENIED_ERROR, $exception);
156159

157160
$event->setResponse($event->getKernel()->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true));
161+
if (method_exists($event, 'allowCustomResponseCode')) {
162+
$event->allowCustomResponseCode();
163+
}
158164
}
159165
} catch (\Exception $e) {
160166
if (null !== $this->logger) {

src/Symfony/Component/Security/Http/Tests/EntryPoint/FormAuthenticationEntryPointTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,6 @@ public function testStartWithUseForward()
6464
$entryPointResponse = $entryPoint->start($request);
6565

6666
$this->assertEquals($response, $entryPointResponse);
67-
$this->assertEquals(401, $entryPointResponse->headers->get('X-Status-Code'));
67+
$this->assertEquals(401, $entryPointResponse->getStatusCode());
6868
}
6969
}

src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,18 @@ public function testAuthenticationExceptionWithoutEntryPoint(\Exception $excepti
4444
/**
4545
* @dataProvider getAuthenticationExceptionProvider
4646
*/
47-
public function testAuthenticationExceptionWithEntryPoint(\Exception $exception, \Exception $eventException = null)
47+
public function testAuthenticationExceptionWithEntryPoint(\Exception $exception)
4848
{
49-
$event = $this->createEvent($exception = new AuthenticationException());
49+
$event = $this->createEvent($exception);
50+
51+
$response = new Response('Forbidden', 403);
5052

51-
$listener = $this->createExceptionListener(null, null, null, $this->createEntryPoint());
53+
$listener = $this->createExceptionListener(null, null, null, $this->createEntryPoint($response));
5254
$listener->onKernelException($event);
5355

54-
$this->assertEquals('OK', $event->getResponse()->getContent());
56+
$this->assertTrue($event->isAllowingCustomResponseCode());
57+
$this->assertEquals('Forbidden', $event->getResponse()->getContent());
58+
$this->assertEquals(403, $event->getResponse()->getStatusCode());
5559
$this->assertSame($exception, $event->getException());
5660
}
5761

@@ -100,7 +104,7 @@ public function testAccessDeniedExceptionFullFledgedAndWithoutAccessDeniedHandle
100104
public function testAccessDeniedExceptionFullFledgedAndWithoutAccessDeniedHandlerAndWithErrorPage(\Exception $exception, \Exception $eventException = null)
101105
{
102106
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
103-
$kernel->expects($this->once())->method('handle')->will($this->returnValue(new Response('error')));
107+
$kernel->expects($this->once())->method('handle')->will($this->returnValue(new Response('Unauthorized', 401)));
104108

105109
$event = $this->createEvent($exception, $kernel);
106110

@@ -110,7 +114,9 @@ public function testAccessDeniedExceptionFullFledgedAndWithoutAccessDeniedHandle
110114
$listener = $this->createExceptionListener(null, $this->createTrustResolver(true), $httpUtils, null, '/error');
111115
$listener->onKernelException($event);
112116

113-
$this->assertEquals('error', $event->getResponse()->getContent());
117+
$this->assertTrue($event->isAllowingCustomResponseCode());
118+
$this->assertEquals('Unauthorized', $event->getResponse()->getContent());
119+
$this->assertEquals(401, $event->getResponse()->getStatusCode());
114120
$this->assertSame(null === $eventException ? $exception : $eventException, $event->getException()->getPrevious());
115121
}
116122

@@ -159,10 +165,10 @@ public function getAccessDeniedExceptionProvider()
159165
);
160166
}
161167

162-
private function createEntryPoint()
168+
private function createEntryPoint(Response $response = null)
163169
{
164170
$entryPoint = $this->getMockBuilder('Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface')->getMock();
165-
$entryPoint->expects($this->once())->method('start')->will($this->returnValue(new Response('OK')));
171+
$entryPoint->expects($this->once())->method('start')->will($this->returnValue($response ?: new Response('OK')));
166172

167173
return $entryPoint;
168174
}

0 commit comments

Comments
 (0)