diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 5a00d11c..39c48f1b 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,6 +1,30 @@ Drupal 7.xx, xxxx-xx-xx (development version) ----------------------- +Drupal 7.69, 2019-12-18 +----------------------- +- Fixed security issues: + - SA-CORE-2019-012 + +Drupal 7.68, 2019-12-04 +----------------------- +- Fixed: Hide toolbar when printing +- Fixed: Settings returned via ajax are not run through hook_js_alter() +- Fixed: Use drupal_http_build_query() in drupal_http_request() +- Fixed: DrupalRequestSanitizer not found fatal error when bootstrap phase order is changed +- Fixed: Block web.config in .htaccess (and vice-versa) +- Fixed: Create "scripts" element to align rendering workflow to how "styles" are handled +- PHP 7.3: Fixed 'Cannot change session id when session is active' +- PHP 7.1: Fixed 'A non-numeric value encountered in theme_pager()' +- PHP 7.x: Fixed file.inc generated .htaccess does not cover PHP 7 +- PHP 5.3: Fixed check_plain() 'Invalid multibyte sequence in argument' test failures +- Fixed: Allow passing data as array to drupal_http_request() +- Fixed: Skip module_invoke/module_hook in calling hook_watchdog (excessive function_exist) +- Fixed: HTTP status 200 returned for 'Additional uncaught exception thrown while handling exception' +- Fixed: theme_table() should take an optional footer variable and produce +- Fixed: 'uasort() expects parameter 1 to be array, null given in node_view_multiple()' +- [regression] Fix default.settings.php permission + Drupal 7.67, 2019-05-08 ----------------------- - Fixed security issues: diff --git a/MAINTAINERS.txt b/MAINTAINERS.txt index 460658c1..4ea5572a 100644 --- a/MAINTAINERS.txt +++ b/MAINTAINERS.txt @@ -11,11 +11,8 @@ The Drupal Core branch maintainers oversee the development of Drupal as a whole. The branch maintainers for Drupal 7 are: - Dries Buytaert 'dries' https://www.drupal.org/u/dries -- Angela Byron 'webchick' https://www.drupal.org/u/webchick - Fabian Franz 'Fabianx' https://www.drupal.org/u/fabianx -- David Rothstein 'David_Rothstein' https://www.drupal.org/u/david_rothstein -- Stefan Ruijsenaars 'stefan.r' https://www.drupal.org/u/stefanr-0 -- (provisional) Pol Dellaiera 'Pol' https://www.drupal.org/u/pol +- (provisional) Drew Webber 'mcdruid' https://www.drupal.org/u/mcdruid Component maintainers diff --git a/includes/ajax.inc b/includes/ajax.inc index f059209b..db53e31b 100644 --- a/includes/ajax.inc +++ b/includes/ajax.inc @@ -294,6 +294,7 @@ function ajax_render($commands = array()) { // Now add a command to merge changes and additions to Drupal.settings. $scripts = drupal_add_js(); + drupal_alter('js', $scripts); if (!empty($scripts['settings'])) { $settings = $scripts['settings']; array_unshift($commands, ajax_command_settings(drupal_array_merge_deep_array($settings['data']), TRUE)); diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index 8b05bc5c..10e2a420 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -8,7 +8,7 @@ /** * The current system version. */ -define('VERSION', '7.67'); +define('VERSION', '7.69'); /** * Core API compatibility. @@ -1998,7 +1998,7 @@ function watchdog($type, $message, $variables = array(), $severity = WATCHDOG_NO // It is possible that the error handling will itself trigger an error. In that case, we could // end up in an infinite loop. To avoid that, we implement a simple static semaphore. - if (!$in_error_state && function_exists('module_implements')) { + if (!$in_error_state && function_exists('module_invoke_all')) { $in_error_state = TRUE; // The user object may not exist in all conditions, so 0 is substituted if needed. @@ -2021,9 +2021,7 @@ function watchdog($type, $message, $variables = array(), $severity = WATCHDOG_NO ); // Call the logging hooks to log/process the message - foreach (module_implements('watchdog') as $module) { - module_invoke($module, 'watchdog', $log_entry); - } + module_invoke_all('watchdog', $log_entry); // It is critical that the semaphore is only cleared here, in the parent // watchdog() call (not outside the loop), to prevent recursive execution. @@ -2518,6 +2516,7 @@ function drupal_bootstrap($phase = NULL, $new_phase = TRUE) { switch ($current_phase) { case DRUPAL_BOOTSTRAP_CONFIGURATION: + require_once DRUPAL_ROOT . '/includes/request-sanitizer.inc'; _drupal_bootstrap_configuration(); break; @@ -2622,6 +2621,10 @@ function _drupal_exception_handler($exception) { _drupal_log_error(_drupal_decode_exception($exception), TRUE); } catch (Exception $exception2) { + // Add a 500 status code in case an exception was thrown before the 500 + // status could be set (e.g. while loading a maintenance theme from cache). + drupal_add_http_header('Status', '500 Internal Server Error'); + // Another uncaught exception was thrown while handling the first one. // If we are displaying errors, then do so with no possibility of a further uncaught exception being thrown. if (error_displayable()) { @@ -2647,7 +2650,6 @@ function _drupal_bootstrap_configuration() { drupal_settings_initialize(); // Sanitize unsafe keys from the request. - require_once DRUPAL_ROOT . '/includes/request-sanitizer.inc'; DrupalRequestSanitizer::sanitize(); } diff --git a/includes/common.inc b/includes/common.inc index 44ff4607..d370bb8f 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -760,9 +760,10 @@ function drupal_access_denied() { * (optional) An array that can have one or more of the following elements: * - headers: An array containing request headers to send as name/value pairs. * - method: A string containing the request method. Defaults to 'GET'. - * - data: A string containing the request body, formatted as - * 'param=value¶m=value&...'; to generate this, use http_build_query(). - * Defaults to NULL. + * - data: An array containing the values for the request body or a string + * containing the request body, formatted as + * 'param=value¶m=value&...'; to generate this, use + * drupal_http_build_query(). Defaults to NULL. * - max_redirects: An integer representing how many times a redirect * may be followed. Defaults to 3. * - timeout: A float representing the maximum number of seconds the function @@ -788,7 +789,7 @@ function drupal_access_denied() { * easy access the array keys are returned in lower case. * - data: A string containing the response body that was received. * - * @see http_build_query() + * @see drupal_http_build_query() */ function drupal_http_request($url, array $options = array()) { // Allow an alternate HTTP client library to replace Drupal's default @@ -930,6 +931,11 @@ function drupal_http_request($url, array $options = array()) { $path .= '?' . $uri['query']; } + // Convert array $options['data'] to query string. + if (is_array($options['data'])) { + $options['data'] = drupal_http_build_query($options['data']); + } + // Only add Content-Length if we actually have any content or if it is a POST // or PUT request. Some non-standard servers get confused by Content-Length in // at least HEAD/GET requests, and Squid always requires Content-Length in @@ -4441,12 +4447,54 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS } } - $output = ''; - // The index counter is used to keep aggregated and non-aggregated files in - // order by weight. - $index = 1; - $processed = array(); - $files = array(); + // Sort the JavaScript so that it appears in the correct order. + uasort($items, 'drupal_sort_css_js'); + + // Provide the page with information about the individual JavaScript files + // used, information not otherwise available when aggregation is enabled. + $setting['ajaxPageState']['js'] = array_fill_keys(array_keys($items), 1); + unset($setting['ajaxPageState']['js']['settings']); + drupal_add_js($setting, 'setting'); + + // If we're outputting the header scope, then this might be the final time + // that drupal_get_js() is running, so add the setting to this output as well + // as to the drupal_add_js() cache. If $items['settings'] doesn't exist, it's + // because drupal_get_js() was intentionally passed a $javascript argument + // stripped off settings, potentially in order to override how settings get + // output, so in this case, do not add the setting to this output. + if ($scope == 'header' && isset($items['settings'])) { + $items['settings']['data'][] = $setting; + } + + $elements = array( + '#type' => 'scripts', + '#items' => $items, + ); + + return drupal_render($elements); +} + +/** + * The #pre_render callback for the "scripts" element. + * + * This callback adds elements needed for