From 5ef912e9659131fd31d1522e3216d37323a0c047 Mon Sep 17 00:00:00 2001
From: Dries <dries@buytaert.net>
Date: Wed, 3 Sep 2014 22:58:45 -0400
Subject: [PATCH] Issue #2303673 by dawehner, damiankloip, effulgentsia,
 Fabianx: Implement stackphp; cleanup handlePageCache() and preHandle()

---
 composer.json                                 |   3 +-
 composer.lock                                 |  52 +-
 core/core.services.yml                        |  27 +-
 .../Authentication/AuthenticationManager.php  |   2 +-
 core/lib/Drupal/Core/CoreServiceProvider.php  |   3 +
 .../Compiler/StackedKernelPass.php            |  45 ++
 core/lib/Drupal/Core/DrupalKernel.php         |   8 +-
 .../lib/Drupal/Core/DrupalKernelInterface.php |   8 +
 .../ReverseProxySubscriber.php                |  63 ---
 core/lib/Drupal/Core/Form/FormBuilder.php     |   5 +-
 .../Core/StackMiddleware/KernelPreHandle.php  |  57 ++
 .../Drupal/Core/StackMiddleware/PageCache.php |  55 ++
 .../ReverseProxyMiddleware.php                |  61 +++
 .../HttpKernel/StackKernelIntegrationTest.php |  50 ++
 .../httpkernel_test/httpkernel_test.info.yml  |   6 +
 .../httpkernel_test.services.yml              |  10 +
 .../src/HttpKernel/TestMiddleware.php         |  60 +++
 .../ReverseProxySubscriberUnitTest.php        | 103 ----
 .../ReverseProxyMiddlewareTest.php            | 100 ++++
 core/vendor/composer/autoload_namespaces.php  |   1 +
 core/vendor/composer/installed.json           |  52 ++
 core/vendor/stack/builder/.travis.yml         |  19 +
 core/vendor/stack/builder/CHANGELOG.md        |  14 +
 core/vendor/stack/builder/LICENSE             |  19 +
 core/vendor/stack/builder/README.md           |  62 +++
 core/vendor/stack/builder/composer.json       |  26 +
 core/vendor/stack/builder/composer.lock       | 488 ++++++++++++++++++
 core/vendor/stack/builder/phpunit.xml.dist    |  30 ++
 .../stack/builder/src/Stack/Builder.php       |  63 +++
 .../builder/src/Stack/StackedHttpKernel.php   |  34 ++
 .../tests/functional/SilexApplicationTest.php |  60 +++
 .../builder/tests/unit/Stack/BuilderTest.php  | 215 ++++++++
 .../unit/Stack/StackedHttpKernelTest.php      |  80 +++
 index.php                                     |   3 +-
 34 files changed, 1699 insertions(+), 185 deletions(-)
 create mode 100644 core/lib/Drupal/Core/DependencyInjection/Compiler/StackedKernelPass.php
 delete mode 100644 core/lib/Drupal/Core/EventSubscriber/ReverseProxySubscriber.php
 create mode 100644 core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php
 create mode 100644 core/lib/Drupal/Core/StackMiddleware/PageCache.php
 create mode 100644 core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php
 create mode 100644 core/modules/system/src/Tests/HttpKernel/StackKernelIntegrationTest.php
 create mode 100644 core/modules/system/tests/modules/httpkernel_test/httpkernel_test.info.yml
 create mode 100644 core/modules/system/tests/modules/httpkernel_test/httpkernel_test.services.yml
 create mode 100644 core/modules/system/tests/modules/httpkernel_test/src/HttpKernel/TestMiddleware.php
 delete mode 100644 core/tests/Drupal/Tests/Core/EventSubscriber/ReverseProxySubscriberUnitTest.php
 create mode 100644 core/tests/Drupal/Tests/Core/StackMiddleware/ReverseProxyMiddlewareTest.php
 create mode 100644 core/vendor/stack/builder/.travis.yml
 create mode 100644 core/vendor/stack/builder/CHANGELOG.md
 create mode 100644 core/vendor/stack/builder/LICENSE
 create mode 100644 core/vendor/stack/builder/README.md
 create mode 100644 core/vendor/stack/builder/composer.json
 create mode 100644 core/vendor/stack/builder/composer.lock
 create mode 100644 core/vendor/stack/builder/phpunit.xml.dist
 create mode 100644 core/vendor/stack/builder/src/Stack/Builder.php
 create mode 100644 core/vendor/stack/builder/src/Stack/StackedHttpKernel.php
 create mode 100644 core/vendor/stack/builder/tests/functional/SilexApplicationTest.php
 create mode 100644 core/vendor/stack/builder/tests/unit/Stack/BuilderTest.php
 create mode 100644 core/vendor/stack/builder/tests/unit/Stack/StackedHttpKernelTest.php

diff --git a/composer.json b/composer.json
index 7e647d5453b7..ac5d6faea175 100644
--- a/composer.json
+++ b/composer.json
@@ -26,7 +26,8 @@
     "phpunit/phpunit": "4.1.*",
     "phpunit/phpunit-mock-objects": "dev-master#e60bb929c50ae4237aaf680a4f6773f4ee17f0a2",
     "zendframework/zend-feed": "2.2.*",
-    "mikey179/vfsStream": "1.*"
+    "mikey179/vfsStream": "1.*",
+    "stack/builder": "1.0.*"
   },
   "autoload": {
     "psr-4": {
diff --git a/composer.lock b/composer.lock
index 082fd938a067..981d888e3947 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "hash": "6a7a4ba69644c6cf110d03b1a5346e3e",
+    "hash": "8afb97667c2791fec2fb1fc43853da24",
     "packages": [
         {
             "name": "doctrine/annotations",
@@ -1413,6 +1413,56 @@
             "homepage": "https://github.com/sebastianbergmann/version",
             "time": "2014-03-07 15:35:33"
         },
+        {
+            "name": "stack/builder",
+            "version": "v1.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/stackphp/builder.git",
+                "reference": "b4af43e7b7f3f7fac919ff475b29f7c5dc7b23b7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/stackphp/builder/zipball/b4af43e7b7f3f7fac919ff475b29f7c5dc7b23b7",
+                "reference": "b4af43e7b7f3f7fac919ff475b29f7c5dc7b23b7",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0",
+                "symfony/http-foundation": "~2.1",
+                "symfony/http-kernel": "~2.1"
+            },
+            "require-dev": {
+                "silex/silex": "~1.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Stack": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Igor Wiedler",
+                    "email": "igor@wiedler.ch",
+                    "homepage": "http://wiedler.ch/igor/"
+                }
+            ],
+            "description": "Builder for stack middlewares based on HttpKernelInterface.",
+            "keywords": [
+                "stack"
+            ],
+            "time": "2014-01-28 19:42:24"
+        },
         {
             "name": "symfony-cmf/routing",
             "version": "1.2.0",
diff --git a/core/core.services.yml b/core/core.services.yml
index 72bf10e04312..c43da8c81437 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -370,8 +370,30 @@ services:
     class: Drupal\Core\Controller\TitleResolver
     arguments: ['@controller_resolver', '@string_translation']
   http_kernel:
+    class: Symfony\Component\HttpKernel\HttpKernel
+    factory_method: resolve
+    factory_service: http_kernel_factory
+    arguments: ['@http_kernel.basic']
+  http_kernel_factory:
+    class: Stack\Builder
+  http_kernel.basic:
     class: Symfony\Component\HttpKernel\HttpKernel
     arguments: ['@event_dispatcher', '@controller_resolver', '@request_stack']
+  http_middleware.reverse_proxy:
+    class: Drupal\Core\StackMiddleware\ReverseProxyMiddleware
+    arguments: ['@settings']
+    tags:
+      - { name: http_middleware, priority: 300 }
+  http_middleware.page_cache:
+    class: Drupal\Core\StackMiddleware\PageCache
+    arguments: ['@kernel']
+    tags:
+      - { name: http_middleware, priority: 200 }
+  http_middleware.kernel_pre_handle:
+    class: Drupal\Core\StackMiddleware\KernelPreHandle
+    arguments: ['@kernel']
+    tags:
+      - { name: http_middleware, priority: 100 }
   language_manager:
     class: Drupal\Core\Language\LanguageManager
     arguments: ['@language.default']
@@ -560,11 +582,6 @@ services:
     tags:
       - { name: event_subscriber }
     arguments: ['@resolver_manager.entity']
-  reverse_proxy_subscriber:
-    class: Drupal\Core\EventSubscriber\ReverseProxySubscriber
-    tags:
-      - { name: event_subscriber }
-    arguments: ['@settings']
   ajax_subscriber:
     class: Drupal\Core\EventSubscriber\AjaxSubscriber
     tags:
diff --git a/core/lib/Drupal/Core/Authentication/AuthenticationManager.php b/core/lib/Drupal/Core/Authentication/AuthenticationManager.php
index 9580fa9cc475..7c357c9d16d5 100644
--- a/core/lib/Drupal/Core/Authentication/AuthenticationManager.php
+++ b/core/lib/Drupal/Core/Authentication/AuthenticationManager.php
@@ -183,7 +183,7 @@ public function handleException(GetResponseForExceptionEvent $event) {
     $active_providers = ($route && $route->getOption('_auth')) ? $route->getOption('_auth') : array($this->defaultProviderId());
 
     // Get the sorted list of active providers for the given route.
-    $providers = array_intersect($active_providers, array_keys($this->providers));
+    $providers = array_intersect($active_providers, array_keys($this->getSortedProviders()));
 
     foreach ($providers as $provider_id) {
       if ($this->providers[$provider_id]->handleException($event) == TRUE) {
diff --git a/core/lib/Drupal/Core/CoreServiceProvider.php b/core/lib/Drupal/Core/CoreServiceProvider.php
index 8662d640e403..8393903fb650 100644
--- a/core/lib/Drupal/Core/CoreServiceProvider.php
+++ b/core/lib/Drupal/Core/CoreServiceProvider.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Cache\CacheContextsPass;
 use Drupal\Core\Cache\ListCacheBinsPass;
 use Drupal\Core\DependencyInjection\Compiler\BackendCompilerPass;
+use Drupal\Core\DependencyInjection\Compiler\StackedKernelPass;
 use Drupal\Core\DependencyInjection\ServiceProviderInterface;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\DependencyInjection\Compiler\ModifyServiceDefinitionsPass;
@@ -50,6 +51,8 @@ public function register(ContainerBuilder $container) {
 
     $container->addCompilerPass(new BackendCompilerPass());
 
+    $container->addCompilerPass(new StackedKernelPass());
+
     // Collect tagged handler services as method calls on consumer services.
     $container->addCompilerPass(new TaggedHandlersPass());
 
diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/StackedKernelPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/StackedKernelPass.php
new file mode 100644
index 000000000000..bf8efc0745b7
--- /dev/null
+++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/StackedKernelPass.php
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\DependencyInjection\Compiler\StackedKernelPass.
+ */
+
+namespace Drupal\Core\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * Provides a compiler pass for stacked HTTP kernels.
+ *
+ * @see \Stack\Builder
+ */
+class StackedKernelPass implements CompilerPassInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function process(ContainerBuilder $container) {
+    if (!$container->hasDefinition('http_kernel_factory')) {
+      return;
+    }
+
+    $http_kernel_factory = $container->getDefinition('http_kernel_factory');
+    $middleware_priorities = array();
+    $middleware_arguments = array();
+    foreach ($container->findTaggedServiceIds('http_middleware') as $id => $attributes) {
+      $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
+      $middleware_priorities[$id] = $priority;
+      $definition = $container->getDefinition($id);
+      $middleware_arguments[$id] = $definition->getArguments();
+      array_unshift($middleware_arguments[$id], $definition->getClass());
+    }
+    array_multisort($middleware_priorities, SORT_DESC, $middleware_arguments, SORT_DESC);
+
+    foreach ($middleware_arguments as $id => $push_arguments) {
+      $http_kernel_factory->addMethodCall('push', $push_arguments);
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index 7a303a20a5b7..5377c36c8747 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -418,12 +418,9 @@ public function getContainer() {
   }
 
   /**
-   * Helper method that does request related initialization.
-   *
-   * @param \Symfony\Component\HttpFoundation\Request $request
-   *   The current request.
+   * {@inheritdoc}
    */
-  protected function preHandle(Request $request) {
+  public function preHandle(Request $request) {
     // Load all enabled modules.
     $this->container->get('module_handler')->loadAll();
 
@@ -568,7 +565,6 @@ public function terminate(Request $request, Response $response) {
    */
   public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
     $this->boot();
-    $this->preHandle($request);
     return $this->getHttpKernel()->handle($request, $type, $catch);
   }
 
diff --git a/core/lib/Drupal/Core/DrupalKernelInterface.php b/core/lib/Drupal/Core/DrupalKernelInterface.php
index 08d007c49135..ca7af2bd8b38 100644
--- a/core/lib/Drupal/Core/DrupalKernelInterface.php
+++ b/core/lib/Drupal/Core/DrupalKernelInterface.php
@@ -108,4 +108,12 @@ public function handlePageCache(Request $request);
    */
   public function prepareLegacyRequest(Request $request);
 
+  /**
+   * Helper method that does request related initialization.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   */
+  public function preHandle(Request $request);
+
 }
diff --git a/core/lib/Drupal/Core/EventSubscriber/ReverseProxySubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ReverseProxySubscriber.php
deleted file mode 100644
index 788076abba98..000000000000
--- a/core/lib/Drupal/Core/EventSubscriber/ReverseProxySubscriber.php
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\EventSubscriber\ReverseProxySubscriber.
- */
-
-namespace Drupal\Core\EventSubscriber;
-
-use Drupal\Core\Site\Settings;
-use Symfony\Component\HttpKernel\KernelEvents;
-use Symfony\Component\HttpKernel\Event\GetResponseEvent;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-/**
- * Reverse proxy subscriber for controller requests.
- */
-class ReverseProxySubscriber implements EventSubscriberInterface {
-
-  /**
-   * A settings object.
-   *
-   * @var \Drupal\Core\Site\Settings
-   */
-  protected $settings;
-
-  /**
-   * Construct the ReverseProxySubscriber.
-   *
-   * @param \Drupal\Core\Site\Settings $settings
-   *   The read-only settings object of this request.
-   */
-  public function __construct(Settings $settings) {
-    $this->settings = $settings;
-  }
-
-  /**
-   * Passes reverse proxy settings to current request.
-   *
-   * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
-   *   The Event to process.
-   */
-  public function onKernelRequestReverseProxyCheck(GetResponseEvent $event) {
-    $request = $event->getRequest();
-    if ($this->settings->get('reverse_proxy', 0)) {
-      $reverse_proxy_header = $this->settings->get('reverse_proxy_header', 'HTTP_X_FORWARDED_FOR');
-      $request::setTrustedHeaderName($request::HEADER_CLIENT_IP, $reverse_proxy_header);
-      $reverse_proxy_addresses = $this->settings->get('reverse_proxy_addresses', array());
-      $request::setTrustedProxies($reverse_proxy_addresses);
-    }
-  }
-
-  /**
-   * Registers the methods in this class that should be listeners.
-   *
-   * @return array
-   *   An array of event listener definitions.
-   */
-  static function getSubscribedEvents() {
-    $events[KernelEvents::REQUEST][] = array('onKernelRequestReverseProxyCheck', 10);
-    return $events;
-  }
-}
diff --git a/core/lib/Drupal/Core/Form/FormBuilder.php b/core/lib/Drupal/Core/Form/FormBuilder.php
index b1e226014213..3417549bb284 100644
--- a/core/lib/Drupal/Core/Form/FormBuilder.php
+++ b/core/lib/Drupal/Core/Form/FormBuilder.php
@@ -22,7 +22,6 @@
 use Symfony\Component\HttpFoundation\RequestStack;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
-use Symfony\Component\HttpKernel\HttpKernel;
 use Symfony\Component\HttpKernel\HttpKernelInterface;
 use Symfony\Component\HttpKernel\KernelEvents;
 
@@ -127,10 +126,10 @@ class FormBuilder implements FormBuilderInterface, FormValidatorInterface, FormS
    *   The theme manager.
    * @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token
    *   The CSRF token generator.
-   * @param \Symfony\Component\HttpKernel\HttpKernel $http_kernel
+   * @param \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel
    *   The HTTP kernel.
    */
-  public function __construct(FormValidatorInterface $form_validator, FormSubmitterInterface $form_submitter, FormCacheInterface $form_cache, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher, RequestStack $request_stack, ClassResolverInterface $class_resolver, ThemeManagerInterface $theme_manager, CsrfTokenGenerator $csrf_token = NULL, HttpKernel $http_kernel = NULL) {
+  public function __construct(FormValidatorInterface $form_validator, FormSubmitterInterface $form_submitter, FormCacheInterface $form_cache, ModuleHandlerInterface $module_handler, EventDispatcherInterface $event_dispatcher, RequestStack $request_stack, ClassResolverInterface $class_resolver, ThemeManagerInterface $theme_manager, CsrfTokenGenerator $csrf_token = NULL, HttpKernelInterface $http_kernel = NULL) {
     $this->formValidator = $form_validator;
     $this->formSubmitter = $form_submitter;
     $this->formCache = $form_cache;
diff --git a/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php b/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php
new file mode 100644
index 000000000000..1ccdea11f78f
--- /dev/null
+++ b/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\StackMiddleware\KernelBoot.
+ */
+
+namespace Drupal\Core\StackMiddleware;
+
+use Drupal\Core\DrupalKernelInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+
+/**
+ * Prepares the environment after page caching ran.
+ */
+class KernelPreHandle implements HttpKernelInterface {
+
+  /**
+   * The wrapped HTTP kernel.
+   *
+   * @var \Symfony\Component\HttpKernel\HttpKernelInterface
+   */
+  protected $httpKernel;
+
+  /**
+   * The main Drupal kernel.
+   *
+   * @var \Drupal\Core\DrupalKernelInterface
+   */
+  protected $drupalKernel;
+
+  /**
+   * Constructs a new KernelPreHandle instance.
+   *
+   * @param \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel
+   *   The wrapped HTTP kernel.
+   *
+   * @param \Drupal\Core\DrupalKernelInterface $drupal_kernel
+   *   The main Drupal kernel.
+   */
+  public function __construct(HttpKernelInterface $http_kernel, DrupalKernelInterface $drupal_kernel) {
+    $this->httpKernel = $http_kernel;
+    $this->drupalKernel = $drupal_kernel;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
+    $this->drupalKernel->preHandle($request);
+
+    return $this->httpKernel->handle($request, $type, $catch);
+  }
+
+}
+
diff --git a/core/lib/Drupal/Core/StackMiddleware/PageCache.php b/core/lib/Drupal/Core/StackMiddleware/PageCache.php
new file mode 100644
index 000000000000..ba59e936f48e
--- /dev/null
+++ b/core/lib/Drupal/Core/StackMiddleware/PageCache.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\StackMiddleware\PageCache.
+ */
+
+namespace Drupal\Core\StackMiddleware;
+
+use Drupal\Core\DrupalKernelInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+
+/**
+ * Executes the page caching before the main kernel takes over the request.
+ */
+class PageCache implements HttpKernelInterface {
+
+  /**
+   * The wrapped HTTP kernel.
+   *
+   * @var \Symfony\Component\HttpKernel\HttpKernelInterface
+   */
+  protected $httpKernel;
+
+  /**
+   * The main Drupal kernel.
+   *
+   * @var \Drupal\Core\DrupalKernelInterface
+   */
+  protected $drupalKernel;
+
+  /**
+   * Constructs a ReverseProxyMiddleware object.
+   *
+   * @param \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel
+   *   The decorated kernel.
+   * @param \Drupal\Core\DrupalKernelInterface $drupal_kernel
+   *   The main Drupal kernel.
+   */
+  public function __construct(HttpKernelInterface $http_kernel, DrupalKernelInterface $drupal_kernel) {
+    $this->httpKernel = $http_kernel;
+    $this->drupalKernel = $drupal_kernel;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
+    $this->drupalKernel->handlePageCache($request);
+
+    return $this->httpKernel->handle($request, $type, $catch);
+  }
+
+}
diff --git a/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php b/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php
new file mode 100644
index 000000000000..344364d088fa
--- /dev/null
+++ b/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\Core\StackMiddleware\ReverseProxyMiddleware
+ */
+
+namespace Drupal\Core\StackMiddleware;
+
+use Drupal\Core\Site\Settings;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+
+/**
+ *
+ */
+class ReverseProxyMiddleware implements HttpKernelInterface {
+
+  /**
+   * The decorated kernel.
+   *
+   * @var \Symfony\Component\HttpKernel\HttpKernelInterface
+   */
+  protected $httpKernel;
+
+  /**
+   * The site settings.
+   *
+   * @var \Drupal\Core\Site\Settings
+   */
+  protected $settings;
+
+  /**
+   * Constructs a ReverseProxyMiddleware object.
+   *
+   * @param \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel
+   *   The decorated kernel.
+   * @param \Drupal\Core\Site\Settings $settings
+   *   The site settings.
+   */
+  public function __construct(HttpKernelInterface $http_kernel, Settings $settings) {
+    $this->httpKernel = $http_kernel;
+    $this->settings = $settings;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
+    // Initialize proxy settings.
+    if ($this->settings->get('reverse_proxy', FALSE)) {
+      $reverse_proxy_header = $this->settings->get('reverse_proxy_header', 'X_FORWARDED_FOR');
+      $request::setTrustedHeaderName($request::HEADER_CLIENT_IP, $reverse_proxy_header);
+      $proxies = $this->settings->get('reverse_proxy_addresses', array());
+      if (count($proxies) > 0) {
+        $request::setTrustedProxies($proxies);
+      }
+    }
+    return $this->httpKernel->handle($request, $type, $catch);
+  }
+
+}
diff --git a/core/modules/system/src/Tests/HttpKernel/StackKernelIntegrationTest.php b/core/modules/system/src/Tests/HttpKernel/StackKernelIntegrationTest.php
new file mode 100644
index 000000000000..ee37f7e9b7a9
--- /dev/null
+++ b/core/modules/system/src/Tests/HttpKernel/StackKernelIntegrationTest.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Tests\HttpKernel\StackKernelIntegrationTest.
+ */
+
+namespace Drupal\system\Tests\HttpKernel;
+
+use Drupal\simpletest\KernelTestBase;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Tests the stacked kernel functionality.
+ *
+ * @group Routing.
+ */
+class StackKernelIntegrationTest extends KernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('httpkernel_test', 'system');
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installSchema('system', 'router');
+  }
+
+  /**
+   * Tests a request.
+   */
+  public function testRequest() {
+    $request = new Request();
+    /** @var \Symfony\Component\HttpKernel\HttpKernelInterface $http_kernel */
+    $http_kernel = \Drupal::service('http_kernel');
+    $http_kernel->handle($request);
+
+    $this->assertEqual($request->attributes->get('_hello'), 'world');
+    $this->assertEqual($request->attributes->get('_previous_optional_argument'), 'test_argument');
+  }
+
+}
+
diff --git a/core/modules/system/tests/modules/httpkernel_test/httpkernel_test.info.yml b/core/modules/system/tests/modules/httpkernel_test/httpkernel_test.info.yml
new file mode 100644
index 000000000000..5f1375f2825a
--- /dev/null
+++ b/core/modules/system/tests/modules/httpkernel_test/httpkernel_test.info.yml
@@ -0,0 +1,6 @@
+name: 'HttpKernel test'
+type: module
+description: 'Support module for httpkernel tests.'
+package: Testing
+version: VERSION
+core: 8.x
diff --git a/core/modules/system/tests/modules/httpkernel_test/httpkernel_test.services.yml b/core/modules/system/tests/modules/httpkernel_test/httpkernel_test.services.yml
new file mode 100644
index 000000000000..c4784de32b6a
--- /dev/null
+++ b/core/modules/system/tests/modules/httpkernel_test/httpkernel_test.services.yml
@@ -0,0 +1,10 @@
+services:
+  httpkernel_test.test_middleware:
+    class: Drupal\httpkernel_test\HttpKernel\TestMiddleware
+    tags:
+      - { name: http_middleware }
+  httpkernel_test.test_middleware2:
+    class: Drupal\httpkernel_test\HttpKernel\TestMiddleware
+    arguments: ['test_argument']
+    tags:
+      - { name: http_middleware, priority: 20 }
diff --git a/core/modules/system/tests/modules/httpkernel_test/src/HttpKernel/TestMiddleware.php b/core/modules/system/tests/modules/httpkernel_test/src/HttpKernel/TestMiddleware.php
new file mode 100644
index 000000000000..93e1a89ca189
--- /dev/null
+++ b/core/modules/system/tests/modules/httpkernel_test/src/HttpKernel/TestMiddleware.php
@@ -0,0 +1,60 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\httpkernel_test\HttpKernel\TestMiddleware.
+ */
+
+namespace Drupal\httpkernel_test\HttpKernel;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+
+/**
+ * Provides a test middleware.
+ */
+class TestMiddleware implements HttpKernelInterface {
+
+ /**
+  * The decorated kernel.
+  *
+  * @var \Symfony\Component\HttpKernel\HttpKernelInterface
+  */
+ protected $kernel;
+
+  /**
+   * An optional argument.
+   *
+   * @var mixed
+   */
+  protected $optionalArgument;
+
+  /**
+   * Constructs a new TestMiddleware object.
+   *
+   * @param \Symfony\Component\HttpKernel\HttpKernelInterface $kernel
+   *   The decorated kernel.
+   * @param mixed $optional_argument
+   *   (optional) An optional argument.
+   */
+  public function __construct(HttpKernelInterface $kernel, $optional_argument = NULL) {
+    $this->kernel = $kernel;
+    $this->optionalArgument = $optional_argument;
+ }
+
+ /**
+  * {@inheritdoc}
+  */
+ public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
+   $request->attributes->set('_hello', 'world');
+   if ($request->attributes->has('_optional_argument')) {
+     $request->attributes->set('_previous_optional_argument', $request->attributes->get('_optional_argument'));
+   }
+   elseif (isset($this->optionalArgument)) {
+     $request->attributes->set('_optional_argument', $this->optionalArgument);
+   }
+
+   return $this->kernel->handle($request, $type, $catch);
+ }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/EventSubscriber/ReverseProxySubscriberUnitTest.php b/core/tests/Drupal/Tests/Core/EventSubscriber/ReverseProxySubscriberUnitTest.php
deleted file mode 100644
index 2b197882e449..000000000000
--- a/core/tests/Drupal/Tests/Core/EventSubscriber/ReverseProxySubscriberUnitTest.php
+++ /dev/null
@@ -1,103 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Core\EventSubscriber\ReverseProxySubscriberUnitTest.
- */
-
-namespace Drupal\Tests\Core\EventSubscriber;
-
-use Drupal\Core\EventSubscriber\ReverseProxySubscriber;
-use Drupal\Core\Site\Settings;
-use Drupal\Tests\UnitTestCase;
-use Symfony\Component\HttpFoundation\Request;
-
-/**
- * Unit test the reverse proxy event subscriber.
- *
- * @group EventSubscriber
- */
-class ReverseProxySubscriberUnitTest extends UnitTestCase {
-
-  /**
-   * Tests that subscriber does not act when reverse proxy is not set.
-   */
-  public function testNoProxy() {
-    $settings = new Settings(array());
-    $this->assertEquals(0, $settings->get('reverse_proxy'));
-
-    $subscriber = new ReverseProxySubscriber($settings);
-    // Mock a request object.
-    $request = $this->getMock('Symfony\Component\HttpFoundation\Request', array('setTrustedHeaderName', 'setTrustedProxies'));
-    // setTrustedHeaderName() should never fire.
-    $request->expects($this->never())
-      ->method('setTrustedHeaderName');
-    // Mock a response event.
-    $event = $this->getMockedEvent($request);
-    // Actually call the check method.
-    $subscriber->onKernelRequestReverseProxyCheck($event);
-  }
-
-  /**
-   * Tests that subscriber sets trusted headers when reverse proxy is set.
-   */
-  public function testReverseProxyEnabled() {
-    $cases = array(
-      array(
-        'reverse_proxy_header' => 'HTTP_X_FORWARDED_FOR',
-        'reverse_proxy_addresses' => array(),
-      ),
-      array(
-        'reverse_proxy_header' => 'X_FORWARDED_HOST',
-        'reverse_proxy_addresses' => array('127.0.0.2', '127.0.0.3'),
-      ),
-    );
-    foreach ($cases as $case) {
-      // Enable reverse proxy and add test values.
-      $settings = new Settings(array('reverse_proxy' => 1) + $case);
-      $this->trustedHeadersAreSet($settings);
-    }
-  }
-
-  /**
-   * Tests that trusted header methods are called.
-   *
-   * \Symfony\Component\HttpFoundation\Request::setTrustedHeaderName() and
-   * \Symfony\Component\HttpFoundation\Request::setTrustedProxies() should
-   * always be called when reverse proxy settings are enabled.
-   *
-   * @param \Drupal\Core\Site\Settings $settings
-   *   The settings object that holds reverse proxy configuration.
-   */
-  protected function trustedHeadersAreSet(Settings $settings) {
-    $subscriber = new ReverseProxySubscriber($settings);
-    $request = new Request();
-
-    $event = $this->getMockedEvent($request);
-    $subscriber->onKernelRequestReverseProxyCheck($event);
-    $this->assertSame($settings->get('reverse_proxy_header'), $request->getTrustedHeaderName($request::HEADER_CLIENT_IP));
-    $this->assertSame($settings->get('reverse_proxy_addresses'), $request->getTrustedProxies());
-  }
-
-  /**
-   * Creates a mocked event.
-   *
-   * Mocks a \Symfony\Component\HttpKernel\Event\GetResponseEvent object
-   * and stubs its getRequest() method to return a mocked request object.
-   *
-   * @param \Symfony\Component\HttpFoundation\Request $request
-   *   A mocked Request object.
-   *
-   * @return \Symfony\Component\HttpKernel\Event\GetResponseEvent
-   *   The GetResponseEvent mocked object.
-   */
-  protected function getMockedEvent($request) {
-    $event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent')
-      ->disableOriginalConstructor()
-      ->getMock();
-    $event->expects($this->once())
-      ->method('getRequest')
-      ->will($this->returnValue($request));
-    return $event;
-  }
-}
diff --git a/core/tests/Drupal/Tests/Core/StackMiddleware/ReverseProxyMiddlewareTest.php b/core/tests/Drupal/Tests/Core/StackMiddleware/ReverseProxyMiddlewareTest.php
new file mode 100644
index 000000000000..231f833e8a76
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/StackMiddleware/ReverseProxyMiddlewareTest.php
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\StackMiddleware\ReverseProxyMiddlewareTest.
+ */
+
+namespace Drupal\Tests\Core\StackMiddleware;
+
+use Drupal\Core\Site\Settings;
+use Drupal\Core\StackMiddleware\ReverseProxyMiddleware;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Unit test the reverse proxy stack middleware.
+ *
+ * @group StackMiddleware
+ */
+class ReverseProxyMiddlewareTest extends UnitTestCase {
+
+  /**
+   * @var \Symfony\Component\HttpKernel\HttpKernelInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $mockHttpKernel;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    $this->mockHttpKernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
+  }
+
+  /**
+   * Tests that subscriber does not act when reverse proxy is not set.
+   */
+  public function testNoProxy() {
+    $settings = new Settings(array());
+    $this->assertEquals(0, $settings->get('reverse_proxy'));
+
+    $middleware = new ReverseProxyMiddleware($this->mockHttpKernel, $settings);
+    // Mock a request object.
+    $request = $this->getMock('Symfony\Component\HttpFoundation\Request', array('setTrustedHeaderName', 'setTrustedProxies'));
+    // setTrustedHeaderName() should never fire.
+    $request->expects($this->never())
+      ->method('setTrustedHeaderName');
+    // Actually call the check method.
+    $middleware->handle($request);
+  }
+
+  /**
+   * Tests that subscriber sets trusted headers when reverse proxy is set.
+   *
+   * @dataProvider testReverseProxyEnabledProvider
+   */
+  public function testReverseProxyEnabled($provided_settings) {
+      // Enable reverse proxy and add test values.
+      $settings = new Settings(array('reverse_proxy' => 1) + $provided_settings);
+      $this->trustedHeadersAreSet($settings);
+  }
+
+  /**
+   * Data provider for testReverseProxyEnabled.
+   */
+  public function testReverseProxyEnabledProvider() {
+    return array(
+      array(
+        array(
+          'reverse_proxy_header' => 'HTTP_X_FORWARDED_FOR',
+          'reverse_proxy_addresses' => array(),
+        ),
+      ),
+      array(
+        array(
+          'reverse_proxy_header' => 'X_FORWARDED_HOST',
+          'reverse_proxy_addresses' => array('127.0.0.2', '127.0.0.3'),
+        ),
+      ),
+    );
+  }
+
+  /**
+   * Tests that trusted header methods are called.
+   *
+   * \Symfony\Component\HttpFoundation\Request::setTrustedHeaderName() and
+   * \Symfony\Component\HttpFoundation\Request::setTrustedProxies() should
+   * always be called when reverse proxy settings are enabled.
+   *
+   * @param \Drupal\Core\Site\Settings $settings
+   *   The settings object that holds reverse proxy configuration.
+   */
+  protected function trustedHeadersAreSet(Settings $settings) {
+    $middleware = new ReverseProxyMiddleware($this->mockHttpKernel, $settings);
+    $request = new Request();
+
+    $middleware->handle($request);
+    $this->assertSame($settings->get('reverse_proxy_header'), $request->getTrustedHeaderName($request::HEADER_CLIENT_IP));
+    $this->assertSame($settings->get('reverse_proxy_addresses'), $request->getTrustedProxies());
+  }
+}
diff --git a/core/vendor/composer/autoload_namespaces.php b/core/vendor/composer/autoload_namespaces.php
index f49ab2c3c06c..5bb8438c1b11 100644
--- a/core/vendor/composer/autoload_namespaces.php
+++ b/core/vendor/composer/autoload_namespaces.php
@@ -26,6 +26,7 @@
     'Symfony\\Component\\CssSelector\\' => array($vendorDir . '/symfony/css-selector'),
     'Symfony\\Component\\ClassLoader\\' => array($vendorDir . '/symfony/class-loader'),
     'Symfony\\Cmf\\Component\\Routing' => array($vendorDir . '/symfony-cmf/routing'),
+    'Stack' => array($vendorDir . '/stack/builder/src'),
     'Psr\\Log\\' => array($vendorDir . '/psr/log'),
     'Gliph' => array($vendorDir . '/sdboyer/gliph/src'),
     'EasyRdf_' => array($vendorDir . '/easyrdf/easyrdf/lib'),
diff --git a/core/vendor/composer/installed.json b/core/vendor/composer/installed.json
index 97c0fa48a225..5b56c2add953 100644
--- a/core/vendor/composer/installed.json
+++ b/core/vendor/composer/installed.json
@@ -2512,5 +2512,57 @@
             "database",
             "routing"
         ]
+    },
+    {
+        "name": "stack/builder",
+        "version": "v1.0.2",
+        "version_normalized": "1.0.2.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/stackphp/builder.git",
+            "reference": "b4af43e7b7f3f7fac919ff475b29f7c5dc7b23b7"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/stackphp/builder/zipball/b4af43e7b7f3f7fac919ff475b29f7c5dc7b23b7",
+            "reference": "b4af43e7b7f3f7fac919ff475b29f7c5dc7b23b7",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=5.3.0",
+            "symfony/http-foundation": "~2.1",
+            "symfony/http-kernel": "~2.1"
+        },
+        "require-dev": {
+            "silex/silex": "~1.0"
+        },
+        "time": "2014-01-28 19:42:24",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "1.0-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-0": {
+                "Stack": "src"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Igor Wiedler",
+                "email": "igor@wiedler.ch",
+                "homepage": "http://wiedler.ch/igor/"
+            }
+        ],
+        "description": "Builder for stack middlewares based on HttpKernelInterface.",
+        "keywords": [
+            "stack"
+        ]
     }
 ]
diff --git a/core/vendor/stack/builder/.travis.yml b/core/vendor/stack/builder/.travis.yml
new file mode 100644
index 000000000000..1d50df4d17bb
--- /dev/null
+++ b/core/vendor/stack/builder/.travis.yml
@@ -0,0 +1,19 @@
+language: php
+
+php:
+  - 5.3.3
+  - 5.3
+  - 5.4
+  - 5.5
+  - hhvm
+
+before_script:
+  - composer self-update
+  - composer install --no-interaction --prefer-source
+
+script: phpunit --coverage-text
+
+matrix:
+  allow_failures:
+    - php: hhvm
+  fast_finish: true
diff --git a/core/vendor/stack/builder/CHANGELOG.md b/core/vendor/stack/builder/CHANGELOG.md
new file mode 100644
index 000000000000..f6f35d6d71c6
--- /dev/null
+++ b/core/vendor/stack/builder/CHANGELOG.md
@@ -0,0 +1,14 @@
+CHANGELOG
+=========
+
+* 1.0.2 (2014-xx-xx)
+
+  * Validate missing arguments (@bajbnet).
+
+* 1.0.1 (2013-10-25)
+
+  * Lower PHP requirement to 5.3.
+
+* 1.0.0 (2013-08-02)
+
+  * Initial release.
diff --git a/core/vendor/stack/builder/LICENSE b/core/vendor/stack/builder/LICENSE
new file mode 100644
index 000000000000..ceac72c5c27d
--- /dev/null
+++ b/core/vendor/stack/builder/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2013 Igor Wiedler
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/core/vendor/stack/builder/README.md b/core/vendor/stack/builder/README.md
new file mode 100644
index 000000000000..812406c24584
--- /dev/null
+++ b/core/vendor/stack/builder/README.md
@@ -0,0 +1,62 @@
+# Stack/Builder
+
+Builder for stack middlewares based on HttpKernelInterface.
+
+Stack/Builder is a small library that helps you construct a nested
+HttpKernelInterface decorator tree. It models it as a stack of middlewares.
+
+## Example
+
+If you want to decorate a [silex](https://github.com/fabpot/Silex) app with
+session and cache middlewares, you'll have to do something like this:
+
+    use Symfony\Component\HttpKernel\HttpCache\Store;
+
+    $app = new Silex\Application();
+
+    $app->get('/', function () {
+        return 'Hello World!';
+    });
+
+    $app = new Stack\Session(
+        new Symfony\Component\HttpKernel\HttpCache\HttpCache(
+            $app,
+            new Store(__DIR__.'/cache')
+        )
+    );
+
+This can get quite annoying indeed. Stack/Builder simplifies that:
+
+    $stack = (new Stack\Builder())
+        ->push('Stack\Session')
+        ->push('Symfony\Component\HttpKernel\HttpCache\HttpCache', new Store(__DIR__.'/cache'));
+
+    $app = $stack->resolve($app);
+
+As you can see, by arranging the layers as a stack, they become a lot easier
+to work with.
+
+In the front controller, you need to serve the request:
+
+    use Symfony\Component\HttpFoundation\Request;
+
+    $request = Request::createFromGlobals();
+    $response = $app->handle($request)->send();
+    $app->terminate($request, $response);
+
+Stack/Builder also supports pushing a `callable` on to the stack, for situations
+where instantiating middlewares might be more complicated. The `callable` should
+accept a `HttpKernelInterface` as the first argument and should also return a
+`HttpKernelInterface`. The example above could be rewritten as:
+
+    $stack = (new Stack\Builder())
+        ->push('Stack\Session')
+        ->push(function ($app) {
+            $cache = new HttpCache($app, new Store(__DIR__.'/cache'));
+            return $cache;
+        });
+
+## Inspiration
+
+* [Rack::Builder](http://rack.rubyforge.org/doc/Rack/Builder.html)
+* [HttpKernel middlewares](https://igor.io/2013/02/02/http-kernel-middlewares.html)
diff --git a/core/vendor/stack/builder/composer.json b/core/vendor/stack/builder/composer.json
new file mode 100644
index 000000000000..e9f164cccdab
--- /dev/null
+++ b/core/vendor/stack/builder/composer.json
@@ -0,0 +1,26 @@
+{
+    "name": "stack/builder",
+    "description": "Builder for stack middlewares based on HttpKernelInterface.",
+    "keywords": ["stack"],
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Igor Wiedler",
+            "email": "igor@wiedler.ch"
+        }
+    ],
+    "require": {
+        "php": ">=5.3.0",
+        "symfony/http-foundation": "~2.1",
+        "symfony/http-kernel": "~2.1"
+    },
+    "require-dev": {
+        "silex/silex": "~1.0"
+    },
+    "autoload": {
+        "psr-0": { "Stack": "src" }
+    },
+    "extra": {
+        "branch-alias": { "dev-master": "1.0-dev" }
+    }
+}
diff --git a/core/vendor/stack/builder/composer.lock b/core/vendor/stack/builder/composer.lock
new file mode 100644
index 000000000000..26c6a994a725
--- /dev/null
+++ b/core/vendor/stack/builder/composer.lock
@@ -0,0 +1,488 @@
+{
+    "_readme": [
+        "This file locks the dependencies of your project to a known state",
+        "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
+    ],
+    "hash": "78698481679eca710495d5aca028baaa",
+    "packages": [
+        {
+            "name": "psr/log",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/log.git",
+                "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
+                "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
+                "shasum": ""
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Psr\\Log\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for logging libraries",
+            "keywords": [
+                "log",
+                "psr",
+                "psr-3"
+            ],
+            "time": "2012-12-21 11:40:51"
+        },
+        {
+            "name": "symfony/debug",
+            "version": "v2.4.1",
+            "target-dir": "Symfony/Component/Debug",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/Debug.git",
+                "reference": "74110be5ec681a83fc5bd66dd5fd29fe85fe9c1f"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/Debug/zipball/74110be5ec681a83fc5bd66dd5fd29fe85fe9c1f",
+                "reference": "74110be5ec681a83fc5bd66dd5fd29fe85fe9c1f",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "symfony/http-foundation": "~2.1",
+                "symfony/http-kernel": "~2.1"
+            },
+            "suggest": {
+                "symfony/http-foundation": "",
+                "symfony/http-kernel": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.4-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Symfony\\Component\\Debug\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "http://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Debug Component",
+            "homepage": "http://symfony.com",
+            "time": "2014-01-01 09:02:49"
+        },
+        {
+            "name": "symfony/event-dispatcher",
+            "version": "v2.4.1",
+            "target-dir": "Symfony/Component/EventDispatcher",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/EventDispatcher.git",
+                "reference": "e3ba42f6a70554ed05749e61b829550f6ac33601"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/e3ba42f6a70554ed05749e61b829550f6ac33601",
+                "reference": "e3ba42f6a70554ed05749e61b829550f6ac33601",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "symfony/dependency-injection": "~2.0"
+            },
+            "suggest": {
+                "symfony/dependency-injection": "",
+                "symfony/http-kernel": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.4-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Symfony\\Component\\EventDispatcher\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "http://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony EventDispatcher Component",
+            "homepage": "http://symfony.com",
+            "time": "2013-12-28 08:12:03"
+        },
+        {
+            "name": "symfony/http-foundation",
+            "version": "v2.4.1",
+            "target-dir": "Symfony/Component/HttpFoundation",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/HttpFoundation.git",
+                "reference": "6c6b8a7bcd7e2cc920cd6acace563fdbf121d844"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/6c6b8a7bcd7e2cc920cd6acace563fdbf121d844",
+                "reference": "6c6b8a7bcd7e2cc920cd6acace563fdbf121d844",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.4-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Symfony\\Component\\HttpFoundation\\": ""
+                },
+                "classmap": [
+                    "Symfony/Component/HttpFoundation/Resources/stubs"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "http://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony HttpFoundation Component",
+            "homepage": "http://symfony.com",
+            "time": "2014-01-05 02:10:50"
+        },
+        {
+            "name": "symfony/http-kernel",
+            "version": "v2.4.1",
+            "target-dir": "Symfony/Component/HttpKernel",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/HttpKernel.git",
+                "reference": "0605eedeb52c4d3a3144128d8336395a57be60d4"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/HttpKernel/zipball/0605eedeb52c4d3a3144128d8336395a57be60d4",
+                "reference": "0605eedeb52c4d3a3144128d8336395a57be60d4",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3",
+                "psr/log": "~1.0",
+                "symfony/debug": "~2.3",
+                "symfony/event-dispatcher": "~2.1",
+                "symfony/http-foundation": "~2.4"
+            },
+            "require-dev": {
+                "symfony/browser-kit": "~2.2",
+                "symfony/class-loader": "~2.1",
+                "symfony/config": "~2.0",
+                "symfony/console": "~2.2",
+                "symfony/dependency-injection": "~2.0",
+                "symfony/finder": "~2.0",
+                "symfony/process": "~2.0",
+                "symfony/routing": "~2.2",
+                "symfony/stopwatch": "~2.2",
+                "symfony/templating": "~2.2"
+            },
+            "suggest": {
+                "symfony/browser-kit": "",
+                "symfony/class-loader": "",
+                "symfony/config": "",
+                "symfony/console": "",
+                "symfony/dependency-injection": "",
+                "symfony/finder": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.4-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Symfony\\Component\\HttpKernel\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "http://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony HttpKernel Component",
+            "homepage": "http://symfony.com",
+            "time": "2014-01-05 02:12:11"
+        }
+    ],
+    "packages-dev": [
+        {
+            "name": "pimple/pimple",
+            "version": "v1.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/fabpot/Pimple.git",
+                "reference": "471c7d7c52ad6594e17b8ec33efdd1be592b5d83"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/fabpot/Pimple/zipball/471c7d7c52ad6594e17b8ec33efdd1be592b5d83",
+                "reference": "471c7d7c52ad6594e17b8ec33efdd1be592b5d83",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Pimple": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                }
+            ],
+            "description": "Pimple is a simple Dependency Injection Container for PHP 5.3",
+            "homepage": "http://pimple.sensiolabs.org",
+            "keywords": [
+                "container",
+                "dependency injection"
+            ],
+            "time": "2013-09-19 04:53:08"
+        },
+        {
+            "name": "silex/silex",
+            "version": "v1.1.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/silexphp/Silex.git",
+                "reference": "47cc7d6545450ef8a91f50c04e8c7b3b04fceae9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/silexphp/Silex/zipball/47cc7d6545450ef8a91f50c04e8c7b3b04fceae9",
+                "reference": "47cc7d6545450ef8a91f50c04e8c7b3b04fceae9",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3",
+                "pimple/pimple": "~1.0",
+                "symfony/event-dispatcher": ">=2.3,<2.5-dev",
+                "symfony/http-foundation": ">=2.3,<2.5-dev",
+                "symfony/http-kernel": ">=2.3,<2.5-dev",
+                "symfony/routing": ">=2.3,<2.5-dev"
+            },
+            "require-dev": {
+                "doctrine/dbal": ">=2.2.0,<2.4.0-dev",
+                "monolog/monolog": "~1.4,>=1.4.1",
+                "phpunit/phpunit": "~3.7",
+                "swiftmailer/swiftmailer": "5.*",
+                "symfony/browser-kit": ">=2.3,<2.5-dev",
+                "symfony/config": ">=2.3,<2.5-dev",
+                "symfony/css-selector": ">=2.3,<2.5-dev",
+                "symfony/debug": ">=2.3,<2.5-dev",
+                "symfony/dom-crawler": ">=2.3,<2.5-dev",
+                "symfony/finder": ">=2.3,<2.5-dev",
+                "symfony/form": ">=2.3,<2.5-dev",
+                "symfony/locale": ">=2.3,<2.5-dev",
+                "symfony/monolog-bridge": ">=2.3,<2.5-dev",
+                "symfony/options-resolver": ">=2.3,<2.5-dev",
+                "symfony/process": ">=2.3,<2.5-dev",
+                "symfony/security": ">=2.3,<2.5-dev",
+                "symfony/serializer": ">=2.3,<2.5-dev",
+                "symfony/translation": ">=2.3,<2.5-dev",
+                "symfony/twig-bridge": ">=2.3,<2.5-dev",
+                "symfony/validator": ">=2.3,<2.5-dev",
+                "twig/twig": ">=1.8.0,<2.0-dev"
+            },
+            "suggest": {
+                "symfony/browser-kit": ">=2.3,<2.5-dev",
+                "symfony/css-selector": ">=2.3,<2.5-dev",
+                "symfony/dom-crawler": ">=2.3,<2.5-dev",
+                "symfony/form": ">=2.3,<2.5-dev"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Silex": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Igor Wiedler",
+                    "email": "igor@wiedler.ch",
+                    "homepage": "http://wiedler.ch/igor/"
+                }
+            ],
+            "description": "The PHP micro-framework based on the Symfony2 Components",
+            "homepage": "http://silex.sensiolabs.org",
+            "keywords": [
+                "microframework"
+            ],
+            "time": "2013-10-30 08:53:26"
+        },
+        {
+            "name": "symfony/routing",
+            "version": "v2.4.1",
+            "target-dir": "Symfony/Component/Routing",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/Routing.git",
+                "reference": "4abfb500aab8be458c9e3a227ea56b190584f78a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/Routing/zipball/4abfb500aab8be458c9e3a227ea56b190584f78a",
+                "reference": "4abfb500aab8be458c9e3a227ea56b190584f78a",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "doctrine/annotations": "~1.0",
+                "psr/log": "~1.0",
+                "symfony/config": "~2.2",
+                "symfony/expression-language": "~2.4",
+                "symfony/yaml": "~2.0"
+            },
+            "suggest": {
+                "doctrine/annotations": "For using the annotation loader",
+                "symfony/config": "For using the all-in-one router or any loader",
+                "symfony/expression-language": "For using expression matching",
+                "symfony/yaml": "For using the YAML loader"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.4-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Symfony\\Component\\Routing\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "http://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Routing Component",
+            "homepage": "http://symfony.com",
+            "keywords": [
+                "router",
+                "routing",
+                "uri",
+                "url"
+            ],
+            "time": "2014-01-05 02:10:50"
+        }
+    ],
+    "aliases": [
+
+    ],
+    "minimum-stability": "stable",
+    "stability-flags": [
+
+    ],
+    "platform": {
+        "php": ">=5.3.0"
+    },
+    "platform-dev": [
+
+    ]
+}
diff --git a/core/vendor/stack/builder/phpunit.xml.dist b/core/vendor/stack/builder/phpunit.xml.dist
new file mode 100644
index 000000000000..a2437ecdde94
--- /dev/null
+++ b/core/vendor/stack/builder/phpunit.xml.dist
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit backupGlobals="false"
+         colors="true"
+         bootstrap="vendor/autoload.php"
+>
+    <testsuites>
+        <testsuite name="unit">
+            <directory>./tests/unit/</directory>
+        </testsuite>
+    </testsuites>
+
+    <testsuites>
+        <testsuite name="integration">
+            <directory>./tests/integration/</directory>
+        </testsuite>
+    </testsuites>
+
+    <testsuites>
+        <testsuite name="functional">
+            <directory>./tests/functional/</directory>
+        </testsuite>
+    </testsuites>
+
+    <filter>
+        <whitelist>
+            <directory>./src/</directory>
+        </whitelist>
+    </filter>
+</phpunit>
diff --git a/core/vendor/stack/builder/src/Stack/Builder.php b/core/vendor/stack/builder/src/Stack/Builder.php
new file mode 100644
index 000000000000..c7ee05a196d4
--- /dev/null
+++ b/core/vendor/stack/builder/src/Stack/Builder.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace Stack;
+
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+
+class Builder
+{
+    private $specs;
+
+    public function __construct()
+    {
+        $this->specs = new \SplStack();
+    }
+
+    public function unshift(/*$kernelClass, $args...*/)
+    {
+        if (func_num_args() === 0) {
+            throw new \InvalidArgumentException("Missing argument(s) when calling unshift");
+        }
+
+        $spec = func_get_args();
+        $this->specs->unshift($spec);
+
+        return $this;
+    }
+
+    public function push(/*$kernelClass, $args...*/)
+    {
+        if (func_num_args() === 0) {
+            throw new \InvalidArgumentException("Missing argument(s) when calling push");
+        }
+
+        $spec = func_get_args();
+        $this->specs->push($spec);
+
+        return $this;
+    }
+
+    public function resolve(HttpKernelInterface $app)
+    {
+        $middlewares = array($app);
+
+        foreach ($this->specs as $spec) {
+            $args = $spec;
+            $firstArg = array_shift($args);
+
+            if (is_callable($firstArg)) {
+                $app = $firstArg($app);
+            } else {
+                $kernelClass = $firstArg;
+                array_unshift($args, $app);
+
+                $reflection = new \ReflectionClass($kernelClass);
+                $app = $reflection->newInstanceArgs($args);
+            }
+
+            array_unshift($middlewares, $app);
+        }
+
+        return new StackedHttpKernel($app, $middlewares);
+    }
+}
diff --git a/core/vendor/stack/builder/src/Stack/StackedHttpKernel.php b/core/vendor/stack/builder/src/Stack/StackedHttpKernel.php
new file mode 100644
index 000000000000..2b96dd952096
--- /dev/null
+++ b/core/vendor/stack/builder/src/Stack/StackedHttpKernel.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Stack;
+
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpKernel\TerminableInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+
+class StackedHttpKernel implements HttpKernelInterface, TerminableInterface
+{
+    private $app;
+    private $middlewares = array();
+
+    public function __construct(HttpKernelInterface $app, array $middlewares)
+    {
+        $this->app = $app;
+        $this->middlewares = $middlewares;
+    }
+
+    public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
+    {
+        return $this->app->handle($request, $type, $catch);
+    }
+
+    public function terminate(Request $request, Response $response)
+    {
+        foreach ($this->middlewares as $kernel) {
+            if ($kernel instanceof TerminableInterface) {
+                $kernel->terminate($request, $response);
+            }
+        }
+    }
+}
diff --git a/core/vendor/stack/builder/tests/functional/SilexApplicationTest.php b/core/vendor/stack/builder/tests/functional/SilexApplicationTest.php
new file mode 100644
index 000000000000..5636336a8478
--- /dev/null
+++ b/core/vendor/stack/builder/tests/functional/SilexApplicationTest.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace functional;
+
+use Silex\Application;
+use Stack\Builder;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+
+class SilexApplicationTest extends \PHPUnit_Framework_TestCase
+{
+    public function testWithAppendMiddlewares()
+    {
+        $app = new Application();
+
+        $app->get('/foo', function () {
+            return 'bar';
+        });
+
+        $finished = false;
+
+        $app->finish(function () use (&$finished) {
+            $finished = true;
+        });
+
+        $stack = new Builder();
+        $stack
+            ->push('functional\Append', '.A')
+            ->push('functional\Append', '.B');
+
+        $app = $stack->resolve($app);
+
+        $request = Request::create('/foo');
+        $response = $app->handle($request);
+        $app->terminate($request, $response);
+
+        $this->assertSame('bar.B.A', $response->getContent());
+        $this->assertTrue($finished);
+    }
+}
+
+class Append implements HttpKernelInterface
+{
+    private $app;
+    private $appendix;
+
+    public function __construct(HttpKernelInterface $app, $appendix)
+    {
+        $this->app = $app;
+        $this->appendix = $appendix;
+    }
+
+    public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
+    {
+        $response = clone $this->app->handle($request, $type, $catch);
+        $response->setContent($response->getContent().$this->appendix);
+
+        return $response;
+    }
+}
diff --git a/core/vendor/stack/builder/tests/unit/Stack/BuilderTest.php b/core/vendor/stack/builder/tests/unit/Stack/BuilderTest.php
new file mode 100644
index 000000000000..4092d01a54fd
--- /dev/null
+++ b/core/vendor/stack/builder/tests/unit/Stack/BuilderTest.php
@@ -0,0 +1,215 @@
+<?php
+
+namespace Stack;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpKernel\TerminableInterface;
+
+/** @covers Stack\Builder */
+class BuilderTest extends \PHPUnit_Framework_TestCase
+{
+    /** @test */
+    public function withoutMiddlewaresItShouldReturnOriginalResponse()
+    {
+        $app = $this->getHttpKernelMock(new Response('ok'));
+
+        $stack = new Builder();
+        $resolved = $stack->resolve($app);
+
+        $request = Request::create('/');
+        $response = $resolved->handle($request);
+
+        $this->assertInstanceOf('Stack\StackedHttpKernel', $resolved);
+        $this->assertSame('ok', $response->getContent());
+    }
+
+    /** @test */
+    public function resolvedKernelShouldDelegateTerminateCalls()
+    {
+        $app = $this->getTerminableMock();
+
+        $stack = new Builder();
+        $resolved = $stack->resolve($app);
+
+        $request = Request::create('/');
+        $response = new Response('ok');
+
+        $resolved->handle($request);
+        $resolved->terminate($request, $response);
+    }
+
+    /** @test */
+    public function pushShouldReturnSelf()
+    {
+        $stack = new Builder();
+        $this->assertSame($stack, $stack->push('Stack\AppendA'));
+    }
+
+    /** @test */
+    public function pushShouldThrowOnInvalidInput()
+    {
+        $this->setExpectedException('InvalidArgumentException', 'Missing argument(s) when calling push');
+        $stack = new Builder();
+        $stack->push();
+    }
+
+    /** @test */
+    public function unshiftShouldReturnSelf()
+    {
+        $stack = new Builder();
+        $this->assertSame($stack, $stack->unshift('Stack\AppendA'));
+    }
+
+    /** @test */
+    public function unshiftShouldThrowOnInvalidInput()
+    {
+        $this->setExpectedException('InvalidArgumentException', 'Missing argument(s) when calling unshift');
+        $stack = new Builder();
+        $stack->unshift();
+    }
+
+    /** @test */
+    public function appendMiddlewareShouldAppendToBody()
+    {
+        $app = $this->getHttpKernelMock(new Response('ok'));
+
+        $stack = new Builder();
+        $stack->push('Stack\AppendA');
+        $resolved = $stack->resolve($app);
+
+        $request = Request::create('/');
+        $response = $resolved->handle($request);
+
+        $this->assertSame('ok.A', $response->getContent());
+    }
+
+    /** @test */
+    public function unshiftMiddlewareShouldPutMiddlewareBeforePushed()
+    {
+        $app = $this->getHttpKernelMock(new Response('ok'));
+
+        $stack = new Builder();
+        $stack->push('Stack\Append', '2.');
+        $stack->unshift('Stack\Append', '1.');
+        $resolved = $stack->resolve($app);
+
+        $request = Request::create('/');
+        $response = $resolved->handle($request);
+
+        $this->assertSame('ok2.1.', $response->getContent());
+    }
+
+    /** @test */
+    public function stackedMiddlewaresShouldWrapInReverseOrder()
+    {
+        $app = $this->getHttpKernelMock(new Response('ok'));
+
+        $stack = new Builder();
+        $stack->push('Stack\AppendA');
+        $stack->push('Stack\AppendB');
+        $resolved = $stack->resolve($app);
+
+        $request = Request::create('/');
+        $response = $resolved->handle($request);
+
+        $this->assertSame('ok.B.A', $response->getContent());
+    }
+
+    /** @test */
+    public function resolveShouldPassPushArgumentsToMiddlewareConstructor()
+    {
+        $app = $this->getHttpKernelMock(new Response('ok'));
+
+        $stack = new Builder();
+        $stack->push('Stack\Append', '.foo');
+        $stack->push('Stack\Append', '.bar');
+        $resolved = $stack->resolve($app);
+
+        $request = Request::create('/');
+        $response = $resolved->handle($request);
+
+        $this->assertSame('ok.bar.foo', $response->getContent());
+    }
+
+    /** @test */
+    public function resolveShouldCallSpecFactories()
+    {
+        $app = $this->getHttpKernelMock(new Response('ok'));
+
+        $stack = new Builder();
+        $stack->push(function ($app) { return new Append($app, '.foo'); });
+        $stack->push(function ($app) { return new Append($app, '.bar'); });
+        $resolved = $stack->resolve($app);
+
+        $request = Request::create('/');
+        $response = $resolved->handle($request);
+
+        $this->assertSame('ok.bar.foo', $response->getContent());
+    }
+
+    private function getHttpKernelMock(Response $response)
+    {
+        $app = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
+        $app->expects($this->any())
+            ->method('handle')
+            ->with($this->isInstanceOf('Symfony\Component\HttpFoundation\Request'))
+            ->will($this->returnValue($response));
+
+        return $app;
+    }
+
+    private function getTerminableMock()
+    {
+        $app = $this->getMock('Stack\TerminableHttpKernel');
+        $app->expects($this->once())
+            ->method('terminate')
+            ->with(
+                $this->isInstanceOf('Symfony\Component\HttpFoundation\Request'),
+                $this->isInstanceOf('Symfony\Component\HttpFoundation\Response')
+            );
+
+        return $app;
+    }
+}
+
+abstract class TerminableHttpKernel implements HttpKernelInterface, TerminableInterface
+{
+}
+
+class Append implements HttpKernelInterface
+{
+    private $app;
+    private $appendix;
+
+    public function __construct(HttpKernelInterface $app, $appendix)
+    {
+        $this->app = $app;
+        $this->appendix = $appendix;
+    }
+
+    public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
+    {
+        $response = clone $this->app->handle($request, $type, $catch);
+        $response->setContent($response->getContent().$this->appendix);
+
+        return $response;
+    }
+}
+
+class AppendA extends Append
+{
+    public function __construct(HttpKernelInterface $app)
+    {
+        parent::__construct($app, '.A');
+    }
+}
+
+class AppendB extends Append
+{
+    public function __construct(HttpKernelInterface $app)
+    {
+        parent::__construct($app, '.B');
+    }
+}
diff --git a/core/vendor/stack/builder/tests/unit/Stack/StackedHttpKernelTest.php b/core/vendor/stack/builder/tests/unit/Stack/StackedHttpKernelTest.php
new file mode 100644
index 000000000000..e2ced544afa4
--- /dev/null
+++ b/core/vendor/stack/builder/tests/unit/Stack/StackedHttpKernelTest.php
@@ -0,0 +1,80 @@
+<?php
+
+namespace Stack;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpKernel\TerminableInterface;
+
+class StackedHttpKernelTest extends \PHPUnit_Framework_TestCase
+{
+    /** @test */
+    public function handleShouldDelegateToApp()
+    {
+        $app = $this->getHttpKernelMock(new Response('ok'));
+        $kernel = new StackedHttpKernel($app, array($app));
+
+        $request = Request::create('/');
+        $response = $kernel->handle($request);
+
+        $this->assertSame('ok', $response->getContent());
+    }
+
+    /** @test */
+    public function handleShouldStillDelegateToAppWithMiddlewares()
+    {
+        $app = $this->getHttpKernelMock(new Response('ok'));
+        $foo = $this->getHttpKernelMock(new Response('foo'));
+        $bar = $this->getHttpKernelMock(new Response('bar'));
+        $kernel = new StackedHttpKernel($app, array($app, $foo, $bar));
+
+        $request = Request::create('/');
+        $response = $kernel->handle($request);
+
+        $this->assertSame('ok', $response->getContent());
+    }
+
+    /** @test */
+    public function terminateShouldDelegateToMiddlewares()
+    {
+        $app = $this->getTerminableMock(new Response('ok'));
+        $foo = $this->getTerminableMock();
+        $bar = $this->getTerminableMock();
+        $kernel = new StackedHttpKernel($app, array($app, $foo, $bar));
+
+        $request = Request::create('/');
+        $response = $kernel->handle($request);
+        $kernel->terminate($request, $response);
+    }
+
+    private function getHttpKernelMock(Response $response)
+    {
+        $app = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
+        $app->expects($this->any())
+            ->method('handle')
+            ->with($this->isInstanceOf('Symfony\Component\HttpFoundation\Request'))
+            ->will($this->returnValue($response));
+
+        return $app;
+    }
+
+    private function getTerminableMock(Response $response = null)
+    {
+        $app = $this->getMock('Stack\TerminableHttpKernel');
+        if ($response) {
+            $app->expects($this->any())
+                ->method('handle')
+                ->with($this->isInstanceOf('Symfony\Component\HttpFoundation\Request'))
+                ->will($this->returnValue($response));
+        }
+        $app->expects($this->once())
+            ->method('terminate')
+            ->with(
+                $this->isInstanceOf('Symfony\Component\HttpFoundation\Request'),
+                $this->isInstanceOf('Symfony\Component\HttpFoundation\Response')
+            );
+
+        return $app;
+    }
+}
diff --git a/index.php b/index.php
index 78ee18c2ecf5..406d3dcbe329 100644
--- a/index.php
+++ b/index.php
@@ -19,8 +19,7 @@
   $request = Request::createFromGlobals();
   $kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
   $response = $kernel
-    ->handlePageCache($request)
-    ->handle($request)
+      ->handle($request)
       // Handle the response object.
       ->prepare($request)->send();
   $kernel->terminate($request, $response);
-- 
GitLab