Issue #2389811 by znerol, mpdonadio, alexpott, hussainweb, neclimdul: Move all the logic out of index.php (again)
parent
2f853b1863
commit
90d6fb15ed
|
@ -35,6 +35,7 @@ use Symfony\Component\HttpFoundation\Request;
|
|||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
|
||||
use Symfony\Component\HttpKernel\TerminableInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
|
@ -213,53 +214,9 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
|
|||
* In case the host name in the request is not trusted.
|
||||
*/
|
||||
public static function createFromRequest(Request $request, $class_loader, $environment, $allow_dumping = TRUE) {
|
||||
// Include our bootstrap file.
|
||||
$core_root = dirname(dirname(dirname(__DIR__)));
|
||||
require_once $core_root . '/includes/bootstrap.inc';
|
||||
$class_loader_class = get_class($class_loader);
|
||||
|
||||
$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(dirname($core_root), $site_path, $class_loader);
|
||||
|
||||
// Initialize our list of trusted HTTP Host headers to protect against
|
||||
// header attacks.
|
||||
$host_patterns = Settings::get('trusted_host_patterns', array());
|
||||
if (PHP_SAPI !== 'cli' && !empty($host_patterns)) {
|
||||
if (static::setupTrustedHosts($request, $host_patterns) === FALSE) {
|
||||
throw new BadRequestHttpException('The provided host name is not valid for this server.');
|
||||
}
|
||||
}
|
||||
|
||||
// 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() && PHP_SAPI !== 'cli') {
|
||||
$response = new RedirectResponse($request->getBasePath() . '/core/install.php');
|
||||
$response->prepare($request)->send();
|
||||
}
|
||||
|
||||
// If the class loader is still the same, possibly upgrade to the APC class
|
||||
// loader.
|
||||
if ($class_loader_class == get_class($class_loader)
|
||||
&& Settings::get('class_loader_auto_detect', TRUE)
|
||||
&& function_exists('apc_fetch')) {
|
||||
$prefix = Settings::getApcuPrefix('class_loader', $core_root);
|
||||
$apc_loader = new \Symfony\Component\ClassLoader\ApcClassLoader($prefix, $class_loader);
|
||||
$class_loader->unregister();
|
||||
$apc_loader->register();
|
||||
$class_loader = $apc_loader;
|
||||
}
|
||||
|
||||
// Ensure that the class loader reference is up-to-date.
|
||||
$kernel->classLoader = $class_loader;
|
||||
|
||||
$kernel->initializeSettings($request);
|
||||
return $kernel;
|
||||
}
|
||||
|
||||
|
@ -379,6 +336,9 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function setSitePath($path) {
|
||||
if ($this->booted) {
|
||||
throw new \LogicException('Site path cannot be changed after calling boot()');
|
||||
}
|
||||
$this->sitePath = $path;
|
||||
}
|
||||
|
||||
|
@ -595,8 +555,77 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
|
||||
$this->boot();
|
||||
return $this->getHttpKernel()->handle($request, $type, $catch);
|
||||
// Ensure sane PHP environment variables.
|
||||
static::bootEnvironment();
|
||||
|
||||
try {
|
||||
$this->initializeSettings($request);
|
||||
|
||||
// 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() && PHP_SAPI !== 'cli') {
|
||||
$response = new RedirectResponse($request->getBasePath() . '/core/install.php');
|
||||
}
|
||||
else {
|
||||
$this->boot();
|
||||
$response = $this->getHttpKernel()->handle($request, $type, $catch);
|
||||
}
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
if ($catch === FALSE) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$response = $this->handleException($e, $request, $type);
|
||||
}
|
||||
|
||||
// Adapt response headers to the current request.
|
||||
$response->prepare($request);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an exception into a response.
|
||||
*
|
||||
* @param \Exception $e
|
||||
* An exception
|
||||
* @param Request $request
|
||||
* A Request instance
|
||||
* @param int $type
|
||||
* The type of the request (one of HttpKernelInterface::MASTER_REQUEST or
|
||||
* HttpKernelInterface::SUB_REQUEST)
|
||||
*
|
||||
* @return Response
|
||||
* A Response instance
|
||||
*/
|
||||
protected function handleException(\Exception $e, $request, $type) {
|
||||
if ($e instanceof HttpExceptionInterface) {
|
||||
$response = new Response($e->getMessage(), $e->getStatusCode());
|
||||
$response->headers->add($e->getHeaders());
|
||||
return $response;
|
||||
}
|
||||
else {
|
||||
// @todo: _drupal_log_error() and thus _drupal_exception_handler() prints
|
||||
// the message directly. Extract a function which generates and returns it
|
||||
// instead, then remove the output buffer hack here.
|
||||
ob_start();
|
||||
try {
|
||||
// @todo: The exception handler prints the message directly. Extract a
|
||||
// function which returns the message instead.
|
||||
_drupal_exception_handler($e);
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
$message = Settings::get('rebuild_message', 'If you have just changed code (for example deployed a new module or moved an existing one) read <a href="https://www.drupal.org/documentation/rebuild">https://www.drupal.org/documentation/rebuild</a>');
|
||||
if ($message && Settings::get('rebuild_access', FALSE)) {
|
||||
$rebuild_path = $GLOBALS['base_url'] . '/rebuild.php';
|
||||
$message .= " or run the <a href=\"$rebuild_path\">rebuild script</a>";
|
||||
}
|
||||
print $message;
|
||||
}
|
||||
return new Response(ob_get_clean(), 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -796,6 +825,10 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
|
|||
return;
|
||||
}
|
||||
|
||||
// Include our bootstrap file.
|
||||
$core_root = dirname(dirname(dirname(__DIR__)));
|
||||
require_once $core_root . '/includes/bootstrap.inc';
|
||||
|
||||
// Enforce E_STRICT, but allow users to set levels not part of E_STRICT.
|
||||
error_reporting(E_STRICT | E_ALL);
|
||||
|
||||
|
@ -847,6 +880,43 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
|
|||
static::$isEnvironmentInitialized = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate site path and initialize settings singleton.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request.
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
|
||||
* In case the host name in the request is not trusted.
|
||||
*/
|
||||
protected function initializeSettings(Request $request) {
|
||||
$site_path = static::findSitePath($request);
|
||||
$this->setSitePath($site_path);
|
||||
$class_loader_class = get_class($this->classLoader);
|
||||
Settings::initialize($this->root, $site_path, $this->classLoader);
|
||||
|
||||
// Initialize our list of trusted HTTP Host headers to protect against
|
||||
// header attacks.
|
||||
$host_patterns = Settings::get('trusted_host_patterns', array());
|
||||
if (PHP_SAPI !== 'cli' && !empty($host_patterns)) {
|
||||
if (static::setupTrustedHosts($request, $host_patterns) === FALSE) {
|
||||
throw new BadRequestHttpException('The provided host name is not valid for this server.');
|
||||
}
|
||||
}
|
||||
|
||||
// If the class loader is still the same, possibly upgrade to the APC class
|
||||
// loader.
|
||||
if ($class_loader_class == get_class($this->classLoader)
|
||||
&& Settings::get('class_loader_auto_detect', TRUE)
|
||||
&& function_exists('apc_fetch')) {
|
||||
$prefix = Settings::getApcuPrefix('class_loader', $this->root);
|
||||
$apc_loader = new \Symfony\Component\ClassLoader\ApcClassLoader($prefix, $this->classLoader);
|
||||
$this->classLoader->unregister();
|
||||
$apc_loader->register();
|
||||
$this->classLoader = $apc_loader;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstraps the legacy global request variables.
|
||||
*
|
||||
|
|
|
@ -60,8 +60,11 @@ interface DrupalKernelInterface extends HttpKernelInterface {
|
|||
/**
|
||||
* Set the current site path.
|
||||
*
|
||||
* @param $path
|
||||
* @param string $path
|
||||
* The current site path.
|
||||
*
|
||||
* @throws \LogicException
|
||||
* In case the kernel is already booted.
|
||||
*/
|
||||
public function setSitePath($path);
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
namespace Drupal\Core\Test;
|
||||
|
||||
use Drupal\Core\DrupalKernel;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Kernel to mock requests to test simpletest.
|
||||
|
@ -18,17 +17,17 @@ class TestKernel extends DrupalKernel {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function createFromRequest(Request $request, $class_loader, $environment, $allow_dumping = TRUE) {
|
||||
public function __construct($environment, $class_loader, $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');
|
||||
header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
|
||||
exit;
|
||||
}
|
||||
|
||||
return parent::createFromRequest($request, $class_loader, $environment, $allow_dumping);
|
||||
parent::__construct($environment, $class_loader, $allow_dumping);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,8 +42,8 @@ class TestRunnerKernel extends DrupalKernel {
|
|||
'simpletest' => 0,
|
||||
);
|
||||
$this->moduleData = array(
|
||||
'system' => new Extension(DRUPAL_ROOT, 'module', 'core/modules/system/system.info.yml', 'system.module'),
|
||||
'simpletest' => new Extension(DRUPAL_ROOT, 'module', 'core/modules/simpletest/simpletest.info.yml', 'simpletest.module'),
|
||||
'system' => new Extension($this->root, 'module', 'core/modules/system/system.info.yml', 'system.module'),
|
||||
'simpletest' => new Extension($this->root, 'module', 'core/modules/simpletest/simpletest.info.yml', 'simpletest.module'),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -166,7 +166,7 @@ class DrupalKernelTest extends KernelTestBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Test repeated loading of compiled DIC with different environment.
|
||||
* Tests repeated loading of compiled DIC with different environment.
|
||||
*/
|
||||
public function testRepeatedBootWithDifferentEnvironment() {
|
||||
$request = Request::createFromGlobals();
|
||||
|
@ -189,4 +189,26 @@ class DrupalKernelTest extends KernelTestBase {
|
|||
$this->pass('Repeatedly loaded compiled DIC with different environment');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests setting of site path after kernel boot.
|
||||
*/
|
||||
public function testPreventChangeOfSitePath() {
|
||||
// @todo: write a memory based storage backend for testing.
|
||||
$modules_enabled = array(
|
||||
'system' => 'system',
|
||||
'user' => 'user',
|
||||
);
|
||||
|
||||
$request = Request::createFromGlobals();
|
||||
$kernel = $this->getTestKernel($request, $modules_enabled);
|
||||
$pass = FALSE;
|
||||
try {
|
||||
$kernel->setSitePath('/dev/null');
|
||||
}
|
||||
catch (\LogicException $e) {
|
||||
$pass = TRUE;
|
||||
}
|
||||
$this->assertTrue($pass, 'Throws LogicException if DrupalKernel::setSitePath() is called after boot');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,10 +20,10 @@ foreach ($_SERVER as &$value) {
|
|||
$value = str_replace('https://', 'http://', $value);
|
||||
}
|
||||
|
||||
$kernel = new TestKernel('testing', $autoloader, TRUE);
|
||||
|
||||
$request = Request::createFromGlobals();
|
||||
$kernel = TestKernel::createFromRequest($request, $autoloader, 'testing', TRUE);
|
||||
$response = $kernel
|
||||
->handle($request)
|
||||
// Handle the response object.
|
||||
->prepare($request)->send();
|
||||
$response = $kernel->handle($request);
|
||||
$response->send();
|
||||
|
||||
$kernel->terminate($request, $response);
|
||||
|
|
|
@ -22,10 +22,10 @@ foreach ($_SERVER as &$value) {
|
|||
$value = str_replace('http://', 'https://', $value);
|
||||
}
|
||||
|
||||
$kernel = new TestKernel('testing', $autoloader, TRUE);
|
||||
|
||||
$request = Request::createFromGlobals();
|
||||
$kernel = TestKernel::createFromRequest($request, $autoloader, 'testing', TRUE);
|
||||
$response = $kernel
|
||||
->handle($request)
|
||||
// Handle the response object.
|
||||
->prepare($request)->send();
|
||||
$response = $kernel->handle($request);
|
||||
$response->send();
|
||||
|
||||
$kernel->terminate($request, $response);
|
||||
|
|
34
index.php
34
index.php
|
@ -9,36 +9,14 @@
|
|||
*/
|
||||
|
||||
use Drupal\Core\DrupalKernel;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
$autoloader = require_once 'autoload.php';
|
||||
try {
|
||||
|
||||
$request = Request::createFromGlobals();
|
||||
$kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
|
||||
$response = $kernel
|
||||
->handle($request)
|
||||
// Handle the response object.
|
||||
->prepare($request)->send();
|
||||
$kernel->terminate($request, $response);
|
||||
}
|
||||
catch (HttpExceptionInterface $e) {
|
||||
$response = new Response($e->getMessage(), $e->getStatusCode());
|
||||
$response->prepare($request)->send();
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$message = 'If you have just changed code (for example deployed a new module or moved an existing one) read <a href="https://www.drupal.org/documentation/rebuild">https://www.drupal.org/documentation/rebuild</a>';
|
||||
if (Settings::get('rebuild_access', FALSE)) {
|
||||
$rebuild_path = $GLOBALS['base_url'] . '/rebuild.php';
|
||||
$message .= " or run the <a href=\"$rebuild_path\">rebuild script</a>";
|
||||
}
|
||||
$kernel = new DrupalKernel('prod', $autoloader);
|
||||
|
||||
// Set the response code manually. Otherwise, this response will default to a
|
||||
// 200.
|
||||
http_response_code(500);
|
||||
print $message;
|
||||
throw $e;
|
||||
}
|
||||
$request = Request::createFromGlobals();
|
||||
$response = $kernel->handle($request);
|
||||
$response->send();
|
||||
|
||||
$kernel->terminate($request, $response);
|
||||
|
|
Loading…
Reference in New Issue