=== modified file 'includes/bootstrap.inc'
--- includes/bootstrap.inc	2009-01-31 16:50:56 +0000
+++ includes/bootstrap.inc	2009-02-10 17:59:31 +0000
@@ -28,13 +28,6 @@ define('CACHE_DISABLED', 0);
 define('CACHE_NORMAL', 1);
 
 /**
- * Indicates that page caching is using "aggressive" mode. This bypasses
- * loading any modules for additional speed, which may break functionality in
- * modules that expect to be run on each page load.
- */
-define('CACHE_AGGRESSIVE', 2);
-
-/**
  * Log message severity -- Emergency: system is unusable.
  *
  * @see watchdog()
@@ -104,10 +97,9 @@ define('WATCHDOG_DEBUG', 7);
 define('DRUPAL_BOOTSTRAP_CONFIGURATION', 0);
 
 /**
- * Second bootstrap phase: try to call a non-database cache
- * fetch routine.
+ * Second bootstrap phase: serve the page from cache if possible.
  */
-define('DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE', 1);
+define('DRUPAL_BOOTSTRAP_PAGE_CACHE', 1);
 
 /**
  * Third bootstrap phase: initialize database layer.
@@ -120,20 +112,19 @@ define('DRUPAL_BOOTSTRAP_DATABASE', 2);
 define('DRUPAL_BOOTSTRAP_ACCESS', 3);
 
 /**
- * Fifth bootstrap phase: initialize session handling.
+ * Fifth bootstrap phase: initialize the variable system.
  */
-define('DRUPAL_BOOTSTRAP_SESSION', 4);
+define('DRUPAL_BOOTSTRAP_VARIABLES', 4);
 
 /**
- * Sixth bootstrap phase: initialize the variable system.
+ * Sixth bootstrap phase: initialize session handling.
  */
-define('DRUPAL_BOOTSTRAP_VARIABLES', 5);
+define('DRUPAL_BOOTSTRAP_SESSION', 5);
 
 /**
- * Seventh bootstrap phase: load bootstrap.inc and module.inc, start
- * the variable system and try to serve a page from the cache.
+ * Seventh bootstrap phase: set up the page header.
  */
-define('DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE', 6);
+define('DRUPAL_BOOTSTRAP_PAGE_HEADER', 6);
 
 /**
  * Eighth bootstrap phase: find out language of the page.
@@ -393,6 +384,14 @@ function conf_path($require_settings = T
 }
 
 /**
+ * Returns the base URL path of the Drupal installation.
+ * At the very least, this will always default to /.
+ */
+function base_path() {
+  return $GLOBALS['base_path'];
+}
+
+/**
  * Initialize variables needed for the rest of the execution.
  */
 function drupal_initialize_variables() {
@@ -526,7 +525,9 @@ function conf_init() {
   if (count(explode('.', $cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $cookie_domain))) {
     ini_set('session.cookie_domain', $cookie_domain);
   }
-  session_name('SESS' . md5($session_name));
+  // For Drupal 7, we add a 7 to SESS, ensuring that no one from Drupal 6
+  // stays logged in.
+  session_name('SESS7' . md5($session_name));
 }
 
 /**
@@ -682,36 +683,57 @@ function variable_del($name) {
  * from a form submission, the contents of a shopping cart, or other user-
  * specific content that should not be cached and displayed to other users.
  *
- * @param $retrieve
- *   If TRUE, look up and return the current page in the cache, or start output
- *   buffering if the conditions for caching are satisfied. If FALSE, only
- *   return a boolean value indicating whether the current request may be
- *   cached.
+ * @param $caching_mode
+ *   If set, then one of CACHE_DISABLED or CACHE_NORMAL. If NULL, then it will
+ *   be looked up in the database.
  * @return
- *   The cache object, if the page was found in the cache; TRUE if the page was
- *   not found, but output buffering was started in order to possibly cache the
- *   current request; FALSE if the page was not found, and the current request
- *   may not be cached (e.g. because it belongs to an authenticated user). If
- *   $retrieve is TRUE, only return either TRUE or FALSE.
+ *   The cache object, if the page was found in the cache; FALSE if the page
+ *   was not found.
  */
-function page_get_cache($retrieve) {
-  global $user, $base_root;
-  static $ob_started = FALSE;
-
-  if ($user->uid || ($_SERVER['REQUEST_METHOD'] != 'GET' && $_SERVER['REQUEST_METHOD'] != 'HEAD') || count(drupal_get_messages(NULL, FALSE))) {
-    return FALSE;
-  }
-  if ($retrieve) {
-    $cache = cache_get($base_root . request_uri(), 'cache_page');
-    if ($cache) {
-      return $cache;
-    }
-    else {
+function page_get_cache($caching_mode = NULL) {
+  global $base_root;
+  $cache = FALSE;
+  $ob = FALSE;
+  if (_page_cache_can_be_set($caching_mode)) {
+    // Although this cookie is easy to be forged or deleted, the only
+    // consequence of forgery is that the attacker receives an uncached page.
+    if (!isset($_COOKIE['drupal_nocache'])) {
+      $cache = cache_get($base_root . request_uri(), 'cache_page');
+    }
+    // Regardless of the cookie, start output buffering to allow destroying
+    // the session at the end of the request if it only contained messages.
+    if (!$cache) {
       ob_start();
-      $ob_started = TRUE;
     }
   }
-  return $ob_started;
+  return $cache;
+}
+
+/**
+ * Check whether page caching is allowed for this request.
+ *
+ * Note that if this function returns TRUE then output buffering has been
+ * started in page_get_cache().
+ *
+ * @param $caching_mode
+ *   If set, then one of CACHE_DISABLED or CACHE_NORMAL. If NULL, then it will
+ *   be looked up in the database.
+ * @return
+ *   Boolean, TRUE if the current request may be cached.
+ */
+function _page_cache_can_be_set($caching_mode = NULL) {
+  global $user;
+  if (!isset($caching_mode)) {
+    $caching_mode = variable_get('cache', CACHE_DISABLED);
+  }
+  return $caching_mode == CACHE_NORMAL && empty($user->uid) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD');
+}
+
+/**
+ * Set a cookie to disallow page caching.
+ */
+function _page_cache_cookie() {
+  setcookie('drupal_nocache', 1, time() + 20 * 365 * 86400, base_path(), ini_get('session.cookie_domain'));
 }
 
 /**
@@ -770,7 +792,7 @@ function drupal_page_header() {
  * logged out and the page has not been modified.
  *
  */
-function drupal_page_cache_header($cache) {
+function drupal_serve_cached_page($cache) {
   // Create entity tag based on cache update time.
   $etag = '"' . md5($cache->created) . '"';
 
@@ -989,6 +1011,7 @@ function drupal_set_message($message = N
 
     if ($repeat || !in_array($message, $_SESSION['messages'][$type])) {
       $_SESSION['messages'][$type][] = $message;
+      _page_cache_cookie();
     }
   }
 
@@ -1039,20 +1062,31 @@ function drupal_get_messages($type = NUL
  *
  * @param $ip string
  *   IP address to check.
+ * @param $full
+ *   TRUE if you want to issue a 403 header and exit if the IP is denied.
  * @return bool
  *   TRUE if access is denied, FALSE if access is allowed.
  */
-function drupal_is_denied($ip) {
+function drupal_is_denied($ip, $full = FALSE) {
   // Because this function is called on every page request, we first check
   // for an array of IP addresses in settings.php before querying the
   // database.
   $blocked_ips = variable_get('blocked_ips');
+  $denied = FALSE;
   if (isset($blocked_ips) && is_array($blocked_ips)) {
-    return in_array($ip, $blocked_ips);
+    $denied = in_array($ip, $blocked_ips);
   }
-  else {
-    return (bool)db_query("SELECT 1 FROM {blocked_ips} WHERE ip = :ip", array(':ip' => $ip))->fetchField();
+  // Only check if database.inc is loaded already.
+  elseif (function_exists('db_is_active')) {
+    $denied = (bool)db_query("SELECT 1 FROM {blocked_ips} WHERE ip = :ip", array(':ip' => $ip))->fetchField();
+  }
+  // Deny access to blocked IP addresses - t() is not yet available.
+  if ($denied && $full) {
+    header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
+    print 'Sorry, ' . check_plain(ip_address()) . ' has been banned.';
+    exit();
   }
+  return $denied;
 }
 
 /**
@@ -1093,13 +1127,15 @@ function drupal_anonymous_user($session 
  *     DRUPAL_BOOTSTRAP_FULL: Drupal is fully loaded, validate and fix input data.
  */
 function drupal_bootstrap($phase = NULL) {
-  static $phases = array(DRUPAL_BOOTSTRAP_CONFIGURATION, DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE, DRUPAL_BOOTSTRAP_DATABASE, DRUPAL_BOOTSTRAP_ACCESS, DRUPAL_BOOTSTRAP_SESSION, DRUPAL_BOOTSTRAP_VARIABLES, DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE, DRUPAL_BOOTSTRAP_LANGUAGE, DRUPAL_BOOTSTRAP_PATH, DRUPAL_BOOTSTRAP_FULL), $completed_phase = -1;
+  static $phases = array(DRUPAL_BOOTSTRAP_CONFIGURATION, DRUPAL_BOOTSTRAP_PAGE_CACHE, DRUPAL_BOOTSTRAP_DATABASE, DRUPAL_BOOTSTRAP_ACCESS, DRUPAL_BOOTSTRAP_VARIABLES, DRUPAL_BOOTSTRAP_SESSION, DRUPAL_BOOTSTRAP_PAGE_HEADER, DRUPAL_BOOTSTRAP_LANGUAGE, DRUPAL_BOOTSTRAP_PATH, DRUPAL_BOOTSTRAP_FULL), $completed_phase = -1;
 
   if (isset($phase)) {
     while ($phases && $phase > $completed_phase) {
       $current_phase = array_shift($phases);
       _drupal_bootstrap($current_phase);
-      $completed_phase = $current_phase;
+      if ($current_phase > $completed_phase) {
+        $completed_phase = $current_phase;
+      }
     }
   }
   return $completed_phase;
@@ -1118,6 +1154,7 @@ function drupal_get_bootstrap_phase() {
 
 function _drupal_bootstrap($phase) {
   global $conf, $user;
+  static $cache;
 
   switch ($phase) {
 
@@ -1129,15 +1166,32 @@ function _drupal_bootstrap($phase) {
       conf_init();
       break;
 
-    case DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE:
+    case DRUPAL_BOOTSTRAP_PAGE_CACHE:
       // Allow specifying special cache handlers in settings.php, like
       // using memcached or files for storing cache information.
       require_once DRUPAL_ROOT . '/' . variable_get('cache_inc', 'includes/cache.inc');
-      // If the page_cache_fastpath is set to TRUE in settings.php and
-      // page_cache_fastpath (implemented in the special implementation of
-      // cache.inc) printed the page and indicated this with a returned TRUE
-      // then we are done.
-      if (variable_get('page_cache_fastpath', FALSE) && page_cache_fastpath()) {
+      // Allow cache mode to be set from settings.php as well.
+      $cache_mode = variable_get('cache');
+      if (isset($cache_mode)) {
+        // We have a cache mode override from settings.php, we check for denied
+        // addresses but only from settings.php.
+        drupal_is_denied(ip_address(), TRUE);
+      }
+      else {
+        // We need to initialize the variable system. This will also load the
+        // database and check denied addresses.
+        drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES);
+      }
+      $cache = page_get_cache($cache_mode);
+      if (is_object($cache)) {
+        if (variable_get('page_cache_fire_hooks', TRUE)) {
+          require_once DRUPAL_ROOT . '/includes/module.inc';
+          module_invoke_all('boot');
+        }
+        drupal_serve_cached_page($cache);
+        if (variable_get('page_cache_fire_hooks', TRUE)) {
+          module_invoke_all('exit');
+        }
         exit;
       }
       break;
@@ -1152,12 +1206,12 @@ function _drupal_bootstrap($phase) {
       break;
 
     case DRUPAL_BOOTSTRAP_ACCESS:
-      // Deny access to blocked IP addresses - t() is not yet available.
-      if (drupal_is_denied(ip_address())) {
-        header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
-        print 'Sorry, ' . check_plain(ip_address()) . ' has been banned.';
-        exit();
-      }
+      // Check denied addresses, using the database if necessary.
+      drupal_is_denied(ip_address(), TRUE);
+
+    case DRUPAL_BOOTSTRAP_VARIABLES:
+      // Initialize configuration variables, using values from settings.php if available.
+      $conf = variable_init(isset($conf) ? $conf : array());
       break;
 
     case DRUPAL_BOOTSTRAP_SESSION:
@@ -1175,44 +1229,23 @@ function _drupal_bootstrap($phase) {
       }
       break;
 
-    case DRUPAL_BOOTSTRAP_VARIABLES:
-      // Initialize configuration variables, using values from settings.php if available.
-      $conf = variable_init(isset($conf) ? $conf : array());
-      break;
-
-    case DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE:
-      $cache_mode = variable_get('cache', CACHE_DISABLED);
-      // Get the page from the cache.
-      $cache = $cache_mode == CACHE_DISABLED ? FALSE : page_get_cache(TRUE);
-      // If the skipping of the bootstrap hooks is not enforced, call hook_boot.
-      if (!is_object($cache) || $cache_mode != CACHE_AGGRESSIVE) {
-        // Load module handling.
-        require_once DRUPAL_ROOT . '/includes/module.inc';
-        module_invoke_all('boot');
-      }
-      // If there is a cached page, display it.
-      if (is_object($cache)) {
-        // Destroy empty anonymous sessions.
-        if (drupal_session_is_started() && empty($_SESSION)) {
-          session_destroy();
-        }
-        drupal_page_cache_header($cache);
-        // If the skipping of the bootstrap hooks is not enforced, call hook_exit.
-        if ($cache_mode != CACHE_AGGRESSIVE) {
-          module_invoke_all('exit');
-        }
-        // We are done.
-        exit;
-      }
+    case DRUPAL_BOOTSTRAP_PAGE_HEADER:
       // Prepare for non-cached page workflow.
-      drupal_page_header();
+      require_once DRUPAL_ROOT . '/includes/module.inc';
+      // If the user is anonymous but has the nocache cookie then it was only
+      // valid for one request, so delete it by setting it back to a past time.
+      if (!$user->uid && isset($_COOKIE['drupal_nocache'])) {
+        setcookie('drupal_nocache', 1, 280299600, base_path(), ini_get('session.cookie_domain'));
+      }
       // If the session has not already been started and output buffering is
       // not enabled, the session must be started now before the HTTP headers
       // are sent. If output buffering is enabled, the session may be started
-      // at any time using drupal_session_start().
-      if ($cache === FALSE) {
+      // at any time using drupal_session_start()
+      if (!_page_cache_can_be_set()) {
         drupal_session_start();
       }
+      drupal_page_header();
+      module_invoke_all('boot');
       break;
 
     case DRUPAL_BOOTSTRAP_LANGUAGE:

=== modified file 'includes/common.inc'
--- includes/common.inc	2009-02-09 03:29:53 +0000
+++ includes/common.inc	2009-02-10 06:04:52 +0000
@@ -1856,9 +1856,7 @@ function drupal_page_footer() {
     watchdog('session', '$_SESSION is non-empty yet no code has called drupal_session_start().', array(), WATCHDOG_NOTICE);
   }
 
-  if (variable_get('cache', CACHE_DISABLED) != CACHE_DISABLED) {
-    page_set_cache();
-  }
+  page_set_cache();
 
   module_invoke_all('exit');
 
@@ -1959,14 +1957,6 @@ function drupal_get_path($type, $name) {
 }
 
 /**
- * Returns the base URL path of the Drupal installation.
- * At the very least, this will always default to /.
- */
-function base_path() {
-  return $GLOBALS['base_path'];
-}
-
-/**
  * Add a <link> tag to the page's HEAD.
  *
  * This function can be called as long the HTML header hasn't been sent.
@@ -3001,7 +2991,7 @@ function _drupal_bootstrap_full() {
 function page_set_cache() {
   global $user, $base_root;
 
-  if (page_get_cache(FALSE)) {
+  if (_page_cache_can_be_set() && !isset($_COOKIE['drupal_nocache'])) {
     $cache = TRUE;
     $data = ob_get_contents();
     if (variable_get('page_compression', TRUE) && function_exists('gzencode')) {
@@ -3254,7 +3244,7 @@ function drupal_render_page($page) {
  *
  * Recursively iterates over each of the array elements, generating HTML code.
  *
- * HTML generation is controlled by two properties containing theme functions, 
+ * HTML generation is controlled by two properties containing theme functions,
  * #theme and #theme_wrapper.
  *
  * #theme is the theme function called first. If it is set and the element has any
@@ -3265,13 +3255,13 @@ function drupal_render_page($page) {
  *
  * The theme function in #theme_wrapper will be called after #theme has run. It
  * can be used to add further markup around the rendered children, e.g. fieldsets
- * add the required markup for a fieldset around their rendered child elements. 
+ * add the required markup for a fieldset around their rendered child elements.
  * A wrapper theme function always has to include the element's #children property
- * in its output, as this contains the rendered children. 
+ * in its output, as this contains the rendered children.
  *
  * For example, for the form element type, by default only the #theme_wrapper
  * property is set, which adds the form markup around the rendered child elements
- * of the form. This allows you to set the #theme property on a specific form to 
+ * of the form. This allows you to set the #theme property on a specific form to
  * a custom theme function, giving you complete control over the placement of the
  * form's children while not at all having to deal with the form markup itself.
  *
@@ -3305,7 +3295,7 @@ function drupal_render(&$elements) {
   else {
     $elements += element_basic_defaults();
   }
-  
+
   // If #markup is not empty and no theme function is set, use theme_markup.
   // This allows to specify just #markup on an element without setting the #type.
   if (!empty($elements['#markup']) && empty($elements['#theme'])) {

=== modified file 'modules/simpletest/tests/bootstrap.test'
--- modules/simpletest/tests/bootstrap.test	2009-01-31 16:50:56 +0000
+++ modules/simpletest/tests/bootstrap.test	2009-02-10 06:04:52 +0000
@@ -212,16 +212,16 @@ class HookBootExitTestCase extends Drupa
     $this->assertEqual(db_query("SELECT COUNT(*) FROM {watchdog} WHERE type = 'system_test' AND message = 'hook_boot'")->fetchField(), $calls, t('hook_boot called with normal cache.'));
     $this->assertEqual(db_query("SELECT COUNT(*) FROM {watchdog} WHERE type = 'system_test' AND message = 'hook_exit'")->fetchField(), $calls, t('hook_exit called with normal cache.'));
 
-    // Test with aggressive cache. Boot and exit should not fire since the
-    // page is cached.
-    variable_set('cache', CACHE_AGGRESSIVE);
-    $this->assertTrue(cache_get(url('', array('absolute' => TRUE)), 'cache_page'), t('Page has been cached.'));
+    // Test whether disabling boot and exit works.
+    variable_set('page_cache_fire_hooks', FALSE);
+    $cache = cache_get(url('', array('absolute' => TRUE)), 'cache_page');
+    $this->assertTrue(is_object($cache), t('Page has been cached.'));
     $this->drupalGet('');
     $this->assertEqual(db_query("SELECT COUNT(*) FROM {watchdog} WHERE type = 'system_test' AND message = 'hook_boot'")->fetchField(), $calls, t('hook_boot not called with agressive cache and a cached page.'));
     $this->assertEqual(db_query("SELECT COUNT(*) FROM {watchdog} WHERE type = 'system_test' AND message = 'hook_exit'")->fetchField(), $calls, t('hook_exit not called with agressive cache and a cached page.'));
 
-    // Test with aggressive cache and page cache cleared. Boot and exit should
-    // be called.
+    // Test whether disabling boot and exit only is in effect if page is
+    // cached.
     $this->assertTrue(db_delete('cache_page')->execute(), t('Page cache cleared.'));
     $this->drupalGet('');
     $calls++;

=== modified file 'modules/simpletest/tests/session.test'
--- modules/simpletest/tests/session.test	2009-01-19 10:46:50 +0000
+++ modules/simpletest/tests/session.test	2009-02-10 06:04:52 +0000
@@ -157,8 +157,8 @@ class SessionTestCase extends DrupalWebT
 
     variable_set('cache', CACHE_NORMAL);
 
-    // During this request the session is destroyed in drupal_page_footer(),
-    // and the session cookie is unset.
+    // During this request the session is destroyed and the session cookie is
+    // unset.
     $this->drupalGet('');
     $this->assertSessionCookie(TRUE);
     $this->assertSessionStarted(TRUE);
@@ -168,41 +168,39 @@ class SessionTestCase extends DrupalWebT
     // expires=..."
     $this->assertTrue(preg_match('/SESS\w+=deleted/', $this->drupalGetHeader('Set-Cookie')), t('Session cookie was deleted.'));
 
-    // Verify that the session cookie was actually deleted.
+    // Verify that page caching works.
     $this->drupalGet('');
-    $this->assertSessionCookie(FALSE);
-    $this->assertSessionStarted(FALSE);
+    $this->assertTrue($this->drupalGetHeader('ETag'), t('Page cached.'));
     $this->assertFalse($this->drupalGetHeader('Set-Cookie'), t('New session was not started.'));
 
     // Start a new session by setting a message.
     $this->drupalGet('session-test/set-message');
+    $this->assertText(t('A message was set.'), t('A message was set.'));
     $this->assertSessionCookie(FALSE);
     $this->assertSessionStarted(FALSE);
     $this->assertTrue($this->drupalGetHeader('Set-Cookie'), t('New session was started.'));
 
-    // Display the message.
+    // Display the message. Session cookie is destroyed at the end of the request.
     $this->drupalGet('');
     $this->assertSessionCookie(TRUE);
     $this->assertSessionStarted(TRUE);
     $this->assertSessionEmpty(FALSE);
     $this->assertFalse($this->drupalGetHeader('ETag'), t('Page was not cached.'));
     $this->assertText(t('This is a dummy message.'), t('Message was displayed.'));
+    $this->assertTrue(preg_match('/SESS\w+=deleted/', $this->drupalGetHeader('Set-Cookie')), t('Session cookie was deleted.'));
 
-    // During this request the session is destroyed in _drupal_bootstrap(),
-    // and the session cookie is unset.
+    // The next request is cached. Cached requests skip the session system.
     $this->drupalGet('');
-    $this->assertSessionCookie(TRUE);
-    $this->assertSessionStarted(TRUE);
-    $this->assertSessionEmpty(TRUE);
-    $this->assertTrue($this->drupalGetHeader('ETag'), t('Page was cached.'));
+    $this->assertSessionCookie(FALSE);
+    $this->assertSessionStarted(FALSE);
+    $this->assertTrue($this->drupalGetHeader('ETag'), t('Page cached.'));
     $this->assertNoText(t('This is a dummy message.'), t('Message was not cached.'));
-    $this->assertTrue(preg_match('/SESS\w+=deleted/', $this->drupalGetHeader('Set-Cookie')), t('Session cookie was deleted.'));
 
-    // Verify that session was destroyed.
-    $this->drupalGet('');
+    // Next, check an uncached page for no session start.
+    $this->drupalGet($this->randomName());
     $this->assertSessionCookie(FALSE);
     $this->assertSessionStarted(FALSE);
-    $this->assertTrue($this->drupalGetHeader('ETag'), t('Page was cached.'));
+    $this->assertFalse($this->drupalGetHeader('ETag'), t('Page was not cached.'));
     $this->assertFalse($this->drupalGetHeader('Set-Cookie'), t('New session was not started.'));
 
     // Verify that modifying $_SESSION without having started a session

=== modified file 'modules/simpletest/tests/session_test.module'
--- modules/simpletest/tests/session_test.module	2009-01-26 14:08:40 +0000
+++ modules/simpletest/tests/session_test.module	2009-02-10 06:07:50 +0000
@@ -52,7 +52,8 @@ function session_test_menu() {
  */
 function session_test_boot() {
   header('X-Session-Cookie: ' . intval(isset($_COOKIE[session_name()])));
-  header('X-Session-Started: ' . intval(drupal_session_is_started()));
+  // When called from hook_boot() for cached pages, the session system is not loaded.
+  header('X-Session-Started: ' . intval(function_exists('drupal_session_is_started') && drupal_session_is_started()));
   header('X-Session-Empty: ' . intval(empty($_SESSION)));
 }
 

=== modified file 'modules/system/system.admin.inc'
--- modules/system/system.admin.inc	2009-02-03 18:55:29 +0000
+++ modules/system/system.admin.inc	2009-02-10 06:04:52 +0000
@@ -1309,15 +1309,6 @@ function system_performance_settings() {
     $description .= '<p>' . t("When caching is enabled, anonymous user sessions are only saved to the database when needed, so the \"Who's online\" block does not display the number of anonymous users.") . '</p>';
   }
 
-  $problem_modules = array_unique(array_merge(module_implements('boot'), module_implements('exit')));
-  sort($problem_modules);
-
-  if (count($problem_modules) > 0) {
-    $description .= '<p>' . t('<strong class="error">The following enabled modules are incompatible with aggressive mode caching and will not function properly: %modules</strong>', array('%modules' => implode(', ', $problem_modules))) . '.</p>';
-  }
-  else {
-    $description .= '<p>' . t('<strong class="ok">Currently, all enabled modules are compatible with the aggressive caching policy.</strong> Please note, if you use aggressive caching and enable new modules, you will need to check this page again to ensure compatibility.') . '</p>';
-  }
   $form['page_cache'] = array(
     '#type' => 'fieldset',
     '#title' => t('Page cache'),
@@ -1328,7 +1319,7 @@ function system_performance_settings() {
     '#type' => 'radios',
     '#title' => t('Caching mode'),
     '#default_value' => variable_get('cache', CACHE_DISABLED),
-    '#options' => array(CACHE_DISABLED => t('Disabled'), CACHE_NORMAL => t('Normal (recommended for production sites, no side effects)'), CACHE_AGGRESSIVE => t('Aggressive (experts only, possible side effects)')),
+    '#options' => array(CACHE_DISABLED => t('Disabled'), CACHE_NORMAL => t('Normal (recommended for production sites, no side effects)')),
     '#description' => $description
   );
 

=== modified file 'modules/system/system.install'
--- modules/system/system.install	2009-02-03 12:30:14 +0000
+++ modules/system/system.install	2009-02-10 17:47:45 +0000
@@ -3213,6 +3213,20 @@ function system_update_7018() {
 }
 
 /**
+ * CACHE_AGGRESSIVE is gone, change it to normal caching and add a warning to
+ * read the documentation.
+ */
+function system_update_7019() {
+  $ret = array();
+  if (variable_get('cache') == 2) {
+    variable_set('cache', CACHE_NORMAL);
+    $t = get_t();
+    $ret[] = array('success' => TRUE, 'query' => $t('This site previously had aggressive caching enabled, to keep this setting, add a variable override for page_cache_fire_hooks in settings.php'));
+  }
+  return $ret;
+}
+
+/**
  * @} End of "defgroup updates-6.x-to-7.x"
  * The next series of updates should start at 8000.
  */

=== modified file 'modules/user/user.module'
--- modules/user/user.module	2009-02-09 07:36:15 +0000
+++ modules/user/user.module	2009-02-10 06:04:52 +0000
@@ -1583,6 +1583,7 @@ function user_authenticate_finalize(&$ed
   // This is called before hook_user in case one of those functions fails
   // or incorrectly does a redirect which would leave the old session in place.
   drupal_session_regenerate();
+  _page_cache_cookie();
   user_module_invoke('login', $edit, $user);
 }
 

=== modified file 'sites/default/default.settings.php'
--- sites/default/default.settings.php	2008-12-23 19:59:17 +0000
+++ sites/default/default.settings.php	2009-02-10 06:04:52 +0000
@@ -46,7 +46,7 @@
 /**
  * Database settings:
  *
- * The $databases array specifies the database connection or 
+ * The $databases array specifies the database connection or
  * connections that Drupal may use.  Drupal is able to connect
  * to multiple databases, including multiple types of databases,
  * during the same request.
@@ -63,7 +63,7 @@
  *   'port' => 3306,
  * );
  *
- * The "driver" property indicates what Drupal database driver the 
+ * The "driver" property indicates what Drupal database driver the
  * connection should use.  This is usually the same as the name of the
  * database type, such as mysql or sqlite, but not always.  The other
  * properties will vary depending on the driver.  For SQLite, you must
@@ -80,7 +80,7 @@
  * A target database allows Drupal to try to send certain queries to a
  * different database if it can but fall back to the default connection if not.
  * That is useful for master/slave replication, as Drupal may try to connect
- * to a slave server when appropriate and if one is not available will simply 
+ * to a slave server when appropriate and if one is not available will simply
  * fall back to the single master server.
  *
  * The general format for the $databases array is as follows:
@@ -290,6 +290,17 @@ ini_set('session.cookie_lifetime', 20000
 # );
 
 /**
+ * Page caching behaviour.
+ *
+ * To use page caching without touching the database set cache to
+ * CACHE_NORMAL. To bypass the various hook_boot and hook_exit implementations,
+ * set the page_cache_fire_hooks variable to FALSE. Also see the IP blocking
+ * section below.
+ */
+# $conf['cache'] = CACHE_NORMAL;
+# $conf['page_cache_fire_hooks'] = FALSE;
+
+/**
  *
  * IP blocking:
  *
@@ -311,3 +322,4 @@ ini_set('session.cookie_lifetime', 20000
 # $conf['blocked_ips'] = array(
 #   'a.b.c.d',
 # );
+

