diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 1109452..75e68ed 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -17,6 +17,11 @@
 use Drupal\Core\Lock\DatabaseLockBackend;
 use Drupal\Core\Lock\LockBackendInterface;
 use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\Core\Cache\Cache;
+
+use Symfony\Component\HttpKernel\HttpCache\Esi;
+use Symfony\Component\HttpKernel\HttpCache\HttpCache;
+use Symfony\Component\HttpKernel\HttpCache\Store;
 
 /**
  * @file
@@ -1353,109 +1358,6 @@ function drupal_page_header() {
 }
 
 /**
- * Sets HTTP headers in preparation for a cached page response.
- *
- * The headers allow as much as possible in proxies and browsers without any
- * particular knowledge about the pages. Modules can override these headers
- * using drupal_add_http_header().
- *
- * If the request is conditional (using If-Modified-Since and If-None-Match),
- * and the conditions match those currently in the cache, a 304 Not Modified
- * response is sent.
- */
-function drupal_serve_page_from_cache(stdClass $cache) {
-  $config = config('system.performance');
-
-  // Negotiate whether to use compression.
-  $page_compression = $config->get('response.gzip') && extension_loaded('zlib');
-  $return_compressed = $page_compression && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE;
-
-  // Get headers. Keys are lower-case.
-  $boot_headers = drupal_get_http_header();
-
-  // Headers generated in this function, that may be replaced or unset using
-  // drupal_add_http_headers(). Keys are mixed-case.
-  $default_headers = array();
-
-  foreach ($cache->data['headers'] as $name => $value) {
-    // In the case of a 304 response, certain headers must be sent, and the
-    // remaining may not (see RFC 2616, section 10.3.5).
-    $name_lower = strtolower($name);
-    if (in_array($name_lower, array('content-location', 'expires', 'cache-control', 'vary')) && !isset($boot_headers[$name_lower])) {
-      drupal_add_http_header($name, $value);
-      unset($cache->data['headers'][$name]);
-    }
-  }
-
-  // If the client sent a session cookie, a cached copy will only be served
-  // to that one particular client due to Vary: Cookie. Thus, do not set
-  // max-age > 0, allowing the page to be cached by external proxies, when a
-  // session cookie is present unless the Vary header has been replaced.
-  $max_age = !isset($_COOKIE[session_name()]) || isset($boot_headers['vary']) ? $config->get('cache.page.max_age') : 0;
-  $default_headers['Cache-Control'] = 'public, max-age=' . $max_age;
-
-  // Entity tag should change if the output changes.
-  $etag = '"' . $cache->created . '-' . intval($return_compressed) . '"';
-  header('Etag: ' . $etag);
-
-  // See if the client has provided the required HTTP headers.
-  $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) : FALSE;
-  $if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) : FALSE;
-
-  if ($if_modified_since && $if_none_match
-      && $if_none_match == $etag // etag must match
-      && $if_modified_since == $cache->created) {  // if-modified-since must match
-    header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');
-    drupal_send_headers($default_headers);
-    return;
-  }
-
-  // Send the remaining headers.
-  foreach ($cache->data['headers'] as $name => $value) {
-    drupal_add_http_header($name, $value);
-  }
-
-  $default_headers['Last-Modified'] = gmdate(DATE_RFC1123, $cache->created);
-
-  // HTTP/1.0 proxies does not support the Vary header, so prevent any caching
-  // by sending an Expires date in the past. HTTP/1.1 clients ignores the
-  // Expires header if a Cache-Control: max-age= directive is specified (see RFC
-  // 2616, section 14.9.3).
-  $default_headers['Expires'] = 'Sun, 19 Nov 1978 05:00:00 GMT';
-
-  drupal_send_headers($default_headers);
-
-  // Allow HTTP proxies to cache pages for anonymous users without a session
-  // cookie. The Vary header is used to indicates the set of request-header
-  // fields that fully determines whether a cache is permitted to use the
-  // response to reply to a subsequent request for a given URL without
-  // revalidation. If a Vary header has been set in hook_boot(), it is assumed
-  // that the module knows how to cache the page.
-  if (!isset($boot_headers['vary']) && !settings()->get('cache.page.omit_vary_cookie')) {
-    header('Vary: Cookie');
-  }
-
-  if ($page_compression) {
-    header('Vary: Accept-Encoding', FALSE);
-    // If page_compression is enabled, the cache contains gzipped data.
-    if ($return_compressed) {
-      // $cache->data['body'] is already gzip'ed, so make sure
-      // zlib.output_compression does not compress it once more.
-      ini_set('zlib.output_compression', '0');
-      header('Content-Encoding: gzip');
-    }
-    else {
-      // The client does not support compression, so unzip the data in the
-      // cache. Strip the gzip header and run uncompress.
-      $cache->data['body'] = gzinflate(substr(substr($cache->data['body'], 10), 0, -8));
-    }
-  }
-
-  // Print the page.
-  print $cache->data['body'];
-}
-
-/**
  * Defines the critical hooks that force modules to always be loaded.
  */
 function bootstrap_hooks() {
@@ -2096,7 +1998,6 @@ function drupal_bootstrap($phase = NULL, $new_phase = TRUE) {
   static $phases = array(
     DRUPAL_BOOTSTRAP_CONFIGURATION,
     DRUPAL_BOOTSTRAP_KERNEL,
-    DRUPAL_BOOTSTRAP_PAGE_CACHE,
     DRUPAL_BOOTSTRAP_DATABASE,
     DRUPAL_BOOTSTRAP_VARIABLES,
     DRUPAL_BOOTSTRAP_SESSION,
@@ -2137,10 +2038,6 @@ function drupal_bootstrap($phase = NULL, $new_phase = TRUE) {
           _drupal_bootstrap_kernel();
           break;
 
-        case DRUPAL_BOOTSTRAP_PAGE_CACHE:
-          _drupal_bootstrap_page_cache();
-          break;
-
         case DRUPAL_BOOTSTRAP_DATABASE:
           _drupal_bootstrap_database();
           break;
@@ -2207,6 +2104,11 @@ function drupal_handle_request($test_only = FALSE) {
   $kernel->boot();
   drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE);
 
+  if (settings()->get('use_http_cache', TRUE)) {
+    $store_path = variable_get('file_public_path', conf_path() . '/files/http_cache');
+    $kernel = new HttpCache($kernel, new Store($store_path));
+  }
+
   // Create a request object from the HttpFoundation.
   $request = Request::createFromGlobals();
   $response = $kernel->handle($request)->prepare($request)->send();
@@ -2215,6 +2117,48 @@ function drupal_handle_request($test_only = FALSE) {
 }
 
 /**
+ * Instantiates and statically caches the correct class for a cache bin.
+ *
+ * By default, this returns an instance of the Drupal\Core\Cache\DatabaseBackend
+ * class.
+ *
+ * Classes implementing Drupal\Core\Cache\CacheBackendInterface can register
+ * themselves both as a default implementation and for specific bins.
+ *
+ * @param $bin
+ *   The cache bin for which the cache object should be returned, defaults to
+ *   'cache'.
+ *
+ * @return Drupal\Core\Cache\CacheBackendInterface
+ *   The cache object associated with the specified bin.
+ *
+ * @see Drupal\Core\Cache\CacheBackendInterface
+ */
+function cache($bin = 'cache') {
+  return Drupal::cache($bin);
+}
+
+/**
+ * Marks cache items from all bins with any of the specified tags as invalid.
+ *
+ * Many sites have more than one active cache backend, and each backend my use
+ * a different strategy for storing tags against cache items, and invalidating
+ * cache items associated with a given tag.
+ *
+ * When invalidating a given list of tags, we iterate over each cache backend,
+ * and call invalidateTags() on each.
+ *
+ * @param array $tags
+ *   The list of tags to invalidate cache items for.
+ *
+ * @deprecated 8.x
+ *   Use \Drupal\Core\Cache\Cache::invalidateTags().
+ */
+function cache_invalidate_tags(array $tags) {
+  Cache::invalidateTags($tags);
+}
+
+/**
  * Returns the time zone of the current user.
  */
 function drupal_get_user_timezone() {
@@ -2326,52 +2270,6 @@ function _drupal_bootstrap_kernel() {
 }
 
 /**
- * Attempts to serve a page from the cache.
- */
-function _drupal_bootstrap_page_cache() {
-  global $user;
-
-  // Allow specifying special cache handlers in settings.php, like
-  // using memcached or files for storing cache information.
-  require_once DRUPAL_ROOT . '/core/includes/cache.inc';
-  foreach (variable_get('cache_backends', array()) as $include) {
-    require_once DRUPAL_ROOT . '/' . $include;
-  }
-  // Check for a cache mode force from settings.php.
-  if (settings()->get('page_cache_without_database')) {
-    $cache_enabled = TRUE;
-  }
-  else {
-    drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES, FALSE);
-    $config = config('system.performance');
-    $cache_enabled = $config->get('cache.page.use_internal');
-  }
-  // If there is no session cookie and cache is enabled (or forced), try
-  // to serve a cached page.
-  if (!isset($_COOKIE[session_name()]) && $cache_enabled) {
-    // Make sure there is a user object because its timestamp will be checked.
-    $user = drupal_anonymous_user();
-    // Get the page from the cache.
-    $cache = drupal_page_get_cache();
-    // If there is a cached page, display it.
-    if (is_object($cache)) {
-      header('X-Drupal-Cache: HIT');
-      // Restore the metadata cached with the page.
-      _current_path($cache->data['path']);
-      drupal_set_title($cache->data['title'], PASS_THROUGH);
-      date_default_timezone_set(drupal_get_user_timezone());
-
-      drupal_serve_page_from_cache($cache);
-      // We are done.
-      exit;
-    }
-    else {
-      header('X-Drupal-Cache: MISS');
-    }
-  }
-}
-
-/**
  * In a test environment, get the test db prefix and set it in $databases.
  */
 function _drupal_initialize_db_test_prefix() {
diff --git a/core/includes/cache.inc b/core/includes/cache.inc
deleted file mode 100644
index edc47c7..0000000
--- a/core/includes/cache.inc
+++ /dev/null
@@ -1,50 +0,0 @@
-<?php
-
-/**
- * @file
- * Functions and interfaces for cache handling.
- */
-
-use Drupal\Core\Cache\Cache;
-
-/**
- * Instantiates and statically caches the correct class for a cache bin.
- *
- * By default, this returns an instance of the Drupal\Core\Cache\DatabaseBackend
- * class.
- *
- * Classes implementing Drupal\Core\Cache\CacheBackendInterface can register
- * themselves both as a default implementation and for specific bins.
- *
- * @param $bin
- *   The cache bin for which the cache object should be returned, defaults to
- *   'cache'.
- *
- * @return Drupal\Core\Cache\CacheBackendInterface
- *   The cache object associated with the specified bin.
- *
- * @see Drupal\Core\Cache\CacheBackendInterface
- */
-function cache($bin = 'cache') {
-  return Drupal::cache($bin);
-}
-
-/**
- * Marks cache items from all bins with any of the specified tags as invalid.
- *
- * Many sites have more than one active cache backend, and each backend my use
- * a different strategy for storing tags against cache items, and invalidating
- * cache items associated with a given tag.
- *
- * When invalidating a given list of tags, we iterate over each cache backend,
- * and call invalidateTags() on each.
- *
- * @param array $tags
- *   The list of tags to invalidate cache items for.
- *
- * @deprecated 8.x
- *   Use \Drupal\Core\Cache\Cache::invalidateTags().
- */
-function cache_invalidate_tags(array $tags) {
-  Cache::invalidateTags($tags);
-}
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index df688ab..84a95b2 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -406,8 +406,6 @@ function install_begin_request(&$install_state) {
   }
   $module_handler->load('system');
 
-  require_once DRUPAL_ROOT . '/core/includes/cache.inc';
-
   // Prepare for themed output. We need to run this at the beginning of the
   // page request to avoid a different theme accidentally getting set. (We also
   // need to run it even in the case of command-line installations, to prevent
diff --git a/core/lib/Drupal.php b/core/lib/Drupal.php
index 0e9bf49..8031c2b 100644
--- a/core/lib/Drupal.php
+++ b/core/lib/Drupal.php
@@ -122,32 +122,6 @@ public static function service($id) {
   }
 
   /**
-   * Retrieves the currently active request object.
-   *
-   * Note: The use of this wrapper in particular is especially discourged. Most
-   * code should not need to access the request directly.  Doing so means it
-   * will only function when handling an HTTP request, and will require special
-   * modification or wrapping when run from a command line tool, from certain
-   * queue processors, or from automated tests.
-   *
-   * If code must access the request, it is considerably better to register
-   * an object with the Service Container and give it a setRequest() method
-   * that is configured to run when the service is created.  That way, the
-   * correct request object can always be provided by the container and the
-   * service can still be unit tested.
-   *
-   * If this method must be used, never save the request object that is
-   * returned.  Doing so may lead to inconsistencies as the request object is
-   * volatile and may change at various times, such as during a subrequest.
-   *
-   * @return \Symfony\Component\HttpFoundation\Request
-   *   The currently active request object.
-   */
-  public static function request() {
-    return static::$container->get('request');
-  }
-
-  /**
    * Returns the current primary database.
    *
    * @return \Drupal\Core\Database\Connection
diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index ee63bfa..0b5408c 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -17,6 +17,7 @@
 use Drupal\Core\DependencyInjection\Compiler\RegisterRouteEnhancersPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterParamConvertersPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterServicesForDestructionPass;
+use Drupal\Core\DependencyInjection\Compiler\RegisterFragmentRenderersPass;
 use Symfony\Component\DependencyInjection\ContainerBuilder;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\DependencyInjection\Reference;
@@ -172,6 +173,13 @@ public function build(ContainerBuilder $container) {
       ->addArgument(new Reference('service_container'))
       ->addArgument(new Reference('controller_resolver'));
 
+    $container->register('fragment_handler', 'Symfony\Component\HttpKernel\Fragment\FragmentHandler')
+      ->addTag('event_subscriber');
+
+    $container->register('renderer_inline', 'Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer')
+      ->addArgument(new Reference('http_kernel'))
+      ->addTag('render_strategy');
+
     // Register the 'language_manager' service.
     $container->register('language_manager', 'Drupal\Core\Language\LanguageManager');
 
@@ -325,6 +333,8 @@ public function build(ContainerBuilder $container) {
     $container->addCompilerPass(new RegisterRouteEnhancersPass());
     // Add a compiler pass for registering services needing destruction.
     $container->addCompilerPass(new RegisterServicesForDestructionPass());
+    // Add a compiler pass for registering services needing destruction.
+    $container->addCompilerPass(new RegisterFragmentRenderersPass());
   }
 
   /**
diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterFragmentRenderersPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterFragmentRenderersPass.php
new file mode 100644
index 0000000..9eb6316
--- /dev/null
+++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterFragmentRenderersPass.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\DependencyInjection\Compiler\RegisterFragmentRenderersPass.
+ */
+
+namespace Drupal\Core\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+
+/**
+ * Adds services tagged 'render_strategy' to the 'fragment_handler' service.
+ */
+class RegisterFragmentRenderersPass implements CompilerPassInterface {
+
+  /**
+   * Adds services tagged 'render_strategy' to the 'fragment_handler' service.
+   *
+   * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
+   *  The container to process.
+   */
+  public function process(ContainerBuilder $container) {
+    if (!$container->hasDefinition('fragment_handler')) {
+      return;
+    }
+    $matcher = $container->getDefinition('fragment_handler');
+    foreach ($container->findTaggedServiceIds('render_strategy') as $id => $attributes) {
+      $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0;
+      $matcher->addMethodCall('addRenderer', array(new Reference($id)));
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
index c5c491c..c80e65b 100644
--- a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
@@ -55,6 +55,26 @@ public function onRespond(FilterResponseEvent $event) {
     // Set the Content-language header.
     $response->headers->set('Content-language', $this->languageManager->getLanguage(LANGUAGE_TYPE_INTERFACE)->langcode);
 
+    // Max age of 0 means to disable all caching. That is rarely advisable
+    // except during development.
+    // Note: We have to do this one first, because as soon as we set a
+    // cache-related header (such as expires or last-modified, below) the
+    // cache defaults to private. Once we set the cache to public, though,
+    // future cache settings won't revert to that default. That allows a
+    // controller to return a response with custom headers on it already,
+    // including a private cache, while allowing the majority of pages to
+    // use the default aggressive cache settings.
+    $max_age = config('system.performance')->get('cache.page.max_age');
+    if ($max_age > 0) {
+      $this->setCacheHeaders($response, $event, $max_age);
+    }
+
+    // Set a default response time in the past, so that pages are uncachable
+    // unless the Cache-Control headers say otherwise. Those take priority.
+    if (!$response->headers->has('Expires')) {
+      $response->headers->set('Expires', 'Sun, 19 Nov 1978 05:00:00 GMT');
+    }
+
     // Because pages are highly dynamic, set the last-modified time to now
     // since the page is in fact being regenerated right now.
     // @todo Remove this and use a more intelligent default so that HTTP
@@ -91,16 +111,41 @@ public function onRespond(FilterResponseEvent $event) {
     //   use partial page caching more extensively.
     // Commit the user session, if needed.
     drupal_session_commit();
-    $max_age = config('system.performance')->get('cache.page.max_age');
-    if ($max_age > 0 && ($cache = drupal_page_set_cache($response->getContent()))) {
-      drupal_serve_page_from_cache($cache);
-      // drupal_serve_page_from_cache() already printed the response.
-      $response->setContent('');
-      $response->headers->remove('cache-control');
+
+  }
+
+  /**
+   * Sets appropriate cache headers on a response object.
+   *
+   * @param \Symfony\Component\HttpFoundation\Response $response
+   *   The response on which to set headers.
+   * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
+   *   The response event.
+   * @param int $max_age
+   *   The max age in seconds for which the response should be cached.
+   */
+  protected function setCacheHeaders($response, $event, $max_age) {
+    $response->isNotModified($event->getRequest());
+
+    // Set the Vary headers to encoding (mime type) and cookie. If they're
+    // already set, though, leave them as is.
+    if(!$response->hasVary()) {
+      $vary = array('Accept-Encoding');
+      if (!settings()->get('cache.page.omit_vary_cookie')) {
+        $vary[] = 'Cookie';
+      }
+      $response->setVary($vary);
     }
-    else {
-      $response->headers->set('Expires', 'Sun, 19 Nov 1978 05:00:00 GMT');
-      $response->headers->set('Cache-Control', 'no-cache, must-revalidate, post-check=0, pre-check=0');
+
+    // Default to public cache, meaning intermediaries between us and the
+    // browser may cache it.
+
+    if (!$response->headers->hasCacheControlDirective('private')) {
+      $response->setPublic();
+    }
+
+    if (!$response->getMaxAge()) {
+      $response->setMaxAge($max_age);
     }
   }
 
diff --git a/core/lib/Drupal/Core/HtmlPageController.php b/core/lib/Drupal/Core/HtmlPageController.php
index ab9af59..96ea1e8 100644
--- a/core/lib/Drupal/Core/HtmlPageController.php
+++ b/core/lib/Drupal/Core/HtmlPageController.php
@@ -11,6 +11,7 @@
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\DependencyInjection\ContainerAwareInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpKernel\Controller\ControllerReference;
 
 /**
  * Default controller for most HTML pages.
@@ -60,13 +61,11 @@ public function content(Request $request, $_content) {
     $attributes->remove('system_path');
     $attributes->remove('_content');
 
-    $response = $this->container->get('http_kernel')->forward($controller, $attributes->all(), $request->query->all());
+    $attributes_array = $attributes->all() ?: array();
+    $query = $request->query->all() ?: array();
+    $page_content = $this->container->get('fragment_handler')->render(new ControllerReference($controller, $attributes_array, $query));
 
-    // For successful (HTTP status 200) responses, decorate with blocks.
-    if ($response->isOk()) {
-      $page_content = $response->getContent();
-      $response = new Response(drupal_render_page($page_content));
-    }
+    $response = new Response(drupal_render_page($page_content));
 
     return $response;
   }
diff --git a/core/lib/Drupal/Core/HttpKernel.php b/core/lib/Drupal/Core/HttpKernel.php
index ca0c002..d89eeff 100644
--- a/core/lib/Drupal/Core/HttpKernel.php
+++ b/core/lib/Drupal/Core/HttpKernel.php
@@ -3,241 +3,39 @@
 /**
  * @file
  * Definition of Drupal\Core\HttpKernel.
- *
- * @todo This file is copied verbatim, with the exception of the namespace
- * change and this commment block, from Symfony full stack's FrameworkBundle.
- * Once the FrameworkBundle is available as a Composer package we should switch
- * to pulling it via Composer.
  */
 
 namespace Drupal\Core;
 
-use Symfony\Cmf\Component\Routing\RouteObjectInterface;
-use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpFoundation\Response;
-use Symfony\Component\HttpFoundation\StreamedResponse;
 use Symfony\Component\HttpKernel\HttpKernelInterface;
-use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\HttpKernel\HttpKernel as BaseHttpKernel;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel as BaseHttpKernel;
 
 /**
- * This HttpKernel is used to manage scope changes of the DI container.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ * HttpKernel extension to allow easy in-process subrequests.
  */
-class HttpKernel extends BaseHttpKernel
-{
-    protected $container;
-
-    private $esiSupport;
-
-    public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver)
-    {
-        parent::__construct($dispatcher, $controllerResolver);
-
-        $this->container = $container;
-    }
-
-    public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
-    {
-        $request->headers->set('X-Php-Ob-Level', ob_get_level());
-
-        $this->container->enterScope('request');
-        $this->container->set('request', $request, 'request');
-
-        try {
-            $response = parent::handle($request, $type, $catch);
-        } catch (\Exception $e) {
-            $this->container->leaveScope('request');
-
-            throw $e;
-        }
-
-        $this->container->leaveScope('request');
-
-        return $response;
-    }
+class HttpKernel extends BaseHttpKernel {
 
     /**
      * Forwards the request to another controller.
      *
-     * @param string $controller The controller name (a string like BlogBundle:Post:index)
-     * @param array  $attributes An array of request attributes
-     * @param array  $query      An array of request query parameters
-     *
-     * @return Response A Response instance
-     */
-    public function forward($controller, array $attributes = array(), array $query = array())
-    {
-        $attributes['_controller'] = $controller;
-        $subRequest = $this->container->get('request')->duplicate($query, null, $attributes);
-
-        return $this->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
-    }
-
-    /**
-     * Renders a Controller and returns the Response content.
-     *
-     * Note that this method generates an esi:include tag only when both the standalone
-     * option is set to true and the request has ESI capability (@see Symfony\Component\HttpKernel\HttpCache\ESI).
+     * If what you want back is just a string, do not use this method. Use
+     * the FragmentHandler.  Only use this method if you want back a Response
+     * object.
      *
-     * Available options:
+     * @param string $controller
+     *   The controller name (a string like BlogBundle:Post:index)
+     * @param array  $attributes
+     *   An array of request attributes
+     * @param array  $query
+     *   An array of request query parameters
      *
-     *  * attributes: An array of request attributes (only when the first argument is a controller)
-     *  * query: An array of request query parameters (only when the first argument is a controller)
-     *  * ignore_errors: true to return an empty string in case of an error
-     *  * alt: an alternative controller to execute in case of an error (can be a controller, a URI, or an array with the controller, the attributes, and the query arguments)
-     *  * standalone: whether to generate an esi:include tag or not when ESI is supported
-     *  * comment: a comment to add when returning an esi:include tag
-     *
-     * @param string $controller A controller name to execute (a string like BlogBundle:Post:index), or a relative URI
-     * @param array  $options    An array of options
-     *
-     * @return string The Response content
+     * @return Response
+     *   A Response instance
      */
-    public function render($controller, array $options = array())
-    {
-        $options = array_merge(array(
-            'attributes'    => array(),
-            'query'         => array(),
-            'ignore_errors' => !$this->container->getParameter('kernel.debug'),
-            'alt'           => array(),
-            'standalone'    => false,
-            'comment'       => '',
-        ), $options);
-
-        if (!is_array($options['alt'])) {
-            $options['alt'] = array($options['alt']);
-        }
-
-        if (null === $this->esiSupport) {
-            $this->esiSupport = $this->container->has('esi') && $this->container->get('esi')->hasSurrogateEsiCapability($this->container->get('request'));
-        }
-
-        if ($this->esiSupport && (true === $options['standalone'] || 'esi' === $options['standalone'])) {
-            $uri = $this->generateInternalUri($controller, $options['attributes'], $options['query']);
-
-            $alt = '';
-            if ($options['alt']) {
-                $alt = $this->generateInternalUri($options['alt'][0], isset($options['alt'][1]) ? $options['alt'][1] : array(), isset($options['alt'][2]) ? $options['alt'][2] : array());
-            }
-
-            return $this->container->get('esi')->renderIncludeTag($uri, $alt, $options['ignore_errors'], $options['comment']);
-        }
-
-        if ('js' === $options['standalone']) {
-            $uri = $this->generateInternalUri($controller, $options['attributes'], $options['query'], false);
-            $defaultContent = null;
-
-            if ($template = $this->container->getParameter('templating.hinclude.default_template')) {
-                $defaultContent = $this->container->get('templating')->render($template);
-            }
-
-            return $this->renderHIncludeTag($uri, $defaultContent);
-        }
-
-        $request = $this->container->get('request');
-
-        // controller or URI?
-        if (0 === strpos($controller, '/')) {
-            $subRequest = Request::create($request->getUriForPath($controller), 'get', array(), $request->cookies->all(), array(), $request->server->all());
-            if ($session = $request->getSession()) {
-                $subRequest->setSession($session);
-            }
-        } else {
-            $options['attributes']['_controller'] = $controller;
-
-            if (!isset($options['attributes']['_format'])) {
-                $options['attributes']['_format'] = $request->getRequestFormat();
-            }
-
-            $options['attributes'][RouteObjectInterface::ROUTE_OBJECT] = '_internal';
-            $subRequest = $request->duplicate($options['query'], null, $options['attributes']);
-            $subRequest->setMethod('GET');
-        }
-
-        $level = ob_get_level();
-        try {
-            $response = $this->handle($subRequest, HttpKernelInterface::SUB_REQUEST, false);
-
-            if (!$response->isSuccessful()) {
-                throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $request->getUri(), $response->getStatusCode()));
-            }
-
-            if (!$response instanceof StreamedResponse) {
-                return $response->getContent();
-            }
-
-            $response->sendContent();
-        } catch (\Exception $e) {
-            if ($options['alt']) {
-                $alt = $options['alt'];
-                unset($options['alt']);
-                $options['attributes'] = isset($alt[1]) ? $alt[1] : array();
-                $options['query'] = isset($alt[2]) ? $alt[2] : array();
-
-                return $this->render($alt[0], $options);
-            }
-
-            if (!$options['ignore_errors']) {
-                throw $e;
-            }
-
-            // let's clean up the output buffers that were created by the sub-request
-            while (ob_get_level() > $level) {
-                ob_get_clean();
-            }
-        }
-    }
-
-    /**
-     * Generates an internal URI for a given controller.
-     *
-     * This method uses the "_internal" route, which should be available.
-     *
-     * @param string  $controller A controller name to execute (a string like BlogBundle:Post:index), or a relative URI
-     * @param array   $attributes An array of request attributes
-     * @param array   $query      An array of request query parameters
-     * @param boolean $secure
-     *
-     * @return string An internal URI
-     */
-    public function generateInternalUri($controller, array $attributes = array(), array $query = array(), $secure = true)
-    {
-        if (0 === strpos($controller, '/')) {
-            return $controller;
-        }
-
-        $path = http_build_query($attributes, '', '&');
-        $uri = $this->container->get('router')->generate($secure ? '_internal' : '_internal_public', array(
-            'controller' => $controller,
-            'path'       => $path ?: 'none',
-            '_format'    => $this->container->get('request')->getRequestFormat(),
-        ));
-
-        if ($queryString = http_build_query($query, '', '&')) {
-            $uri .= '?'.$queryString;
-        }
-
-        return $uri;
-    }
-
-    /**
-     * Renders an HInclude tag.
-     *
-     * @param string $uri A URI
-     * @param string $defaultContent Default content
-     */
-    public function renderHIncludeTag($uri, $defaultContent = null)
-    {
-        return sprintf('<hx:include src="%s">%s</hx:include>', $uri, $defaultContent);
-    }
+    public function forward($controller, array $attributes = array(), array $query = array()) {
+      $attributes['_controller'] = $controller;
+      $subRequest = $this->container->get('request')->duplicate($query, null, $attributes);
 
-    public function hasEsiSupport()
-    {
-        return $this->esiSupport;
+      return $this->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
     }
 }
diff --git a/core/misc/create/create-editonly.js b/core/misc/create/create-editonly.js
index aed84a4..4279a1b 100644
--- a/core/misc/create/create-editonly.js
+++ b/core/misc/create/create-editonly.js
@@ -334,6 +334,7 @@
         element: this.element,
         instance: this.options.model
       };
+
       var propertyParams = (predicate) ? {
         predicate: predicate,
         propertyEditor: this.options.propertyEditors[predicate],
@@ -516,11 +517,11 @@
 
     disable: function () {
       _.each(this.options.propertyEditors, function (editable) {
-        this.disablePropertyEditor({
+        this.disableEditor({
           widget: this,
           editable: editable,
           entity: this.options.model,
-          element: editable.element
+          element: jQuery(editable)
         });
       }, this);
       this.options.propertyEditors = {};
@@ -591,7 +592,7 @@
         return;
       }
       var widgetType = propertyElement.data('createWidgetName');
-      this.options.propertyEditors[predicate] = propertyElement.data('Midgard-' + widgetType);
+      this.options.propertyEditors[predicate] = propertyElement.data(widgetType);
 
       // Deprecated.
       this.options.editables.push(propertyElement);
@@ -672,13 +673,18 @@
     },
 
     disablePropertyEditor: function (data) {
-      data.element[data.editable.widgetName]({
-        disabled: true
-      });
-      jQuery(data.element).removeClass('ui-state-disabled');
+      var widgetName = jQuery(data.element).data('createWidgetName');
+
+      data.disabled = true;
 
-      if (data.element.is(':focus')) {
-        data.element.blur();
+      if (widgetName) {
+        // only if there has been an editing widget registered
+        jQuery(data.element)[widgetName](data);
+        jQuery(data.element).removeClass('ui-state-disabled');
+
+        if (data.element.is(':focus')) {
+          data.element.blur();
+        }
       }
     },
 
@@ -749,7 +755,7 @@
   //     jQuery.widget('Namespace.MyWidget', jQuery.Create.editWidget, {
   //       // override any properties
   //     });
-  jQuery.widget('Midgard.editWidget', {
+  jQuery.widget('Create.editWidget', {
     options: {
       disabled: false,
       vie: null
@@ -843,7 +849,7 @@
   //
   // Due to licensing incompatibilities, Aloha Editor needs to be installed
   // and configured separately.
-  jQuery.widget('Midgard.alohaWidget', jQuery.Midgard.editWidget, {
+  jQuery.widget('Create.alohaWidget', jQuery.Create.editWidget, {
     _initialize: function () {},
     enable: function () {
       var options = this.options;
@@ -906,7 +912,7 @@
   //
   // This widget allows editing textual content areas with the
   // [CKEditor](http://ckeditor.com/) rich text editor.
-  jQuery.widget('Midgard.ckeditorWidget', jQuery.Midgard.editWidget, {
+  jQuery.widget('Create.ckeditorWidget', jQuery.Create.editWidget, {
     enable: function () {
       this.element.attr('contentEditable', 'true');
       this.editor = CKEDITOR.inline(this.element.get(0));
@@ -918,7 +924,6 @@
       });
       this.editor.on('blur', function () {
         widget.options.activated();
-        widget.options.changed(widget.editor.getData());
       });
       this.editor.on('key', function () {
         widget.options.changed(widget.editor.getData());
@@ -929,11 +934,6 @@
       this.editor.on('afterCommandExec', function () {
         widget.options.changed(widget.editor.getData());
       });
-      this.editor.on('configLoaded', function() {
-        jQuery.each(widget.options.editorOptions, function(optionName, option) {
-          widget.editor.config[optionName] = option;
-        });
-      });
     },
 
     disable: function () {
@@ -964,7 +964,7 @@
   //
   // This widget allows editing textual content areas with the
   // [Hallo](http://hallojs.org) rich text editor.
-  jQuery.widget('Midgard.halloWidget', jQuery.Midgard.editWidget, {
+  jQuery.widget('Create.halloWidget', jQuery.Create.editWidget, {
     options: {
       editorOptions: {},
       disabled: true,
@@ -1006,10 +1006,6 @@
           return;
         }
         self.options.toolbarState = data.display;
-        if (!self.element.data('IKS-hallo')) {
-          // Hallo not yet instantiated
-          return;
-        }
         var newOptions = self.getHalloOptions();
         self.element.hallo('changeToolbar', newOptions.parentElement, newOptions.toolbar, true);
       });
@@ -1065,7 +1061,7 @@
   //
   // This widget allows editing textual content areas with the
   // [Redactor](http://redactorjs.com/) rich text editor.
-  jQuery.widget('Midgard.redactorWidget', jQuery.Midgard.editWidget, {
+  jQuery.widget('Create.redactorWidget', jQuery.Create.editWidget, {
     editor: null,
 
     options: {
diff --git a/core/modules/edit/js/app.js b/core/modules/edit/js/app.js
index 14d76a0..07f006f 100644
--- a/core/modules/edit/js/app.js
+++ b/core/modules/edit/js/app.js
@@ -317,7 +317,7 @@
         // Discarded if it transitions from a changed state to 'candidate'.
         if (from === 'changed' || from === 'invalid') {
           // Retrieve the storage widget from DOM.
-          var createStorageWidget = this.$el.data('DrupalCreateStorage');
+          var createStorageWidget = this.$el.data('createStorage');
           // Revert changes in the model, this will trigger the direct editable
           // content to be reset and redrawn.
           createStorageWidget.revertChanges(editor.options.entity);
diff --git a/core/modules/edit/js/createjs/editingWidgets/drupalcontenteditablewidget.js b/core/modules/edit/js/createjs/editingWidgets/drupalcontenteditablewidget.js
index cde6163..bc86a04 100644
--- a/core/modules/edit/js/createjs/editingWidgets/drupalcontenteditablewidget.js
+++ b/core/modules/edit/js/createjs/editingWidgets/drupalcontenteditablewidget.js
@@ -8,7 +8,7 @@
 
   // @todo D8: use jQuery UI Widget bridging.
   // @see http://drupal.org/node/1874934#comment-7124904
-  jQuery.widget('Midgard.direct', jQuery.Midgard.editWidget, {
+  jQuery.widget('DrupalEditEditor.direct', jQuery.Create.editWidget, {
 
     /**
      * Implements getEditUISettings() method.
diff --git a/core/modules/edit/js/createjs/editingWidgets/formwidget.js b/core/modules/edit/js/createjs/editingWidgets/formwidget.js
index aa2dd0a..8824a5d 100644
--- a/core/modules/edit/js/createjs/editingWidgets/formwidget.js
+++ b/core/modules/edit/js/createjs/editingWidgets/formwidget.js
@@ -8,7 +8,7 @@
 
   // @todo D8: change the name to "form" + use jQuery UI Widget bridging.
   // @see http://drupal.org/node/1874934#comment-7124904
-  $.widget('Midgard.formEditEditor', $.Midgard.editWidget, {
+  $.widget('DrupalEditEditor.formEditEditor', $.Create.editWidget, {
 
     id: null,
     $formContainer: null,
diff --git a/core/modules/editor/js/editor.createjs.js b/core/modules/editor/js/editor.createjs.js
index de15c77..c4bfae6 100644
--- a/core/modules/editor/js/editor.createjs.js
+++ b/core/modules/editor/js/editor.createjs.js
@@ -18,7 +18,7 @@
 
 // @todo D8: use jQuery UI Widget bridging.
 // @see http://drupal.org/node/1874934#comment-7124904
-jQuery.widget('Midgard.editor', jQuery.Midgard.direct, {
+jQuery.widget('DrupalEditEditor.editor', jQuery.DrupalEditEditor.direct, {
 
   textFormat: null,
   textFormatHasTransformations: null,
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index 2880a5d..4f67090 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -139,7 +139,6 @@ function _toolbar_subtrees_access($hash) {
  * @see toolbar_menu().
  */
 function toolbar_subtrees_jsonp($hash) {
-  _toolbar_initialize_page_cache();
   $subtrees = toolbar_get_rendered_subtrees();
   $response = new JsonResponse($subtrees);
   $response->setCallback('Drupal.toolbar.setSubtrees');
@@ -147,46 +146,6 @@ function toolbar_subtrees_jsonp($hash) {
 }
 
 /**
- * Use Drupal's page cache for toolbar/subtrees/*, even for authenticated users.
- *
- * This gets invoked after full bootstrap, so must duplicate some of what's
- * done by _drupal_bootstrap_page_cache().
- *
- * @todo Replace this hack with something better integrated with DrupalKernel
- *   once Drupal's page caching itself is properly integrated.
- */
-function _toolbar_initialize_page_cache() {
-  $GLOBALS['conf']['system.performance']['cache']['page']['enabled'] = TRUE;
-  drupal_page_is_cacheable(TRUE);
-
-  // If we have a cache, serve it.
-  // @see _drupal_bootstrap_page_cache()
-  $cache = drupal_page_get_cache();
-  if (is_object($cache)) {
-    header('X-Drupal-Cache: HIT');
-    // Restore the metadata cached with the page.
-    $_GET['q'] = $cache->data['path'];
-    date_default_timezone_set(drupal_get_user_timezone());
-
-    drupal_serve_page_from_cache($cache);
-
-    // We are done.
-    exit;
-  }
-
-  // Otherwise, create a new page response (that will be cached).
-  header('X-Drupal-Cache: MISS');
-
-  // The Expires HTTP header is the heart of the client-side HTTP caching. The
-  // additional server-side page cache only takes effect when the client
-  // accesses the callback URL again (e.g., after clearing the browser cache or
-  // when force-reloading a Drupal page).
-  $max_age = 3600 * 24 * 365;
-  drupal_add_http_header('Expires', gmdate(DATE_RFC1123, REQUEST_TIME + $max_age));
-  drupal_add_http_header('Cache-Control', 'private, max-age=' . $max_age);
-}
-
-/**
  * Implements hook_page_build().
  *
  * Add admin toolbar to the page_top region automatically.
