Loading core/lib/Drupal/Core/DependencyInjection/Compiler/StackedKernelPass.php +9 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,8 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\TerminableInterface; /** * Provides a compiler pass for stacked HTTP kernels. Loading Loading @@ -100,7 +102,14 @@ public function process(ContainerBuilder $container) { $first_responder = FALSE; } elseif ($first_responder) { // Use interface proxying to allow middleware classes declared final // to be set as lazy. $decorator->setLazy(TRUE); foreach ([HttpKernelInterface::class, TerminableInterface::class] as $interface) { if (is_a($decorator->getClass(), $interface, TRUE)) { $decorator->addTag('proxy', ['interface' => $interface]); } } } $decorated_id = $id; Loading core/lib/Drupal/Core/StackMiddleware/StackedHttpKernel.php +3 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,9 @@ public function handle(Request $request, $type = HttpKernelInterface::MAIN_REQUE /** * {@inheritdoc} * * phpcs:ignore Drupal.Commenting.FunctionComment.VoidReturn * @return void */ public function terminate(Request $request, Response $response) { $previous = NULL; Loading core/modules/big_pipe/src/StackMiddleware/ContentLength.php +1 −1 Original line number Diff line number Diff line Loading @@ -12,7 +12,7 @@ /** * Defines a big pipe middleware that removes Content-Length headers. */ class ContentLength implements HttpKernelInterface { final class ContentLength implements HttpKernelInterface { /** * Constructs a new ContentLength instance. Loading core/tests/Drupal/Tests/Core/DependencyInjection/Compiler/StackedKernelPassTest.php +57 −0 Original line number Diff line number Diff line Loading @@ -7,8 +7,13 @@ use Drupal\Core\DependencyInjection\Compiler\StackedKernelPass; use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\StackMiddleware\StackedHttpKernel; use Drupal\Tests\Core\DependencyInjection\Fixture\FinalTestHttpMiddlewareClass; use Drupal\Tests\Core\DependencyInjection\Fixture\FinalTestNonTerminableHttpMiddlewareClass; use Drupal\Tests\UnitTestCase; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\HttpKernel\HttpKernel; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * @coversDefaultClass \Drupal\Core\DependencyInjection\Compiler\StackedKernelPass Loading Loading @@ -95,6 +100,58 @@ public function testProcessWithHttpKernel() { $this->assertSame($kernel->getArguments(), $unprocessed_kernel->getArguments()); } /** * Tests that class declared 'final' can be added as http_middleware. */ public function testProcessWithStackedKernelAndFinalHttpMiddleware(): void { $stacked_kernel = new Definition(StackedHttpKernel::class); $stacked_kernel->setPublic(TRUE); $this->containerBuilder->setDefinition('http_kernel', $stacked_kernel); $basic_kernel = $this->getMockBuilder(HttpKernel::class) ->disableOriginalConstructor() ->onlyMethods(['handle', 'terminate']) ->getMock(); $basic_definition = (new Definition($basic_kernel::class)) ->setPublic(TRUE); $this->containerBuilder->setDefinition('http_kernel.basic', $basic_definition); // Services tagged 'http_middleware', other than the highest priority // middleware that is a responder, is also set as lazy by // StackedKernelPass::process(). Add middleware classes declared final and // confirm they are interface proxied correctly. // @see https://symfony.com/doc/current/service_container/lazy_services.html#interface-proxifying $first_responder = $this->getMockBuilder(HttpKernelInterface::class) ->getMock(); $this->containerBuilder->setDefinition('http_kernel.one', (new Definition($first_responder::class)) ->setPublic(TRUE) ->addTag('http_middleware', [ 'priority' => 200, 'responder' => TRUE, ])); // First middleware class declared final. $this->containerBuilder->setDefinition('http_kernel.two', (new Definition(FinalTestHttpMiddlewareClass::class)) ->setPublic(TRUE) ->addTag('http_middleware', [ 'priority' => 100, 'responder' => TRUE, ])); // Second middleware class declared final, this time without implementing // TerminableInterface. $this->containerBuilder->setDefinition('http_kernel.three', (new Definition(FinalTestNonTerminableHttpMiddlewareClass::class)) ->setPublic(TRUE) ->addTag('http_middleware', [ 'priority' => 50, 'responder' => TRUE, ])); $this->stackedKernelPass->process($this->containerBuilder); try { $this->containerBuilder->get('http_kernel'); } catch (InvalidArgumentException $e) { $this->fail($e->getMessage()); } } /** * Creates a middleware definition. * Loading core/tests/Drupal/Tests/Core/DependencyInjection/Fixture/FinalTestHttpMiddlewareClass.php 0 → 100644 +30 −0 Original line number Diff line number Diff line <?php namespace Drupal\Tests\Core\DependencyInjection\Fixture; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\TerminableInterface; /** * Stub of http_middleware class that is declared final. */ final class FinalTestHttpMiddlewareClass implements HttpKernelInterface, TerminableInterface { /** * {@inheritdoc} */ public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = TRUE): Response { return new Response(); } /** * {@inheritdoc} * * phpcs:ignore Drupal.Commenting.FunctionComment.VoidReturn * @return void */ public function terminate(Request $request, Response $response) {} } Loading
core/lib/Drupal/Core/DependencyInjection/Compiler/StackedKernelPass.php +9 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,8 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\TerminableInterface; /** * Provides a compiler pass for stacked HTTP kernels. Loading Loading @@ -100,7 +102,14 @@ public function process(ContainerBuilder $container) { $first_responder = FALSE; } elseif ($first_responder) { // Use interface proxying to allow middleware classes declared final // to be set as lazy. $decorator->setLazy(TRUE); foreach ([HttpKernelInterface::class, TerminableInterface::class] as $interface) { if (is_a($decorator->getClass(), $interface, TRUE)) { $decorator->addTag('proxy', ['interface' => $interface]); } } } $decorated_id = $id; Loading
core/lib/Drupal/Core/StackMiddleware/StackedHttpKernel.php +3 −0 Original line number Diff line number Diff line Loading @@ -53,6 +53,9 @@ public function handle(Request $request, $type = HttpKernelInterface::MAIN_REQUE /** * {@inheritdoc} * * phpcs:ignore Drupal.Commenting.FunctionComment.VoidReturn * @return void */ public function terminate(Request $request, Response $response) { $previous = NULL; Loading
core/modules/big_pipe/src/StackMiddleware/ContentLength.php +1 −1 Original line number Diff line number Diff line Loading @@ -12,7 +12,7 @@ /** * Defines a big pipe middleware that removes Content-Length headers. */ class ContentLength implements HttpKernelInterface { final class ContentLength implements HttpKernelInterface { /** * Constructs a new ContentLength instance. Loading
core/tests/Drupal/Tests/Core/DependencyInjection/Compiler/StackedKernelPassTest.php +57 −0 Original line number Diff line number Diff line Loading @@ -7,8 +7,13 @@ use Drupal\Core\DependencyInjection\Compiler\StackedKernelPass; use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\StackMiddleware\StackedHttpKernel; use Drupal\Tests\Core\DependencyInjection\Fixture\FinalTestHttpMiddlewareClass; use Drupal\Tests\Core\DependencyInjection\Fixture\FinalTestNonTerminableHttpMiddlewareClass; use Drupal\Tests\UnitTestCase; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\HttpKernel\HttpKernel; use Symfony\Component\HttpKernel\HttpKernelInterface; /** * @coversDefaultClass \Drupal\Core\DependencyInjection\Compiler\StackedKernelPass Loading Loading @@ -95,6 +100,58 @@ public function testProcessWithHttpKernel() { $this->assertSame($kernel->getArguments(), $unprocessed_kernel->getArguments()); } /** * Tests that class declared 'final' can be added as http_middleware. */ public function testProcessWithStackedKernelAndFinalHttpMiddleware(): void { $stacked_kernel = new Definition(StackedHttpKernel::class); $stacked_kernel->setPublic(TRUE); $this->containerBuilder->setDefinition('http_kernel', $stacked_kernel); $basic_kernel = $this->getMockBuilder(HttpKernel::class) ->disableOriginalConstructor() ->onlyMethods(['handle', 'terminate']) ->getMock(); $basic_definition = (new Definition($basic_kernel::class)) ->setPublic(TRUE); $this->containerBuilder->setDefinition('http_kernel.basic', $basic_definition); // Services tagged 'http_middleware', other than the highest priority // middleware that is a responder, is also set as lazy by // StackedKernelPass::process(). Add middleware classes declared final and // confirm they are interface proxied correctly. // @see https://symfony.com/doc/current/service_container/lazy_services.html#interface-proxifying $first_responder = $this->getMockBuilder(HttpKernelInterface::class) ->getMock(); $this->containerBuilder->setDefinition('http_kernel.one', (new Definition($first_responder::class)) ->setPublic(TRUE) ->addTag('http_middleware', [ 'priority' => 200, 'responder' => TRUE, ])); // First middleware class declared final. $this->containerBuilder->setDefinition('http_kernel.two', (new Definition(FinalTestHttpMiddlewareClass::class)) ->setPublic(TRUE) ->addTag('http_middleware', [ 'priority' => 100, 'responder' => TRUE, ])); // Second middleware class declared final, this time without implementing // TerminableInterface. $this->containerBuilder->setDefinition('http_kernel.three', (new Definition(FinalTestNonTerminableHttpMiddlewareClass::class)) ->setPublic(TRUE) ->addTag('http_middleware', [ 'priority' => 50, 'responder' => TRUE, ])); $this->stackedKernelPass->process($this->containerBuilder); try { $this->containerBuilder->get('http_kernel'); } catch (InvalidArgumentException $e) { $this->fail($e->getMessage()); } } /** * Creates a middleware definition. * Loading
core/tests/Drupal/Tests/Core/DependencyInjection/Fixture/FinalTestHttpMiddlewareClass.php 0 → 100644 +30 −0 Original line number Diff line number Diff line <?php namespace Drupal\Tests\Core\DependencyInjection\Fixture; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\TerminableInterface; /** * Stub of http_middleware class that is declared final. */ final class FinalTestHttpMiddlewareClass implements HttpKernelInterface, TerminableInterface { /** * {@inheritdoc} */ public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = TRUE): Response { return new Response(); } /** * {@inheritdoc} * * phpcs:ignore Drupal.Commenting.FunctionComment.VoidReturn * @return void */ public function terminate(Request $request, Response $response) {} }