#732486: Make the signature of drupal_add_http_header() more sane and more robust. From: Damien Tournoud --- authorize.php | 2 +- bootstrap.inc | 22 ++++++++-------------- common.inc | 6 +++--- database/database.inc | 2 +- errors.inc | 2 +- aggregator/tests/aggregator_test.module | 2 +- image/image.module | 4 ++-- update.php | 2 +- 8 files changed, 18 insertions(+), 24 deletions(-) diff --git authorize.php authorize.php index 2e68352..3adbbee 100644 --- authorize.php +++ authorize.php @@ -39,7 +39,7 @@ define('MAINTENANCE_MODE', 'update'); * Render a 403 access denied page for authorize.php */ function authorize_access_denied_page() { - drupal_add_http_header('403 Forbidden'); + drupal_add_http_header('Status', '403 Forbidden'); watchdog('access denied', 'authorize.php', NULL, WATCHDOG_WARNING); drupal_set_title('Access denied'); return t('You are not allowed to access this page.'); diff --git includes/bootstrap.inc includes/bootstrap.inc index cb149cb..0610a91 100644 --- includes/bootstrap.inc +++ includes/bootstrap.inc @@ -906,29 +906,23 @@ function drupal_load($type, $name) { * too. This is necessary to avoid security bugs (e.g. UTF-7 XSS). * * @param $name - * The HTTP header name, or a status code followed by a reason phrase, e.g. - * "404 Not Found". + * The HTTP header name, or the special 'Status' header name. * @param $value * The HTTP header value; if omitted, the specified header is unset. + * If $name is 'Status', this is expected to be a status code followed by a + * reason phrase, e.g. "404 Not Found". * @param $append * Whether to append the value to an existing header or to replace it. */ -function drupal_add_http_header($name = NULL, $value = NULL, $append = FALSE) { +function drupal_add_http_header($name, $value, $append = FALSE) { // The headers as name/value pairs. - $headers = &drupal_static(__FUNCTION__, array()); + $headers = &drupal_static('drupal_http_headers', array()); if (!isset($name)) { return $headers; } - // Save status codes using the special key ":status". - if (preg_match('/^\d{3} /', $name)) { - $value = $name; - $name = $name_lower = ':status'; - } - else { - $name_lower = strtolower($name); - } + $name_lower = strtolower($name); _drupal_set_preferred_header_name($name); if (!isset($value)) { @@ -956,7 +950,7 @@ function drupal_add_http_header($name = NULL, $value = NULL, $append = FALSE) { * or NULL if the header has not been set. */ function drupal_get_http_header($name = NULL) { - $headers = drupal_add_http_header(); + $headers = &drupal_static('drupal_http_headers', array()); if (isset($name)) { $name = strtolower($name); return isset($headers[$name]) ? $headers[$name] : NULL; @@ -1006,7 +1000,7 @@ function drupal_send_headers($default_headers = array(), $only_default = FALSE) } } foreach ($headers as $name_lower => $value) { - if ($name_lower == ':status') { + if ($name_lower == 'status') { header($_SERVER['SERVER_PROTOCOL'] . ' ' . $value); } // Skip headers that have been unset. diff --git includes/common.inc includes/common.inc index 239a979..2d3b043 100644 --- includes/common.inc +++ includes/common.inc @@ -2339,7 +2339,7 @@ function drupal_deliver_html_page($page_callback_result) { switch ($page_callback_result) { case MENU_NOT_FOUND: // Print a 404 page. - drupal_add_http_header('404 Not Found'); + drupal_add_http_header('Status', '404 Not Found'); watchdog('page not found', check_plain($_GET['q']), NULL, WATCHDOG_WARNING); @@ -2369,7 +2369,7 @@ function drupal_deliver_html_page($page_callback_result) { case MENU_ACCESS_DENIED: // Print a 403 page. - drupal_add_http_header('403 Forbidden'); + drupal_add_http_header('Status', '403 Forbidden'); watchdog('access denied', check_plain($_GET['q']), NULL, WATCHDOG_WARNING); // Keep old path for reference, and to allow forms to redirect to it. @@ -2397,7 +2397,7 @@ function drupal_deliver_html_page($page_callback_result) { case MENU_SITE_OFFLINE: // Print a 503 page. drupal_maintenance_theme(); - drupal_add_http_header('503 Service unavailable'); + drupal_add_http_header('Status', '503 Service unavailable'); drupal_set_title(t('Site under maintenance')); print theme('maintenance_page', array('content' => filter_xss_admin(variable_get('maintenance_mode_message', t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal'))))))); diff --git includes/database/database.inc includes/database/database.inc index b92ee63..4a42f68 100644 --- includes/database/database.inc +++ includes/database/database.inc @@ -2722,7 +2722,7 @@ function _db_error_page($error = '') { global $db_type; drupal_language_initialize(); drupal_maintenance_theme(); - drupal_add_http_header($_SERVER['SERVER_PROTOCOL'] . ' 503 Service Unavailable'); + drupal_add_http_header('Status', '503 Service Unavailable'); drupal_set_title('Site offline'); } diff --git includes/errors.inc includes/errors.inc index 42bd3a1..4e2dbdc 100644 --- includes/errors.inc +++ includes/errors.inc @@ -172,7 +172,7 @@ function _drupal_log_error($error, $fatal = FALSE) { } if ($fatal) { - drupal_add_http_header('500 Service unavailable (with message)'); + drupal_add_http_header('Status', '500 Service unavailable (with message)'); } if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') { diff --git modules/aggregator/tests/aggregator_test.module modules/aggregator/tests/aggregator_test.module index d5293ce..a516826 100644 --- modules/aggregator/tests/aggregator_test.module +++ modules/aggregator/tests/aggregator_test.module @@ -40,7 +40,7 @@ function aggregator_test_feed($use_last_modified = FALSE, $use_etag = FALSE) { } // Return 304 not modified if either last modified or etag match. if ($last_modified == $if_modified_since || $etag == $if_none_match) { - drupal_add_http_header('304 Not Modified'); + drupal_add_http_header('Status', '304 Not Modified'); return; } diff --git modules/image/image.module modules/image/image.module index 6755a6d..ac06836 100644 --- modules/image/image.module +++ modules/image/image.module @@ -609,7 +609,7 @@ function image_style_generate() { if (!$lock_acquired) { // Tell client to retry again in 3 seconds. Currently no browsers are known // to support Retry-After. - drupal_add_http_header('503 Service Unavailable'); + drupal_add_http_header('Status', '503 Service Unavailable'); drupal_add_http_header('Retry-After', 3); print t('Image generation in progress. Try again shortly.'); drupal_exit(); @@ -630,7 +630,7 @@ function image_style_generate() { } else { watchdog('image', 'Unable to generate the derived image located at %path.', array('%path' => $destination)); - drupal_add_http_header('500 Internal Server Error'); + drupal_add_http_header('Status', '500 Internal Server Error'); print t('Error generating image.'); drupal_exit(); } diff --git update.php update.php index 988024e..a93fc37 100644 --- update.php +++ update.php @@ -237,7 +237,7 @@ function update_info_page() { } function update_access_denied_page() { - drupal_add_http_header('403 Forbidden'); + drupal_add_http_header('Status', '403 Forbidden'); watchdog('access denied', 'update.php', NULL, WATCHDOG_WARNING); drupal_set_title('Access denied'); return '

Access denied. You are not authorized to access this page. Log in using either an account with the administer software updates permission or the site maintenance account (the account you created during installation). If you cannot log in, you will have to edit settings.php to bypass this access check. To do this: