diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 7962015..06d7554 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -773,94 +773,6 @@ function _drupal_set_preferred_header_name($name = NULL) { } /** - * Sends the HTTP response headers that were previously set, adding defaults. - * - * Headers are set in drupal_add_http_header(). Default headers are not set - * if they have been replaced or unset using drupal_add_http_header(). - * - * @param array $default_headers - * (optional) An array of headers as name/value pairs. - * @param bool $only_default - * (optional) If TRUE and headers have already been sent, send only the - * specified headers. - * - * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0. - * See https://drupal.org/node/2181523. - */ -function drupal_send_headers($default_headers = array(), $only_default = FALSE) { - $headers_sent = &drupal_static(__FUNCTION__, FALSE); - $headers = drupal_get_http_header(); - if ($only_default && $headers_sent) { - $headers = array(); - } - $headers_sent = TRUE; - - $header_names = _drupal_set_preferred_header_name(); - foreach ($default_headers as $name => $value) { - $name_lower = strtolower($name); - if (!isset($headers[$name_lower])) { - $headers[$name_lower] = $value; - $header_names[$name_lower] = $name; - } - } - foreach ($headers as $name_lower => $value) { - if ($name_lower == 'status') { - header($_SERVER['SERVER_PROTOCOL'] . ' ' . $value); - } - // Skip headers that have been unset. - elseif ($value !== FALSE) { - header($header_names[$name_lower] . ': ' . $value); - } - } -} - -/** - * Sets HTTP headers in preparation for a page response. - * - * Authenticated users are always given a 'no-cache' header, and will fetch a - * fresh page on every request. This prevents authenticated users from seeing - * locally cached pages. - * - * Also give each page a unique ETag. This will force clients to include both - * an If-Modified-Since header and an If-None-Match header when doing - * conditional requests for the page (required by RFC 2616, section 13.3.4), - * making the validation more robust. This is a workaround for a bug in Mozilla - * Firefox that is triggered when Drupal's caching is enabled and the user - * accesses Drupal via an HTTP proxy (see - * https://bugzilla.mozilla.org/show_bug.cgi?id=269303): When an authenticated - * user requests a page, and then logs out and requests the same page again, - * Firefox may send a conditional request based on the page that was cached - * locally when the user was logged in. If this page did not have an ETag - * header, the request only contains an If-Modified-Since header. The date will - * be recent, because with authenticated users the Last-Modified header always - * refers to the time of the request. If the user accesses Drupal via a proxy - * server, and the proxy already has a cached copy of the anonymous page with an - * older Last-Modified date, the proxy may respond with 304 Not Modified, making - * the client think that the anonymous and authenticated pageviews are - * identical. - * - * @see drupal_page_set_cache() - * - * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0. - * See https://drupal.org/node/2181523. - */ -function drupal_page_header() { - $headers_sent = &drupal_static(__FUNCTION__, FALSE); - if ($headers_sent) { - return TRUE; - } - $headers_sent = TRUE; - - $default_headers = array( - 'Expires' => 'Sun, 19 Nov 1978 05:00:00 GMT', - 'Last-Modified' => gmdate(DATE_RFC1123, REQUEST_TIME), - 'Cache-Control' => 'no-cache, must-revalidate, post-check=0, pre-check=0', - 'ETag' => '"' . REQUEST_TIME . '"', - ); - drupal_send_headers($default_headers); -} - -/** * Sets HTTP headers in preparation for a cached page response. * * The headers allow as much as possible in proxies and browsers without any @@ -1599,8 +1511,10 @@ function _drupal_bootstrap_configuration() { Unicode::check(); // Set the Drupal custom error handler. (requires \Drupal::config()) - set_error_handler('_drupal_error_handler'); - set_exception_handler('_drupal_exception_handler'); + if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE !== 'install') { + 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 diff --git a/core/includes/common.inc b/core/includes/common.inc index d18c0c1..1be6731 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -3225,8 +3225,6 @@ function _drupal_bootstrap_full($skip = FALSE) { * The response body. * @return * The cached object or NULL if the page cache was not set. - * - * @see drupal_page_header() */ function drupal_page_set_cache(Response $response, Request $request) { if (drupal_page_is_cacheable()) { @@ -3635,9 +3633,21 @@ function drupal_prepare_page($page) { drupal_set_page_content($page); $page = element_info('page'); } + // Special front controllers (like install.php and update.php) are returning a + // proper #type 'page' render array (in order to set a custom #theme template), + // so just ensure that #type 'page' is complete. + elseif (isset($page['#type']) && $page['#type'] === 'page') { + $page += element_info('page'); + } // Modules can add elements to $page as needed in hook_page_build(). - foreach (\Drupal::moduleHandler()->getImplementations('page_build') as $module) { + if (!defined('MAINTENANCE_MODE')) { + $implementations = \Drupal::moduleHandler()->getImplementations('page_build'); + } + else { + $implementations = array('system'); + } + foreach ($implementations as $module) { $function = $module . '_page_build'; $function($page); } @@ -3662,7 +3672,7 @@ function drupal_prepare_page($page) { // If no module has taken care of the main content, add it to the page now. // This allows the site to still be usable even if no modules that // control page regions (for example, the Block module) are enabled. - if (!$main_content_display) { + if (!$main_content_display && !isset($page['content']['system_main'])) { $page['content']['system_main'] = drupal_set_page_content(); } @@ -4290,6 +4300,9 @@ function _drupal_render_process_post_render_cache(array &$elements) { $modified_elements = $elements; foreach ($elements['#post_render_cache'] as $callback => $options) { foreach ($elements['#post_render_cache'][$callback] as $token => $context) { + if (!is_callable($callback)) { + continue; + } // The advanced option, when setting #post_render_cache directly. if (is_numeric($token)) { $modified_elements = call_user_func_array($callback, array($modified_elements, $context)); diff --git a/core/includes/errors.inc b/core/includes/errors.inc index 56c276f..3bdd246 100644 --- a/core/includes/errors.inc +++ b/core/includes/errors.inc @@ -228,7 +228,7 @@ function _drupal_log_error($error, $fatal = FALSE) { '#title' => 'Error', '#markup' => $message, ); - install_display_output($output, $GLOBALS['install_state']); + $response = install_display_output($output, $GLOBALS['install_state']); } else { $output = array( @@ -236,11 +236,10 @@ function _drupal_log_error($error, $fatal = FALSE) { '#title' => 'Error', '#content' => $message, ); - $output = drupal_render($output); + $response = new Response($output, 500); + $response->setStatusCode(500, '500 Service unavailable (with message)'); } - $response = new Response($output, 500); - $response->setStatusCode(500, '500 Service unavailable (with message)'); // An exception must halt script execution. $response->send(); exit; diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 8d27e08..b7ed134 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -14,6 +14,7 @@ use Drupal\Core\Installer\Exception\NoProfilesException; use Drupal\Core\Language\Language; use Drupal\Core\Language\LanguageManager; +use Drupal\Core\Page\HtmlPage; use Drupal\Core\StringTranslation\Translator\FileTranslation; use Drupal\Core\Extension\ExtensionDiscovery; use Drupal\Core\DependencyInjection\ContainerBuilder; @@ -299,6 +300,7 @@ function install_begin_request(&$install_state) { require_once __DIR__ . '/form.inc'; require_once __DIR__ . '/batch.inc'; require_once __DIR__ . '/ajax.inc'; + require_once __DIR__ . '/menu.inc'; // Load module basics (needed for hook invokes). include_once __DIR__ . '/module.inc'; @@ -349,6 +351,14 @@ function install_begin_request(&$install_state) { if (!$install_state['base_system_verified']) { $environment = 'install'; $GLOBALS['conf']['container_service_providers']['InstallerServiceProvider'] = 'Drupal\Core\Installer\InstallerServiceProvider'; + + // Various services need a database connection. Supply one. + if (!$install_state['database_verified']) { + Database::addConnectionInfo('install', 'default', array( + 'driver' => 'sqlite', + 'database' => ':memory:', + )); + } } else { $environment = 'prod'; @@ -884,8 +894,6 @@ function install_display_output($output, $install_state) { // reached in case of an early installer error. drupal_maintenance_theme(); - drupal_page_header(); - // Prevent install.php from being indexed when installed in a sub folder. // robots.txt rules are not read if the site is within domain.com/subfolder // resulting in /subfolder/install.php being found through search engines. @@ -900,6 +908,15 @@ function install_display_output($output, $install_state) { ); drupal_add_html_head($noindex_meta_tag, 'install_meta_robots'); + $install_page = array( + '#type' => 'page', + '#theme' => 'install_page', + '#title' => $output['#title'], + 'content' => array( + 'system_main' => $output, + ), + ); + // Only show the task list if there is an active task; otherwise, the page // request has ended before tasks have even been started, so there is nothing // meaningful to show. @@ -913,20 +930,36 @@ function install_display_output($output, $install_state) { '#active' => $active_task, '#variant' => 'install', ); - drupal_add_region_content('sidebar_first', drupal_render($task_list)); + $install_page['sidebar_first'] = $task_list; } - $install_page = array( - '#theme' => 'install_page', - // $output has to be rendered here, because the install page template is not - // wrapped into the html template, which means that any #attached libraries - // in $output will not be loaded, because the wrapping HTML has been printed - // already. - '#content' => drupal_render($output), - ); - if (isset($output['#title'])) { - $install_page['#page']['#title'] = $output['#title']; - } - print drupal_render($install_page); + + // @see \Drupal\Core\Page\DefaultHtmlFragmentRenderer::render() + // @see \Drupal\system\Controller\BatchController::render() + $page = new HtmlPage('', array(), $output['#title']); + $page_array = drupal_prepare_page($install_page); + + $page = \Drupal::service('html_fragment_renderer')->preparePage($page, $page_array); + $page->setBodyTop(drupal_render($page_array['page_top'])); + $page->setBodyBottom(drupal_render($page_array['page_bottom'])); + $page->setContent(drupal_render($page_array)); + + $response = new Response(\Drupal::service('html_page_renderer')->render($page)); + + // @todo Does it make sense to set all this HTTP heads for the installer? + // @todo This kind of information would be added by the + // FinishResponseSubscriber which could be used once we use a proper kernel + // in the installer. + $date = new DateTime('Sun, 19 Nov 1978 05:00:00 GMT'); + $response->setExpires($date); + $date = new DateTime('now'); + $response->setLastModified($date); + + $response->headers->set('Cache-Control', 'no-cache, must-revalidate, post-check=0, pre-check=0'); + $response->headers->set('ETag', '"' . REQUEST_TIME . '"'); + + $response->send(); + // @todo On the longrun there should be a single place which calls send on the + // response. exit; } diff --git a/core/includes/theme.inc b/core/includes/theme.inc index cfd8427..ab2f37b 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1967,9 +1967,6 @@ function template_preprocess_html(&$variables) { } } - // Initializes attributes which are specific to the html and body elements. - $variables['html_attributes'] = new Attribute; - // HTML element attributes. $language_interface = \Drupal::service('language_manager')->getCurrentLanguage(); $variables['html_attributes']['lang'] = $language_interface->id; @@ -2213,12 +2210,6 @@ function theme_get_suggestions($args, $base, $delimiter = '__') { * * Default template: maintenance-page.html.twig. * - * The variables array generated here is a mirror of - * template_preprocess_page(). This preprocessor will run its course when - * theme_maintenance_page() is invoked. An alternate template file of - * maintenance-page--offline.html.twig can be used when the database is offline - * to hide errors and completely replace the content. - * * @param array $variables * An associative array containing: * - content - An array of page content. @@ -2226,117 +2217,28 @@ function theme_get_suggestions($args, $base, $delimiter = '__') { * @see system_page_build() */ function template_preprocess_maintenance_page(&$variables) { - $language_interface = \Drupal::languageManager()->getCurrentLanguage(); - - // Initializes attributes which are specific to the html element. - $variables['html_attributes'] = new Attribute; - - // HTML element attributes. - $variables['html_attributes']['lang'] = $language_interface->id; - $variables['html_attributes']['dir'] = $language_interface->direction ? 'rtl' : 'ltr'; - - // Add favicon - if (theme_get_setting('features.favicon')) { - $favicon = theme_get_setting('favicon.url'); - $type = theme_get_setting('favicon.mimetype'); - $build['#attached']['drupal_add_html_head_link'][][] = array( - 'rel' => 'shortcut icon', - 'href' => UrlHelper::stripDangerousProtocols($favicon), - 'type' => $type, - ); - drupal_render($build); - } - - foreach (system_region_list($GLOBALS['theme']) as $region_key => $region_name) { - if (!isset($variables[$region_key])) { - $variables[$region_key] = array(); - } - // Append region content set with drupal_add_region_content() as markup. - if ($region_content = drupal_get_region_content($region_key)) { - $variables[$region_key][]['#markup'] = $region_content; - } - } - - // Setup layout variable. - $variables['layout'] = 'none'; - if (!empty($variables['sidebar_first'])) { - $variables['layout'] = 'first'; - } - if (!empty($variables['sidebar_second'])) { - $variables['layout'] = ($variables['layout'] == 'first') ? 'both' : 'second'; - } - - $site_config = \Drupal::config('system.site'); - $site_name = $site_config->get('name'); - $site_slogan = $site_config->get('slogan'); - - // Construct the page title. - if (isset($variables['page']['#title'])) { - $head_title = array( - 'title' => strip_tags($variables['page']['#title']), - 'name' => String::checkPlain($site_config->get('name')), - ); - } - else { - $head_title = array('name' => String::checkPlain($site_name)); - if ($site_slogan) { - $head_title['slogan'] = strip_tags(filter_xss_admin($site_slogan)); - } - } + // @todo Rename the templates to page--maintenance + page--install. + template_preprocess_page($variables); - // These are usually added from system_page_build() except maintenance.css. - // When the database is inactive it's not called so we add it here. - $default_css['library'][] = 'core/normalize'; - $default_css['library'][] = 'system/maintenance'; - $attached = array('#attached' => $default_css); - drupal_render($attached); - $variables['messages'] = array( - '#theme' => 'status_messages', - '#access' => $variables['show_messages'], - ); - - $variables['head_title_array'] = $head_title; - $variables['head_title'] = implode(' | ', $head_title); - $variables['front_page'] = url(); - $variables['help'] = ''; - $variables['language'] = $language_interface; - $variables['logo'] = theme_get_setting('logo.url'); - $variables['site_name'] = (theme_get_setting('features.name') ? String::checkPlain($site_name) : ''); - $variables['site_slogan'] = (theme_get_setting('features.slogan') ? filter_xss_admin($site_slogan) : ''); + $page_object = $variables['page']['#page']; + $attributes = $page_object->getBodyAttributes(); + $classes = $attributes['class']; - // Compile a list of classes that are going to be applied to the body element. - $variables['attributes']['class'][] = 'maintenance-page'; - $variables['attributes']['class'][] = 'in-maintenance'; + $classes[] = 'maintenance-page'; + $classes[] = 'in-maintenance'; if (isset($variables['db_is_active']) && !$variables['db_is_active']) { - $variables['attributes']['class'][] = 'db-offline'; - } - if ($variables['layout'] == 'both') { - $variables['attributes']['class'][] = 'two-sidebars'; - } - elseif ($variables['layout'] == 'none') { - $variables['attributes']['class'][] = 'no-sidebars'; - } - else { - $variables['attributes']['class'][] = 'one-sidebar'; - $variables['attributes']['class'][] = 'sidebar-' . $variables['layout']; + $classes[] = 'db-offline'; } + $attributes['class'] = $classes; - $variables['head'] = drupal_get_html_head(); - - // While this code is used in the installer, the language module may not be - // enabled yet (even maybe no database set up yet), but an RTL language - // selected should result in RTL stylesheets loaded properly already. - $css = _drupal_add_css(); - include_once DRUPAL_ROOT . '/core/modules/language/language.module'; - // Wrapping drupal_get_css() and drupal_get_js() in an object so they can - // be called when printed. - $variables['styles'] = new RenderWrapper('drupal_get_css', array($css)); - $variables['scripts'] = new RenderWrapper('drupal_get_js'); - - // Allow the page to define a title. - if (isset($variables['page']['#title'])) { - $variables['title'] = $variables['page']['#title']; - } + $attached = array( + '#attached' => array( + 'library' => array( + 'system/maintenance', + ), + ), + ); + drupal_render($attached); } /** @@ -2357,7 +2259,15 @@ function template_preprocess_maintenance_page(&$variables) { */ function template_preprocess_install_page(&$variables) { template_preprocess_maintenance_page($variables); - $variables['attributes']['class'][] = 'install-page'; + + $page_object = $variables['page']['#page']; + $attributes = $page_object->getBodyAttributes(); + $classes = $attributes['class']; + + $classes[] = 'install-page'; + + $attributes['class'] = $classes; + // Override the site name that is displayed on the page, since Drupal is // still in the process of being installed. $distribution_name = String::checkPlain(drupal_install_profile_distribution_name()); @@ -2472,11 +2382,11 @@ function drupal_common_theme() { ), // From theme.maintenance.inc. 'maintenance_page' => array( - 'variables' => array('content' => NULL, 'show_messages' => TRUE, 'page' => array()), + 'render element' => 'page', 'template' => 'maintenance-page', ), 'install_page' => array( - 'variables' => array('content' => NULL, 'show_messages' => TRUE, 'page' => array()), + 'render element' => 'page', 'template' => 'install-page', ), 'task_list' => array( diff --git a/core/includes/theme.maintenance.inc b/core/includes/theme.maintenance.inc index 429b932..903c63f 100644 --- a/core/includes/theme.maintenance.inc +++ b/core/includes/theme.maintenance.inc @@ -30,6 +30,7 @@ function _drupal_maintenance_theme() { require_once __DIR__ . '/unicode.inc'; require_once __DIR__ . '/file.inc'; require_once __DIR__ . '/module.inc'; + require_once __DIR__ . '/database.inc'; Unicode::check(); // Install and update pages are treated differently to prevent theming overrides. @@ -42,13 +43,6 @@ function _drupal_maintenance_theme() { } } else { - // The bootstrap was not complete. So we are operating in a crippled - // environment, we need to bootstrap just enough to allow hook invocations - // to work. See _drupal_log_error(). - if (!class_exists('Drupal\Core\Database\Database', FALSE)) { - require_once __DIR__ . '/database.inc'; - } - // Use the maintenance theme if specified, otherwise attempt to use the // default site theme. try { diff --git a/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php b/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php index 2389a62..26b1d7d 100644 --- a/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php +++ b/core/lib/Drupal/Core/Installer/InstallerServiceProvider.php @@ -7,6 +7,7 @@ namespace Drupal\Core\Installer; +use Drupal\Core\Database\Database; use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\ServiceProviderInterface; use Drupal\Core\DependencyInjection\ServiceModifierInterface; @@ -66,6 +67,8 @@ public function alter(ContainerBuilder $container) { // throws an exception upon trying to load a non-existing file. $container->get('config.factory')->setOverrideState(FALSE); + $container->set('database', Database::getConnection('default', 'install')); + // No service may persist when the early installer kernel is rebooted into // the production environment. // @todo The DrupalKernel reboot performed by drupal_install_system() is diff --git a/core/modules/system/templates/install-page.html.twig b/core/modules/system/templates/install-page.html.twig index 031013e..45f37d2 100644 --- a/core/modules/system/templates/install-page.html.twig +++ b/core/modules/system/templates/install-page.html.twig @@ -11,56 +11,45 @@ * @ingroup themeable */ #} - - -
- {{ head }} -