diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 9dd3f56..1f98e87 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -17,6 +17,7 @@ use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Exception\RuntimeException as DependencyInjectionRuntimeException; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; use Drupal\Core\Language\Language; use Drupal\Core\Lock\DatabaseLockBackend; use Drupal\Core\Lock\LockBackendInterface; @@ -1068,6 +1069,8 @@ function drupal_load($type, $name) { * reason phrase, e.g. "404 Not Found". * @param $append * Whether to append the value to an existing header or to replace it. + * + * @deprecated Header handling is being shifted to a Symfony response object. */ function drupal_add_http_header($name, $value, $append = FALSE) { // The headers as name/value pairs. @@ -1087,7 +1090,6 @@ function drupal_add_http_header($name, $value, $append = FALSE) { else { $headers[$name_lower] = $value; } - drupal_send_headers(array($name => $headers[$name_lower]), TRUE); } /** @@ -1100,6 +1102,8 @@ function drupal_add_http_header($name, $value, $append = FALSE) { * @return * A string containing the header value, or FALSE if the header has been set, * or NULL if the header has not been set. + * + * @deprecated Header handling is being shifted to a Symfony response object. */ function drupal_get_http_header($name = NULL) { $headers = &drupal_static('drupal_http_headers', array()); @@ -1116,7 +1120,9 @@ function drupal_get_http_header($name = NULL) { * Sets the preferred name for the HTTP header. * * Header names are case-insensitive, but for maximum compatibility they should - * follow "common form" (see RFC 2617, section 4.2). + * follow "common form" (see RFC 2616, section 4.2). + * + * @deprecated Header handling is being shifted to a Symfony response object. */ function _drupal_set_preferred_header_name($name = NULL) { static $header_names = array(); @@ -1138,6 +1144,8 @@ function _drupal_set_preferred_header_name($name = NULL) { * @param bool $only_default * (optional) If TRUE and headers have already been sent, send only the * specified headers. + * + * @deprecated Header handling is being shifted to a Symfony response object. */ function drupal_send_headers($default_headers = array(), $only_default = FALSE) { $headers_sent = &drupal_static(__FUNCTION__, FALSE); @@ -1192,6 +1200,8 @@ function drupal_send_headers($default_headers = array(), $only_default = FALSE) * identical. * * @see drupal_page_set_cache() + * + * @deprecated Header handling is being shifted to a Symfony response object. */ function drupal_page_header() { $headers_sent = &drupal_static(__FUNCTION__, FALSE); @@ -1220,26 +1230,24 @@ function drupal_page_header() { * and the conditions match those currently in the cache, a 304 Not Modified * response is sent. */ -function drupal_serve_page_from_cache(stdClass $cache) { +function drupal_serve_page_from_cache(stdClass $cache, Response $response, Request $request) { $config = config('system.performance'); + // First half: we must determine if we should be returning a 304. + // Negotiate whether to use compression. $page_compression = $config->get('response.gzip') && extension_loaded('zlib'); - $return_compressed = $page_compression && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE; + $return_compressed = $page_compression && $request->server->has('HTTP_ACCEPT_ENCODING') && strpos($request->server->get('HTTP_ACCEPT_ENCODING'), 'gzip') !== FALSE; // Get headers. Keys are lower-case. $boot_headers = drupal_get_http_header(); - // Headers generated in this function, that may be replaced or unset using - // drupal_add_http_headers(). Keys are mixed-case. - $default_headers = array(); - foreach ($cache->data['headers'] as $name => $value) { // In the case of a 304 response, certain headers must be sent, and the // remaining may not (see RFC 2616, section 10.3.5). $name_lower = strtolower($name); if (in_array($name_lower, array('content-location', 'expires', 'cache-control', 'vary')) && !isset($boot_headers[$name_lower])) { - drupal_add_http_header($name, $value); + $response->headers->set($name, $value); unset($cache->data['headers'][$name]); } } @@ -1248,39 +1256,40 @@ function drupal_serve_page_from_cache(stdClass $cache) { // to that one particular client due to Vary: Cookie. Thus, do not set // max-age > 0, allowing the page to be cached by external proxies, when a // session cookie is present unless the Vary header has been replaced. - $max_age = !isset($_COOKIE[session_name()]) || isset($boot_headers['vary']) ? $config->get('cache.page.max_age') : 0; - $default_headers['Cache-Control'] = 'public, max-age=' . $max_age; + $max_age = !$request->cookies->has(session_name()) || isset($boot_headers['vary']) ? $config->get('cache.page.max_age') : 0; + $response->headers->set('Cache-Control', 'public, max-age=' . $max_age); // Entity tag should change if the output changes. - $etag = '"' . $cache->created . '-' . intval($return_compressed) . '"'; - header('Etag: ' . $etag); + $response->setEtag($cache->created); // See if the client has provided the required HTTP headers. - $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) : FALSE; - $if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) : FALSE; + $if_modified_since = $request->server->has('HTTP_IF_MODIFIED_SINCE') ? strtotime($request->server->get('HTTP_IF_MODIFIED_SINCE')) : FALSE; + $if_none_match = $request->server->has('HTTP_IF_NONE_MATCH') ? stripslashes($request->server->get('HTTP_IF_NONE_MATCH')) : FALSE; if ($if_modified_since && $if_none_match - && $if_none_match == $etag // etag must match + && $if_none_match == $response->headers->get('etag') // etag must match && $if_modified_since == $cache->created) { // if-modified-since must match - header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified'); - drupal_send_headers($default_headers); + $response->setStatusCode(304); return; } + // Second half: we're not returning a 304, so put in other headers. + // Send the remaining headers. foreach ($cache->data['headers'] as $name => $value) { + $response->headers->set($name, $value); drupal_add_http_header($name, $value); } - $default_headers['Last-Modified'] = gmdate(DATE_RFC1123, $cache->created); + $response->setLastModified(\DateTime::createFromFormat('U', $cache->created)); // HTTP/1.0 proxies does not support the Vary header, so prevent any caching // by sending an Expires date in the past. HTTP/1.1 clients ignores the // Expires header if a Cache-Control: max-age= directive is specified (see RFC // 2616, section 14.9.3). - $default_headers['Expires'] = 'Sun, 19 Nov 1978 05:00:00 GMT'; - - drupal_send_headers($default_headers); + if (!$response->getExpires()) { + $response->setExpires(\DateTime::createFromFormat('j-M-Y H:i:s T', '19-Nov-1978 05:00:00 GMT')); + } // Allow HTTP proxies to cache pages for anonymous users without a session // cookie. The Vary header is used to indicates the set of request-header @@ -1288,17 +1297,17 @@ function drupal_serve_page_from_cache(stdClass $cache) { // response to reply to a subsequent request for a given URL without // revalidation. if (!isset($boot_headers['vary']) && !settings()->get('omit_vary_cookie')) { - header('Vary: Cookie'); + $response->setVary('Cookie', FALSE); } if ($page_compression) { - header('Vary: Accept-Encoding', FALSE); + $response->setVary('accept-encoding', FALSE); // If page_compression is enabled, the cache contains gzipped data. if ($return_compressed) { // $cache->data['body'] is already gzip'ed, so make sure // zlib.output_compression does not compress it once more. ini_set('zlib.output_compression', '0'); - header('Content-Encoding: gzip'); + $response->headers->set('content-encoding', 'gzip'); } else { // The client does not support compression, so unzip the data in the @@ -1307,8 +1316,7 @@ function drupal_serve_page_from_cache(stdClass $cache) { } } - // Print the page. - print $cache->data['body']; + $response->setContent($cache->data['body']); } /** @@ -2066,27 +2074,34 @@ function _drupal_bootstrap_page_cache() { $config = config('system.performance'); $cache_enabled = $config->get('cache.page.use_internal'); } + + // @todo this is *criminal*. but, necessary, until we fix bootstrap ordering. + $request = Request::createFromGlobals(); // If there is no session cookie and cache is enabled (or forced), try // to serve a cached page. - if (!isset($_COOKIE[session_name()]) && $cache_enabled) { + if (!$request->cookies->has(session_name()) && $cache_enabled) { // Make sure there is a user object because its timestamp will be checked. $user = drupal_anonymous_user(); // Get the page from the cache. $cache = drupal_page_get_cache(); // If there is a cached page, display it. if (is_object($cache)) { - header('X-Drupal-Cache: HIT'); + $response = new Response(); + $response->headers->set('X-Drupal-Cache', 'HIT'); // Restore the metadata cached with the page. _current_path($cache->data['path']); drupal_set_title($cache->data['title'], PASS_THROUGH); date_default_timezone_set(drupal_get_user_timezone()); - drupal_serve_page_from_cache($cache); + drupal_serve_page_from_cache($cache, $response, $request); + // We are done. + $response->prepare($request); + $response->send(); exit; } else { - header('X-Drupal-Cache: MISS'); + drupal_add_http_header('X-Drupal-Cache', 'MISS'); } } } diff --git a/core/includes/common.inc b/core/includes/common.inc index c4bf7e2..0d0a8f7 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -8,6 +8,8 @@ use Drupal\Core\Language\Language; use Symfony\Component\DependencyInjection\Container; use Symfony\Component\Yaml\Parser; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Request; use Drupal\Component\PhpStorage\PhpStorageFactory; use Drupal\Component\Utility\NestedArray; use Drupal\Core\Cache\CacheBackendInterface; @@ -4396,15 +4398,15 @@ function _drupal_bootstrap_full($skip = FALSE) { * * @see drupal_page_header() */ -function drupal_page_set_cache($body) { +function drupal_page_set_cache(Response $response, Request $request) { global $base_root; if (drupal_page_is_cacheable()) { $cache = (object) array( - 'cid' => $base_root . request_uri(), + 'cid' => $base_root . $request->getRequestUri(), 'data' => array( - 'path' => current_path(), - 'body' => $body, + 'path' => $request->attributes->get('system_path'), + 'body' => $response->getContent(), 'title' => drupal_get_title(), 'headers' => array(), ), @@ -4413,16 +4415,18 @@ function drupal_page_set_cache($body) { 'created' => REQUEST_TIME, ); - // Restore preferred header names based on the lower-case names returned - // by drupal_get_http_header(). - $header_names = _drupal_set_preferred_header_name(); - foreach (drupal_get_http_header() as $name_lower => $value) { - $cache->data['headers'][$header_names[$name_lower]] = $value; - if ($name_lower == 'expires') { - // Use the actual timestamp from an Expires header if available. - $date = new DrupalDateTime($value); - $cache->expire = $date->getTimestamp(); - } + $cache->data['headers'] = $response->headers->all(); + + // Hack: exclude the x-drupal-cache header; it may make it in here because + // of awkwardness in how we defer sending it over in _drupal_page_get_cache. + if (isset($cache->data['headers']['x-drupal-cache'])) { + unset($cache->data['headers']['x-drupal-cache']); + } + + // Use the actual timestamp from an Expires header, if available. + if ($date = $response->getExpires()) { + $date = new DrupalDateTime($date); + $cache->expire = $date->getTimestamp(); } if ($cache->data['body']) { diff --git a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php index 163d5c8..0b9bbad 100644 --- a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php @@ -47,6 +47,7 @@ public function onRespond(FilterResponseEvent $event) { return; } + $request = $event->getRequest(); $response = $event->getResponse(); // Set the X-UA-Compatible HTTP header to force IE to use the most recent @@ -60,7 +61,7 @@ public function onRespond(FilterResponseEvent $event) { // since the page is in fact being regenerated right now. // @todo Remove this and use a more intelligent default so that HTTP // caching can function properly. - $response->headers->set('Last-Modified', gmdate(DATE_RFC1123, REQUEST_TIME)); + $response->setLastModified(new \DateTime(gmdate(DATE_RFC1123, REQUEST_TIME))); // 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 @@ -82,25 +83,31 @@ public function onRespond(FilterResponseEvent $event) { // identical. // @todo Remove this line as no longer necessary per // http://drupal.org/node/1573064 - $response->headers->set('ETag', '"' . REQUEST_TIME . '"'); + $response->setEtag(REQUEST_TIME); // 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. // @todo Revisit whether or not this is still appropriate now that the - // Response object does its own cache control procesisng and we intend to + // Response object does its own cache control processing and we intend to // use partial page caching more extensively. // Commit the user session, if needed. drupal_session_commit(); + + // Attach globally-declared headers to the response object so that Symfony + // can send them for us correctly. + // @todo remove this once we have removed all drupal_add_http_header() calls + $headers = drupal_get_http_header(); + foreach ($headers as $name => $value) { + $response->headers->set($name, $value, FALSE); + } + $max_age = config('system.performance')->get('cache.page.max_age'); - if ($max_age > 0 && ($cache = drupal_page_set_cache($response->getContent()))) { - drupal_serve_page_from_cache($cache); - // drupal_serve_page_from_cache() already printed the response. - $response->setContent(''); - $response->headers->remove('cache-control'); + if ($max_age > 0 && ($cache = drupal_page_set_cache($response, $request))) { + drupal_serve_page_from_cache($cache, $response, $request); } else { - $response->headers->set('Expires', 'Sun, 19 Nov 1978 05:00:00 GMT'); + $response->setExpires(\DateTime::createFromFormat('j-M-Y H:i:s T', '19-Nov-1978 05:00:00 GMT')); $response->headers->set('Cache-Control', 'no-cache, must-revalidate, post-check=0, pre-check=0'); } } diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php index acdec6d..a2bb55a 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php @@ -54,16 +54,6 @@ protected $headers; /** - * Indicates that headers should be dumped if verbose output is enabled. - * - * Headers are dumped to verbose by drupalGet(), drupalHead(), and - * drupalPost(). - * - * @var bool - */ - protected $dumpHeaders = FALSE; - - /** * The content of the page currently loaded in the internal browser. * * @var string @@ -1201,15 +1191,9 @@ protected function drupalGet($path, array $options = array(), array $headers = a if ($new = $this->checkForMetaRefresh()) { $out = $new; } - - $verbose = 'GET request to: ' . $path . - '
Ending URL: ' . $this->getUrl(); - if ($this->dumpHeaders) { - $verbose .= '
Headers:
' . check_plain(var_export(array_map('trim', $this->headers), TRUE)) . '
'; - } - $verbose .= '
' . $out; - - $this->verbose($verbose); + $this->verbose('GET request to: ' . $path . + '
Ending URL: ' . $this->getUrl() . + '
' . $out); return $out; } @@ -1389,16 +1373,10 @@ protected function drupalPost($path, $edit, $submit, array $options = array(), a if ($new = $this->checkForMetaRefresh()) { $out = $new; } - - $verbose = 'POST request to: ' . $path; - $verbose .= '
Ending URL: ' . $this->getUrl(); - if ($this->dumpHeaders) { - $verbose .= '
Headers:
' . check_plain(var_export(array_map('trim', $this->headers), TRUE)) . '
'; - } - $verbose .= '
Fields: ' . highlight_string('' . $out; - - $this->verbose($verbose); + $this->verbose('POST request to: ' . $path . + '
Ending URL: ' . $this->getUrl() . + '
Fields: ' . highlight_string('' . $out); return $out; } } @@ -1655,13 +1633,6 @@ protected function drupalHead($path, array $options = array(), array $headers = $options['absolute'] = TRUE; $out = $this->curlExec(array(CURLOPT_NOBODY => TRUE, CURLOPT_URL => url($path, $options), CURLOPT_HTTPHEADER => $headers)); $this->refreshVariables(); // Ensure that any changes to variables in the other thread are picked up. - - if ($this->dumpHeaders) { - $this->verbose('GET request to: ' . $path . - '
Ending URL: ' . $this->getUrl() . - '
Headers:
' . check_plain(var_export(array_map('trim', $this->headers), TRUE)) . '
'); - } - return $out; } diff --git a/core/modules/system/lib/Drupal/system/Tests/Bootstrap/PageCacheTest.php b/core/modules/system/lib/Drupal/system/Tests/Bootstrap/PageCacheTest.php index 253c463..ca2d7b3 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Bootstrap/PageCacheTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Bootstrap/PageCacheTest.php @@ -92,21 +92,25 @@ function testPageCache() { $config = config('system.performance'); $config->set('cache.page.use_internal', 1); $config->set('cache.page.max_age', 300); + $config->set('response.gzip', 1); $config->save(); // Fill the cache. $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Foo', 'value' => 'bar'))); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.'); - $this->assertEqual($this->drupalGetHeader('Vary'), 'Cookie,Accept-Encoding', 'Vary header was sent.'); - $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'public, max-age=300', 'Cache-Control header was sent.'); + $this->assertEqual(strtolower($this->drupalGetHeader('Vary')), 'cookie,accept-encoding', 'Vary header was sent.'); + // Symfony's Response logic determines a specific order for the subvalues + // of the Cache-Control header, even if they are explicitly passed in to + // the response header bag in a different order. + $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'max-age=300, public', 'Cache-Control header was sent.'); $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.'); $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.'); // Check cache. $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Foo', 'value' => 'bar'))); $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.'); - $this->assertEqual($this->drupalGetHeader('Vary'), 'Cookie,Accept-Encoding', 'Vary: Cookie header was sent.'); - $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'public, max-age=300', 'Cache-Control header was sent.'); + $this->assertEqual(strtolower($this->drupalGetHeader('Vary')), 'cookie,accept-encoding', 'Vary: Cookie header was sent.'); + $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'max-age=300, public', 'Cache-Control header was sent.'); $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.'); $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.'); @@ -114,14 +118,14 @@ function testPageCache() { $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Expires', 'value' => 'Fri, 19 Nov 2008 05:00:00 GMT'))); $this->assertEqual($this->drupalGetHeader('Expires'), 'Fri, 19 Nov 2008 05:00:00 GMT', 'Default header was replaced.'); $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Vary', 'value' => 'User-Agent'))); - $this->assertEqual($this->drupalGetHeader('Vary'), 'User-Agent,Accept-Encoding', 'Default header was replaced.'); + $this->assertEqual(strtolower($this->drupalGetHeader('Vary')), 'user-agent,accept-encoding', 'Default header was replaced.'); // Check that authenticated users bypass the cache. $user = $this->drupalCreateUser(); $this->drupalLogin($user); $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Foo', 'value' => 'bar'))); $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'), 'Caching was bypassed.'); - $this->assertTrue(strpos($this->drupalGetHeader('Vary'), 'Cookie') === FALSE, 'Vary: Cookie header was not sent.'); + $this->assertTrue(strpos(strtolower($this->drupalGetHeader('Vary')), 'cookie') === FALSE, 'Vary: Cookie header was not sent.'); $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'must-revalidate, no-cache, post-check=0, pre-check=0, private', 'Cache-Control header was sent.'); $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.'); $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.'); @@ -148,6 +152,7 @@ function testPageCompression() { $config = config('system.performance'); $config->set('cache.page.use_internal', 1); $config->set('cache.page.max_age', 300); + $config->set('response.gzip', 1); $config->save(); // Fill the cache and verify that output is compressed. diff --git a/core/modules/system/lib/Drupal/system/Tests/Session/SessionTest.php b/core/modules/system/lib/Drupal/system/Tests/Session/SessionTest.php index d1a601a..f96b13e 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Session/SessionTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Session/SessionTest.php @@ -18,6 +18,8 @@ class SessionTest extends WebTestBase { */ public static $modules = array('session_test'); + protected $dumpHeaders = TRUE; + public static function getInfo() { return array( 'name' => 'Session tests', diff --git a/core/modules/system/lib/Drupal/system/Tests/Update/UpdateScriptTest.php b/core/modules/system/lib/Drupal/system/Tests/Update/UpdateScriptTest.php index 2bb96b9..b0e255e 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Update/UpdateScriptTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Update/UpdateScriptTest.php @@ -21,6 +21,8 @@ class UpdateScriptTest extends WebTestBase { */ public static $modules = array('update_script_test', 'dblog'); + protected $dumpHeaders = TRUE; + private $update_url; private $update_user; diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module index c9f0c22..e1d55f3 100644 --- a/core/modules/toolbar/toolbar.module +++ b/core/modules/toolbar/toolbar.module @@ -9,6 +9,7 @@ use Symfony\Component\HttpFoundation\JsonResponse; use Drupal\Core\Template\Attribute; use Drupal\Component\Utility\Crypt; +use Symfony\Component\HttpFoundation\Response; /** * Implements hook_help(). @@ -129,19 +130,23 @@ function _toolbar_initialize_page_cache() { // @see _drupal_bootstrap_page_cache() $cache = drupal_page_get_cache(); if (is_object($cache)) { - header('X-Drupal-Cache: HIT'); + $response = new Response(); + $request = \Drupal::request(); + $response->headers->set('X-Drupal-Cache', 'HIT'); // Restore the metadata cached with the page. $_GET['q'] = $cache->data['path']; date_default_timezone_set(drupal_get_user_timezone()); - drupal_serve_page_from_cache($cache); + drupal_serve_page_from_cache($cache, $response, $request); + $response->prepare($request); + $response->send(); // We are done. exit; } // Otherwise, create a new page response (that will be cached). - header('X-Drupal-Cache: MISS'); + drupal_add_http_header('X-Drupal-Cache', 'MISS'); // The Expires HTTP header is the heart of the client-side HTTP caching. The // additional server-side page cache only takes effect when the client diff --git a/core/update.php b/core/update.php index cee23c4..6e85b0f 100644 --- a/core/update.php +++ b/core/update.php @@ -302,6 +302,7 @@ function update_info_page() { */ function update_access_denied_page() { drupal_add_http_header('Status', '403 Forbidden'); + header($_SERVER['SERVER_PROTOCOL'] . ' 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: