From ca1c40e66ded3da631bf111f6b0a4ab50c9b97d4 Mon Sep 17 00:00:00 2001 From: Ismail Turan Date: Fri, 28 Jul 2023 08:26:11 +0200 Subject: [PATCH] [HttpKernel] Fix missing Request in RequestStack for StreamedResponse --- .../HttpFoundation/StreamedResponse.php | 5 +++++ .../Component/HttpKernel/HttpKernel.php | 20 +++++++++++++++++-- .../HttpKernel/Tests/HttpKernelTest.php | 18 +++++++++++++++++ .../Component/HttpKernel/composer.json | 2 +- 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/StreamedResponse.php b/src/Symfony/Component/HttpFoundation/StreamedResponse.php index 2c8ff15f3650e..5c7817e3c9afd 100644 --- a/src/Symfony/Component/HttpFoundation/StreamedResponse.php +++ b/src/Symfony/Component/HttpFoundation/StreamedResponse.php @@ -56,6 +56,11 @@ public function setCallback(callable $callback): static return $this; } + public function getCallback(): \Closure + { + return ($this->callback)(...); + } + /** * This method only sends the headers once. * diff --git a/src/Symfony/Component/HttpKernel/HttpKernel.php b/src/Symfony/Component/HttpKernel/HttpKernel.php index 794a55dc18f9c..4999870e4c55d 100644 --- a/src/Symfony/Component/HttpKernel/HttpKernel.php +++ b/src/Symfony/Component/HttpKernel/HttpKernel.php @@ -15,6 +15,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface; use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; @@ -70,8 +71,9 @@ public function handle(Request $request, int $type = HttpKernelInterface::MAIN_R $request->headers->set('X-Php-Ob-Level', (string) ob_get_level()); $this->requestStack->push($request); + $response = null; try { - return $this->handleRaw($request, $type); + return $response = $this->handleRaw($request, $type); } catch (\Throwable $e) { if ($e instanceof \Error && !$this->handleAllThrowables) { throw $e; @@ -86,9 +88,23 @@ public function handle(Request $request, int $type = HttpKernelInterface::MAIN_R throw $e; } - return $this->handleThrowable($e, $request, $type); + return $response = $this->handleThrowable($e, $request, $type); } finally { $this->requestStack->pop(); + + if ($response instanceof StreamedResponse) { + $callback = $response->getCallback(); + $requestStack = $this->requestStack; + + $response->setCallback(static function () use ($request, $callback, $requestStack) { + $requestStack->push($request); + try { + $callback(); + } finally { + $requestStack->pop(); + } + }); + } } } diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php index a5a240a6265ec..311934e2210c0 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php @@ -18,6 +18,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface; use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; use Symfony\Component\HttpKernel\Event\ExceptionEvent; @@ -457,6 +458,23 @@ public function testVerifyRequestStackPushPopDuringHandle() $kernel->handle($request, HttpKernelInterface::MAIN_REQUEST); } + public function testVerifyRequestStackPushPopWithStreamedResponse() + { + $request = new Request(); + $stack = new RequestStack(); + $dispatcher = new EventDispatcher(); + $kernel = $this->getHttpKernel($dispatcher, fn () => new StreamedResponse(function () use ($stack) { + echo $stack->getMainRequest()::class; + }), $stack); + + $response = $kernel->handle($request, HttpKernelInterface::MAIN_REQUEST); + self::assertNull($stack->getMainRequest()); + ob_start(); + $response->send(); + self::assertSame(Request::class, ob_get_clean()); + self::assertNull($stack->getMainRequest()); + } + public function testInconsistentClientIpsOnMainRequests() { $this->expectException(BadRequestHttpException::class); diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index bf8be24d05ab4..682e741cd9f49 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -20,7 +20,7 @@ "symfony/deprecation-contracts": "^2.5|^3", "symfony/error-handler": "^6.3", "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/http-foundation": "^6.2.7", + "symfony/http-foundation": "^6.3.4", "symfony/polyfill-ctype": "^1.8", "psr/log": "^1|^2|^3" },