Index: includes/bootstrap.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v
retrieving revision 1.120
diff -u -F^f -r1.120 bootstrap.inc
--- includes/bootstrap.inc	30 Aug 2006 08:46:16 -0000	1.120
+++ includes/bootstrap.inc	30 Aug 2006 20:33:35 -0000
@@ -10,7 +10,8 @@
 define('CACHE_TEMPORARY', -1);
 
 define('CACHE_DISABLED', 0);
-define('CACHE_ENABLED', 1);
+define('CACHE_RECOMMENDED', 1);
+define('CACHE_EXPERT', 2);
 
 define('WATCHDOG_NOTICE', 0);
 define('WATCHDOG_WARNING', 1);
@@ -139,7 +140,7 @@ function conf_path() {
 function drupal_unset_globals() {
   if (ini_get('register_globals')) {
     $allowed = array('_ENV' => 1, '_GET' => 1, '_POST' => 1, '_COOKIE' => 1, '_FILES' => 1, '_SERVER' => 1, '_REQUEST' => 1, 'access_check' => 1, 'GLOBALS' => 1);
-    foreach ($GLOBALS as $key => $value) {
+    foreach ($GLOBALS as $key) {
       if (!isset($allowed[$key])) {
         unset($GLOBALS[$key]);
       }
@@ -382,11 +383,6 @@ function drupal_load($type, $name) {
 /**
  * Set HTTP headers in preparation for a page response.
  *
- * The general approach here is that anonymous users can keep a local
- * cache of the page, but must revalidate it on every request.  Then,
- * they are given a '304 Not Modified' response as long as they stay
- * logged out and the page has not been modified.
- *
  * Authenticated users are always given a 'no-cache' header, and will
  * fetch a fresh page on every request.  This prevents authenticated
  * users seeing locally cached pages that show them as logged out.
@@ -394,62 +390,66 @@ function drupal_load($type, $name) {
  * @see page_set_cache
  */
 function drupal_page_header() {
-  if (variable_get('cache', 0) && $cache = page_get_cache()) {
-    bootstrap_invoke_all('init');
-
-    // Set default values:
-    $last_modified = gmdate('D, d M Y H:i:s', $cache->created) .' GMT';
-    $etag = '"'.md5($last_modified).'"';
-
-    // See if the client has provided the required HTTP headers:
-    $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']) : FALSE;
-    $if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) : FALSE;
-
-    if ($if_modified_since && $if_none_match
-        && $if_none_match == $etag // etag must match
-        && $if_modified_since == $last_modified) {  // if-modified-since must match
-      header('HTTP/1.1 304 Not Modified');
-      // All 304 responses must send an etag if the 200 response for the same object contained an etag
-      header("Etag: $etag");
-      exit();
-    }
-
-    // Send appropriate response:
-    header("Last-Modified: $last_modified");
-    header("ETag: $etag");
+  header("Expires: Sun, 19 Nov 1978 05:00:00 GMT");
+  header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
+  header("Cache-Control: no-store, no-cache, must-revalidate");
+  header("Cache-Control: post-check=0, pre-check=0", FALSE);
+  header("Pragma: no-cache");
+}
 
-    // The following headers force validation of cache:
-    header("Expires: Sun, 19 Nov 1978 05:00:00 GMT");
-    header("Cache-Control: must-revalidate");
+/**
+ * Set HTTP headers in preparation for a cached page response.
+ *
+ * The general approach here is that anonymous users can keep a local
+ * cache of the page, but must revalidate it on every request.  Then,
+ * they are given a '304 Not Modified' response as long as they stay
+ * logged out and the page has not been modified.
+ *
+ */
+function drupal_page_cache_header($cache) {
+  // Set default values:
+  $last_modified = gmdate('D, d M Y H:i:s', $cache->created) .' GMT';
+  $etag = '"'.md5($last_modified).'"';
+
+  // See if the client has provided the required HTTP headers:
+  $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']) : FALSE;
+  $if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) : FALSE;
+
+  if ($if_modified_since && $if_none_match
+      && $if_none_match == $etag // etag must match
+      && $if_modified_since == $last_modified) {  // if-modified-since must match
+    header('HTTP/1.1 304 Not Modified');
+    // All 304 responses must send an etag if the 200 response for the same object contained an etag
+    header("Etag: $etag");
+    exit();
+  }
 
-    // Determine if the browser accepts gzipped data.
-    if (@strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') === FALSE && function_exists('gzencode')) {
-      // Strip the gzip header and run uncompress.
-      $cache->data = gzinflate(substr(substr($cache->data, 10), 0, -8));
-    }
-    elseif (function_exists('gzencode')) {
-      header('Content-Encoding: gzip');
-    }
+  // Send appropriate response:
+  header("Last-Modified: $last_modified");
+  header("ETag: $etag");
 
-    // Send the original request's headers. We send them one after
-    // another so PHP's header() function can deal with duplicate
-    // headers.
-    $headers = explode("\n", $cache->headers);
-    foreach ($headers as $header) {
-      header($header);
-    }
+  // The following headers force validation of cache:
+  header("Expires: Sun, 19 Nov 1978 05:00:00 GMT");
+  header("Cache-Control: must-revalidate");
 
-    print $cache->data;
-    bootstrap_invoke_all('exit');
-    exit();
+  // Determine if the browser accepts gzipped data.
+  if (@strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') === FALSE && function_exists('gzencode')) {
+    // Strip the gzip header and run uncompress.
+    $cache->data = gzinflate(substr(substr($cache->data, 10), 0, -8));
   }
-  else {
-    header("Expires: Sun, 19 Nov 1978 05:00:00 GMT");
-    header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
-    header("Cache-Control: no-store, no-cache, must-revalidate");
-    header("Cache-Control: post-check=0, pre-check=0", FALSE);
-    header("Pragma: no-cache");
+  elseif (function_exists('gzencode')) {
+    header('Content-Encoding: gzip');
+  }
+
+  // Send the original request's headers. We send them one after
+  // another so PHP's header() function can deal with duplicate
+  // headers.
+  $headers = explode("\n", $cache->headers);
+  foreach ($headers as $header) {
+    header($header);
   }
+
+  print $cache->data;
 }
 
 /**
@@ -677,18 +677,17 @@ function _drupal_bootstrap($phase) {
   global $conf;
 
   switch ($phase) {
+
     case DRUPAL_BOOTSTRAP_CONFIGURATION:
       drupal_unset_globals();
       // Initialize the configuration
       conf_init();
       break;
+
     case DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE:
-      if (variable_get('page_cache_fastpath', 0)) {
-        require_once variable_get('cache_inc', './includes/cache.inc');
-        page_cache_fastpath();
-        exit;
-      }
+      _drupal_cache_init($phase);
       break;
+
     case DRUPAL_BOOTSTRAP_DATABASE:
       // Initialize the default database.
       require_once './includes/database.inc';
@@ -702,10 +701,10 @@ function _drupal_bootstrap($phase) {
       break;
 
     case DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE:
-      require_once variable_get('cache_inc', './includes/cache.inc');
-      require_once './includes/module.inc';
-      // Start a page timer:
-      timer_start('page');
+      // Initialize configuration variables, using values from settings.php if available.
+      $conf = variable_init(isset($conf) ? $conf : array());
+
+      _drupal_cache_init($phase);
 
       // deny access to hosts which were banned. t() is not yet available.
       if (drupal_is_denied('host', $_SERVER['REMOTE_ADDR'])) {
@@ -714,8 +713,9 @@ function _drupal_bootstrap($phase) {
         exit();
       }
 
-      // Initialize configuration variables, using values from conf.php if available.
-      $conf = variable_init(isset($conf) ? $conf : array());
+      // Start a page timer:
+      timer_start('page');
+
       drupal_page_header();
       break;
 
@@ -733,6 +733,36 @@ function _drupal_bootstrap($phase) {
 }
 
 /**
+ * Initialize the caching strategy, which loads at different stages within
+ * Drupal's bootstrap process.
+ */
+function _drupal_cache_init($phase) {
+  require_once variable_get('cache_inc', './includes/cache.inc');
+
+  if ($phase == DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE && variable_get('page_cache_fastpath', 0)) {
+    if (page_cache_fastpath()) {
+      exit();
+    }
+  }
+  elseif ($phase == DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE) {
+    if ($cache = page_get_cache()) {
+      if (variable_get('cache', CACHE_DISABLED) == CACHE_EXPERT) {
+        drupal_page_cache_header($cache);
+        exit();
+      }
+      elseif (variable_get('cache', CACHE_DISABLED) == CACHE_RECOMMENDED) {
+        require_once './includes/module.inc';
+        bootstrap_invoke_all('init');
+        drupal_page_cache_header($cache);
+        bootstrap_invoke_all('exit');
+        exit();
+      }
+    }
+    require_once './includes/module.inc';
+  }
+}
+
+/**
  * Enables use of the theme system without requiring database access. Since
  * there is not database access no theme will be enabled and the default
  * themeable functions will be called. Some themeable functions can not be used
Index: modules/system/system.css
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.css,v
retrieving revision 1.5
diff -u -F^f -r1.5 system.css
--- modules/system/system.css	21 Aug 2006 07:33:26 -0000	1.5
+++ modules/system/system.css	30 Aug 2006 20:33:36 -0000
@@ -38,6 +38,9 @@
 .error {
   color: red;
 }
+.ok {
+  color: green;
+}
 .item-list .icon {
   color: #555;
   float: right;
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.355
diff -u -F^f -r1.355 system.module
--- modules/system/system.module	29 Aug 2006 20:19:41 -0000	1.355
+++ modules/system/system.module	30 Aug 2006 20:33:38 -0000
@@ -34,6 +34,8 @@ function system_help($section) {
       return t('Handles general site configuration for administrators.');
     case 'admin':
       return t('<p>Welcome to the administration section. Here you may control how your site functions.</p>');
+    case 'admin/settings/page-caching':
+      return t('Enabling the cache will offer a sufficient performance boost for most low-traffic and medium-traffic sites. Drupal can store and send compressed cached pages requested by "anonymous" users. By caching a web page, Drupal does not have to create the page each time someone wants to view it.');
     case 'admin/build/themes':
       return t('<p>Select which themes are available to your users and specify the default theme. To configure site-wide display settings, click the "configure" task above. Alternately, to override these settings in a specific theme, click the "configure" link for the corresponding theme. Note that different themes may have different regions available for rendering content like blocks. If you want consistency in what your users see, you may wish to enable only one theme.</p>');
     case 'admin/build/themes/settings':
@@ -586,12 +588,24 @@ function system_error_reporting_settings
 
 function system_page_caching_settings() {
 
+  $description = '<p>'. t("The 'Recommended' cache mode is suitable for most sites without any side effects. The 'Expert' cache mode causes Drupal to skip the loading (init) and unloading (exit) of enabled modules when serving a cached page for a performance boost.") .'</p>';
+
+  $problem_modules = array_unique(array_merge(module_implements('init'), module_implements('exit')));
+  sort($problem_modules);
+
+  if (count($problem_modules) > 0) {
+    $description .= '<p>'. t("<strong class=\"error\">The following enabled modules are incompatible with expert 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 expert mode caching.</strong> Please note, if you use expert caching and enable new modules, you'll need to check this page again to ensure compatibility.") .'</p>';
+  }
+
   $form['cache'] = array(
     '#type' => 'radios',
-    '#title' => t('Page cache'),
+    '#title' => t('Caching mode'),
     '#default_value' => variable_get('cache', CACHE_DISABLED),
-    '#options' => array(CACHE_DISABLED => t('Disabled'), CACHE_ENABLED => t('Enabled')),
-    '#description' => t("Drupal has a caching mechanism which stores dynamically generated web pages in a database. By caching a web page, Drupal does not have to create the page each time someone wants to view it, instead it takes only one SQL query to display it, reducing response time and the server's load. Only pages requested by \"anonymous\" users are cached. In order to reduce server load and save bandwidth, Drupal stores and sends compressed cached pages.")
+    '#options' => array(CACHE_DISABLED => t('Disabled'), CACHE_RECOMMENDED => t('Recommended'), CACHE_EXPERT => t('Expert (possible side effects)')),
+    '#description' => $description
   );
 
   $period = drupal_map_assoc(array(0, 60, 180, 300, 600, 900, 1800, 2700, 3600, 10800, 21600, 32400, 43200, 86400), 'format_interval');
