From 5656f5a68ad0d186bcaff3e12faa9fb2c3192160 Mon Sep 17 00:00:00 2001 From: bach Date: Mon, 12 Jul 2021 10:11:08 +0200 Subject: [PATCH] updated core to 7.80 --- CHANGELOG.txt | 80 +++- MAINTAINERS.txt | 5 +- includes/ajax.inc | 1 + includes/batch.inc | 15 +- includes/bootstrap.inc | 119 ++++- includes/common.inc | 177 ++++++-- includes/database/database.inc | 93 +++- includes/database/mysql/database.inc | 417 +++++++++++++++++- includes/database/mysql/query.inc | 18 + includes/database/mysql/schema.inc | 9 +- includes/database/pgsql/database.inc | 6 +- includes/database/schema.inc | 70 ++- includes/database/select.inc | 11 +- includes/database/sqlite/database.inc | 44 +- includes/database/sqlite/query.inc | 7 +- includes/database/sqlite/schema.inc | 31 ++ includes/errors.inc | 5 +- includes/file.inc | 73 ++- includes/filetransfer/filetransfer.inc | 2 +- includes/form.inc | 27 +- includes/mail.inc | 64 ++- includes/menu.inc | 9 +- includes/pager.inc | 32 +- includes/path.inc | 14 +- includes/request-sanitizer.inc | 2 +- includes/session.inc | 75 +++- includes/theme.inc | 67 ++- misc/ajax.js | 24 +- misc/autocomplete.js | 3 +- misc/drupal.js | 17 + misc/jquery-html-prefilter-3.5.0-backport.js | 251 +++++++++++ misc/jquery.js | 1 - misc/typo3/phar-stream-wrapper/README.md | 5 +- misc/typo3/phar-stream-wrapper/composer.json | 4 +- misc/typo3/phar-stream-wrapper/src/Helper.php | 4 +- .../phar-stream-wrapper/src/Phar/Reader.php | 40 +- .../src/PharStreamWrapper.php | 2 +- .../src/Resolver/PharInvocationResolver.php | 18 +- modules/aggregator/aggregator.info | 6 +- modules/aggregator/tests/aggregator_test.info | 6 +- modules/block/block.info | 6 +- modules/block/block.module | 3 +- modules/block/tests/block_test.info | 6 +- .../block_test_theme/block_test_theme.info | 6 +- modules/blog/blog.info | 6 +- modules/book/book.info | 6 +- modules/book/book.test | 8 +- modules/color/color.info | 6 +- modules/color/color.module | 5 +- modules/comment/comment.info | 6 +- modules/comment/comment.install | 3 - modules/comment/comment.test | 55 +++ modules/contact/contact.info | 6 +- modules/contextual/contextual.info | 6 +- modules/dashboard/dashboard.info | 6 +- modules/dblog/dblog.info | 6 +- modules/field/field.info | 6 +- .../field_sql_storage/field_sql_storage.info | 6 +- .../field_sql_storage.module | 96 ++++ .../field_sql_storage/field_sql_storage.test | 71 ++- modules/field/modules/list/list.info | 6 +- .../field/modules/list/tests/list_test.info | 6 +- modules/field/modules/number/number.info | 6 +- modules/field/modules/number/number.test | 2 +- modules/field/modules/options/options.info | 6 +- modules/field/modules/text/text.info | 6 +- modules/field/tests/field_test.info | 6 +- modules/field/tests/field_test.storage.inc | 111 +---- modules/field_ui/field_ui.admin.inc | 4 + modules/field_ui/field_ui.info | 6 +- modules/field_ui/field_ui.module | 7 +- modules/file/file.field.inc | 13 +- modules/file/file.info | 6 +- modules/file/file.module | 5 +- modules/file/tests/file.test | 2 +- modules/file/tests/file_module_test.info | 6 +- modules/filter/filter.api.php | 4 +- modules/filter/filter.info | 6 +- modules/forum/forum.info | 6 +- modules/forum/forum.module | 3 +- modules/help/help.info | 6 +- modules/image/image.info | 6 +- modules/image/image.test | 2 +- modules/image/tests/image_module_test.info | 6 +- modules/locale/locale.info | 6 +- modules/locale/locale.module | 1 + modules/locale/tests/locale_test.info | 6 +- modules/menu/menu.info | 6 +- modules/node/node.info | 6 +- modules/node/node.module | 2 +- modules/node/tests/node_access_test.info | 6 +- modules/node/tests/node_test.info | 6 +- modules/node/tests/node_test_exception.info | 6 +- modules/openid/openid.inc | 3 +- modules/openid/openid.info | 6 +- modules/openid/openid.module | 2 +- modules/openid/tests/openid_test.info | 6 +- modules/overlay/overlay.info | 6 +- modules/path/path.info | 6 +- modules/php/php.info | 6 +- modules/poll/poll.info | 6 +- modules/profile/profile.info | 6 +- modules/rdf/rdf.info | 6 +- modules/rdf/tests/rdf_test.info | 6 +- modules/search/search.extender.inc | 2 +- modules/search/search.info | 6 +- modules/search/search.module | 2 +- .../search/tests/search_embedded_form.info | 6 +- modules/search/tests/search_extra_type.info | 6 +- modules/search/tests/search_node_tags.info | 6 +- modules/shortcut/shortcut.info | 6 +- modules/simpletest/drupal_web_test_case.php | 23 +- modules/simpletest/simpletest.info | 7 +- modules/simpletest/simpletest.module | 2 +- modules/simpletest/simpletest.test | 19 +- .../simpletest/tests/actions_loop_test.info | 6 +- modules/simpletest/tests/ajax_forms_test.info | 6 +- modules/simpletest/tests/ajax_test.info | 6 +- modules/simpletest/tests/batch_test.info | 6 +- modules/simpletest/tests/boot_test_1.info | 6 +- modules/simpletest/tests/boot_test_2.info | 6 +- modules/simpletest/tests/bootstrap.test | 8 +- modules/simpletest/tests/common.test | 40 +- modules/simpletest/tests/common_test.info | 6 +- .../tests/common_test_cron_helper.info | 6 +- modules/simpletest/tests/database_test.info | 6 +- .../simpletest/tests/database_test.install | 19 + modules/simpletest/tests/database_test.test | 215 ++++++++- .../drupal_autoload_test.info | 6 +- ...drupal_system_listing_compatible_test.info | 6 +- ...upal_system_listing_incompatible_test.info | 6 +- .../simpletest/tests/entity_cache_test.info | 6 +- .../tests/entity_cache_test_dependency.info | 6 +- .../tests/entity_crud_hook_test.info | 6 +- .../tests/entity_query_access_test.info | 6 +- modules/simpletest/tests/error.test | 5 +- modules/simpletest/tests/error_test.info | 6 +- modules/simpletest/tests/error_test.module | 8 +- modules/simpletest/tests/file.test | 211 ++++++++- modules/simpletest/tests/file_test.info | 6 +- modules/simpletest/tests/file_test.module | 16 +- modules/simpletest/tests/filter_test.info | 6 +- modules/simpletest/tests/form.test | 26 +- modules/simpletest/tests/form_test.info | 6 +- modules/simpletest/tests/image_test.info | 6 +- modules/simpletest/tests/mail.test | 75 ++++ modules/simpletest/tests/menu_test.info | 6 +- modules/simpletest/tests/module_test.info | 6 +- modules/simpletest/tests/pager.test | 17 +- modules/simpletest/tests/path_test.info | 6 +- .../tests/psr_0_test/psr_0_test.info | 6 +- .../tests/psr_4_test/psr_4_test.info | 6 +- .../simpletest/tests/request_sanitizer.test | 354 +++++++++++++++ .../simpletest/tests/requirements1_test.info | 6 +- .../simpletest/tests/requirements2_test.info | 6 +- modules/simpletest/tests/schema.test | 56 +++ modules/simpletest/tests/session.test | 195 ++++++++ modules/simpletest/tests/session_test.info | 6 +- modules/simpletest/tests/session_test.module | 13 + .../tests/system_dependencies_test.info | 6 +- ...atible_core_version_dependencies_test.info | 6 +- ...system_incompatible_core_version_test.info | 6 +- ...ible_module_version_dependencies_test.info | 6 +- ...stem_incompatible_module_version_test.info | 6 +- .../tests/system_project_namespace_test.info | 6 +- modules/simpletest/tests/system_test.info | 6 +- modules/simpletest/tests/taxonomy_test.info | 6 +- modules/simpletest/tests/theme.test | 21 + modules/simpletest/tests/theme_test.info | 6 +- .../themes/test_basetheme/test_basetheme.info | 6 +- .../themes/test_subtheme/test_subtheme.info | 6 +- .../tests/themes/test_theme/test_theme.info | 6 +- .../test_theme_nyan_cat.info | 6 +- .../simpletest/tests/update_script_test.info | 6 +- modules/simpletest/tests/update_test_1.info | 6 +- modules/simpletest/tests/update_test_2.info | 6 +- modules/simpletest/tests/update_test_3.info | 6 +- .../drupal-7.bare.minimal.database.php.gz | Bin 0 -> 39843 bytes ...drupal-7.bare.standard_all.database.php.gz | Bin 0 -> 77424 bytes .../drupal-7.filled.minimal.database.php.gz | Bin 0 -> 41805 bytes ...upal-7.filled.standard_all.database.php.gz | Bin 0 -> 97603 bytes .../tests/upgrade/upgrade.locale.test | 2 +- modules/simpletest/tests/url_alter_test.info | 6 +- modules/simpletest/tests/xmlrpc_test.info | 6 +- modules/statistics/statistics.info | 6 +- modules/statistics/statistics.module | 2 - modules/syslog/syslog.info | 6 +- modules/system/system.archiver.inc | 4 +- modules/system/system.info | 6 +- modules/system/system.install | 14 + modules/system/system.module | 7 +- modules/system/system.tar.inc | 171 ++++--- modules/system/system.test | 17 +- modules/system/tests/cron_queue_test.info | 6 +- modules/system/tests/system_cron_test.info | 6 +- modules/taxonomy/taxonomy.info | 6 +- modules/taxonomy/taxonomy.install | 2 +- modules/toolbar/toolbar-print.css | 6 + modules/toolbar/toolbar.info | 6 +- modules/toolbar/toolbar.module | 3 + modules/tracker/tracker.info | 6 +- .../translation/tests/translation_test.info | 6 +- modules/translation/translation.info | 6 +- modules/trigger/tests/trigger_test.info | 6 +- modules/trigger/trigger.info | 6 +- modules/update/tests/aaa_update_test.info | 6 +- modules/update/tests/aaa_update_test.tar.gz | Bin 0 -> 383 bytes modules/update/tests/bbb_update_test.info | 6 +- modules/update/tests/ccc_update_test.info | 6 +- .../update_test_admintheme.info | 6 +- .../update_test_basetheme.info | 6 +- .../update_test_subtheme.info | 6 +- modules/update/tests/update_test.info | 6 +- modules/update/update.info | 6 +- modules/user/tests/user_flood_test.info | 11 + modules/user/tests/user_flood_test.module | 18 + modules/user/tests/user_form_test.info | 6 +- modules/user/tests/user_form_test.module | 41 +- modules/user/tests/user_session_test.info | 11 + modules/user/tests/user_session_test.module | 29 ++ modules/user/user.admin.inc | 3 +- modules/user/user.api.php | 30 ++ modules/user/user.info | 6 +- modules/user/user.module | 23 + modules/user/user.pages.inc | 83 +++- modules/user/user.test | 202 ++++++++- profiles/minimal/minimal.info | 6 +- profiles/standard/standard.info | 6 +- ...drupal_system_listing_compatible_test.info | 6 +- ...upal_system_listing_incompatible_test.info | 6 +- profiles/testing/testing.info | 6 +- scripts/run-tests.sh | 6 +- themes/bartik/bartik.info | 6 +- themes/garland/garland.info | 6 +- themes/seven/seven.info | 6 +- themes/stark/stark.info | 6 +- 236 files changed, 4149 insertions(+), 888 deletions(-) create mode 100644 misc/jquery-html-prefilter-3.5.0-backport.js create mode 100644 modules/simpletest/tests/request_sanitizer.test create mode 100644 modules/simpletest/tests/upgrade/drupal-7.bare.minimal.database.php.gz create mode 100644 modules/simpletest/tests/upgrade/drupal-7.bare.standard_all.database.php.gz create mode 100644 modules/simpletest/tests/upgrade/drupal-7.filled.minimal.database.php.gz create mode 100644 modules/simpletest/tests/upgrade/drupal-7.filled.standard_all.database.php.gz create mode 100644 modules/toolbar/toolbar-print.css create mode 100644 modules/update/tests/aaa_update_test.tar.gz create mode 100644 modules/user/tests/user_flood_test.info create mode 100644 modules/user/tests/user_flood_test.module create mode 100644 modules/user/tests/user_session_test.info create mode 100644 modules/user/tests/user_session_test.module diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 5a00d11..dcef8ea 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,5 +1,83 @@ -Drupal 7.xx, xxxx-xx-xx (development version) +Drupal 7.80, 2021-04-20 ----------------------- +- Fixed security issues: + - SA-CORE-2021-002 + +Drupal 7.79, 2021-04-07 +----------------------- +- Initial support for PHP 8 +- Support for SameSite cookie attribute +- Avoid write for unchanged fields (opt-in) + +Drupal 7.78, 2021-01-19 +----------------------- +- Fixed security issues: + - SA-CORE-2021-001 + +Drupal 7.77, 2020-12-03 +----------------------- +- Hotfix for schema.prefixed tables + +Drupal 7.76, 2020-12-02 +----------------------- +- Support for MySQL 8 +- Core tests pass in SQLite +- Better user flood control logging + +Drupal 7.75, 2020-11-26 +----------------------- +- Fixed security issues: + - SA-CORE-2020-013 + +Drupal 7.74, 2020-11-17 +----------------------- +- Fixed security issues: + - SA-CORE-2020-012 + +Drupal 7.73, 2020-09-16 +----------------------- +- Fixed security issues: + - SA-CORE-2020-007 + +Drupal 7.72, 2020-06-17 +----------------------- +- Fixed security issues: + - SA-CORE-2020-004 + +Drupal 7.71, 2020-06-03 +----------------------- +- Fix for jQuery Form bug in Chromium-based browsers +- Full support for PHP 7.4 + +Drupal 7.70, 2020-05-19 +----------------------- +- Fixed security issues: + - SA-CORE-2020-002 + - SA-CORE-2020-003 + +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 ----------------------- diff --git a/MAINTAINERS.txt b/MAINTAINERS.txt index 460658c..cbc9f51 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 +- Drew Webber 'mcdruid' https://www.drupal.org/u/mcdruid Component maintainers diff --git a/includes/ajax.inc b/includes/ajax.inc index f059209..db53e31 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/batch.inc b/includes/batch.inc index e89ab8d..4d4e504 100644 --- a/includes/batch.inc +++ b/includes/batch.inc @@ -478,18 +478,17 @@ function _batch_finished() { $queue->deleteQueue(); } } + // Clean-up the session. Not needed for CLI updates. + if (isset($_SESSION)) { + unset($_SESSION['batches'][$batch['id']]); + if (empty($_SESSION['batches'])) { + unset($_SESSION['batches']); + } + } } $_batch = $batch; $batch = NULL; - // Clean-up the session. Not needed for CLI updates. - if (isset($_SESSION)) { - unset($_SESSION['batches'][$batch['id']]); - if (empty($_SESSION['batches'])) { - unset($_SESSION['batches']); - } - } - // Redirect if needed. if ($_batch['progressive']) { // Revert the 'destination' that was saved in batch_process(). diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index 8b05bc5..f9202da 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -8,7 +8,7 @@ /** * The current system version. */ -define('VERSION', '7.67'); +define('VERSION', '7.80'); /** * Core API compatibility. @@ -1189,19 +1189,21 @@ function variable_initialize($conf = array()) { $variables = $cached->data; } else { - // Cache miss. Avoid a stampede. + // Cache miss. Avoid a stampede by acquiring a lock. If the lock fails to + // acquire, optionally just continue with uncached processing. $name = 'variable_init'; - if (!lock_acquire($name, 1)) { - // Another request is building the variable cache. - // Wait, then re-run this function. + $lock_acquired = lock_acquire($name, 1); + if (!$lock_acquired && variable_get('variable_initialize_wait_for_lock', FALSE)) { lock_wait($name); return variable_initialize($conf); } else { - // Proceed with variable rebuild. + // Load the variables from the table. $variables = array_map('unserialize', db_query('SELECT name, value FROM {variable}')->fetchAllKeyed()); - cache_set('variables', $variables, 'cache_bootstrap'); - lock_release($name); + if ($lock_acquired) { + cache_set('variables', $variables, 'cache_bootstrap'); + lock_release($name); + } } } @@ -1998,7 +2000,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 +2023,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 +2518,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; @@ -2595,13 +2596,10 @@ function drupal_get_hash_salt() { * The filename that the error was raised in. * @param $line * The line number the error was raised at. - * @param $context - * An array that points to the active symbol table at the point the error - * occurred. */ -function _drupal_error_handler($error_level, $message, $filename, $line, $context) { +function _drupal_error_handler($error_level, $message, $filename, $line) { require_once DRUPAL_ROOT . '/includes/errors.inc'; - _drupal_error_handler_real($error_level, $message, $filename, $line, $context); + _drupal_error_handler_real($error_level, $message, $filename, $line); } /** @@ -2622,6 +2620,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 +2649,6 @@ function _drupal_bootstrap_configuration() { drupal_settings_initialize(); // Sanitize unsafe keys from the request. - require_once DRUPAL_ROOT . '/includes/request-sanitizer.inc'; DrupalRequestSanitizer::sanitize(); } @@ -3875,3 +3876,85 @@ function drupal_clear_opcode_cache($filepath) { @apc_delete_file($filepath); } } + +/** + * Drupal's wrapper around PHP's setcookie() function. + * + * This allows the cookie's $value and $options to be altered. + * + * @param $name + * The name of the cookie. + * @param $value + * The value of the cookie. + * @param $options + * An associative array which may have any of the keys expires, path, domain, + * secure, httponly, samesite. + * + * @see setcookie() + * @ingroup php_wrappers + */ +function drupal_setcookie($name, $value, $options) { + $options = _drupal_cookie_params($options); + if (\PHP_VERSION_ID >= 70300) { + setcookie($name, $value, $options); + } + else { + setcookie($name, $value, $options['expires'], $options['path'], $options['domain'], $options['secure'], $options['httponly']); + } +} + +/** + * Process the params for cookies. This emulates support for the SameSite + * attribute in earlier versions of PHP, and allows the value of that attribute + * to be overridden. + * + * @param $options + * An associative array which may have any of the keys expires, path, domain, + * secure, httponly, samesite. + * + * @return + * An associative array which may have any of the keys expires, path, domain, + * secure, httponly, and samesite. + */ +function _drupal_cookie_params($options) { + $options['samesite'] = _drupal_samesite_cookie($options); + if (\PHP_VERSION_ID < 70300) { + // Emulate SameSite support in older PHP versions. + if (!empty($options['samesite'])) { + // Ensure the SameSite attribute is only added once. + if (!preg_match('/SameSite=/i', $options['path'])) { + $options['path'] .= '; SameSite=' . $options['samesite']; + } + } + } + return $options; +} + +/** + * Determine the value for the samesite cookie attribute, in the following order + * of precedence: + * + * 1) A value explicitly passed to drupal_setcookie() + * 2) A value set in $conf['samesite_cookie_value'] + * 3) The setting from php ini + * 4) The default of None, or FALSE (no attribute) if the cookie is not Secure + * + * @param $options + * An associative array as passed to drupal_setcookie(). + * @return + * The value for the samesite cookie attribute. + */ +function _drupal_samesite_cookie($options) { + if (isset($options['samesite'])) { + return $options['samesite']; + } + $override = variable_get('samesite_cookie_value', NULL); + if ($override !== NULL) { + return $override; + } + $ini_options = session_get_cookie_params(); + if (isset($ini_options['samesite'])) { + return $ini_options['samesite']; + } + return empty($options['secure']) ? FALSE : 'None'; +} diff --git a/includes/common.inc b/includes/common.inc index 44ff460..690c004 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -391,7 +391,7 @@ function drupal_add_feed($url = NULL, $title = '') { */ function drupal_get_feeds($delimiter = "\n") { $feeds = drupal_add_feed(); - return implode($feeds, $delimiter); + return implode($delimiter, $feeds); } /** @@ -684,7 +684,10 @@ function drupal_goto($path = '', array $options = array(), $http_response_code = // We do not allow absolute URLs to be passed via $_GET, as this can be an attack vector. if (isset($_GET['destination']) && !url_is_external($_GET['destination'])) { $destination = drupal_parse_url($_GET['destination']); - $path = $destination['path']; + // Double check the path derived by drupal_parse_url() is not external. + if (!url_is_external($destination['path'])) { + $path = $destination['path']; + } $options['query'] = $destination['query']; $options['fragment'] = $destination['fragment']; } @@ -760,9 +763,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 +792,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 +934,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 @@ -1550,7 +1559,7 @@ function _filter_xss_split($m, $store = FALSE) { return '<'; } - if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9\-]+)([^>]*)>?|()$%', $string, $matches)) { + if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9\-]+)\s*([^>]*)>?|()$%', $string, $matches)) { // Seriously malformed. return ''; } @@ -1609,7 +1618,13 @@ function _filter_xss_attributes($attr) { // Attribute name, href for instance. if (preg_match('/^([-a-zA-Z]+)/', $attr, $match)) { $attrname = strtolower($match[1]); - $skip = ($attrname == 'style' || substr($attrname, 0, 2) == 'on'); + $skip = ( + $attrname == 'style' || + substr($attrname, 0, 2) == 'on' || + substr($attrname, 0, 1) == '-' || + // Ignore long attributes to avoid unnecessary processing overhead. + strlen($attrname) > 96 + ); $working = $mode = 1; $attr = preg_replace('/^[-a-zA-Z]+/', '', $attr); } @@ -2320,6 +2335,7 @@ function url($path = NULL, array $options = array()) { } elseif (!empty($path) && !$options['alias']) { $language = isset($options['language']) && isset($options['language']->language) ? $options['language']->language : ''; + require_once DRUPAL_ROOT . '/' . variable_get('path_inc', 'includes/path.inc'); $alias = drupal_get_path_alias($original_path, $language); if ($alias != $original_path) { // Strip leading slashes from internal path aliases to prevent them @@ -3734,7 +3750,7 @@ function _drupal_build_css_path($matches, $base = NULL) { } // Prefix with base and remove '../' segments where possible. - $path = $_base . $matches[1]; + $path = $_base . (isset($matches[1]) ? $matches[1] : ''); $last = ''; while ($path != $last) { $last = $path; @@ -4441,12 +4457,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