From 5e58da00e6472598de73b9156daa935aa2743910 Mon Sep 17 00:00:00 2001
From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org>
Date: Thu, 26 Jun 2014 11:47:01 +0100
Subject: [PATCH] Issue #2016629 by larowlan, neclimdul, sun, alexpott, jibran,
 ParisLiakos, donquixote, effulgentsia, msonnabaum: Refactor bootstrap to
 better utilize the kernel.

---
 .htaccess                                     |   7 +-
 core/authorize.php                            |  19 +-
 core/core.services.yml                        |   8 +-
 core/includes/bootstrap.inc                   | 560 ++------------
 core/includes/common.inc                      |  64 --
 core/includes/errors.inc                      |   8 +-
 core/includes/install.core.inc                |  24 +-
 core/includes/install.inc                     |  33 +-
 core/includes/path.inc                        |   4 +-
 core/includes/schema.inc                      |   2 +-
 core/includes/theme.inc                       |  14 +-
 core/includes/utility.inc                     |  26 +-
 core/lib/Drupal/Core/DrupalKernel.php         | 710 ++++++++++++++++--
 .../lib/Drupal/Core/DrupalKernelInterface.php |  43 ++
 .../LegacyRequestSubscriber.php               |  64 --
 .../ThemeNegotiatorRequestSubscriber.php      |  48 ++
 .../Drupal/Core/Installer/InstallerKernel.php |  36 +
 core/lib/Drupal/Core/Site/Settings.php        |  27 +
 core/lib/Drupal/Core/Test/TestKernel.php      |  44 +-
 .../lib/Drupal/Core/Test/TestRunnerKernel.php |  85 +++
 .../ckeditor/src/Tests/CKEditorAdminTest.php  |   2 +-
 .../src/Tests/CKEditorLoadingTest.php         |  15 +-
 core/modules/dblog/src/Tests/DbLogTest.php    |   4 +-
 .../modules/field/src/Tests/FieldHelpTest.php |   1 +
 .../src/Tests/LanguageNegotiationInfoTest.php |   2 +-
 .../simpletest/src/InstallerTestBase.php      |  16 +-
 .../modules/simpletest/src/KernelTestBase.php |  32 +-
 core/modules/simpletest/src/TestBase.php      |   3 +-
 core/modules/simpletest/src/WebTestBase.php   |  64 +-
 core/modules/statistics/statistics.php        |  19 +-
 .../DrupalKernel/DrupalKernelSiteTest.php     |   2 +-
 .../Tests/DrupalKernel/DrupalKernelTest.php   |  89 ++-
 .../Tests/Entity/EntityViewControllerTest.php |   2 +
 .../system/src/Tests/Menu/MenuRouterTest.php  |   1 +
 .../src/Tests/Module/InstallUninstallTest.php |   1 +
 .../system/src/Tests/System/ScriptTest.php    |  16 +
 .../Tests/Theme/ThemeSuggestionsAlterTest.php |   6 +
 core/modules/system/tests/http.php            |  26 +-
 core/modules/system/tests/https.php           |  26 +-
 core/modules/toolbar/toolbar.module           |   4 +-
 core/modules/user/src/Tests/UserLoginTest.php |   1 +
 .../views_ui/src/Tests/PreviewTest.php        |   2 +
 core/rebuild.php                              |  23 +-
 core/scripts/password-hash.sh                 |  11 +-
 core/scripts/rebuild_token_calculator.sh      |  10 +-
 core/scripts/run-tests.sh                     |  53 +-
 core/tests/bootstrap.php                      |   2 +-
 core/update.php                               |  40 +-
 index.php                                     |  15 +-
 sites/default/default.settings.php            |   6 +-
 web.config                                    |   3 +-
 51 files changed, 1286 insertions(+), 1037 deletions(-)
 delete mode 100644 core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php
 create mode 100644 core/lib/Drupal/Core/EventSubscriber/ThemeNegotiatorRequestSubscriber.php
 create mode 100644 core/lib/Drupal/Core/Installer/InstallerKernel.php
 create mode 100644 core/lib/Drupal/Core/Test/TestRunnerKernel.php

diff --git a/.htaccess b/.htaccess
index 3e742b6a1eb1..00830a527af6 100644
--- a/.htaccess
+++ b/.htaccess
@@ -25,8 +25,9 @@ ErrorDocument 404 /index.php
 DirectoryIndex index.php index.html index.htm
 
 # Override PHP settings that cannot be changed at runtime. See
-# sites/default/default.settings.php and drupal_environment_initialize() in
-# core/includes/bootstrap.inc for settings that can be changed at runtime.
+# sites/default/default.settings.php and
+# Drupal\Core\DrupalKernel::bootEnvironment() for settings that can be
+# changed at runtime.
 
 # PHP 5, Apache 1 and 2.
 <IfModule mod_php5.c>
@@ -119,7 +120,7 @@ DirectoryIndex index.php index.html index.htm
   RewriteRule ^ %1/core/%2 [L,QSA,R=301]
 
   # Pass all requests not referring directly to files in the filesystem to
-  # index.php. Clean URLs are handled in drupal_environment_initialize().
+  # index.php.
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteCond %{REQUEST_FILENAME} !-d
   RewriteCond %{REQUEST_URI} !=/favicon.ico
diff --git a/core/authorize.php b/core/authorize.php
index f938f3903324..96fe9aeb3b69 100644
--- a/core/authorize.php
+++ b/core/authorize.php
@@ -20,13 +20,15 @@
  * @link authorize Authorized operation helper functions @endlink
  */
 
+use Drupal\Core\DrupalKernel;
+use Symfony\Component\HttpFoundation\Request;
 use Drupal\Core\Site\Settings;
 use Drupal\Core\Page\DefaultHtmlPageRenderer;
 
 // Change the directory to the Drupal root.
 chdir('..');
 
-require_once __DIR__ . '/vendor/autoload.php';
+$autoloader = require_once __DIR__ . '/vendor/autoload.php';
 
 /**
  * Global flag to identify update.php and authorize.php runs.
@@ -51,18 +53,9 @@ function authorize_access_allowed() {
   return Settings::get('allow_authorize_operations', TRUE) && user_access('administer software updates');
 }
 
-// *** Real work of the script begins here. ***
-
-require_once __DIR__ . '/includes/bootstrap.inc';
-require_once __DIR__ . '/includes/common.inc';
-require_once __DIR__ . '/includes/file.inc';
-require_once __DIR__ . '/includes/module.inc';
-require_once __DIR__ . '/includes/ajax.inc';
-
-// Prepare a minimal bootstrap.
-drupal_bootstrap(DRUPAL_BOOTSTRAP_PAGE_CACHE);
-$request = \Drupal::request();
-\Drupal::service('request_stack')->push($request);
+$request = Request::createFromGlobals();
+$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
+$kernel->prepareLegacyRequest($request);
 
 // We have to enable the user and system modules, even to check access and
 // display errors via the maintenance theme.
diff --git a/core/core.services.yml b/core/core.services.yml
index ce0db128a554..2629efc4b194 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -204,6 +204,10 @@ services:
     arguments: ['@access_check.theme']
     tags:
       - { name: service_collector, tag: theme_negotiator, call: addNegotiator }
+  theme.negotiator.request_subscriber:
+    class: Drupal\Core\EventSubscriber\ThemeNegotiatorRequestSubscriber
+    tags:
+      - { name: event_subscriber }
   theme.negotiator.default:
     class: Drupal\Core\Theme\DefaultNegotiator
     arguments: ['@config.factory']
@@ -608,10 +612,6 @@ services:
     tags:
       - { name: event_subscriber }
     arguments: ['@path.alias_manager', '@path_processor_manager']
-  legacy_request_subscriber:
-    class: Drupal\Core\EventSubscriber\LegacyRequestSubscriber
-    tags:
-      - { name: event_subscriber }
   finish_response_subscriber:
     class: Drupal\Core\EventSubscriber\FinishResponseSubscriber
     tags:
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index a9ea984deb07..6c7cf6f67849 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -6,30 +6,16 @@
 
 use Drupal\Component\Utility\Crypt;
 use Drupal\Component\Utility\Environment;
-use Drupal\Component\Utility\NestedArray;
 use Drupal\Component\Utility\String;
-use Drupal\Component\Utility\Timer;
 use Drupal\Component\Utility\Unicode;
-use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\DrupalKernel;
-use Drupal\Core\Database\Database;
-use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\Extension\ExtensionDiscovery;
 use Drupal\Core\Site\Settings;
-use Drupal\Core\Utility\Title;
 use Drupal\Core\Utility\Error;
 use Symfony\Component\ClassLoader\ApcClassLoader;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\DependencyInjection\Container;
-use Symfony\Component\DependencyInjection\Reference;
-use Symfony\Component\DependencyInjection\Exception\RuntimeException as DependencyInjectionRuntimeException;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
-use Drupal\Core\Language\Language;
 use Drupal\Core\Language\LanguageInterface;
-use Drupal\Core\Lock\DatabaseLockBackend;
-use Drupal\Core\Lock\LockBackendInterface;
-use Drupal\Core\Session\AnonymousUserSession;
 
 /**
  * Minimum supported version of PHP.
@@ -127,26 +113,36 @@
 
 /**
  * First bootstrap phase: initialize configuration.
+ *
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
  */
 const DRUPAL_BOOTSTRAP_CONFIGURATION = 0;
 
 /**
- * Second bootstrap phase, initalize a kernel.
+ * Second bootstrap phase, initialize a kernel.
+ *
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
  */
 const DRUPAL_BOOTSTRAP_KERNEL = 1;
 
 /**
  * Third bootstrap phase: try to serve a cached page.
+ *
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
  */
 const DRUPAL_BOOTSTRAP_PAGE_CACHE = 2;
 
 /**
  * Fourth bootstrap phase: load code for subsystems and modules.
+ *
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
  */
 const DRUPAL_BOOTSTRAP_CODE = 3;
 
 /**
  * Final bootstrap phase: initialize language, path, theme, and modules.
+ *
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
  */
 const DRUPAL_BOOTSTRAP_FULL = 4;
 
@@ -208,11 +204,6 @@
 /**
  * Returns the appropriate configuration directory.
  *
- * Returns the configuration path based on the site's hostname, port, and
- * pathname. Uses find_conf_path() to find the current configuration directory.
- * See default.settings.php for examples on how the URL is converted to a
- * directory.
- *
  * @param bool $require_settings
  *   Only configuration directories with an existing settings.php file
  *   will be recognized. Defaults to TRUE. During initial installation,
@@ -221,100 +212,36 @@
  * @param bool $reset
  *   Force a full search for matching directories even if one had been
  *   found previously. Defaults to FALSE.
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ *   (optional) The current request. Defaults to \Drupal::request() or a new
+ *   request created from globals.
  *
- * @return
- *   The path of the matching directory.
+ * @return string
+ *   The path of the matching directory.@see default.settings.php
  *
- * @see default.settings.php
- */
-function conf_path($require_settings = TRUE, $reset = FALSE) {
-  static $conf_path;
-
-  if (isset($conf_path) && !$reset) {
-    return $conf_path;
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
+ *   Use \Drupal\Core\DrupalKernel::getSitePath() instead. If the kernel is
+ *   unavailable or the site path needs to be recalculated then
+ *   Drupal\Core\DrupalKernel::findSitePath() can be used.
+ */
+function conf_path($require_settings = TRUE, $reset = FALSE, Request $request = NULL) {
+  if (!isset($request)) {
+    if (\Drupal::hasRequest()) {
+      $request = \Drupal::request();
+    }
+    // @todo Remove once external CLI scripts (Drush) are updated.
+    else {
+      $request = Request::createFromGlobals();
+    }
   }
-
-  // Check for a simpletest override.
-  if ($test_prefix = drupal_valid_test_ua()) {
-    $conf_path = 'sites/simpletest/' . substr($test_prefix, 10);
-    return $conf_path;
+  if (\Drupal::hasService('kernel')) {
+    $site_path = \Drupal::service('kernel')->getSitePath();
   }
-
-  // Otherwise, use the normal $conf_path.
-  $script_name = $_SERVER['SCRIPT_NAME'];
-  if (!$script_name) {
-    $script_name = $_SERVER['SCRIPT_FILENAME'];
+  if (!isset($site_path) || empty($site_path)) {
+    $site_path = DrupalKernel::findSitePath($request, $require_settings);
   }
-  $http_host = $_SERVER['HTTP_HOST'];
-  $conf_path = find_conf_path($http_host, $script_name, $require_settings);
-  return $conf_path;
+  return $site_path;
 }
-
-/**
- * Finds the appropriate configuration directory for a given host and path.
- *
- * Finds a matching configuration directory file by stripping the website's
- * hostname from left to right and pathname from right to left. By default,
- * the directory must contain a 'settings.php' file for it to match. If the
- * parameter $require_settings is set to FALSE, then a directory without a
- * 'settings.php' file will match as well. The first configuration
- * file found will be used and the remaining ones will be ignored. If no
- * configuration file is found, returns a default value '$confdir/default'. See
- * default.settings.php for examples on how the URL is converted to a directory.
- *
- * If a file named sites.php is present in the $confdir, it will be loaded
- * prior to scanning for directories. That file can define aliases in an
- * associative array named $sites. The array is written in the format
- * '<port>.<domain>.<path>' => 'directory'. As an example, to create a
- * directory alias for http://www.drupal.org:8080/mysite/test whose configuration
- * file is in sites/example.com, the array should be defined as:
- * @code
- * $sites = array(
- *   '8080.www.drupal.org.mysite.test' => 'example.com',
- * );
- * @endcode
- *
- * @param $http_host
- *   The hostname and optional port number, e.g. "www.example.com" or
- *   "www.example.com:8080".
- * @param $script_name
- *   The part of the URL following the hostname, including the leading slash.
- * @param $require_settings
- *   Defaults to TRUE. If TRUE, then only match directories with a
- *   'settings.php' file. Otherwise match any directory.
- *
- * @return
- *   The path of the matching configuration directory.
- *
- * @see default.settings.php
- * @see example.sites.php
- * @see conf_path()
- */
-function find_conf_path($http_host, $script_name, $require_settings = TRUE) {
-  // Determine whether multi-site functionality is enabled.
-  if (!file_exists(DRUPAL_ROOT . '/sites/sites.php')) {
-    return 'sites/default';
-  }
-
-  $sites = array();
-  include DRUPAL_ROOT . '/sites/sites.php';
-
-  $uri = explode('/', $script_name);
-  $server = explode('.', implode('.', array_reverse(explode(':', rtrim($http_host, '.')))));
-  for ($i = count($uri) - 1; $i > 0; $i--) {
-    for ($j = count($server); $j > 0; $j--) {
-      $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
-      if (isset($sites[$dir]) && file_exists(DRUPAL_ROOT . '/sites/' . $sites[$dir])) {
-        $dir = $sites[$dir];
-      }
-      if (file_exists(DRUPAL_ROOT . '/sites/' . $dir . '/settings.php') || (!$require_settings && file_exists(DRUPAL_ROOT . '/sites/' . $dir))) {
-        return "sites/$dir";
-      }
-    }
-  }
-  return 'sites/default';
-}
-
 /**
  * Returns the path of a configuration directory.
  *
@@ -334,207 +261,6 @@ function config_get_config_directory($type = CONFIG_ACTIVE_DIRECTORY) {
   throw new \Exception(format_string('The configuration directory type %type does not exist.', array('%type' => $type)));
 }
 
-/**
- * Initializes the PHP environment.
- */
-function drupal_environment_initialize() {
-  if (!isset($_SERVER['SERVER_PROTOCOL']) || ($_SERVER['SERVER_PROTOCOL'] != 'HTTP/1.0' && $_SERVER['SERVER_PROTOCOL'] != 'HTTP/1.1')) {
-    $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0';
-  }
-
-  if (isset($_SERVER['HTTP_HOST'])) {
-    // As HTTP_HOST is user input, ensure it only contains characters allowed
-    // in hostnames. See RFC 952 (and RFC 2181).
-    // $_SERVER['HTTP_HOST'] is lowercased here per specifications.
-    $_SERVER['HTTP_HOST'] = strtolower($_SERVER['HTTP_HOST']);
-    if (!drupal_valid_http_host($_SERVER['HTTP_HOST'])) {
-      // HTTP_HOST is invalid, e.g. if containing slashes it may be an attack.
-      header($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request');
-      exit;
-    }
-  }
-  else {
-    // Some pre-HTTP/1.1 clients will not send a Host header. Ensure the key is
-    // defined for E_ALL compliance.
-    $_SERVER['HTTP_HOST'] = '';
-  }
-
-  // @todo Refactor with the Symfony Request object.
-  _current_path(request_path());
-
-  // Enforce E_STRICT, but allow users to set levels not part of E_STRICT.
-  error_reporting(E_STRICT | E_ALL | error_reporting());
-
-  // Override PHP settings required for Drupal to work properly.
-  // sites/default/default.settings.php contains more runtime settings.
-  // The .htaccess file contains settings that cannot be changed at runtime.
-
-  // Use session cookies, not transparent sessions that puts the session id in
-  // the query string.
-  ini_set('session.use_cookies', '1');
-  ini_set('session.use_only_cookies', '1');
-  ini_set('session.use_trans_sid', '0');
-  // Don't send HTTP headers using PHP's session handler.
-  // Send an empty string to disable the cache limiter.
-  ini_set('session.cache_limiter', '');
-  // Use httponly session cookies.
-  ini_set('session.cookie_httponly', '1');
-
-  // Set sane locale settings, to ensure consistent string, dates, times and
-  // numbers handling.
-  setlocale(LC_ALL, 'C');
-}
-
-/**
- * Validates that a hostname (for example $_SERVER['HTTP_HOST']) is safe.
- *
- * @return
- *  TRUE if only containing valid characters, or FALSE otherwise.
- */
-function drupal_valid_http_host($host) {
-  return preg_match('/^\[?(?:[a-zA-Z0-9-:\]_]+\.?)+$/', $host);
-}
-
-/**
- * Sets the base URL, cookie domain, and session name from configuration.
- */
-function drupal_settings_initialize() {
-  // Export these settings.php variables to the global namespace.
-  global $base_url, $cookie_domain, $config_directories, $config;
-  $databases = array();
-  $settings = array();
-  $config = array();
-
-  // Make conf_path() available as local variable in settings.php.
-  $conf_path = conf_path();
-  if (is_readable(DRUPAL_ROOT . '/' . $conf_path . '/settings.php')) {
-    require DRUPAL_ROOT . '/' . $conf_path . '/settings.php';
-  }
-  // Initialize Database.
-  Database::setMultipleConnectionInfo($databases);
-  // Initialize Settings.
-  new Settings($settings);
-}
-
-/**
- * Initializes global request variables.
- *
- * @todo D8: Eliminate this entirely in favor of Request object.
- */
-function _drupal_request_initialize() {
-  // Provided by settings.php.
-  // @see drupal_settings_initialize()
-  global $base_url, $cookie_domain;
-  // Set and derived from $base_url by this function.
-  global $base_path, $base_root, $script_path;
-  global $base_secure_url, $base_insecure_url;
-
-  $is_https = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on';
-
-  if (isset($base_url)) {
-    // Parse fixed base URL from settings.php.
-    $parts = parse_url($base_url);
-    if (!isset($parts['path'])) {
-      $parts['path'] = '';
-    }
-    $base_path = $parts['path'] . '/';
-    // Build $base_root (everything until first slash after "scheme://").
-    $base_root = substr($base_url, 0, strlen($base_url) - strlen($parts['path']));
-  }
-  else {
-    // Create base URL
-    $http_protocol = $is_https ? 'https' : 'http';
-    $base_root = $http_protocol . '://' . $_SERVER['HTTP_HOST'];
-
-    $base_url = $base_root;
-
-    // For a request URI of '/index.php/foo', $_SERVER['SCRIPT_NAME'] is
-    // '/index.php', whereas $_SERVER['PHP_SELF'] is '/index.php/foo'.
-    if ($dir = rtrim(dirname($_SERVER['SCRIPT_NAME']), '\/')) {
-      // Remove "core" directory if present, allowing install.php, update.php,
-      // and others to auto-detect a base path.
-      $core_position = strrpos($dir, '/core');
-      if ($core_position !== FALSE && strlen($dir) - 5 == $core_position) {
-        $base_path = substr($dir, 0, $core_position);
-      }
-      else {
-        $base_path = $dir;
-      }
-      $base_url .= $base_path;
-      $base_path .= '/';
-    }
-    else {
-      $base_path = '/';
-    }
-  }
-  $base_secure_url = str_replace('http://', 'https://', $base_url);
-  $base_insecure_url = str_replace('https://', 'http://', $base_url);
-
-  // Determine the path of the script relative to the base path, and add a
-  // trailing slash. This is needed for creating URLs to Drupal pages.
-  if (!isset($script_path)) {
-    $script_path = '';
-    // We don't expect scripts outside of the base path, but sanity check
-    // anyway.
-    if (strpos($_SERVER['SCRIPT_NAME'], $base_path) === 0) {
-      $script_path = substr($_SERVER['SCRIPT_NAME'], strlen($base_path)) . '/';
-      // If the request URI does not contain the script name, then clean URLs
-      // are in effect and the script path can be similarly dropped from URL
-      // generation. For servers that don't provide $_SERVER['REQUEST_URI'], we
-      // do not know the actual URI requested by the client, and request_uri()
-      // returns a URI with the script name, resulting in non-clean URLs unless
-      // there's other code that intervenes.
-      if (strpos(request_uri(TRUE) . '/', $base_path . $script_path) !== 0) {
-        $script_path = '';
-      }
-      // @todo Temporary BC for install.php, update.php, and other scripts.
-      //   - http://drupal.org/node/1547184
-      //   - http://drupal.org/node/1546082
-      if ($script_path !== 'index.php/') {
-        $script_path = '';
-      }
-    }
-  }
-
-  if ($cookie_domain) {
-    // If the user specifies the cookie domain, also use it for session name.
-    $session_name = $cookie_domain;
-  }
-  else {
-    // Otherwise use $base_url as session name, without the protocol
-    // to use the same session identifiers across HTTP and HTTPS.
-    list( , $session_name) = explode('://', $base_url, 2);
-    // HTTP_HOST can be modified by a visitor, but we already sanitized it
-    // in drupal_settings_initialize().
-    if (!empty($_SERVER['HTTP_HOST'])) {
-      $cookie_domain = $_SERVER['HTTP_HOST'];
-      // Strip leading periods, www., and port numbers from cookie domain.
-      $cookie_domain = ltrim($cookie_domain, '.');
-      if (strpos($cookie_domain, 'www.') === 0) {
-        $cookie_domain = substr($cookie_domain, 4);
-      }
-      $cookie_domain = explode(':', $cookie_domain);
-      $cookie_domain = '.' . $cookie_domain[0];
-    }
-  }
-  // Per RFC 2109, cookie domains must contain at least one dot other than the
-  // first. For hosts such as 'localhost' or IP Addresses we don't set a cookie domain.
-  if (count(explode('.', $cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $cookie_domain))) {
-    ini_set('session.cookie_domain', $cookie_domain);
-  }
-  // To prevent session cookies from being hijacked, a user can configure the
-  // SSL version of their website to only transfer session cookies via SSL by
-  // using PHP's session.cookie_secure setting. The browser will then use two
-  // separate session cookies for the HTTPS and HTTP versions of the site. So we
-  // must use different session identifiers for HTTPS and HTTP to prevent a
-  // cookie collision.
-  if ($is_https) {
-    ini_set('session.cookie_secure', TRUE);
-  }
-  $prefix = ini_get('session.cookie_secure') ? 'SSESS' : 'SESS';
-  session_name($prefix . substr(hash('sha256', $session_name), 0, 32));
-}
-
 /**
  * Returns and optionally sets the filename for a system resource.
  *
@@ -1253,128 +979,49 @@ function drupal_get_messages($type = NULL, $clear_queue = TRUE) {
  * @endcode
  *
  * @param $phase
- *   A constant telling which phase to bootstrap to. When you bootstrap to a
- *   particular phase, all earlier phases are run automatically. Possible
- *   values:
+ *   A constant telling which phase to bootstrap to. Possible values:
  *   - DRUPAL_BOOTSTRAP_CONFIGURATION: Initializes configuration.
  *   - DRUPAL_BOOTSTRAP_KERNEL: Initalizes a kernel.
- *   - DRUPAL_BOOTSTRAP_PAGE_CACHE: Tries to serve a cached page.
- *   - DRUPAL_BOOTSTRAP_CODE: Loads code for subsystems and modules.
- *   - DRUPAL_BOOTSTRAP_FULL: Fully loads Drupal. Validates and fixes input
- *     data.
  *
- * @return
+ * @return int
  *   The most recently completed phase.
+ *
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
+ *   Interact directly with the kernel.
  */
 function drupal_bootstrap($phase = NULL) {
-  // Not drupal_static(), because does not depend on any run-time information.
-  static $phases = array(
-    DRUPAL_BOOTSTRAP_CONFIGURATION,
-    DRUPAL_BOOTSTRAP_KERNEL,
-    DRUPAL_BOOTSTRAP_PAGE_CACHE,
-    DRUPAL_BOOTSTRAP_CODE,
-    DRUPAL_BOOTSTRAP_FULL,
-  );
-  // Not drupal_static(), because the only legitimate API to control this is to
-  // call drupal_bootstrap() with a new phase parameter.
-  static $final_phase = -1;
-  // Not drupal_static(), because it's impossible to roll back to an earlier
-  // bootstrap state.
-  static $stored_phase = -1;
-
-  // Store the phase name so it's not forgotten during recursion. Additionally,
-  // ensure that $final_phase is never rolled back to an earlier bootstrap
-  // state.
-  if ($phase > $final_phase) {
-    $final_phase = $phase;
-  }
+  // Temporary variables used for booting later legacy phases.
+  /** @var \Drupal\Core\DrupalKernel $kernel */
+  static $kernel;
+  static $boot_level = 0;
+
   if (isset($phase)) {
-    // Call a phase if it has not been called before and is below the requested
-    // phase.
-    while ($phases && $phase > $stored_phase && $final_phase > $stored_phase) {
-      $current_phase = array_shift($phases);
-
-      // This function is re-entrant. Only update the completed phase when the
-      // current call actually resulted in a progress in the bootstrap process.
-      if ($current_phase > $stored_phase) {
-        $stored_phase = $current_phase;
-      }
+    $request = Request::createFromGlobals();
+    for ($current_phase = $boot_level; $current_phase <= $phase; $current_phase++) {
 
       switch ($current_phase) {
         case DRUPAL_BOOTSTRAP_CONFIGURATION:
-          _drupal_bootstrap_configuration();
+          $kernel = DrupalKernel::createFromRequest($request, drupal_classloader(), 'prod');
           break;
 
         case DRUPAL_BOOTSTRAP_KERNEL:
-          _drupal_bootstrap_kernel();
+          $kernel->boot();
           break;
 
         case DRUPAL_BOOTSTRAP_PAGE_CACHE:
-          _drupal_bootstrap_page_cache();
+          $kernel->handlePageCache($request);
           break;
 
         case DRUPAL_BOOTSTRAP_CODE:
-          require_once __DIR__ . '/common.inc';
-          _drupal_bootstrap_code();
-          break;
-
         case DRUPAL_BOOTSTRAP_FULL:
-          _drupal_bootstrap_full();
+          $kernel->prepareLegacyRequest($request);
           break;
       }
     }
+    $boot_level = $phase;
   }
-  return $stored_phase;
-}
-
-/**
- * Handles an entire PHP request.
- *
- * This function may be called by PHP scripts (e.g., Drupal's index.php) that
- * want Drupal to take over the entire PHP processing of the request. The only
- * expectation is that PHP's superglobals are initialized as desired (PHP does
- * this automatically, but some scripts might want to alter them) and that the
- * DRUPAL_ROOT constant is defined and set to the absolute server directory of
- * Drupal's codebase.
- *
- * Scripts and applications that want to invoke multiple Drupal requests within
- * a single PHP request, or Drupal request handling within some larger workflow,
- * should not call this function, but instead instantiate and use
- * \Drupal\Core\DrupalKernel as needed.
- *
- * @param boolean $test_only
- *   Whether to restrict handling to only requests invoked by SimpleTest.
- *
- * @see index.php
- */
-function drupal_handle_request($test_only = FALSE) {
-  // Initialize the environment, load settings.php, and activate a PSR-0 class
-  // autoloader with required namespaces registered.
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
-
-  // Exit if we should be in a test environment but aren't.
-  if ($test_only && !drupal_valid_test_ua()) {
-    header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
-    exit;
-  }
-
-  $kernel = new DrupalKernel('prod', drupal_classloader(), !$test_only);
-
-  // @todo Remove this once everything in the bootstrap has been
-  //   converted to services in the DIC.
-  $kernel->boot();
 
-  // Create a request object from the HttpFoundation.
-  $request = Request::createFromGlobals();
-  $container = \Drupal::getContainer();
-  $container->set('request', $request);
-  $container->get('request_stack')->push($request);
-
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE);
-
-  $response = $kernel->handle($request)->prepare($request)->send();
-
-  $kernel->terminate($request, $response);
+  return \Drupal::getContainer() ? DRUPAL_BOOTSTRAP_CODE : DRUPAL_BOOTSTRAP_CONFIGURATION;
 }
 
 /**
@@ -1456,111 +1103,14 @@ function _drupal_exception_handler($exception) {
   }
 }
 
-/**
- * Sets up the script environment and loads settings.php.
- */
-function _drupal_bootstrap_configuration() {
-  drupal_environment_initialize();
-
-  // Indicate that code is operating in a test child site.
-  if ($test_prefix = drupal_valid_test_ua()) {
-    // Only code that interfaces directly with tests should rely on this
-    // constant; e.g., the error/exception handler conditionally adds further
-    // error information into HTTP response headers that are consumed by
-    // Simpletest's internal browser.
-    define('DRUPAL_TEST_IN_CHILD_SITE', TRUE);
-
-    // Log fatal errors to the test site directory.
-    ini_set('log_errors', 1);
-    ini_set('error_log', DRUPAL_ROOT . '/sites/simpletest/' . substr($test_prefix, 10) . '/error.log');
-  }
-  else {
-    // Ensure that no other code defines this.
-    define('DRUPAL_TEST_IN_CHILD_SITE', FALSE);
-  }
-
-  // Initialize the configuration, including variables from settings.php.
-  drupal_settings_initialize();
-  _drupal_request_initialize();
-
-  // Activate the class loader.
-  drupal_classloader();
-
-  // Start a page timer:
-  Timer::start('page');
-
-  // Detect string handling method.
-  Unicode::check();
-
-  // Set the Drupal custom error handler. (requires \Drupal::config())
-  set_error_handler('_drupal_error_handler');
-  set_exception_handler('_drupal_exception_handler');
-
-  // Redirect the user to the installation script if Drupal has not been
-  // installed yet (i.e., if no $databases array has been defined in the
-  // settings.php file) and we are not already installing.
-  if (!Database::getConnectionInfo() && !drupal_installation_attempted() && !drupal_is_cli()) {
-    include_once __DIR__ . '/install.inc';
-    install_goto('core/install.php');
-  }
-}
-
-/**
- * Initialize the kernel / service container.
- */
-function _drupal_bootstrap_kernel() {
-  // Normally, index.php puts a container in the Drupal class by creating a
-  // kernel. If there is no container yet, create one.
-  if (!\Drupal::getContainer()) {
-    $kernel = new DrupalKernel('prod', drupal_classloader());
-    $kernel->boot();
-    $request = Request::createFromGlobals();
-    $container = \Drupal::getContainer();
-    $container->set('request', $request);
-    $container->get('request_stack')->push($request);
-  }
-}
-
-/**
- * Attempts to serve a page from the cache.
- */
-function _drupal_bootstrap_page_cache() {
-  require_once __DIR__ . '/database.inc';
-  // Check for a cache mode force from settings.php.
-  if (Settings::get('page_cache_without_database')) {
-    $cache_enabled = TRUE;
-  }
-  else {
-    $config = \Drupal::config('system.performance');
-    $cache_enabled = $config->get('cache.page.use_internal');
-  }
-
-  $request = \Drupal::request();
-  // If there is no session cookie and cache is enabled (or forced), try
-  // to serve a cached page.
-  if (!$request->cookies->has(session_name()) && $cache_enabled && drupal_page_is_cacheable()) {
-    // Get the page from the cache.
-    $response = drupal_page_get_cache($request);
-    // If there is a cached page, display it.
-    if ($response) {
-      $response->headers->set('X-Drupal-Cache', 'HIT');
-
-      drupal_serve_page_from_cache($response, $request);
-
-      // We are done.
-      $response->prepare($request);
-      $response->send();
-      exit;
-    }
-  }
-}
-
 /**
  * Returns the current bootstrap phase for this Drupal process.
  *
  * The current phase is the one most recently completed by drupal_bootstrap().
  *
  * @see drupal_bootstrap()
+ *
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
  */
 function drupal_get_bootstrap_phase() {
   return drupal_bootstrap();
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 23f6ce3b2b36..c32424392baa 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -2603,70 +2603,6 @@ function drupal_valid_token($token, $value = '') {
   return \Drupal::csrfToken()->validate($token, $value);
 }
 
-/**
- * Loads code for subsystems and modules, and registers stream wrappers.
- */
-function _drupal_bootstrap_code() {
-  require_once __DIR__ . '/../../' . Settings::get('path_inc', 'core/includes/path.inc');
-  require_once __DIR__ . '/module.inc';
-  require_once __DIR__ . '/theme.inc';
-  require_once __DIR__ . '/pager.inc';
-  require_once __DIR__ . '/../../' . Settings::get('menu_inc', 'core/includes/menu.inc');
-  require_once __DIR__ . '/tablesort.inc';
-  require_once __DIR__ . '/file.inc';
-  require_once __DIR__ . '/unicode.inc';
-  require_once __DIR__ . '/form.inc';
-  require_once __DIR__ . '/mail.inc';
-  require_once __DIR__ . '/ajax.inc';
-  require_once __DIR__ . '/errors.inc';
-  require_once __DIR__ . '/schema.inc';
-  require_once __DIR__ . '/entity.inc';
-
-  // Load all enabled modules
-  \Drupal::moduleHandler()->loadAll();
-
-  // Make sure all stream wrappers are registered.
-  file_get_stream_wrappers();
-  // Ensure mt_rand() is reseeded to prevent random values from one page load
-  // being exploited to predict random values in subsequent page loads.
-  $seed = unpack("L", Crypt::randomBytes(4));
-  mt_srand($seed[1]);
-
-  // Set the allowed protocols once we have the config available.
-  $allowed_protocols = \Drupal::config('system.filter')->get('protocols');
-  if (!isset($allowed_protocols)) {
-    // \Drupal\Component\Utility\UrlHelper::filterBadProtocol() is called by the
-    // installer and update.php, in which case the configuration may not exist
-    // (yet). Provide a minimal default set of allowed protocols for these
-    // cases.
-    $allowed_protocols = array('http', 'https');
-  }
-  UrlHelper::setAllowedProtocols($allowed_protocols);
-}
-
-/**
- * Temporary BC function for scripts not using DrupalKernel.
- *
- * DrupalKernel skips this and replicates it via event listeners.
- *
- * @see \Drupal\Core\EventSubscriber\PathSubscriber;
- * @see \Drupal\Core\EventSubscriber\LegacyRequestSubscriber;
- */
-function _drupal_bootstrap_full($skip = FALSE) {
-  static $called = FALSE;
-
-  if ($called || $skip) {
-    $called = TRUE;
-    return;
-  }
-
-  // Let all modules take action before the menu system handles the request.
-  // We do not want this while running update.php.
-  if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
-    drupal_theme_initialize();
-  }
-}
-
 /**
  * Stores the current page in the cache.
  *
diff --git a/core/includes/errors.inc b/core/includes/errors.inc
index 8b0b9e43ec04..ebe1cd5cbda5 100644
--- a/core/includes/errors.inc
+++ b/core/includes/errors.inc
@@ -120,7 +120,7 @@ function _drupal_log_error($error, $fatal = FALSE) {
   $is_installer = drupal_installation_attempted();
   // Initialize a maintenance theme if the bootstrap was not complete.
   // Do it early because drupal_set_message() triggers a drupal_theme_initialize().
-  if ($fatal && (drupal_get_bootstrap_phase() != DRUPAL_BOOTSTRAP_FULL)) {
+  if ($fatal && drupal_get_bootstrap_phase() < DRUPAL_BOOTSTRAP_CODE) {
     // The installer initializes a maintenance theme at the earliest possible
     // point in time already. Do not unset that.
     if (!$is_installer) {
@@ -244,9 +244,9 @@ function _drupal_log_error($error, $fatal = FALSE) {
 /**
  * Returns the current error level.
  *
- * This function should only be used to get the current error level pre
- * DRUPAL_BOOTSTRAP_KERNEL or before Drupal is installed. In all other
- * situations the following code is preferred:
+ * This function should only be used to get the current error level prior to
+ * DRUPAL_BOOTSTRAP_KERNEL or before Drupal is installed. In all other situations
+ * the following code is preferred:
  * @code
  * \Drupal::config('system.logging')->get('error_level');
  * @endcode
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 7c0a3d011b74..158f8a9142df 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -9,6 +9,7 @@
 use Drupal\Core\Installer\Exception\AlreadyInstalledException;
 use Drupal\Core\Installer\Exception\InstallerException;
 use Drupal\Core\Installer\Exception\NoProfilesException;
+use Drupal\Core\Installer\InstallerKernel;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Language\LanguageManager;
 use Drupal\Core\Page\DefaultHtmlPageRenderer;
@@ -272,12 +273,6 @@ function install_begin_request(&$install_state) {
   // Allow command line scripts to override server variables used by Drupal.
   require_once __DIR__ . '/bootstrap.inc';
 
-  // Initialize conf_path().
-  // This primes the site path to be used during installation. By not requiring
-  // settings.php, a bare site folder can be prepared in the /sites directory,
-  // which will be used for installing Drupal.
-  conf_path(FALSE);
-
   // If the hash salt leaks, it becomes possible to forge a valid testing user
   // agent, install a new copy of Drupal, and take over the original site.
   // The user agent header is used to pass a database prefix in the request when
@@ -288,7 +283,8 @@ function install_begin_request(&$install_state) {
     exit;
   }
 
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+  $site_path = DrupalKernel::findSitePath($request, FALSE);
+  Settings::initialize($site_path);
 
   // Ensure that procedural dependencies are loaded as early as possible,
   // since the error/exception handlers depend on them.
@@ -359,22 +355,17 @@ function install_begin_request(&$install_state) {
     $environment = 'prod';
   }
 
-  $kernel = new DrupalKernel($environment, drupal_classloader(), FALSE);
+  $kernel = InstallerKernel::createFromRequest($request, drupal_classloader(), $environment);
+  $kernel->setSitePath($site_path);
   $kernel->boot();
-
-  // Enter the request scope and add the Request.
-  // @todo Remove this after converting all installer screens into controllers.
   $container = $kernel->getContainer();
-  $container->enterScope('request');
-  $container->set('request', $request, 'request');
-  $container->get('request_stack')->push($request);
 
   // Register the file translation service.
   if (isset($GLOBALS['config']['locale.settings']['translation.path'])) {
     $directory = $GLOBALS['config']['locale.settings']['translation.path'];
   }
   else {
-    $directory = conf_path() . '/files/translations';
+    $directory = $site_path . '/files/translations';
   }
   $container->set('string_translator.file_translation', new FileTranslation($directory));
   $container->get('string_translation')
@@ -419,6 +410,8 @@ function install_begin_request(&$install_state) {
   // checked by other subsystems (e.g., the theme system).
   $module_handler->loadAll();
 
+  $kernel->prepareLegacyRequest($request);
+
   // 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
@@ -1458,7 +1451,6 @@ function install_load_profile(&$install_state) {
  *   An array of information about the current installation state.
  */
 function install_bootstrap_full() {
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
   \Drupal::service('session_manager')->initialize();
 }
 
diff --git a/core/includes/install.inc b/core/includes/install.inc
index 176e941fbf4d..d1c159610204 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -9,8 +9,6 @@
 use Drupal\Component\Utility\Crypt;
 use Drupal\Component\Utility\OpCodeCache;
 use Drupal\Component\Utility\UrlHelper;
-use Drupal\Core\Database\Database;
-use Drupal\Core\DrupalKernel;
 use Drupal\Core\Extension\ExtensionDiscovery;
 use Drupal\Core\Site\Settings;
 
@@ -634,24 +632,33 @@ function drupal_verify_profile($install_state) {
  *   to set the default language.
  */
 function drupal_install_system($install_state) {
-  // Boot a new kernel into a regular production environment.
-  $request = \Drupal::hasRequest() ? \Drupal::request() : FALSE;
-
+  // Remove the service provider of the early installer.
   unset($GLOBALS['conf']['container_service_providers']['InstallerServiceProvider']);
-  $kernel = new DrupalKernel('prod', drupal_classloader(), FALSE);
-  $kernel->boot();
 
-  if ($request) {
-    $kernel->getContainer()->enterScope('request');
-    $kernel->getContainer()->set('request', $request, 'request');
-    $kernel->getContainer()->get('request_stack')->push($request);
-  }
+  $request = \Drupal::request();
+  // Reboot into a full production environment to continue the installation.
+  /** @var \Drupal\Core\Installer\InstallerKernel $kernel */
+  $kernel = \Drupal::service('kernel');
+  $kernel->shutdown();
+  // Have installer rebuild from the disk, rather then building from scratch.
+  $kernel->rebuildContainer(FALSE);
+  $kernel->prepareLegacyRequest($request);
 
   // Install base system configuration.
   \Drupal::service('config.installer')->installDefaultConfig('core', 'core');
 
   // Install System module.
-  \Drupal::moduleHandler()->install(array('system'), FALSE);
+  $kernel->getContainer()->get('module_handler')->install(array('system'), FALSE);
+
+  // DrupalKernel::prepareLegacyRequest() above calls into
+  // DrupalKernel::bootCode(), which primes file_get_stream_wrappers()'s static
+  // list of custom stream wrappers that are based on the currently enabled
+  // list of modules (none).
+  // @todo Custom stream wrappers of a new module have to be registered as soon
+  //   as the module is installed/enabled. Fix either ModuleHandler::install()
+  //   and/or DrupalKernel::updateModules().
+  // @see https://drupal.org/node/2028109
+  drupal_static_reset('file_get_stream_wrappers');
 
   // Ensure default language is saved.
   if (isset($install_state['parameters']['langcode'])) {
diff --git a/core/includes/path.inc b/core/includes/path.inc
index 02ab498650c5..616bb475ae9d 100644
--- a/core/includes/path.inc
+++ b/core/includes/path.inc
@@ -59,9 +59,7 @@ function drupal_match_path($path, $patterns) {
  * - http://example.com/path/alias (which is a path alias for node/306) returns
  *   "node/306" as opposed to the path alias.
  *
- * This function is available only after DRUPAL_BOOTSTRAP_FULL.
- *
- * @return
+ * @return string
  *   The current Drupal URL path.
  *
  * @see request_path()
diff --git a/core/includes/schema.inc b/core/includes/schema.inc
index a386e62d1c16..f181c5467e30 100644
--- a/core/includes/schema.inc
+++ b/core/includes/schema.inc
@@ -86,7 +86,7 @@ function drupal_get_complete_schema($rebuild = FALSE) {
 
       // If the schema is empty, avoid saving it: some database engines require
       // the schema to perform queries, and this could lead to infinite loops.
-      if (!empty($schema) && (drupal_get_bootstrap_phase() == DRUPAL_BOOTSTRAP_FULL)) {
+      if (!empty($schema)) {
         \Drupal::cache()->set('schema', $schema, Cache::PERMANENT);
       }
     }
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 4ba39140883d..1a0f58dd4a28 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -18,11 +18,13 @@
 use Drupal\Core\Page\FeedLinkElement;
 use Drupal\Core\Page\LinkElement;
 use Drupal\Core\Page\MetaElement;
+use Drupal\Core\Routing\RouteMatch;
 use Drupal\Core\Template\Attribute;
 use Drupal\Core\Template\RenderWrapper;
 use Drupal\Core\Theme\ThemeSettings;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Render\Element;
+use Symfony\Component\HttpFoundation\Request;
 
 /**
  * @defgroup content_flags Content markers
@@ -90,8 +92,12 @@ function drupal_theme_access($theme) {
 
 /**
  * Initializes the theme system by loading the theme.
+ *
+ * @param RouteMatch $route_match
+ *   The route match to use for theme initialization.
+// @todo Force calling methods to provide as RouteMatch.
  */
-function drupal_theme_initialize() {
+function drupal_theme_initialize(RouteMatch $route_match = NULL) {
   global $theme, $theme_key;
 
   // If $theme is already set, assume the others are set, too, and do nothing
@@ -101,10 +107,12 @@ function drupal_theme_initialize() {
 
   $themes = list_themes();
 
-  // @todo Let the theme.negotiator listen to the kernel request event.
   // Determine the active theme for the theme negotiator service. This includes
   // the default theme as well as really specific ones like the ajax base theme.
-  $theme = \Drupal::service('theme.negotiator')->determineActiveTheme(\Drupal::routeMatch());
+  if (!$route_match) {
+    $route_match = \Drupal::routeMatch();
+  }
+  $theme = \Drupal::service('theme.negotiator')->determineActiveTheme($route_match);
 
   // If no theme could be negotiated, or if the negotiated theme is not within
   // the list of enabled themes, fall back to the default theme output of core
diff --git a/core/includes/utility.inc b/core/includes/utility.inc
index 66031666ada5..135ab2473c18 100644
--- a/core/includes/utility.inc
+++ b/core/includes/utility.inc
@@ -8,6 +8,9 @@
 use Drupal\Component\Utility\Variable;
 use Drupal\Core\PhpStorage\PhpStorageFactory;
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\DrupalKernel;
+use Symfony\Component\HttpFoundation\Request;
+use Composer\Autoload\ClassLoader;
 
 /**
  * Drupal-friendly var_export().
@@ -32,34 +35,39 @@ function drupal_var_export($var, $prefix = '') {
  *
  * Requires DRUPAL_BOOTSTRAP_CONFIGURATION.
  *
+ * @param \Composer\Autoload\ClassLoader $classloader
+ *   The classloader.
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ *   The current request.
+ *
  * @see rebuild.php
  */
-function drupal_rebuild() {
+function drupal_rebuild(ClassLoader $classloader, Request $request) {
   // Remove Drupal's error and exception handlers; they rely on a working
   // service container and other subsystems and will only cause a fatal error
   // that hides the actual error.
   restore_error_handler();
   restore_exception_handler();
 
-  // drupal_bootstrap(DRUPAL_BOOTSTRAP_KERNEL) will build a new kernel. This
-  // comes before DRUPAL_BOOTSTRAP_PAGE_CACHE.
+  // Force kernel to rebuild container.
   PhpStorageFactory::get('service_container')->deleteAll();
   PhpStorageFactory::get('twig')->deleteAll();
 
-  // Disable the page cache.
-  drupal_page_is_cacheable(FALSE);
-
   // Bootstrap up to where caches exist and clear them.
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_PAGE_CACHE);
+  $kernel = new DrupalKernel('prod', $classloader);
+  $kernel->prepareLegacyRequest($request);
+
   foreach (Cache::getBins() as $bin) {
     $bin->deleteAll();
   }
 
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
+  // Disable the page cache.
+  drupal_page_is_cacheable(FALSE);
+
   drupal_flush_all_caches();
 
   // Restore Drupal's error and exception handlers.
-  // @see _drupal_bootstrap_configuration()
+  // @see \Drupal\Core\DrupalKernel::boot()
   set_error_handler('_drupal_error_handler');
   set_exception_handler('_drupal_exception_handler');
 }
diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index 4349d2755cf5..49a4d02144ba 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -7,21 +7,27 @@
 
 namespace Drupal\Core;
 
-use Drupal\Core\PhpStorage\PhpStorageFactory;
+use Drupal\Component\Utility\Crypt;
+use Drupal\Component\Utility\Timer;
+use Drupal\Component\Utility\Unicode;
+use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Config\BootstrapConfigStorageFactory;
 use Drupal\Core\Config\NullStorage;
-use Drupal\Core\CoreServiceProvider;
+use Drupal\Core\Database\Database;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\DependencyInjection\ServiceProviderInterface;
 use Drupal\Core\DependencyInjection\YamlFileLoader;
 use Drupal\Core\Extension\ExtensionDiscovery;
 use Drupal\Core\Language\Language;
-use Symfony\Component\Config\Loader\LoaderInterface;
+use Drupal\Core\PhpStorage\PhpStorageFactory;
+use Drupal\Core\Site\Settings;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
 use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
+use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\RequestStack;
 use Symfony\Component\HttpFoundation\Response;
-use Symfony\Component\HttpKernel\HttpKernelInterface;
 use Symfony\Component\HttpKernel\TerminableInterface;
 use Composer\Autoload\ClassLoader;
 
@@ -61,7 +67,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
    *
    * @var bool
    */
-  protected $booted;
+  protected $booted = FALSE;
 
   /**
    * Holds the list of enabled modules.
@@ -107,13 +113,6 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
    */
   protected $allowDumping;
 
-  /**
-   * Whether the container can be loaded.
-   *
-   * @var bool
-   */
-  protected $allowLoading;
-
   /**
    * Whether the container needs to be dumped once booting is complete.
    *
@@ -154,31 +153,189 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
    */
   protected $serviceProviders;
 
+  /**
+   * Whether the request globals have been initialized.
+   *
+   * @var bool
+   */
+  protected static $isRequestInitialized = FALSE;
+
+  /**
+   * Whether the PHP environment has been initialized.
+   *
+   * This legacy phase can only be booted once because it sets session INI
+   * settings. If a session has already been started, re-generating these
+   * settings would break the session.
+   *
+   * @var bool
+   */
+  protected static $isEnvironmentInitialized = FALSE;
+
+  /**
+   * The site directory.
+   *
+   * @var string
+   */
+  protected $sitePath;
+
+  /**
+   * Create a DrupalKernel object from a request.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   * @param \Composer\Autoload\ClassLoader $class_loader
+   *   (optional) The classloader is only used if $storage is not given or
+   *   the load from storage fails and a container rebuild is required. In
+   *   this case, the loaded modules will be registered with this loader in
+   *   order to be able to find the module serviceProviders.
+   * @param string $environment
+   *   String indicating the environment, e.g. 'prod' or 'dev'.
+   * @param bool $allow_dumping
+   *   (optional) FALSE to stop the container from being written to or read
+   *   from disk. Defaults to TRUE.
+   * @return static
+   */
+  public static function createFromRequest(Request $request, ClassLoader $class_loader, $environment, $allow_dumping = TRUE) {
+    // Include our bootstrap file.
+    require_once dirname(dirname(dirname(__DIR__))) . '/includes/bootstrap.inc';
+
+    $kernel = new static($environment, $class_loader, $allow_dumping);
+
+    // Ensure sane php environment variables..
+    static::bootEnvironment();
+
+    // Get our most basic settings setup.
+    $site_path = static::findSitePath($request);
+    $kernel->setSitePath($site_path);
+    Settings::initialize($site_path);
+
+    // Redirect the user to the installation script if Drupal has not been
+    // installed yet (i.e., if no $databases array has been defined in the
+    // settings.php file) and we are not already installing.
+    if (!Database::getConnectionInfo() && !drupal_installation_attempted() && !drupal_is_cli()) {
+      $response = new RedirectResponse($request->getBasePath() . '/core/install.php');
+      $response->prepare($request)->send();
+    }
+
+    return $kernel;
+  }
+
   /**
    * Constructs a DrupalKernel object.
    *
    * @param string $environment
-   *   String indicating the environment, e.g. 'prod' or 'dev'. Used by
-   *   Symfony\Component\HttpKernel\Kernel::__construct(). Drupal does not use
-   *   this value currently. Pass 'prod'.
+   *   String indicating the environment, e.g. 'prod' or 'dev'.
    * @param \Composer\Autoload\ClassLoader $class_loader
-   *   (optional) The classloader is only used if $storage is not given or
+   *   (optional) The class loader is only used if $storage is not given or
    *   the load from storage fails and a container rebuild is required. In
    *   this case, the loaded modules will be registered with this loader in
    *   order to be able to find the module serviceProviders.
    * @param bool $allow_dumping
    *   (optional) FALSE to stop the container from being written to or read
    *   from disk. Defaults to TRUE.
-   * @param bool $allow_loading
-   *   (optional) FALSE to prevent the kernel attempting to read the dependency
-   *   injection container from disk. Defaults to $allow_dumping.
    */
-  public function __construct($environment, ClassLoader $class_loader, $allow_dumping = TRUE, $allow_loading = NULL) {
+  public function __construct($environment, ClassLoader $class_loader, $allow_dumping = TRUE) {
     $this->environment = $environment;
-    $this->booted = FALSE;
     $this->classLoader = $class_loader;
     $this->allowDumping = $allow_dumping;
-    $this->allowLoading = isset($allow_loading) ? $allow_loading : $allow_dumping;
+  }
+
+  /**
+   * Returns the appropriate site directory for a request.
+   *
+   * Once the kernel has been created DrupalKernelInterface::getSitePath() is
+   * preferred since it gets the statically cached result of this method.
+   *
+   * Site directories contain all site specific code. This includes settings.php
+   * for bootstrap level configuration, file configuration stores, public file
+   * storage and site specific modules and themes.
+   *
+   * Finds a matching site directory file by stripping the website's hostname
+   * from left to right and pathname from right to left. By default, the
+   * directory must contain a 'settings.php' file for it to match. If the
+   * parameter $require_settings is set to FALSE, then a directory without a
+   * 'settings.php' file will match as well. The first configuration file found
+   * will be used and the remaining ones will be ignored. If no configuration
+   * file is found, returns a default value 'sites/default'. See
+   * default.settings.php for examples on how the URL is converted to a
+   * directory.
+   *
+   * If a file named sites.php is present in the sites directory, it will be
+   * loaded prior to scanning for directories. That file can define aliases in
+   * an associative array named $sites. The array is written in the format
+   * '<port>.<domain>.<path>' => 'directory'. As an example, to create a
+   * directory alias for http://www.drupal.org:8080/mysite/test whose
+   * configuration file is in sites/example.com, the array should be defined as:
+   * @code
+   * $sites = array(
+   *   '8080.www.drupal.org.mysite.test' => 'example.com',
+   * );
+   * @endcode
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   * @param bool $require_settings
+   *   Only directories with an existing settings.php file will be recognized.
+   *   Defaults to TRUE. During initial installation, this is set to FALSE so
+   *   that Drupal can detect a matching directory, then create a new
+   *   settings.php file in it.
+   *
+   * @return string
+   *   The path of the matching directory.
+   *
+   * @see \Drupal\Core\DrupalKernelInterface::getSitePath()
+   * @see \Drupal\Core\DrupalKernelInterface::setSitePath()
+   * @see default.settings.php
+   * @see example.sites.php
+   */
+  public static function findSitePath(Request $request, $require_settings = TRUE) {
+    // Check for a simpletest override.
+    if ($test_prefix = drupal_valid_test_ua()) {
+      return 'sites/simpletest/' . substr($test_prefix, 10);
+    }
+
+    // Determine whether multi-site functionality is enabled.
+    if (!file_exists(DRUPAL_ROOT . '/sites/sites.php')) {
+      return 'sites/default';
+    }
+
+    // Otherwise, use find the site path using the request.
+    $script_name = $request->server->get('SCRIPT_NAME');
+    if (!$script_name) {
+      $script_name = $request->server->get('SCRIPT_FILENAME');
+    }
+    $http_host = $request->server->get('HTTP_HOST');
+
+    $sites = array();
+    include DRUPAL_ROOT . '/sites/sites.php';
+
+    $uri = explode('/', $script_name);
+    $server = explode('.', implode('.', array_reverse(explode(':', rtrim($http_host, '.')))));
+    for ($i = count($uri) - 1; $i > 0; $i--) {
+      for ($j = count($server); $j > 0; $j--) {
+        $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
+        if (isset($sites[$dir]) && file_exists(DRUPAL_ROOT . '/sites/' . $sites[$dir])) {
+          $dir = $sites[$dir];
+        }
+        if (file_exists(DRUPAL_ROOT . '/sites/' . $dir . '/settings.php') || (!$require_settings && file_exists(DRUPAL_ROOT . '/sites/' . $dir))) {
+          return "sites/$dir";
+        }
+      }
+    }
+    return 'sites/default';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setSitePath($path) {
+    $this->sitePath = $path;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSitePath() {
+    return $this->sitePath;
   }
 
   /**
@@ -186,13 +343,47 @@ public function __construct($environment, ClassLoader $class_loader, $allow_dump
    */
   public function boot() {
     if ($this->booted) {
-      return;
+      return $this;
+    }
+
+    // Start a page timer:
+    Timer::start('page');
+
+    drupal_classloader();
+
+    // Load legacy and other functional code.
+    require_once DRUPAL_ROOT . '/core/includes/common.inc';
+    require_once DRUPAL_ROOT . '/core/includes/database.inc';
+    require_once DRUPAL_ROOT . '/' . Settings::get('path_inc', 'core/includes/path.inc');
+    require_once DRUPAL_ROOT . '/core/includes/module.inc';
+    require_once DRUPAL_ROOT . '/core/includes/theme.inc';
+    require_once DRUPAL_ROOT . '/core/includes/pager.inc';
+    require_once DRUPAL_ROOT . '/' . Settings::get('menu_inc', 'core/includes/menu.inc');
+    require_once DRUPAL_ROOT . '/core/includes/tablesort.inc';
+    require_once DRUPAL_ROOT . '/core/includes/file.inc';
+    require_once DRUPAL_ROOT . '/core/includes/unicode.inc';
+    require_once DRUPAL_ROOT . '/core/includes/form.inc';
+    require_once DRUPAL_ROOT . '/core/includes/mail.inc';
+    require_once DRUPAL_ROOT . '/core/includes/ajax.inc';
+    require_once DRUPAL_ROOT . '/core/includes/errors.inc';
+    require_once DRUPAL_ROOT . '/core/includes/schema.inc';
+    require_once DRUPAL_ROOT . '/core/includes/entity.inc';
+
+    // Ensure that findSitePath is set.
+    if (!$this->sitePath) {
+      throw new \Exception('Kernel does not have site path set before calling boot()');
     }
+    // Intialize the container.
     $this->initializeContainer();
+
+    // Ensure mt_rand() is reseeded to prevent random values from one page load
+    // being exploited to predict random values in subsequent page loads.
+    $seed = unpack("L", Crypt::randomBytes(4));
+    mt_srand($seed[1]);
+
     $this->booted = TRUE;
-    if ($this->containerNeedsDumping && !$this->dumpDrupalContainer($this->container, static::CONTAINER_BASE_CLASS)) {
-      watchdog('DrupalKernel', 'Container cannot be written to disk');
-    }
+
+    return $this;
   }
 
   /**
@@ -204,15 +395,103 @@ public function shutdown() {
     }
     $this->booted = FALSE;
     $this->container = NULL;
+    $this->moduleList = NULL;
+    $this->moduleData = array();
   }
 
   /**
    * {@inheritdoc}
    */
   public function getContainer() {
+    if ($this->containerNeedsDumping && !$this->dumpDrupalContainer($this->container, static::CONTAINER_BASE_CLASS)) {
+      watchdog('DrupalKernel', 'Container cannot be written to disk');
+    }
     return $this->container;
   }
 
+  /**
+   * Helper method that does request related initialization.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   */
+  protected function preHandle(Request $request) {
+    // Load all enabled modules.
+    $this->container->get('module_handler')->loadAll();
+
+    // Initialize legacy request globals.
+    $this->initializeRequestGlobals($request);
+
+    // Initialize cookie globals.
+    $this->initializeCookieGlobals($request);
+
+    // Ensure container has a request scope so we can load file stream wrappers.
+    if (!$this->container->isScopeActive('request')) {
+      // Enter the request scope so that current_user service is available for
+      // locale/translation sake.
+      $this->container->enterScope('request');
+      $this->container->set('request', $request, 'request');
+      $this->container->get('request_stack')->push($request);
+    }
+
+    // Make sure all stream wrappers are registered.
+    file_get_stream_wrappers();
+
+    // Back out scope required to initialize the file stream wrappers.
+    if ($this->container->isScopeActive('request')) {
+      $this->container->leaveScope('request');
+    }
+
+    // Set the allowed protocols once we have the config available.
+    $allowed_protocols = $this->container->get('config.factory')->get('system.filter')->get('protocols');
+    if (!isset($allowed_protocols)) {
+      // \Drupal\Component\Utility\UrlHelper::filterBadProtocol() is called by
+      // the installer and update.php, in which case the configuration may not
+      // exist (yet). Provide a minimal default set of allowed protocols for
+      // these cases.
+      $allowed_protocols = array('http', 'https');
+    }
+    UrlHelper::setAllowedProtocols($allowed_protocols);
+  }
+
+  /**
+   * {@inheritdoc}
+   *
+   * @todo Invoke proper request/response/terminate events.
+   */
+  public function handlePageCache(Request $request) {
+    $this->boot();
+    $this->initializeCookieGlobals($request);
+
+    // Check for a cache mode force from settings.php.
+    if (Settings::get('page_cache_without_database')) {
+      $cache_enabled = TRUE;
+    }
+    else {
+      $config = $this->getContainer()->get('config.factory')->get('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 (!$request->cookies->has(session_name()) && $cache_enabled && drupal_page_is_cacheable()) {
+      // Get the page from the cache.
+      $response = drupal_page_get_cache($request);
+      // If there is a cached page, display it.
+      if ($response) {
+        $response->headers->set('X-Drupal-Cache', 'HIT');
+
+        drupal_serve_page_from_cache($response, $request);
+
+        // We are done.
+        $response->prepare($request);
+        $response->send();
+        exit;
+      }
+    }
+    return $this;
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -237,14 +516,14 @@ public function discoverServiceProviders() {
     $this->classLoaderAddMultiplePsr4($this->getModuleNamespacesPsr4($module_filenames));
 
     // Load each module's serviceProvider class.
-    foreach ($this->moduleList as $module => $weight) {
+    foreach ($module_filenames as $module => $filename) {
       $camelized = ContainerBuilder::camelize($module);
       $name = "{$camelized}ServiceProvider";
       $class = "Drupal\\{$module}\\{$name}";
       if (class_exists($class)) {
         $this->serviceProviderClasses['app'][$module] = $class;
       }
-      $filename = dirname($module_filenames[$module]) . "/$module.services.yml";
+      $filename = dirname($filename) . "/$module.services.yml";
       if (file_exists($filename)) {
         $this->serviceYamls['app'][$module] = $filename;
       }
@@ -261,7 +540,7 @@ public function discoverServiceProviders() {
     if (!empty($GLOBALS['conf']['container_yamls'])) {
       $this->serviceYamls['site'] = $GLOBALS['conf']['container_yamls'];
     }
-    if (file_exists($site_services_yml = conf_path() . '/services.yml')) {
+    if (file_exists($site_services_yml = $this->getSitePath() . '/services.yml')) {
       $this->serviceYamls['site'][] = $site_services_yml;
     }
   }
@@ -289,14 +568,27 @@ public function terminate(Request $request, Response $response) {
   /**
    * {@inheritdoc}
    */
-  public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = TRUE) {
-    if (FALSE === $this->booted) {
-      $this->boot();
-    }
-
+  public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
+    $this->boot();
+    $this->preHandle($request);
     return $this->getHttpKernel()->handle($request, $type, $catch);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function prepareLegacyRequest(Request $request) {
+    $this->boot();
+    $this->preHandle($request);
+    // Enter the request scope so that current_user service is available for
+    // locale/translation sake.
+    $this->container->enterScope('request');
+    $this->container->set('request', $request);
+    $this->container->get('request_stack')->push($request);
+    $this->container->get('router.request_context')->fromRequest($request);
+    return $this;
+  }
+
   /**
    * Returns module data on the filesystem.
    *
@@ -347,17 +639,12 @@ public function updateModules(array $module_list, array $module_filenames = arra
       $this->moduleData[$name] = $extension;
     }
 
-    // This method is called whenever the list of modules changed. Therefore
-    // disable loading of a dumped container from the disk, because it is
-    // guaranteed to be out of date and needs to be rebuilt anyway.
-    $this->allowLoading = FALSE;
-
     // If we haven't yet booted, we don't need to do anything: the new module
     // list will take effect when boot() is called. If we have already booted,
-    // then reboot in order to refresh the serviceProvider list and container.
+    // then rebuild the container in order to refresh the serviceProvider list
+    // and container.
     if ($this->booted) {
-      $this->booted = FALSE;
-      $this->boot();
+      $this->initializeContainer(TRUE);
     }
   }
 
@@ -386,13 +673,17 @@ protected function getKernelParameters() {
 
   /**
    * Initializes the service container.
+   *
+   * @param bool $rebuild
+   *   Force a container rebuild.
+   * @return \Symfony\Component\DependencyInjection\ContainerInterface
    */
-  protected function initializeContainer() {
+  protected function initializeContainer($rebuild = FALSE) {
     $this->containerNeedsDumping = FALSE;
-    $persist = $this->getServicesToPersist();
     // The request service requires custom persisting logic, since it is also
     // potentially scoped.
     $request_scope = FALSE;
+    $request_stack = $request = NULL;
     if (isset($this->container)) {
       if ($this->container->isScopeActive('request')) {
         $request_scope = TRUE;
@@ -400,62 +691,257 @@ protected function initializeContainer() {
       if ($this->container->initialized('request')) {
         $request = $this->container->get('request');
       }
+      if ($this->container->initialized('request_stack')) {
+        $request_stack = $this->container->get('request_stack');
+      }
     }
-    $this->container = NULL;
-    $class = $this->getClassName();
-    $cache_file = $class . '.php';
 
-    if ($this->allowLoading) {
-      // First, try to load.
+    // If the module list hasn't already been set in updateModules and we are
+    // not forcing a rebuild, then try and load the container from the disk.
+    if (empty($this->moduleList) && !$rebuild) {
+      $class = $this->getClassName();
+      $cache_file = $class . '.php';
+
+      // First, try to load from storage.
       if (!class_exists($class, FALSE)) {
         $this->storage()->load($cache_file);
       }
       // If the load succeeded or the class already existed, use it.
       if (class_exists($class, FALSE)) {
         $fully_qualified_class_name = '\\' . $class;
-        $this->container = new $fully_qualified_class_name;
-        $this->persistServices($persist);
+        $container = new $fully_qualified_class_name;
       }
     }
-    if (isset($this->container)) {
-      // All namespaces must be registered before we attempt to use any service
-      // from the container.
-      $this->classLoaderAddMultiplePsr4($this->container->getParameter('container.namespaces'));
+
+    if (!isset($container)) {
+      $container = $this->compileContainer();
     }
-    else {
-      $this->container = $this->buildContainer();
-      $this->persistServices($persist);
 
-      if ($this->allowDumping) {
-        $this->containerNeedsDumping = TRUE;
+    $this->attachSynthetic($container, $request, $request_stack, $request_scope);
+
+    $this->container = $container;
+    \Drupal::setContainer($this->container);
+    return $this->container;
+  }
+
+  /**
+   * Setup a consistent PHP environment.
+   *
+   * This method sets PHP environment options we want to be sure are set
+   * correctly for security or just saneness.
+   */
+  public static function bootEnvironment() {
+    if (static::$isEnvironmentInitialized) {
+      return;
+    }
+
+    // Enforce E_STRICT, but allow users to set levels not part of E_STRICT.
+    error_reporting(E_STRICT | E_ALL);
+
+    // Override PHP settings required for Drupal to work properly.
+    // sites/default/default.settings.php contains more runtime settings.
+    // The .htaccess file contains settings that cannot be changed at runtime.
+
+    // Use session cookies, not transparent sessions that puts the session id in
+    // the query string.
+    ini_set('session.use_cookies', '1');
+    ini_set('session.use_only_cookies', '1');
+    ini_set('session.use_trans_sid', '0');
+    // Don't send HTTP headers using PHP's session handler.
+    // Send an empty string to disable the cache limiter.
+    ini_set('session.cache_limiter', '');
+    // Use httponly session cookies.
+    ini_set('session.cookie_httponly', '1');
+
+    // Set sane locale settings, to ensure consistent string, dates, times and
+    // numbers handling.
+    setlocale(LC_ALL, 'C');
+
+    // Detect string handling method.
+    Unicode::check();
+
+    // Indicate that code is operating in a test child site.
+    if (!defined('DRUPAL_TEST_IN_CHILD_SITE')) {
+      if ($test_prefix = drupal_valid_test_ua()) {
+        // Only code that interfaces directly with tests should rely on this
+        // constant; e.g., the error/exception handler conditionally adds further
+        // error information into HTTP response headers that are consumed by
+        // Simpletest's internal browser.
+        define('DRUPAL_TEST_IN_CHILD_SITE', TRUE);
+
+        // Log fatal errors to the test site directory.
+        ini_set('log_errors', 1);
+        ini_set('error_log', DRUPAL_ROOT . '/sites/simpletest/' . substr($test_prefix, 10) . '/error.log');
+      }
+      else {
+        // Ensure that no other code defines this.
+        define('DRUPAL_TEST_IN_CHILD_SITE', FALSE);
       }
     }
 
-    $this->container->set('kernel', $this);
+    // Set the Drupal custom error handler.
+    set_error_handler('_drupal_error_handler');
+    set_exception_handler('_drupal_exception_handler');
 
-    // Set the class loader which was registered as a synthetic service.
-    $this->container->set('class_loader', $this->classLoader);
-    // If we have a request set it back to the new container.
-    if ($request_scope) {
-      $this->container->enterScope('request');
+    static::$isEnvironmentInitialized = TRUE;
+  }
+
+  /**
+   * Bootstraps the legacy global request variables.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   *
+   * @todo D8: Eliminate this entirely in favor of Request object.
+   */
+  protected function initializeRequestGlobals(Request $request) {
+    // Provided by settings.php.
+    global $base_url;
+    // Set and derived from $base_url by this function.
+    global $base_path, $base_root, $script_path;
+    global $base_secure_url, $base_insecure_url;
+
+    // @todo Refactor with the Symfony Request object.
+    _current_path(request_path());
+
+    if (isset($base_url)) {
+      // Parse fixed base URL from settings.php.
+      $parts = parse_url($base_url);
+      if (!isset($parts['path'])) {
+        $parts['path'] = '';
+      }
+      $base_path = $parts['path'] . '/';
+      // Build $base_root (everything until first slash after "scheme://").
+      $base_root = substr($base_url, 0, strlen($base_url) - strlen($parts['path']));
     }
-    if (isset($request)) {
-      $this->container->set('request', $request);
+    else {
+      // Create base URL.
+      $http_protocol = $request->isSecure() ? 'https' : 'http';
+      $base_root = $http_protocol . '://' . $request->server->get('HTTP_HOST');
+
+      $base_url = $base_root;
+
+      // For a request URI of '/index.php/foo', $_SERVER['SCRIPT_NAME'] is
+      // '/index.php', whereas $_SERVER['PHP_SELF'] is '/index.php/foo'.
+      if ($dir = rtrim(dirname($request->server->get('SCRIPT_NAME')), '\/')) {
+        // Remove "core" directory if present, allowing install.php, update.php,
+        // and others to auto-detect a base path.
+        $core_position = strrpos($dir, '/core');
+        if ($core_position !== FALSE && strlen($dir) - 5 == $core_position) {
+          $base_path = substr($dir, 0, $core_position);
+        }
+        else {
+          $base_path = $dir;
+        }
+        $base_url .= $base_path;
+        $base_path .= '/';
+      }
+      else {
+        $base_path = '/';
+      }
     }
-    \Drupal::setContainer($this->container);
+    $base_secure_url = str_replace('http://', 'https://', $base_url);
+    $base_insecure_url = str_replace('https://', 'http://', $base_url);
+
+    // Determine the path of the script relative to the base path, and add a
+    // trailing slash. This is needed for creating URLs to Drupal pages.
+    if (!isset($script_path)) {
+      $script_path = '';
+      // We don't expect scripts outside of the base path, but sanity check
+      // anyway.
+      if (strpos($request->server->get('SCRIPT_NAME'), $base_path) === 0) {
+        $script_path = substr($request->server->get('SCRIPT_NAME'), strlen($base_path)) . '/';
+        // If the request URI does not contain the script name, then clean URLs
+        // are in effect and the script path can be similarly dropped from URL
+        // generation. For servers that don't provide $_SERVER['REQUEST_URI'],
+        // we do not know the actual URI requested by the client, and
+        // request_uri() returns a URI with the script name, resulting in
+        // non-clean URLs unless
+        // there's other code that intervenes.
+        if (strpos(request_uri(TRUE) . '/', $base_path . $script_path) !== 0) {
+          $script_path = '';
+        }
+        // @todo Temporary BC for install.php, update.php, and other scripts.
+        //   - http://drupal.org/node/1547184
+        //   - http://drupal.org/node/1546082
+        if ($script_path !== 'index.php/') {
+          $script_path = '';
+        }
+      }
+    }
+
+  }
+
+  /**
+   * Initialize cookie settings.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   *
+   * @todo D8: Eliminate this entirely in favor of a session object.
+   */
+  protected function initializeCookieGlobals(Request $request) {
+    // If we do this more then once per page request we are likely to cause
+    // errors.
+    if (static::$isRequestInitialized) {
+      return;
+    }
+    global $cookie_domain;
+
+    if ($cookie_domain) {
+      // If the user specifies the cookie domain, also use it for session name.
+      $session_name = $cookie_domain;
+    }
+    else {
+      // Otherwise use $base_url as session name, without the protocol
+      // to use the same session identifiers across HTTP and HTTPS.
+      $session_name = $request->getHost() . $request->getBasePath();
+      // Replace "core" out of session_name so core scripts redirect properly,
+      // specifically install.php and update.php.
+      $session_name = preg_replace('/\/core$/', '', $session_name);
+      // HTTP_HOST can be modified by a visitor, but has been sanitized already
+      // in DrupalKernel::bootEnvironment().
+      if ($cookie_domain = $request->server->get('HTTP_HOST')) {
+        // Strip leading periods, www., and port numbers from cookie domain.
+        $cookie_domain = ltrim($cookie_domain, '.');
+        if (strpos($cookie_domain, 'www.') === 0) {
+          $cookie_domain = substr($cookie_domain, 4);
+        }
+        $cookie_domain = explode(':', $cookie_domain);
+        $cookie_domain = '.' . $cookie_domain[0];
+      }
+    }
+    // Per RFC 2109, cookie domains must contain at least one dot other than the
+    // first. For hosts such as 'localhost' or IP Addresses we don't set a
+    // cookie domain.
+    if (count(explode('.', $cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $cookie_domain))) {
+      ini_set('session.cookie_domain', $cookie_domain);
+    }
+    // To prevent session cookies from being hijacked, a user can configure the
+    // SSL version of their website to only transfer session cookies via SSL by
+    // using PHP's session.cookie_secure setting. The browser will then use two
+    // separate session cookies for the HTTPS and HTTP versions of the site. So
+    // we must use different session identifiers for HTTPS and HTTP to prevent a
+    // cookie collision.
+    if ($request->isSecure()) {
+      ini_set('session.cookie_secure', TRUE);
+    }
+    $prefix = ini_get('session.cookie_secure') ? 'SSESS' : 'SESS';
+
+    session_name($prefix . substr(hash('sha256', $session_name), 0, 32));
+
+    static::$isRequestInitialized = TRUE;
   }
 
   /**
    * Returns service instances to persist from an old container to a new one.
    */
-  protected function getServicesToPersist() {
+  protected function getServicesToPersist(ContainerInterface $container) {
     $persist = array();
-    if (isset($this->container)) {
-      foreach ($this->container->getParameter('persistIds') as $id) {
-        // It's pointless to persist services not yet initialized.
-        if ($this->container->initialized($id)) {
-          $persist[$id] = $this->container->get($id);
-        }
+    foreach ($container->getParameter('persistIds') as $id) {
+      // It's pointless to persist services not yet initialized.
+      if ($container->initialized($id)) {
+        $persist[$id] = $container->get($id);
       }
     }
     return $persist;
@@ -464,22 +950,82 @@ protected function getServicesToPersist() {
   /**
    * Moves persistent service instances into a new container.
    */
-  protected function persistServices(array $persist) {
+  protected function persistServices(ContainerInterface $container, array $persist) {
     foreach ($persist as $id => $object) {
       // Do not override services already set() on the new container, for
       // example 'service_container'.
-      if (!$this->container->initialized($id)) {
-        $this->container->set($id, $object);
+      if (!$container->initialized($id)) {
+        $container->set($id, $object);
       }
     }
   }
 
   /**
-   * Builds the service container.
+   * Force a container rebuild.
+   *
+   * @return \Symfony\Component\DependencyInjection\ContainerInterface
+   */
+  public function rebuildContainer() {
+    // Empty module properties and for them to be reloaded from scratch.
+    $this->moduleList = NULL;
+    $this->moduleData = array();
+    return $this->initializeContainer(TRUE);
+  }
+
+  /**
+   * Attach synthetic values on to kernel.
+   *
+   * @param ContainerInterface $container
+   *   Container object
+   * @param Request $request
+   *   Request object.
+   * @param RequestStack $request_stack
+   *   Request stack.
+   * @param null $request_scope
+   * @return ContainerInterface
+   */
+  protected function attachSynthetic(ContainerInterface $container, Request $request = NULL, RequestStack $request_stack = NULL, $request_scope = NULL) {
+
+    $persist = array();
+    if (isset($this->container)) {
+      $persist = $this->getServicesToPersist($this->container);
+    }
+    $this->persistServices($container, $persist);
+
+    // All namespaces must be registered before we attempt to use any service
+    // from the container.
+    $this->classLoaderAddMultiplePsr4($container->getParameter('container.namespaces'));
+
+    $container->set('kernel', $this);
+
+    // Set the class loader which was registered as a synthetic service.
+    $container->set('class_loader', $this->classLoader);
+    // If we have a request set it back to the new container.
+    if ($request_scope) {
+      $container->enterScope('request');
+    }
+    if (isset($request)) {
+      $container->set('request', $request);
+    }
+    if (isset($request_stack)) {
+      $container->set('request_stack', $request_stack);
+    }
+    return $container;
+  }
+
+  /**
+   * Compiles a new service container.
    *
    * @return ContainerBuilder The compiled service container
    */
-  protected function buildContainer() {
+  protected function compileContainer() {
+    // We are forcing a container build so it is reasonable to assume that the
+    // calling method knows something about the system has changed requiring the
+    // container to be dumped to the filesystem.
+    if ($this->allowDumping) {
+      $this->containerNeedsDumping = TRUE;
+    }
+
     $this->initializeServiceProviders();
     $container = $this->getContainerBuilder();
     $container->set('kernel', $this);
@@ -610,7 +1156,7 @@ protected function dumpDrupalContainer(ContainerBuilder $container, $baseClass)
   /**
    * Gets a http kernel from the container
    *
-   * @return HttpKernel
+   * @return \Symfony\Component\HttpKernel\HttpKernelInterface
    */
   protected function getHttpKernel() {
     return $this->container->get('http_kernel');
diff --git a/core/lib/Drupal/Core/DrupalKernelInterface.php b/core/lib/Drupal/Core/DrupalKernelInterface.php
index 1e2ed070fddc..08d007c49135 100644
--- a/core/lib/Drupal/Core/DrupalKernelInterface.php
+++ b/core/lib/Drupal/Core/DrupalKernelInterface.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core;
 
 use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpFoundation\Request;
 
 /**
  * The interface for DrupalKernel, the core of Drupal.
@@ -19,6 +20,8 @@ interface DrupalKernelInterface extends HttpKernelInterface {
 
   /**
    * Boots the current kernel.
+   *
+   * @return $this
    */
   public function boot();
 
@@ -53,6 +56,22 @@ public function getServiceProviders($origin);
    */
   public function getContainer();
 
+  /**
+   * Set the current site path.
+   *
+   * @param $path
+   *   The current site path.
+   */
+  public function setSitePath($path);
+
+  /**
+   * Get the site path.
+   *
+   * @return string
+   *   The current site path.
+   */
+  public function getSitePath();
+
   /**
    * Updates the kernel's list of modules to the new list.
    *
@@ -65,4 +84,28 @@ public function getContainer();
    *   List of module filenames, keyed by module name.
    */
   public function updateModules(array $module_list, array $module_filenames = array());
+
+  /**
+   * Attempts to serve a page from the cache.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   *
+   * @return $this
+   */
+  public function handlePageCache(Request $request);
+
+  /**
+   * Prepare the kernel for handling a request without handling the request.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   *
+   * @return $this
+   *
+   * @deprecated 8.x
+   *   Only used by legacy front-controller scripts.
+   */
+  public function prepareLegacyRequest(Request $request);
+
 }
diff --git a/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php
deleted file mode 100644
index aa7774e90ffa..000000000000
--- a/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\Core\EventSubscriber\LegacyRequestSubscriber.
- */
-
-namespace Drupal\Core\EventSubscriber;
-
-use Symfony\Component\HttpKernel\HttpKernelInterface;
-use Symfony\Component\HttpKernel\KernelEvents;
-use Symfony\Component\HttpKernel\Event\GetResponseEvent;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-/**
- * KernelEvents::REQUEST event subscriber to initialize theme and modules.
- *
- * @todo Remove this subscriber when all of the code in it has been refactored.
- */
-class LegacyRequestSubscriber implements EventSubscriberInterface {
-
-  /**
-   * Initializes the rest of the legacy Drupal subsystems.
-   *
-   * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event
-   *   The Event to process.
-   */
-  public function onKernelRequestLegacy(GetResponseEvent $event) {
-    if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
-      // Tell Drupal it is now fully bootstrapped (for the benefit of code that
-      // calls drupal_get_bootstrap_phase()), but without having
-      // _drupal_bootstrap_full() do anything, since we've already done the
-      // equivalent above and in earlier listeners.
-      _drupal_bootstrap_full(TRUE);
-      drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
-    }
-  }
-
-  /**
-   * Initializes the theme system after the routing system.
-   *
-   * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
-   *   The Event to process.
-   */
-  public function onKernelRequestLegacyAfterRouting(GetResponseEvent $event) {
-    if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
-      drupal_theme_initialize();
-    }
-  }
-
-  /**
-   * 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('onKernelRequestLegacy', 90);
-    // Initialize the theme system after the routing system.
-    $events[KernelEvents::REQUEST][] = array('onKernelRequestLegacyAfterRouting', 30);
-
-    return $events;
-  }
-}
diff --git a/core/lib/Drupal/Core/EventSubscriber/ThemeNegotiatorRequestSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ThemeNegotiatorRequestSubscriber.php
new file mode 100644
index 000000000000..322981d68d58
--- /dev/null
+++ b/core/lib/Drupal/Core/EventSubscriber/ThemeNegotiatorRequestSubscriber.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\EventSubscriber\ThemeNegotiatorRequestSubscriber.
+ */
+
+namespace Drupal\Core\EventSubscriber;
+
+use Drupal\Core\Routing\RouteMatch;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Initializes the theme for the current request.
+ */
+class ThemeNegotiatorRequestSubscriber implements EventSubscriberInterface {
+
+  /**
+   * Initializes the theme system after the routing system.
+   *
+   * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
+   *   The Event to process.
+   */
+  public function onKernelRequestThemeNegotiator(GetResponseEvent $event) {
+    if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
+      if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
+        // @todo Refactor drupal_theme_initialize() into a request subscriber.
+        // @see https://drupal.org/node/2228093
+        drupal_theme_initialize(RouteMatch::createFromRequest($event->getRequest()));
+      }
+    }
+  }
+
+  /**
+   * Registers the methods in this class that should be listeners.
+   *
+   * @return array
+   *   An array of event listener definitions.
+   */
+  public static function getSubscribedEvents() {
+    $events[KernelEvents::REQUEST][] = array('onKernelRequestThemeNegotiator', 29);
+    return $events;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Installer/InstallerKernel.php b/core/lib/Drupal/Core/Installer/InstallerKernel.php
new file mode 100644
index 000000000000..dcac1b556e3b
--- /dev/null
+++ b/core/lib/Drupal/Core/Installer/InstallerKernel.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Installer\InstallerKernel.
+ */
+
+namespace Drupal\Core\Installer;
+
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\DrupalKernel;
+use Drupal\Core\Site\Settings;
+use Symfony\Component\DependencyInjection\Exception\RuntimeException;
+
+/**
+ * Extend DrupalKernel to handle force some kernel behaviors.
+ */
+class InstallerKernel extends DrupalKernel {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function initializeContainer($rebuild = TRUE) {
+    $container = parent::initializeContainer($rebuild);
+    return $container;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function dumpDrupalContainer(ContainerBuilder $container, $baseClass) {
+    if (Settings::get('hash_salt')) {
+      return parent::dumpDrupalContainer($container, $baseClass);
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/Site/Settings.php b/core/lib/Drupal/Core/Site/Settings.php
index 3ac0f03328cf..e2d57d2b6e97 100644
--- a/core/lib/Drupal/Core/Site/Settings.php
+++ b/core/lib/Drupal/Core/Site/Settings.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Core\Site;
 
+use Drupal\Core\Database\Database;
+
 /**
  * Read only settings that are initialized with the class.
  *
@@ -80,6 +82,31 @@ public static function getAll() {
     return self::$instance->storage;
   }
 
+  /**
+   * Bootstraps settings.php and the Settings singleton.
+   *
+   * @param string $site_path
+   *   The current site path.
+   */
+  public static function initialize($site_path) {
+    // Export these settings.php variables to the global namespace.
+    global $base_url, $cookie_domain, $config_directories, $config;
+    $settings = array();
+    $config = array();
+    $databases = array();
+
+    // Make conf_path() available as local variable in settings.php.
+    if (is_readable(DRUPAL_ROOT . '/' . $site_path . '/settings.php')) {
+      require DRUPAL_ROOT . '/' . $site_path . '/settings.php';
+    }
+
+    // Initialize Database.
+    Database::setMultipleConnectionInfo($databases);
+
+    // Initialize Settings.
+    new Settings($settings);
+  }
+
   /**
    * Gets a salt useful for hardening against SQL injection.
    *
diff --git a/core/lib/Drupal/Core/Test/TestKernel.php b/core/lib/Drupal/Core/Test/TestKernel.php
index 12938ce73685..6144dbf7cc55 100644
--- a/core/lib/Drupal/Core/Test/TestKernel.php
+++ b/core/lib/Drupal/Core/Test/TestKernel.php
@@ -8,46 +8,28 @@
 namespace Drupal\Core\Test;
 
 use Drupal\Core\DrupalKernel;
-use Drupal\Core\Extension\Extension;
-use Drupal\Core\Installer\InstallerServiceProvider;
+use Symfony\Component\HttpFoundation\Request;
 use Composer\Autoload\ClassLoader;
 
 /**
- * Kernel for run-tests.sh.
+ * Kernel to mock requests to test simpletest.
  */
 class TestKernel extends DrupalKernel {
 
-  /**
-   * Constructs a TestKernel.
-   *
-   * @param \Composer\Autoload\ClassLoader $class_loader
-   *   The classloader.
-   */
-  public function __construct(ClassLoader $class_loader) {
-    parent::__construct('test_runner', $class_loader, FALSE);
-
-    // Prime the module list and corresponding Extension objects.
-    // @todo Remove System module. Needed because \Drupal\Core\Datetime\Date
-    //   has a (needless) dependency on the 'date_format' entity, so calls to
-    //   format_date()/format_interval() cause a plugin not found exception.
-    $this->moduleList = array(
-      'system' => 0,
-      'simpletest' => 0,
-    );
-    $this->moduleData = array(
-      'system' => new Extension('module', 'core/modules/system/system.info.yml', 'system.module'),
-      'simpletest' => new Extension('module', 'core/modules/simpletest/simpletest.info.yml', 'simpletest.module'),
-    );
-  }
-
   /**
    * {@inheritdoc}
    */
-  public function discoverServiceProviders() {
-    parent::discoverServiceProviders();
-    // The test runner does not require an installed Drupal site to exist.
-    // Therefore, its environment is identical to that of the early installer.
-    $this->serviceProviderClasses['app']['Test'] = 'Drupal\Core\Installer\InstallerServiceProvider';
+  public static function createFromRequest(Request $request, ClassLoader $class_loader, $environment, $allow_dumping = TRUE) {
+    // Include our bootstrap file.
+    require_once __DIR__ . '/../../../../includes/bootstrap.inc';
+
+    // Exit if we should be in a test environment but aren't.
+    if (!drupal_valid_test_ua()) {
+      header($request->server->get('SERVER_PROTOCOL') . ' 403 Forbidden');
+      exit;
+    }
+
+    return parent::createFromRequest($request, $class_loader, $environment, $allow_dumping);
   }
 
 }
diff --git a/core/lib/Drupal/Core/Test/TestRunnerKernel.php b/core/lib/Drupal/Core/Test/TestRunnerKernel.php
new file mode 100644
index 000000000000..7b04673c3fd5
--- /dev/null
+++ b/core/lib/Drupal/Core/Test/TestRunnerKernel.php
@@ -0,0 +1,85 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Test\TestRunnerKernel.
+ */
+
+namespace Drupal\Core\Test;
+
+use Drupal\Core\DrupalKernel;
+use Drupal\Core\Extension\Extension;
+use Drupal\Core\Installer\InstallerServiceProvider;
+use Composer\Autoload\ClassLoader;
+use Drupal\Core\Site\Settings;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Kernel for run-tests.sh.
+ */
+class TestRunnerKernel extends DrupalKernel {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function createFromRequest(Request $request, ClassLoader $class_loader, $environment = 'test_runner', $allow_dumping = TRUE) {
+    return parent::createFromRequest($request, $class_loader, $environment);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct($environment, ClassLoader $class_loader) {
+    parent::__construct($environment, $class_loader, FALSE);
+
+    // Prime the module list and corresponding Extension objects.
+    // @todo Remove System module. Needed because \Drupal\Core\Datetime\Date
+    //   has a (needless) dependency on the 'date_format' entity, so calls to
+    //   format_date()/format_interval() cause a plugin not found exception.
+    $this->moduleList = array(
+      'system' => 0,
+      'simpletest' => 0,
+    );
+    $this->moduleData = array(
+      'system' => new Extension('module', 'core/modules/system/system.info.yml', 'system.module'),
+      'simpletest' => new Extension('module', 'core/modules/simpletest/simpletest.info.yml', 'simpletest.module'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function boot() {
+    // Ensure that required Settings exist.
+    if (!Settings::getAll()) {
+      new Settings(array(
+        'hash_salt' => 'run-tests',
+      ));
+    }
+
+    // Remove Drupal's error/exception handlers; they are designed for HTML
+    // and there is no storage nor a (watchdog) logger here.
+    restore_error_handler();
+    restore_exception_handler();
+
+    // In addition, ensure that PHP errors are not hidden away in logs.
+    ini_set('display_errors', TRUE);
+
+    parent::boot();
+
+    $this->getContainer()->get('module_handler')->loadAll();
+
+    simpletest_classloader_register();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function discoverServiceProviders() {
+    parent::discoverServiceProviders();
+    // The test runner does not require an installed Drupal site to exist.
+    // Therefore, its environment is identical to that of the early installer.
+    $this->serviceProviderClasses['app']['Test'] = 'Drupal\Core\Installer\InstallerServiceProvider';
+  }
+
+}
diff --git a/core/modules/ckeditor/src/Tests/CKEditorAdminTest.php b/core/modules/ckeditor/src/Tests/CKEditorAdminTest.php
index 0d2d5b2d5b0d..d3bf2790570d 100644
--- a/core/modules/ckeditor/src/Tests/CKEditorAdminTest.php
+++ b/core/modules/ckeditor/src/Tests/CKEditorAdminTest.php
@@ -167,7 +167,7 @@ function testExistingFormat() {
     // Now enable the ckeditor_test module, which provides one configurable
     // CKEditor plugin — this should not affect the Editor config entity.
     \Drupal::moduleHandler()->install(array('ckeditor_test'));
-    $this->rebuildContainer();
+    $this->resetAll();
     $this->container->get('plugin.manager.ckeditor.plugin')->clearCachedDefinitions();
     $this->drupalGet('admin/config/content/formats/manage/filtered_html');
     $ultra_llama_mode_checkbox = $this->xpath('//input[@type="checkbox" and @name="editor[settings][plugins][llama_contextual_and_button][ultra_llama_mode]" and not(@checked)]');
diff --git a/core/modules/ckeditor/src/Tests/CKEditorLoadingTest.php b/core/modules/ckeditor/src/Tests/CKEditorLoadingTest.php
index e4231a3e515a..458b47f99801 100644
--- a/core/modules/ckeditor/src/Tests/CKEditorLoadingTest.php
+++ b/core/modules/ckeditor/src/Tests/CKEditorLoadingTest.php
@@ -122,6 +122,7 @@ function testLoading() {
     // configuration also results in modified CKEditor configuration, so we
     // don't test that here.
     \Drupal::moduleHandler()->install(array('ckeditor_test'));
+    $this->resetAll();
     $this->container->get('plugin.manager.ckeditor.plugin')->clearCachedDefinitions();
     $editor_settings = $editor->getSettings();
     $editor_settings['toolbar']['buttons'][0][] = 'Llama';
@@ -129,12 +130,14 @@ function testLoading() {
     $editor->save();
     $this->drupalGet('node/add/article');
     list($settings, $editor_settings_present, $editor_js_present, $body, $format_selector) = $this->getThingsToCheck();
-    $expected = array('formats' => array('filtered_html' => array(
-      'format' => 'filtered_html',
-      'editor' => 'ckeditor',
-      'editorSettings' => $ckeditor_plugin->getJSSettings($editor),
-      'editorSupportsContentFiltering' => TRUE,
-      'isXssSafe' => FALSE,
+    $expected = array(
+      'formats' => array(
+        'filtered_html' => array(
+          'format' => 'filtered_html',
+          'editor' => 'ckeditor',
+          'editorSettings' => $ckeditor_plugin->getJSSettings($editor),
+          'editorSupportsContentFiltering' => TRUE,
+          'isXssSafe' => FALSE,
     )));
     $this->assertTrue($editor_settings_present, "Text Editor module's JavaScript settings are on the page.");
     $this->assertIdentical($expected, $settings['editor'], "Text Editor module's JavaScript settings on the page are correct.");
diff --git a/core/modules/dblog/src/Tests/DbLogTest.php b/core/modules/dblog/src/Tests/DbLogTest.php
index a3dcf7da642b..790924d5f753 100644
--- a/core/modules/dblog/src/Tests/DbLogTest.php
+++ b/core/modules/dblog/src/Tests/DbLogTest.php
@@ -138,7 +138,7 @@ private function generateLogEntries($count, $type = 'custom', $severity = WATCHD
       'user'        => $this->big_user,
       'uid'         => $this->big_user->id(),
       'request_uri' => $base_root . request_uri(),
-      'referer'     => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '',
+      'referer'     => \Drupal::request()->server->get('HTTP_REFERER'),
       'ip'          => '127.0.0.1',
       'timestamp'   => REQUEST_TIME,
       );
@@ -433,7 +433,7 @@ protected function testDBLogAddAndClear() {
       'user'        => $this->big_user,
       'uid'         => $this->big_user->id(),
       'request_uri' => $base_root . request_uri(),
-      'referer'     => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '',
+      'referer'     => \Drupal::request()->server->get('HTTP_REFERER'),
       'ip'          => '127.0.0.1',
       'timestamp'   => REQUEST_TIME,
     );
diff --git a/core/modules/field/src/Tests/FieldHelpTest.php b/core/modules/field/src/Tests/FieldHelpTest.php
index 6eb630eb4ee9..437c6567e44d 100644
--- a/core/modules/field/src/Tests/FieldHelpTest.php
+++ b/core/modules/field/src/Tests/FieldHelpTest.php
@@ -56,6 +56,7 @@ public function testFieldHelp() {
 
     // Enable the Options, Email and Field API Test modules.
     \Drupal::moduleHandler()->install(array('options', 'field_test'));
+    $this->resetAll();
     \Drupal::service('plugin.manager.field.widget')->clearCachedDefinitions();
     \Drupal::service('plugin.manager.field.field_type')->clearCachedDefinitions();
 
diff --git a/core/modules/language/src/Tests/LanguageNegotiationInfoTest.php b/core/modules/language/src/Tests/LanguageNegotiationInfoTest.php
index a3245ca1d1cf..81e4dff71efb 100644
--- a/core/modules/language/src/Tests/LanguageNegotiationInfoTest.php
+++ b/core/modules/language/src/Tests/LanguageNegotiationInfoTest.php
@@ -85,7 +85,7 @@ function testInfoAlterations() {
       'language_test.content_language_type' => TRUE,
     ));
     $this->container->get('module_handler')->install(array('language_test'));
-    $this->rebuildContainer();
+    $this->resetAll();
 
     // Check that fixed language types are properly configured without the need
     // of saving the language negotiation settings.
diff --git a/core/modules/simpletest/src/InstallerTestBase.php b/core/modules/simpletest/src/InstallerTestBase.php
index a8305b4fe0a5..6fa42f9fcc57 100644
--- a/core/modules/simpletest/src/InstallerTestBase.php
+++ b/core/modules/simpletest/src/InstallerTestBase.php
@@ -7,7 +7,10 @@
 
 namespace Drupal\simpletest;
 
+use Drupal\Core\DrupalKernel;
 use Drupal\Core\Session\UserSession;
+use Drupal\Core\Site\Settings;
+use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Base class for testing the interactive installer.
@@ -109,7 +112,8 @@ protected function setUp() {
     $this->setUpSite();
 
     // Import new settings.php written by the installer.
-    drupal_settings_initialize();
+    $request = Request::createFromGlobals();
+    Settings::initialize(DrupalKernel::findSitePath($request));
     foreach ($GLOBALS['config_directories'] as $type => $path) {
       $this->configDirectories[$type] = $path;
     }
@@ -121,12 +125,14 @@ protected function setUp() {
     // WebTestBase::tearDown() will delete the entire test site directory.
     // Not using File API; a potential error must trigger a PHP warning.
     chmod(DRUPAL_ROOT . '/' . $this->siteDirectory, 0777);
-
-    $this->rebuildContainer();
+    $this->kernel = DrupalKernel::createFromRequest($request, drupal_classloader(), 'prod', FALSE);
+    $this->kernel->prepareLegacyRequest($request);
+    $this->container = $this->kernel->getContainer();
+    $config = $this->container->get('config.factory');
 
     // Manually configure the test mail collector implementation to prevent
-    // tests from sending out emails and collect them in state instead.
-    \Drupal::config('system.mail')
+    // tests from sending out e-mails and collect them in state instead.
+    $config->get('system.mail')
       ->set('interface.default', 'test_mail_collector')
       ->save();
 
diff --git a/core/modules/simpletest/src/KernelTestBase.php b/core/modules/simpletest/src/KernelTestBase.php
index a695d2333524..65489f85c8ce 100644
--- a/core/modules/simpletest/src/KernelTestBase.php
+++ b/core/modules/simpletest/src/KernelTestBase.php
@@ -13,6 +13,7 @@
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\KeyValueStore\KeyValueMemoryFactory;
 use Drupal\Core\Language\Language;
+use Drupal\Core\Site\Settings;
 use Drupal\Core\Entity\Schema\EntitySchemaProviderInterface;
 use Symfony\Component\DependencyInjection\Reference;
 use Symfony\Component\HttpFoundation\Request;
@@ -144,23 +145,31 @@ protected function setUp() {
     // Create and set new configuration directories.
     $this->prepareConfigDirectories();
 
-    // Build a minimal, partially mocked environment for unit tests.
-    $this->containerBuild(\Drupal::getContainer());
-    // Make sure it survives kernel rebuilds.
+    // Add this test class as a service provider.
+    // @todo Remove the indirection; implement ServiceProviderInterface instead.
     $GLOBALS['conf']['container_service_providers']['TestServiceProvider'] = 'Drupal\simpletest\TestServiceProvider';
 
-    \Drupal::state()->set('system.module.files', $this->moduleFiles);
-    \Drupal::state()->set('system.theme.files', $this->themeFiles);
-
-    // Bootstrap the kernel.
-    // No need to dump it; this test runs in-memory.
-    $this->kernel = new DrupalKernel('unit_testing', drupal_classloader(), FALSE);
+    // Back up settings from TestBase::prepareEnvironment().
+    $settings = Settings::getAll();
+    // Bootstrap a new kernel. Don't use createFromRequest so we don't mess with settings.
+    $this->kernel = new DrupalKernel('testing', drupal_classloader(), FALSE);
+    $request = Request::create('/');
+    $this->kernel->setSitePath(DrupalKernel::findSitePath($request));
     $this->kernel->boot();
 
-    $request = Request::create('/');
+    // Restore and merge settings.
+    // DrupalKernel::boot() initializes new Settings, and the containerBuild()
+    // method sets additional settings.
+    new Settings($settings + Settings::getAll());
+
+    // Set the request scope.
+    $this->container = $this->kernel->getContainer();
     $this->container->set('request', $request);
     $this->container->get('request_stack')->push($request);
 
+    $this->container->get('state')->set('system.module.files', $this->moduleFiles);
+    $this->container->get('state')->set('system.theme.files', $this->themeFiles);
+
     // Create a minimal core.extension configuration object so that the list of
     // enabled modules can be maintained allowing
     // \Drupal\Core\Config\ConfigInstaller::installDefaultConfig() to work.
@@ -427,8 +436,7 @@ protected function enableModules(array $modules) {
     // Ensure isLoaded() is TRUE in order to make _theme() work.
     // Note that the kernel has rebuilt the container; this $module_handler is
     // no longer the $module_handler instance from above.
-    $module_handler = $this->container->get('module_handler');
-    $module_handler->reload();
+    $this->container->get('module_handler')->reload();
     $this->pass(format_string('Enabled modules: %modules.', array(
       '%modules' => implode(', ', $modules),
     )));
diff --git a/core/modules/simpletest/src/TestBase.php b/core/modules/simpletest/src/TestBase.php
index 0987d3d08d0b..fb09a1f22aa5 100644
--- a/core/modules/simpletest/src/TestBase.php
+++ b/core/modules/simpletest/src/TestBase.php
@@ -15,7 +15,6 @@
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\Database\ConnectionNotDefinedException;
 use Drupal\Core\Config\StorageInterface;
-use Drupal\Core\DrupalKernel;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Session\AccountProxy;
 use Drupal\Core\Session\AnonymousUserSession;
@@ -660,7 +659,7 @@ protected function assertIdenticalObject($object1, $object2, $message = '', $gro
    *   TRUE if the assertion succeeded, FALSE otherwise.
    *
    * @see TestBase::prepareEnvironment()
-   * @see _drupal_bootstrap_configuration()
+   * @see \Drupal\Core\DrupalKernel::bootConfiguration()
    */
   protected function assertNoErrorsLogged() {
     // Since PHP only creates the error.log file when an actual error is
diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php
index 740e95246fd9..f0c52571b1aa 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -20,6 +20,7 @@
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Session\AnonymousUserSession;
 use Drupal\Core\Session\UserSession;
+use Drupal\Core\Site\Settings;
 use Drupal\Core\StreamWrapper\PublicStream;
 use Drupal\Core\Datetime\DrupalDateTime;
 use Drupal\block\Entity\Block;
@@ -175,6 +176,8 @@ abstract class WebTestBase extends TestBase {
 
   /**
    * The kernel used in this test.
+   *
+   * @var \Drupal\Core\DrupalKernel
    */
   protected $kernel;
 
@@ -849,7 +852,6 @@ protected function setUp() {
       'required' => TRUE,
     );
     $this->writeSettings($settings);
-
     // Allow for test-specific overrides.
     $settings_testing_file = DRUPAL_ROOT . '/' . $this->originalSite . '/settings.testing.php';
     if (file_exists($settings_testing_file)) {
@@ -857,7 +859,7 @@ protected function setUp() {
       copy($settings_testing_file, $directory . '/settings.testing.php');
       // Add the name of the testing class to settings.php and include the
       // testing specific overrides
-      file_put_contents($directory . '/settings.php', "\n\$test_class = '" . get_class($this) ."';\n" . 'include DRUPAL_ROOT . \'/\' . $conf_path . \'/settings.testing.php\';' ."\n", FILE_APPEND);
+      file_put_contents($directory . '/settings.php', "\n\$test_class = '" . get_class($this) ."';\n" . 'include DRUPAL_ROOT . \'/\' . $site_path . \'/settings.testing.php\';' ."\n", FILE_APPEND);
     }
     $settings_services_file = DRUPAL_ROOT . '/' . $this->originalSite . '/testing.services.yml';
     if (file_exists($settings_services_file)) {
@@ -868,14 +870,14 @@ protected function setUp() {
     // Since Drupal is bootstrapped already, install_begin_request() will not
     // bootstrap into DRUPAL_BOOTSTRAP_CONFIGURATION (again). Hence, we have to
     // reload the newly written custom settings.php manually.
-    drupal_settings_initialize();
+    Settings::initialize($directory);
 
     // Execute the non-interactive installer.
     require_once DRUPAL_ROOT . '/core/includes/install.core.inc';
     install_drupal($parameters);
 
     // Import new settings.php written by the installer.
-    drupal_settings_initialize();
+    Settings::initialize($directory);
     foreach ($GLOBALS['config_directories'] as $type => $path) {
       $this->configDirectories[$type] = $path;
     }
@@ -888,7 +890,13 @@ protected function setUp() {
     // Not using File API; a potential error must trigger a PHP warning.
     chmod($directory, 0777);
 
-    $this->rebuildContainer();
+    $request = \Drupal::request();
+    $this->kernel = DrupalKernel::createFromRequest($request, drupal_classloader(), 'prod', TRUE);
+    // Force the container to be built from scratch instead of loaded from the
+    // disk. This forces us to not accidently load the parent site.
+    $container = $this->kernel->rebuildContainer();
+    $this->kernel->prepareLegacyRequest($request);
+    $config = $container->get('config.factory');
 
     // Manually create and configure private and temporary files directories.
     // While these could be preset/enforced in settings.php like the public
@@ -896,7 +904,7 @@ protected function setUp() {
     // UI. If declared in settings.php, they would no longer be configurable.
     file_prepare_directory($this->private_files_directory, FILE_CREATE_DIRECTORY);
     file_prepare_directory($this->temp_files_directory, FILE_CREATE_DIRECTORY);
-    \Drupal::config('system.file')
+    $config->get('system.file')
       ->set('path.private', $this->private_files_directory)
       ->set('path.temporary', $this->temp_files_directory)
       ->save();
@@ -905,7 +913,7 @@ protected function setUp() {
     // tests from sending out emails and collect them in state instead.
     // While this should be enforced via settings.php prior to installation,
     // some tests expect to be able to test mail system implementations.
-    \Drupal::config('system.mail')
+    $config->get('system.mail')
       ->set('interface.default', 'test_mail_collector')
       ->save();
 
@@ -913,10 +921,10 @@ protected function setUp() {
     // environment optimizations for all tests to avoid needless overhead and
     // ensure a sane default experience for test authors.
     // @see https://drupal.org/node/2259167
-    \Drupal::config('system.logging')
+    $config->get('system.logging')
       ->set('error_level', 'verbose')
       ->save();
-    \Drupal::config('system.performance')
+    $config->get('system.performance')
       ->set('css.preprocess', FALSE)
       ->set('js.preprocess', FALSE)
       ->save();
@@ -936,22 +944,20 @@ protected function setUp() {
     }
     if ($modules) {
       $modules = array_unique($modules);
-      $success = \Drupal::moduleHandler()->install($modules, TRUE);
+      $success = $container->get('module_handler')->install($modules, TRUE);
       $this->assertTrue($success, String::format('Enabled modules: %modules', array('%modules' => implode(', ', $modules))));
       $this->rebuildContainer();
     }
 
-    // Like DRUPAL_BOOTSTRAP_CONFIGURATION above, any further bootstrap phases
-    // are not re-executed by the installer, as Drupal is bootstrapped already.
     // Reset/rebuild all data structures after enabling the modules, primarily
     // to synchronize all data structures and caches between the test runner and
     // the child site.
     // Affects e.g. file_get_stream_wrappers().
-    // @see _drupal_bootstrap_code()
-    // @see _drupal_bootstrap_full()
+    // @see \Drupal\Core\DrupalKernel::bootCode()
     // @todo Test-specific setUp() methods may set up further fixtures; find a
     //   way to execute this after setUp() is done, or to eliminate it entirely.
     $this->resetAll();
+    $this->kernel->prepareLegacyRequest($request);
 
     // Temporary fix so that when running from run-tests.sh we don't get an
     // empty current path which would indicate we're on the home page.
@@ -1101,34 +1107,16 @@ protected function writeCustomTranslations() {
    * @see TestBase::prepareEnvironment()
    * @see TestBase::restoreEnvironment()
    *
-   * @todo Fix http://drupal.org/node/1708692 so that module enable/disable
+   * @todo Fix https://www.drupal.org/node/2021959 so that module enable/disable
    *   changes are immediately reflected in \Drupal::getContainer(). Until then,
    *   tests can invoke this workaround when requiring services from newly
    *   enabled modules to be immediately available in the same request.
    */
-  protected function rebuildContainer($environment = 'prod') {
-    // Preserve the request object after the container rebuild.
+  protected function rebuildContainer() {
+    // Maintain the current global request object.
     $request = \Drupal::request();
-    // When called from InstallerTestBase, the current container is the minimal
-    // container from TestBase::prepareEnvironment(), which does not contain a
-    // request stack.
-    if (\Drupal::getContainer()->initialized('request_stack')) {
-      $request_stack = \Drupal::service('request_stack');
-    }
-
-    $this->kernel = new DrupalKernel($environment, drupal_classloader(), TRUE, FALSE);
-    $this->kernel->boot();
-    // DrupalKernel replaces the container in \Drupal::getContainer() with a
-    // different object, so we need to replace the instance on this test class.
-    $this->container = \Drupal::getContainer();
-    // The current user is set in TestBase::prepareEnvironment().
-    $this->container->set('request', $request);
-    if (isset($request_stack)) {
-      $this->container->set('request_stack', $request_stack);
-    }
-    else {
-      $this->container->get('request_stack')->push($request);
-    }
+    // Rebuild the kernel and bring it back to a fully bootstrapped state.
+    $this->container = $this->kernel->rebuildContainer();
     $this->container->get('current_user')->setAccount(\Drupal::currentUser());
 
     // The request context is normally set by the router_listener from within
@@ -1450,7 +1438,7 @@ protected function curlClose() {
    *   TRUE if this test was instantiated in a request within the test site,
    *   FALSE otherwise.
    *
-   * @see _drupal_bootstrap_configuration()
+   * @see \Drupal\Core\DrupalKernel::bootConfiguration()
    */
   protected function isInChildSite() {
     return DRUPAL_TEST_IN_CHILD_SITE;
diff --git a/core/modules/statistics/statistics.php b/core/modules/statistics/statistics.php
index 85864e10b587..4d2004646ae6 100644
--- a/core/modules/statistics/statistics.php
+++ b/core/modules/statistics/statistics.php
@@ -5,15 +5,22 @@
  * Handles counts of node views via AJAX with minimal bootstrap.
  */
 
-// Change the directory to the Drupal root.
+use Drupal\Core\DrupalKernel;
+use Symfony\Component\HttpFoundation\Request;
+
 chdir('../../..');
 
-// Load the Drupal bootstrap.
-require_once dirname(dirname(__DIR__)) . '/vendor/autoload.php';
-require_once dirname(dirname(__DIR__)) . '/includes/bootstrap.inc';
-drupal_bootstrap(DRUPAL_BOOTSTRAP_KERNEL);
+$autoloader = require_once dirname(dirname(__DIR__)) . '/vendor/autoload.php';
+
+$kernel = DrupalKernel::createFromRequest(Request::createFromGlobals(), $autoloader, 'prod');
+$kernel->boot();
+
+$views = $kernel->getContainer()
+  ->get('config.factory')
+  ->get('statistics.settings')
+  ->get('count_content_views');
 
-if (\Drupal::config('statistics.settings')->get('count_content_views')) {
+if ($views) {
   $nid = filter_input(INPUT_POST, 'nid', FILTER_VALIDATE_INT);
   if ($nid) {
     \Drupal::database()->merge('node_counter')
diff --git a/core/modules/system/src/Tests/DrupalKernel/DrupalKernelSiteTest.php b/core/modules/system/src/Tests/DrupalKernel/DrupalKernelSiteTest.php
index d6f9fe8a16b5..5813a2dbbe78 100644
--- a/core/modules/system/src/Tests/DrupalKernel/DrupalKernelSiteTest.php
+++ b/core/modules/system/src/Tests/DrupalKernel/DrupalKernelSiteTest.php
@@ -48,7 +48,7 @@ class: Drupal\Core\Cache\MemoryBackendFactory
     file_put_contents($this->siteDirectory . '/services.yml', $doc);
 
     // Rebuild the container.
-    $this->kernel->updateModules(array());
+    $this->kernel->rebuildContainer();
 
     $this->assertTrue($this->container->has('site.service.yml'));
     $this->assertIdentical(get_class($this->container->get('cache.backend.database')), 'Drupal\Core\Cache\MemoryBackendFactory');
diff --git a/core/modules/system/src/Tests/DrupalKernel/DrupalKernelTest.php b/core/modules/system/src/Tests/DrupalKernel/DrupalKernelTest.php
index 17e4b4b9f030..9ec9df936dcc 100644
--- a/core/modules/system/src/Tests/DrupalKernel/DrupalKernelTest.php
+++ b/core/modules/system/src/Tests/DrupalKernel/DrupalKernelTest.php
@@ -10,12 +10,18 @@
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\Site\Settings;
 use Drupal\simpletest\DrupalUnitTestBase;
+use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Tests compilation of the DIC.
  */
 class DrupalKernelTest extends DrupalUnitTestBase {
 
+  /**
+   * @var \Composer\Autoload\ClassLoader
+   */
+  protected $classloader;
+
   public static function getInfo() {
     return array(
       'name' => 'DrupalKernel tests',
@@ -38,25 +44,60 @@ function setUp() {
       'directory' => DRUPAL_ROOT . '/' . $this->public_files_directory . '/php',
       'secret' => drupal_get_hash_salt(),
     )));
+
+    $this->classloader = drupal_classloader();
+  }
+
+  /**
+   * Build a kernel for testings.
+   *
+   * Because the bootstrap is in DrupalKernel::boot and that involved loading
+   * settings from the filesystem we need to go to extra lengths to build a kernel
+   * for testing.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   A request object to use in booting the kernel.
+   * @param array $modules_enabled
+   *   A list of modules to enable on the kernel.
+   * @param bool $read_only
+   *   Build the kernel in a read only state.
+   * @return DrupalKernel
+   */
+  protected function getTestKernel(Request $request, array $modules_enabled = NULL, $read_only = FALSE) {
+    // Manually create kernel to avoid replacing settings.
+    $kernel = DrupalKernel::createFromRequest($request, drupal_classloader(), 'testing');
+    $this->settingsSet('hash_salt', $this->databasePrefix);
+    if (isset($modules_enabled)) {
+      $kernel->updateModules($modules_enabled);
+    }
+    $kernel->boot();
+
+    if ($read_only) {
+      $php_storage = Settings::get('php_storage');
+      $php_storage['service_container']['class'] = 'Drupal\Component\PhpStorage\FileReadOnlyStorage';
+      $this->settingsSet('php_storage', $php_storage);
+    }
+    return $kernel;
   }
 
   /**
    * Tests DIC compilation.
    */
   function testCompileDIC() {
-    $classloader = drupal_classloader();
     // @todo: write a memory based storage backend for testing.
-    $module_enabled = array(
+    $modules_enabled = array(
       'system' => 'system',
       'user' => 'user',
     );
-    $kernel = new DrupalKernel('testing', $classloader);
-    $kernel->updateModules($module_enabled);
-    $kernel->boot();
+
+    $request = Request::createFromGlobals();
+    $this->getTestKernel($request, $modules_enabled)
+      // Trigger Kernel dump.
+      ->getContainer();
+
     // Instantiate it a second time and we should get the compiled Container
     // class.
-    $kernel = new DrupalKernel('testing', $classloader);
-    $kernel->boot();
+    $kernel = $this->getTestKernel($request);
     $container = $kernel->getContainer();
     $refClass = new \ReflectionClass($container);
     $is_compiled_container =
@@ -66,25 +107,24 @@ function testCompileDIC() {
     // Verify that the list of modules is the same for the initial and the
     // compiled container.
     $module_list = array_keys($container->get('module_handler')->getModuleList());
-    $this->assertEqual(array_values($module_enabled), $module_list);
+    $this->assertEqual(array_values($modules_enabled), $module_list);
 
     // Now use the read-only storage implementation, simulating a "production"
     // environment.
-    $php_storage = Settings::get('php_storage');
-    $php_storage['service_container']['class'] = 'Drupal\Component\PhpStorage\FileReadOnlyStorage';
-    $this->settingsSet('php_storage', $php_storage);
-    $kernel = new DrupalKernel('testing', $classloader);
-    $kernel->boot();
-    $container = $kernel->getContainer();
+    $container = $this->getTestKernel($request, NULL, TRUE)
+      ->getContainer();
+
     $refClass = new \ReflectionClass($container);
     $is_compiled_container =
       $refClass->getParentClass()->getName() == 'Drupal\Core\DependencyInjection\Container' &&
       !$refClass->isSubclassOf('Symfony\Component\DependencyInjection\ContainerBuilder');
     $this->assertTrue($is_compiled_container);
+
     // Verify that the list of modules is the same for the initial and the
     // compiled container.
     $module_list = array_keys($container->get('module_handler')->getModuleList());
-    $this->assertEqual(array_values($module_enabled), $module_list);
+    $this->assertEqual(array_values($modules_enabled), $module_list);
+
     // Test that our synthetic services are there.
     $classloader = $container->get('class_loader');
     $refClass = new \ReflectionClass($classloader);
@@ -98,25 +138,26 @@ function testCompileDIC() {
 
     // Add another module so that we can test that the new module's bundle is
     // registered to the new container.
-    $module_enabled['service_provider_test'] = 'service_provider_test';
-    $kernel = new DrupalKernel('testing', $classloader);
-    $kernel->updateModules($module_enabled);
-    $kernel->boot();
+    $modules_enabled['service_provider_test'] = 'service_provider_test';
+    $this->getTestKernel($request, $modules_enabled, TRUE);
+
     // Instantiate it a second time and we should still get a ContainerBuilder
     // class because we are using the read-only PHP storage.
-    $kernel = new DrupalKernel('testing', $classloader);
-    $kernel->updateModules($module_enabled);
-    $kernel->boot();
+    $kernel = $this->getTestKernel($request, $modules_enabled, TRUE);
     $container = $kernel->getContainer();
+
     $refClass = new \ReflectionClass($container);
     $is_container_builder = $refClass->isSubclassOf('Symfony\Component\DependencyInjection\ContainerBuilder');
-    $this->assertTrue($is_container_builder);
+    $this->assertTrue($is_container_builder, 'Container is a builder');
+
     // Assert that the new module's bundle was registered to the new container.
-    $this->assertTrue($container->has('service_provider_test_class'));
+    $this->assertTrue($container->has('service_provider_test_class'), 'Container has test service');
+
     // Test that our synthetic services are there.
     $classloader = $container->get('class_loader');
     $refClass = new \ReflectionClass($classloader);
     $this->assertTrue($refClass->hasMethod('loadClass'), 'Container has a classloader');
+
     // Check that the location of the new module is registered.
     $modules = $container->getParameter('container.modules');
     $this->assertEqual($modules['service_provider_test'], array(
diff --git a/core/modules/system/src/Tests/Entity/EntityViewControllerTest.php b/core/modules/system/src/Tests/Entity/EntityViewControllerTest.php
index 4faec44b5673..e416ddcebdf8 100644
--- a/core/modules/system/src/Tests/Entity/EntityViewControllerTest.php
+++ b/core/modules/system/src/Tests/Entity/EntityViewControllerTest.php
@@ -102,6 +102,8 @@ public function testFieldItemAttributes() {
     // Enable the RDF module to ensure that two modules can add attributes to
     // the same field item.
     \Drupal::moduleHandler()->install(array('rdf'));
+    $this->resetAll();
+
     // Set an RDF mapping for the field_test_text field. This RDF mapping will
     // be turned into RDFa attributes in the field item output.
     $mapping = rdf_get_mapping('entity_test', 'entity_test');
diff --git a/core/modules/system/src/Tests/Menu/MenuRouterTest.php b/core/modules/system/src/Tests/Menu/MenuRouterTest.php
index 4383658ba250..1b6bb2e96f65 100644
--- a/core/modules/system/src/Tests/Menu/MenuRouterTest.php
+++ b/core/modules/system/src/Tests/Menu/MenuRouterTest.php
@@ -312,6 +312,7 @@ protected function doTestMenuOptionalPlaceholders() {
   protected function doTestMenuOnRoute() {
     \Drupal::moduleHandler()->install(array('router_test'));
     \Drupal::service('router.builder')->rebuild();
+    $this->resetAll();
 
     $this->drupalGet('router_test/test2');
     $this->assertLinkByHref('menu_no_title_callback');
diff --git a/core/modules/system/src/Tests/Module/InstallUninstallTest.php b/core/modules/system/src/Tests/Module/InstallUninstallTest.php
index 1f47cc96f82e..fd50c58d48d6 100644
--- a/core/modules/system/src/Tests/Module/InstallUninstallTest.php
+++ b/core/modules/system/src/Tests/Module/InstallUninstallTest.php
@@ -36,6 +36,7 @@ public function testInstallUninstall() {
     $this->assertEqual($this->container->get('state')->get('system_test_preinstall_module'), 'module_test');
     $this->container->get('module_handler')->uninstall(array('module_test'));
     $this->assertEqual($this->container->get('state')->get('system_test_preuninstall_module'), 'module_test');
+    $this->resetAll();
 
     // Try to install and uninstall book, toolbar modules and its dependencies.
     $all_modules = system_rebuild_module_data();
diff --git a/core/modules/system/src/Tests/System/ScriptTest.php b/core/modules/system/src/Tests/System/ScriptTest.php
index 9ba2e5c9f0c4..1b56a2c625fd 100644
--- a/core/modules/system/src/Tests/System/ScriptTest.php
+++ b/core/modules/system/src/Tests/System/ScriptTest.php
@@ -30,6 +30,14 @@ public static function getInfo() {
    * Tests password-hash.sh.
    */
   public function testPasswordHashSh() {
+    // The script requires a settings.php with a hash salt setting.
+    $filename = $this->siteDirectory . '/settings.php';
+    touch($filename);
+    $settings['settings']['hash_salt'] = (object) array(
+      'value' => 'some_random_key',
+      'required' => TRUE,
+    );
+    drupal_rewrite_settings($settings, $filename);
     $_SERVER['argv'] = array(
       'core/scripts/password-hash.sh',
       'xyz',
@@ -45,6 +53,14 @@ public function testPasswordHashSh() {
    * Tests rebuild_token_calculator.sh.
    */
   public function testRebuildTokenCalculatorSh() {
+    // The script requires a settings.php with a hash salt setting.
+    $filename = $this->siteDirectory . '/settings.php';
+    touch($filename);
+    $settings['settings']['hash_salt'] = (object) array(
+      'value' => 'some_random_key',
+      'required' => TRUE,
+    );
+    drupal_rewrite_settings($settings, $filename);
     $_SERVER['argv'] = array(
       'core/scripts/rebuild_token_calculator.sh',
     );
diff --git a/core/modules/system/src/Tests/Theme/ThemeSuggestionsAlterTest.php b/core/modules/system/src/Tests/Theme/ThemeSuggestionsAlterTest.php
index 202ddd2a44bf..a728c1f3e18c 100644
--- a/core/modules/system/src/Tests/Theme/ThemeSuggestionsAlterTest.php
+++ b/core/modules/system/src/Tests/Theme/ThemeSuggestionsAlterTest.php
@@ -69,6 +69,7 @@ function testGeneralSuggestionsAlter() {
     // Enable the theme_suggestions_test module to test modules implementing
     // suggestions alter hooks.
     \Drupal::moduleHandler()->install(array('theme_suggestions_test'));
+    $this->resetAll();
     $this->drupalGet('theme-test/general-suggestion-alter');
     $this->assertText('Template overridden based on new theme suggestion provided by a module via hook_theme_suggestions_alter().');
   }
@@ -90,6 +91,7 @@ function testTemplateSuggestionsAlter() {
     // Enable the theme_suggestions_test module to test modules implementing
     // suggestions alter hooks.
     \Drupal::moduleHandler()->install(array('theme_suggestions_test'));
+    $this->resetAll();
     $this->drupalGet('theme-test/suggestion-alter');
     $this->assertText('Template overridden based on new theme suggestion provided by a module via hook_theme_suggestions_HOOK_alter().');
   }
@@ -113,6 +115,7 @@ function testSpecificSuggestionsAlter() {
 
     // Ensure that the base hook is used to determine the suggestion alter hook.
     \Drupal::moduleHandler()->install(array('theme_suggestions_test'));
+    $this->resetAll();
     $this->drupalGet('theme-test/specific-suggestion-alter');
     $this->assertText('Template overridden based on suggestion alter hook determined by the base hook.');
     $this->assertTrue(strpos($this->drupalGetContent(), 'theme_test_specific_suggestions__variant') < strpos($this->drupalGetContent(), 'theme_test_specific_suggestions__variant__foo'), 'Specific theme call is added to the suggestions array before the suggestions alter hook.');
@@ -135,6 +138,7 @@ function testThemeFunctionSuggestionsAlter() {
     // Enable the theme_suggestions_test module to test modules implementing
     // suggestions alter hooks.
     \Drupal::moduleHandler()->install(array('theme_suggestions_test'));
+    $this->resetAll();
     $this->drupalGet('theme-test/function-suggestion-alter');
     $this->assertText('Theme function overridden based on new theme suggestion provided by a module.');
   }
@@ -151,6 +155,7 @@ public function testSuggestionsAlterInclude() {
     // the include file is always loaded. The file will always be included for
     // the first request because the theme registry is being rebuilt.
     \Drupal::moduleHandler()->install(array('theme_suggestions_test'));
+    $this->resetAll();
     $this->drupalGet('theme-test/suggestion-alter-include');
     $this->assertText('Function suggested via suggestion alter hook found in include file.', 'Include file loaded for initial request.');
     $this->drupalGet('theme-test/suggestion-alter-include');
@@ -169,6 +174,7 @@ function testExecutionOrder() {
       ->set('default', 'test_theme')
       ->save();
     \Drupal::moduleHandler()->install(array('theme_suggestions_test'));
+    $this->resetAll();
 
     // Send two requests so that we get all the messages we've set via
     // drupal_set_message().
diff --git a/core/modules/system/tests/http.php b/core/modules/system/tests/http.php
index 662031f79b45..33869799e316 100644
--- a/core/modules/system/tests/http.php
+++ b/core/modules/system/tests/http.php
@@ -5,19 +5,29 @@
  * Fake an HTTP request, for use during testing.
  */
 
+use Drupal\Core\Test\TestKernel;
+use Symfony\Component\HttpFoundation\Request;
+
+chdir('../../../..');
+
+$autoloader = require_once './core/vendor/autoload.php';
+
 // Set a global variable to indicate a mock HTTP request.
 $is_http_mock = !empty($_SERVER['HTTPS']);
 
 // Change to HTTP.
 $_SERVER['HTTPS'] = NULL;
 ini_set('session.cookie_secure', FALSE);
-foreach ($_SERVER as $key => $value) {
-  $_SERVER[$key] = str_replace('core/modules/system/tests/http.php', 'index.php', $value);
-  $_SERVER[$key] = str_replace('https://', 'http://', $_SERVER[$key]);
+foreach ($_SERVER as &$value) {
+  $value = str_replace('core/modules/system/tests/http.php', 'index.php', $value);
+  $value = str_replace('https://', 'http://', $value);
 }
 
-// Change current directory to the Drupal root.
-chdir('../../../..');
-require_once dirname(dirname(dirname(__DIR__))) . '/vendor/autoload.php';
-require_once dirname(dirname(dirname(__DIR__))) . '/includes/bootstrap.inc';
-drupal_handle_request(TRUE);
+$request = Request::createFromGlobals();
+$kernel = TestKernel::createFromRequest($request, $autoloader, 'testing', TRUE);
+$response = $kernel
+  ->handlePageCache($request)
+  ->handle($request)
+    // Handle the response object.
+    ->prepare($request)->send();
+$kernel->terminate($request, $response);
diff --git a/core/modules/system/tests/https.php b/core/modules/system/tests/https.php
index 247e6e515e0a..00a6b13d6155 100644
--- a/core/modules/system/tests/https.php
+++ b/core/modules/system/tests/https.php
@@ -8,18 +8,28 @@
  *   see http.php.
  */
 
+use Drupal\Core\Test\TestKernel;
+use Symfony\Component\HttpFoundation\Request;
+
+chdir('../../../..');
+
+$autoloader = require_once './core/vendor/autoload.php';
+
 // Set a global variable to indicate a mock HTTPS request.
 $is_https_mock = empty($_SERVER['HTTPS']);
 
 // Change to HTTPS.
 $_SERVER['HTTPS'] = 'on';
-foreach ($_SERVER as $key => $value) {
-  $_SERVER[$key] = str_replace('core/modules/system/tests/https.php', 'index.php', $value);
-  $_SERVER[$key] = str_replace('http://', 'https://', $_SERVER[$key]);
+foreach ($_SERVER as &$value) {
+  $value = str_replace('core/modules/system/tests/https.php', 'index.php', $value);
+  $value = str_replace('http://', 'https://', $value);
 }
 
-// Change current directory to the Drupal root.
-chdir('../../../..');
-require_once dirname(dirname(dirname(__DIR__))) . '/vendor/autoload.php';
-require_once dirname(dirname(dirname(__DIR__))) . '/includes/bootstrap.inc';
-drupal_handle_request(TRUE);
+$request = Request::createFromGlobals();
+$kernel = TestKernel::createFromRequest($request, $autoloader, 'testing', TRUE);
+$response = $kernel
+  ->handlePageCache($request)
+  ->handle($request)
+    // Handle the response object.
+    ->prepare($request)->send();
+$kernel->terminate($request, $response);
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index 131a1a57772c..0c94f59acf17 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -110,7 +110,7 @@ function toolbar_element_info() {
  * 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().
+ * done by \Drupal\Core\DrupalKernel::handlePageCache().
  *
  * @todo Replace this hack with something better integrated with DrupalKernel
  *   once Drupal's page caching itself is properly integrated.
@@ -120,7 +120,7 @@ function _toolbar_initialize_page_cache() {
   drupal_page_is_cacheable(TRUE);
 
   // If we have a cache, serve it.
-  // @see _drupal_bootstrap_page_cache()
+  // @see \Drupal\Core\DrupalKernel::handlePageCache()
   $request = \Drupal::request();
   $response = drupal_page_get_cache($request);
   if ($response) {
diff --git a/core/modules/user/src/Tests/UserLoginTest.php b/core/modules/user/src/Tests/UserLoginTest.php
index 8016987f38df..10ce788d1dff 100644
--- a/core/modules/user/src/Tests/UserLoginTest.php
+++ b/core/modules/user/src/Tests/UserLoginTest.php
@@ -135,6 +135,7 @@ function testPasswordRehashOnLogin() {
     // users password gets rehashed during the login.
     $overridden_count_log2 = 19;
     \Drupal::moduleHandler()->install(array('user_custom_phpass_params_test'));
+    $this->resetAll();
 
     $account->pass_raw = $password;
     $this->drupalLogin($account);
diff --git a/core/modules/views_ui/src/Tests/PreviewTest.php b/core/modules/views_ui/src/Tests/PreviewTest.php
index 01feff62eda2..f9f773c1646a 100644
--- a/core/modules/views_ui/src/Tests/PreviewTest.php
+++ b/core/modules/views_ui/src/Tests/PreviewTest.php
@@ -34,6 +34,8 @@ public static function getInfo() {
    */
   protected function testPreviewContextual() {
     \Drupal::moduleHandler()->install(array('contextual'));
+    $this->resetAll();
+
     $this->drupalGet('admin/structure/views/view/test_preview/edit');
     $this->assertResponse(200);
     $this->drupalPostForm(NULL, $edit = array(), t('Update preview'));
diff --git a/core/rebuild.php b/core/rebuild.php
index 3e8ed1282c15..f7acbcea8a7c 100644
--- a/core/rebuild.php
+++ b/core/rebuild.php
@@ -11,25 +11,30 @@
  */
 
 use Drupal\Component\Utility\Crypt;
+use Drupal\Core\DrupalKernel;
 use Drupal\Core\Site\Settings;
+use Symfony\Component\HttpFoundation\Request;
 
 // Change the directory to the Drupal root.
 chdir('..');
 
-require_once __DIR__ . '/vendor/autoload.php';
-require_once __DIR__ . '/includes/bootstrap.inc';
+$autoloader = require_once __DIR__ . '/vendor/autoload.php';
 require_once __DIR__ . '/includes/utility.inc';
 
-drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+$request = Request::createFromGlobals();
+// Manually resemble early bootstrap of DrupalKernel::boot().
+require_once __DIR__ . '/includes/bootstrap.inc';
+DrupalKernel::bootEnvironment();
+Settings::initialize(DrupalKernel::findSitePath($request));
 
 if (Settings::get('rebuild_access', FALSE) ||
-  (isset($_GET['token'], $_GET['timestamp']) &&
-    ((REQUEST_TIME - $_GET['timestamp']) < 300) &&
-    ($_GET['token'] === Crypt::hmacBase64($_GET['timestamp'], Settings::get('hash_salt')))
+  ($request->get('token') && $request->get('timestamp') &&
+    ((REQUEST_TIME - $request->get('timestamp')) < 300) &&
+    ($request->get('token') === Crypt::hmacBase64($request->get('timestamp'), Settings::get('hash_salt')))
   )) {
 
-  drupal_rebuild();
+  drupal_rebuild($autoloader, $request);
   drupal_set_message('Cache rebuild complete.');
 }
-
-header('Location: ' . $GLOBALS['base_url']);
+$base_path = dirname(dirname($request->getBaseUrl()));
+header('Location: ' . $base_path);
diff --git a/core/scripts/password-hash.sh b/core/scripts/password-hash.sh
index f80d75c6ca8a..ee3c10246dc2 100755
--- a/core/scripts/password-hash.sh
+++ b/core/scripts/password-hash.sh
@@ -9,6 +9,7 @@
  */
 
 use Drupal\Core\DrupalKernel;
+use Symfony\Component\HttpFoundation\Request;
 
 // Check for $_SERVER['argv'] instead of PHP_SAPI === 'cli' to allow this script
 // to be tested with the Simpletest UI test runner.
@@ -56,14 +57,10 @@
 // Password list to be processed.
 $passwords = $_SERVER['argv'];
 
-$core = dirname(__DIR__);
-require_once $core . '/vendor/autoload.php';
-require_once $core . '/includes/bootstrap.inc';
+$autoloader = require __DIR__ . '/../vendor/autoload.php';
 
-// Bootstrap the code so we have the container.
-drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
-
-$kernel = new DrupalKernel('prod', drupal_classloader(), FALSE);
+$request = Request::createFromGlobals();
+$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod', FALSE);
 $kernel->boot();
 
 $password_hasher = $kernel->getContainer()->get('password');
diff --git a/core/scripts/rebuild_token_calculator.sh b/core/scripts/rebuild_token_calculator.sh
index 9e7dc03ddb0f..bcfd2b6fc16a 100755
--- a/core/scripts/rebuild_token_calculator.sh
+++ b/core/scripts/rebuild_token_calculator.sh
@@ -7,7 +7,9 @@
  */
 
 use Drupal\Component\Utility\Crypt;
+use Drupal\Core\DrupalKernel;
 use Drupal\Core\Site\Settings;
+use Symfony\Component\HttpFoundation\Request;
 
 // Check for $_SERVER['argv'] instead of PHP_SAPI === 'cli' to allow this script
 // to be tested with the Simpletest UI test runner.
@@ -16,11 +18,11 @@
   return;
 }
 
-$core = dirname(__DIR__);
-require_once $core . '/vendor/autoload.php';
-require_once $core . '/includes/bootstrap.inc';
+require __DIR__ . '/../vendor/autoload.php';
+require_once __DIR__ . '/../includes/bootstrap.inc';
 
-drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+$request = Request::createFromGlobals();
+Settings::initialize(DrupalKernel::findSitePath($request));
 
 $timestamp = time();
 $token = Crypt::hmacBase64($timestamp, Settings::get('hash_salt'));
diff --git a/core/scripts/run-tests.sh b/core/scripts/run-tests.sh
index 8eff2a29805e..4679325dcf38 100755
--- a/core/scripts/run-tests.sh
+++ b/core/scripts/run-tests.sh
@@ -8,10 +8,10 @@
 use Drupal\Component\Utility\Timer;
 use Drupal\Core\Database\Database;
 use Drupal\Core\Site\Settings;
-use Drupal\Core\Test\TestKernel;
+use Drupal\Core\Test\TestRunnerKernel;
 use Symfony\Component\HttpFoundation\Request;
 
-require_once __DIR__ . '/../vendor/autoload.php';
+$autoloader = require_once __DIR__ . '/../vendor/autoload.php';
 
 const SIMPLETEST_SCRIPT_COLOR_PASS = 32; // Green.
 const SIMPLETEST_SCRIPT_COLOR_FAIL = 31; // Red.
@@ -26,7 +26,10 @@
 }
 
 simpletest_script_init();
-simpletest_script_bootstrap();
+
+$request = Request::createFromGlobals();
+$kernel = TestRunnerKernel::createFromRequest($request, $autoloader);
+$kernel->prepareLegacyRequest($request);
 
 if ($args['execute-test']) {
   simpletest_script_setup_database();
@@ -353,50 +356,6 @@ function simpletest_script_init() {
   }
 
   chdir(realpath(__DIR__ . '/../..'));
-  require_once dirname(__DIR__) . '/includes/bootstrap.inc';
-}
-
-/**
- * Bootstraps a minimal Drupal environment.
- *
- * @see install_begin_request()
- */
-function simpletest_script_bootstrap() {
-  // Load legacy include files.
-  foreach (glob(DRUPAL_ROOT . '/core/includes/*.inc') as $include) {
-    require_once $include;
-  }
-
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
-
-  // Remove Drupal's error/exception handlers; they are designed for HTML
-  // and there is no storage nor a (watchdog) logger here.
-  restore_error_handler();
-  restore_exception_handler();
-
-  // In addition, ensure that PHP errors are not hidden away in logs.
-  ini_set('display_errors', TRUE);
-
-  // Ensure that required Settings exist.
-  if (!Settings::getAll()) {
-    new Settings(array(
-      'hash_salt' => 'run-tests',
-    ));
-  }
-
-  $kernel = new TestKernel(drupal_classloader());
-  $kernel->boot();
-
-  $request = Request::createFromGlobals();
-  $container = $kernel->getContainer();
-  $container->enterScope('request');
-  $container->set('request', $request, 'request');
-  $container->get('request_stack')->push($request);
-
-  $module_handler = $container->get('module_handler');
-  $module_handler->loadAll();
-
-  simpletest_classloader_register();
 }
 
 /**
diff --git a/core/tests/bootstrap.php b/core/tests/bootstrap.php
index 72c5d5bc9300..99fe34d05198 100644
--- a/core/tests/bootstrap.php
+++ b/core/tests/bootstrap.php
@@ -87,7 +87,7 @@ function drupal_phpunit_register_extension_dirs(Composer\Autoload\ClassLoader $l
 
 // Set sane locale settings, to ensure consistent string, dates, times and
 // numbers handling.
-// @see drupal_environment_initialize()
+// @see \Drupal\Core\DrupalKernel::bootEnvironment()
 setlocale(LC_ALL, 'C');
 
 // Set the default timezone. While this doesn't cause any tests to fail, PHP
diff --git a/core/update.php b/core/update.php
index b6accf3a5f42..9147e9ef85f2 100644
--- a/core/update.php
+++ b/core/update.php
@@ -25,7 +25,7 @@
 // Change the directory to the Drupal root.
 chdir('..');
 
-require_once __DIR__ . '/vendor/autoload.php';
+$autoloader = require_once __DIR__ . '/vendor/autoload.php';
 
 // Exit early if an incompatible PHP version would cause fatal errors.
 // The minimum version is specified explicitly, as DRUPAL_MINIMUM_PHP is not
@@ -297,18 +297,17 @@ function update_task_list($active = NULL) {
 
 // We prepare a minimal bootstrap for the update requirements check to avoid
 // reaching the PHP memory limit.
-require_once __DIR__ . '/includes/bootstrap.inc';
 require_once __DIR__ . '/includes/update.inc';
-require_once __DIR__ . '/includes/common.inc';
-require_once __DIR__ . '/includes/file.inc';
-require_once __DIR__ . '/includes/unicode.inc';
 require_once __DIR__ . '/includes/install.inc';
-require_once __DIR__ . '/includes/schema.inc';
-// Bootstrap to configuration.
-drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
 
-// Bootstrap the database.
-require_once __DIR__ . '/includes/database.inc';
+$request = Request::createFromGlobals();
+$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'update', FALSE);
+
+// Enable UpdateServiceProvider service overrides.
+// @see update_flush_all_caches()
+$GLOBALS['conf']['container_service_providers']['UpdateServiceProvider'] = 'Drupal\Core\DependencyInjection\UpdateServiceProvider';
+$GLOBALS['conf']['update_service_provider_overrides'] = TRUE;
+$kernel->boot();
 
 // Updating from a site schema version prior to 8000 should block the update
 // process. Ensure that the site is not attempting to update a database
@@ -321,27 +320,9 @@ function update_task_list($active = NULL) {
   }
 }
 
-// Enable UpdateServiceProvider service overrides.
-// @see update_flush_all_caches()
-$GLOBALS['conf']['container_service_providers']['UpdateServiceProvider'] = 'Drupal\Core\DependencyInjection\UpdateServiceProvider';
-$GLOBALS['conf']['update_service_provider_overrides'] = TRUE;
-
-// module.inc is not yet loaded but there are calls to module_config_sort()
-// below.
-require_once __DIR__ . '/includes/module.inc';
-
-$settings = Settings::getAll();
-new Settings($settings);
-$kernel = new DrupalKernel('update', drupal_classloader(), FALSE);
-$kernel->boot();
-$request = Request::createFromGlobals();
-$container = \Drupal::getContainer();
-$container->set('request', $request);
-$container->get('request_stack')->push($request);
+$kernel->prepareLegacyRequest($request);
 
 // Determine if the current user has access to run update.php.
-drupal_bootstrap(DRUPAL_BOOTSTRAP_PAGE_CACHE);
-
 \Drupal::service('session_manager')->initialize();
 
 // Ensure that URLs generated for the home and admin pages don't have 'update.php'
@@ -378,7 +359,6 @@ function update_task_list($active = NULL) {
   install_goto('core/update.php?op=info');
 }
 
-drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
 drupal_maintenance_theme();
 
 // Turn error reporting back on. From now on, only fatal errors (which are
diff --git a/index.php b/index.php
index 4d8106064e4f..78ee18c2ecf5 100644
--- a/index.php
+++ b/index.php
@@ -8,13 +8,22 @@
  * See COPYRIGHT.txt and LICENSE.txt files in the "core" directory.
  */
 
+use Drupal\Core\DrupalKernel;
 use Drupal\Core\Site\Settings;
+use Symfony\Component\HttpFoundation\Request;
 
-require_once __DIR__ . '/core/vendor/autoload.php';
-require_once __DIR__ . '/core/includes/bootstrap.inc';
+$autoloader = require_once __DIR__ . '/core/vendor/autoload.php';
 
 try {
-  drupal_handle_request();
+
+  $request = Request::createFromGlobals();
+  $kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
+  $response = $kernel
+    ->handlePageCache($request)
+    ->handle($request)
+      // Handle the response object.
+      ->prepare($request)->send();
+  $kernel->terminate($request, $response);
 }
 catch (Exception $e) {
   $message = 'If you have just changed code (for example deployed a new module or moved an existing one) read <a href="http://drupal.org/documentation/rebuild">http://drupal.org/documentation/rebuild</a>';
diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php
index d80ab274b6c0..017fe8ab82c0 100644
--- a/sites/default/default.settings.php
+++ b/sites/default/default.settings.php
@@ -252,7 +252,7 @@
  * directory and reverse proxy address, and temporary configuration, such as
  * turning on Twig debugging and security overrides.
  *
- * @see \Drupal\Component\Utility\Settings::get()
+ * @see \Drupal\Core\Site\Settings::get()
  */
 
 /**
@@ -497,8 +497,8 @@
  * To see what PHP settings are possible, including whether they can be set at
  * runtime (by using ini_set()), read the PHP documentation:
  * http://php.net/manual/ini.list.php
- * See drupal_environment_initialize() in core/includes/bootstrap.inc for
- * required runtime settings and the .htaccess file for non-runtime settings.
+ * See \Drupal\Core\DrupalKernel::bootEnvironment() for required runtime
+ * settings and the .htaccess file for non-runtime settings.
  * Settings defined there should not be duplicated here so as to avoid conflict
  * issues.
  */
diff --git a/web.config b/web.config
index 3336222b476f..b71c37cdcb7a 100644
--- a/web.config
+++ b/web.config
@@ -61,8 +61,7 @@
     -->
 
         <!-- Pass all requests not referring directly to files in the filesystem
-         to index.php. Clean URLs are handled in
-         drupal_environment_initialize(). -->
+         to index.php. -->
         <rule name="Short URLS" stopProcessing="true">
           <match url="^(.*)$" ignoreCase="false" />
           <conditions>
-- 
GitLab