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

Skip to content

Commit ecad2c4

Browse files
author
Ismail Turan
committed
[HttpKernel] Fix missing Request in RequestStack for StreamedResponse
1 parent 4c1d953 commit ecad2c4

File tree

3 files changed

+69
-4
lines changed

3 files changed

+69
-4
lines changed

src/Symfony/Component/HttpFoundation/StreamedResponse.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,17 @@ public function setCallback(callable $callback): static
5656
return $this;
5757
}
5858

59+
/**
60+
* Decorates the PHP callback associated with this Response.
61+
*/
62+
public function getCallback(): callable
63+
{
64+
return $this->callback;
65+
}
66+
5967
/**
6068
* This method only sends the headers once.
6169
*
62-
* @param null|positive-int $statusCode The status code to use, override the statusCode property if set and not null
63-
*
6470
* @return $this
6571
*/
6672
public function sendHeaders(/* int $statusCode = null */): static

src/Symfony/Component/HttpKernel/HttpKernel.php

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\HttpFoundation\Request;
1616
use Symfony\Component\HttpFoundation\RequestStack;
1717
use Symfony\Component\HttpFoundation\Response;
18+
use Symfony\Component\HttpFoundation\StreamedResponse;
1819
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
1920
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
2021
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
@@ -70,8 +71,12 @@ public function handle(Request $request, int $type = HttpKernelInterface::MAIN_R
7071
$request->headers->set('X-Php-Ob-Level', (string) ob_get_level());
7172

7273
$this->requestStack->push($request);
74+
$response = null;
7375
try {
74-
return $this->handleRaw($request, $type);
76+
$response = $this->handleRaw($request, $type);
77+
$response = $this->decorateWhenStreamedResponse($response);
78+
79+
return $response;
7580
} catch (\Throwable $e) {
7681
if ($e instanceof \Error && !$this->handleAllThrowables) {
7782
throw $e;
@@ -88,7 +93,9 @@ public function handle(Request $request, int $type = HttpKernelInterface::MAIN_R
8893

8994
return $this->handleThrowable($e, $request, $type);
9095
} finally {
91-
$this->requestStack->pop();
96+
if (!$response instanceof StreamedResponse) {
97+
$this->requestStack->pop();
98+
}
9299
}
93100
}
94101

@@ -257,6 +264,22 @@ private function handleThrowable(\Throwable $e, Request $request, int $type): Re
257264
}
258265
}
259266

267+
private function decorateWhenStreamedResponse(Response $response): Response
268+
{
269+
if ($response instanceof StreamedResponse) {
270+
$streamedResponseCallback = $response->getCallback();
271+
$response->setCallback(function () use ($streamedResponseCallback) {
272+
try {
273+
$streamedResponseCallback();
274+
} finally {
275+
$this->requestStack->pop();
276+
}
277+
});
278+
}
279+
280+
return $response;
281+
}
282+
260283
/**
261284
* Returns a human-readable string for the specified variable.
262285
*/

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Symfony\Component\HttpFoundation\Request;
1919
use Symfony\Component\HttpFoundation\RequestStack;
2020
use Symfony\Component\HttpFoundation\Response;
21+
use Symfony\Component\HttpFoundation\StreamedResponse;
2122
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
2223
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
2324
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
@@ -457,6 +458,34 @@ public function testVerifyRequestStackPushPopDuringHandle()
457458
$kernel->handle($request, HttpKernelInterface::MAIN_REQUEST);
458459
}
459460

461+
public function testVerifyRequestStackPushPopCallOrderDuringHandle()
462+
{
463+
$request = new Request();
464+
$stack = new RequestStack();
465+
$dispatcher = new EventDispatcher();
466+
$kernel = $this->getHttpKernel($dispatcher, null, $stack);
467+
468+
$response = $kernel->handle($request, HttpKernelInterface::MAIN_REQUEST);
469+
self::assertNull($stack->getMainRequest());
470+
$response->send();
471+
self::assertNull($stack->getMainRequest());
472+
}
473+
474+
public function testVerifyRequestStackPushPopWithStreamedResponse()
475+
{
476+
$request = new Request();
477+
$stack = new RequestStack();
478+
$dispatcher = new EventDispatcher();
479+
$kernel = $this->getHttpKernel($dispatcher, [new TestController(), 'streamedResponseController'], $stack);
480+
481+
$response = $kernel->handle($request, HttpKernelInterface::MAIN_REQUEST);
482+
self::assertNotNull($stack->getMainRequest());
483+
ob_start();
484+
$response->send();
485+
self::assertSame('foo', ob_get_clean());
486+
self::assertNull($stack->getMainRequest());
487+
}
488+
460489
public function testInconsistentClientIpsOnMainRequests()
461490
{
462491
$this->expectException(BadRequestHttpException::class);
@@ -515,6 +544,13 @@ public function controller()
515544
return new Response('foo');
516545
}
517546

547+
public function streamedResponseController()
548+
{
549+
return new StreamedResponse(function () {
550+
echo 'foo';
551+
});
552+
}
553+
518554
public static function staticController()
519555
{
520556
return new Response('foo');

0 commit comments

Comments
 (0)