Commit 9166525d authored by alexpott's avatar alexpott

Issue #2473113 by znerol, dpovshed, Wim Leers, Fabianx, dawehner,...

Issue #2473113 by znerol, dpovshed, Wim Leers, Fabianx, dawehner, effulgentsia: All stack middlewares are constructed at the same time even for cached pages
parent e3615997
......@@ -14,6 +14,40 @@
/**
* Provides a compiler pass for stacked HTTP kernels.
*
* Builds the HTTP kernel by collecting all services tagged 'http_middleware'
* and assembling them into a StackedKernel. The middleware with the lowest
* priority ends up as the outermost while the highest priority middleware
* wraps the actual HTTP kernel defined by the http_kernel.basic service.
*
* The 'http_middleware' service tag additionally accepts a 'responder'
* parameter. It should be set to TRUE if many or most requests will be handled
* directly by the middleware. Any underlying middleware and the HTTP kernel are
* then flagged as 'lazy'. As a result those low priority services and their
* dependencies are only initialized if the 'responder' middleware fails to
* generate a response and the request is delegated to the underlying kernel.
*
* In general middlewares should not have heavy dependencies. This is especially
* important for high-priority services which need to run before the internal
* page cache.
*
* An example of a high priority middleware.
* @code
* http_middleware.reverse_proxy:
* class: Drupal\Core\StackMiddleware\ReverseProxyMiddleware
* arguments: ['@settings']
* tags:
* - { name: http_middleware, priority: 300 }
* @endcode
*
* An example of a responder middleware:
* @code
* http_middleware.page_cache:
* class: Drupal\page_cache\StackMiddleware\PageCache
* arguments: ['@cache.render', '@page_cache_request_policy', '@page_cache_response_policy']
* tags:
* - { name: http_middleware, priority: 200, responder: true }
* @endcode
*
* @see \Stack\Builder
*/
class StackedKernelPass implements CompilerPassInterface {
......@@ -36,16 +70,24 @@ public function process(ContainerBuilder $container) {
$middlewares = [];
$priorities = [];
$responders = [];
foreach ($container->findTaggedServiceIds('http_middleware') as $id => $attributes) {
$priorities[$id] = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
$middlewares[$id] = $container->getDefinition($id);
$responders[$id] = !empty($attributes[0]['responder']);
}
array_multisort($priorities, SORT_ASC, $middlewares);
array_multisort($priorities, SORT_ASC, $middlewares, $responders);
$decorated_id = 'http_kernel.basic';
$middlewares_param = [new Reference($decorated_id)];
$first_responder = array_search(TRUE, array_reverse($responders, TRUE), TRUE);
if ($first_responder) {
$container->getDefinition($decorated_id)->setLazy(TRUE);
}
foreach ($middlewares as $id => $decorator) {
// Prepend a reference to the middlewares container parameter.
array_unshift($middlewares_param, new Reference($id));
......@@ -55,6 +97,13 @@ public function process(ContainerBuilder $container) {
array_unshift($arguments, new Reference($decorated_id));
$decorator->setArguments($arguments);
if ($first_responder === $id) {
$first_responder = FALSE;
}
elseif ($first_responder) {
$decorator->setLazy(TRUE);
}
$decorated_id = $id;
}
......
......@@ -3,4 +3,4 @@ services:
class: Drupal\page_cache\StackMiddleware\PageCache
arguments: ['@cache.render', '@page_cache_request_policy', '@page_cache_response_policy']
tags:
- { name: http_middleware, priority: 200 }
- { name: http_middleware, priority: 200, responder: true }
......@@ -49,4 +49,23 @@ public function testRequest() {
$this->assertEqual($request->attributes->get('_previous_optional_argument'), 'test_argument');
}
/**
* Tests that late middlewares are automatically flagged lazy.
*/
public function testLazyLateMiddlewares() {
$this->assertFalse($this->container->getDefinition('http_middleware.reverse_proxy')->isLazy(), 'lazy flag on http_middleware.reverse_proxy definition is not set');
$this->assertFalse($this->container->getDefinition('http_middleware.kernel_pre_handle')->isLazy(), 'lazy flag on http_middleware.kernel_pre_handle definition is not set');
$this->assertFalse($this->container->getDefinition('http_middleware.session')->isLazy(), 'lazy flag on http_middleware.session definition is not set');
$this->assertFalse($this->container->getDefinition('http_kernel.basic')->isLazy(), 'lazy flag on http_kernel.basic definition is not set');
\Drupal::service('module_installer')->install(['page_cache']);
$this->container = $this->kernel->rebuildContainer();
$this->assertFalse($this->container->getDefinition('http_middleware.reverse_proxy')->isLazy(), 'lazy flag on http_middleware.reverse_proxy definition is not set');
$this->assertFalse($this->container->getDefinition('http_middleware.page_cache')->isLazy(), 'lazy flag on http_middleware.page_cache definition is not set');
$this->assertTrue($this->container->getDefinition('http_middleware.kernel_pre_handle')->isLazy(), 'lazy flag on http_middleware.kernel_pre_handle definition is automatically set if page_cache is enabled.');
$this->assertTrue($this->container->getDefinition('http_middleware.session')->isLazy(), 'lazy flag on http_middleware.session definition is automatically set if page_cache is enabled.');
$this->assertTrue($this->container->getDefinition('http_kernel.basic')->isLazy(), 'lazy flag on http_kernel.basic definition is automatically set if page_cache is enabled.');
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment