? log2.txt
? sites/all/modules/cvs
Index: includes/bootstrap.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v
retrieving revision 1.267
diff -u -p -r1.267 bootstrap.inc
--- includes/bootstrap.inc	22 Jan 2009 03:05:17 -0000	1.267
+++ includes/bootstrap.inc	23 Jan 2009 05:21:02 -0000
@@ -673,7 +673,6 @@ function variable_del($name) {
   unset($conf[$name]);
 }
 
-
 /**
  * Retrieve the current page from the cache.
  *
@@ -695,10 +694,10 @@ function variable_del($name) {
  *   $retrieve is TRUE, only return either TRUE or FALSE.
  */
 function page_get_cache($retrieve) {
-  global $user, $base_root;
+  global $base_root;
   static $ob_started = FALSE;
 
-  if ($user->uid || ($_SERVER['REQUEST_METHOD'] != 'GET' && $_SERVER['REQUEST_METHOD'] != 'HEAD') || count(drupal_get_messages(NULL, FALSE))) {
+  if (!page_cache_allowed()) {
     return FALSE;
   }
   if ($retrieve) {
@@ -715,6 +714,36 @@ function page_get_cache($retrieve) {
 }
 
 /**
+ * Retrieves and optionally sets the current page caching status.
+ *
+ * This function is useful if page caching has been started but needs to be
+ * disabled for the current page if something unique is being displayed on the
+ * page, like a message with drupal_set_message().
+ *
+ * @param $set_status
+ *   (optional) A boolean that sets the current page caching status.
+ * @return
+ *   TRUE if the current page should be cached, FALSE if otherwise.
+ */
+function page_cache_allowed($set_status = NULL) {
+  global $user;
+  static $status = NULL;
+
+  if (!isset($status)) {
+    // Do not allow caching when status messages are waiting (from a redirected
+    // form submission which was completed).
+    $status = !count(drupal_get_messages(NULL, FALSE));
+  }
+
+  if (isset($set_status)) {
+    $status = $set_status;
+  }
+
+  // Always check the request method and that the user is logged out.
+  return $status && !$user->uid && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD');
+}
+
+/**
  * Includes a file with the provided type and name. This prevents
  * including a theme, engine, module, etc., more than once.
  *
@@ -989,6 +1018,8 @@ function drupal_set_message($message = N
 
     if ($repeat || !in_array($message, $_SESSION['messages'][$type])) {
       $_SESSION['messages'][$type][] = $message;
+      // Disable the current request from being cached.
+      page_cache_allowed(FALSE);
     }
   }
 
@@ -1191,7 +1222,7 @@ function _drupal_bootstrap($phase) {
         module_invoke_all('boot');
       }
       // If there is a cached page, display it.
-      if (is_object($cache)) {
+      if (is_object($cache) && page_cache_allowed()) {
         // Destroy empty anonymous sessions.
         if (drupal_session_is_started() && empty($_SESSION)) {
           session_destroy();
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.855
diff -u -p -r1.855 common.inc
--- includes/common.inc	22 Jan 2009 05:01:39 -0000	1.855
+++ includes/common.inc	23 Jan 2009 05:21:05 -0000
@@ -1854,6 +1854,11 @@ function drupal_page_footer() {
 
   module_invoke_all('exit');
 
+  // Send the output buffer now since this will end execution on HEAD requests.
+  if (page_get_cache(FALSE)) {
+    ob_end_flush();
+  }
+
   module_implements(MODULE_IMPLEMENTS_WRITE_CACHE);
   _registry_check_code(REGISTRY_WRITE_LOOKUP_CACHE);
 }
@@ -2988,19 +2993,19 @@ function _drupal_bootstrap_full() {
  * We thus only deal with the gzip variant and unzip the cache in case
  * the browser does not accept gzip encoding.
  *
- * @see drupal_page_header
+ * @see drupal_page_header()
+ * @see page_cache_allowed()
  */
 function page_set_cache() {
-  global $user, $base_root;
+  global $base_root;
 
-  if (page_get_cache(FALSE)) {
-    $cache = TRUE;
+  if (ob_get_level() && page_get_cache(FALSE)) {
     $data = ob_get_contents();
     if (variable_get('page_compression', TRUE) && function_exists('gzencode')) {
       // We do not store the data in case the zlib mode is deflate. This should
       // be rarely happening.
       if (zlib_get_coding_type() == 'deflate') {
-        $cache = FALSE;
+        page_cache_allowed(FALSE);
       }
       elseif (zlib_get_coding_type() == FALSE) {
         $data = gzencode($data, 9, FORCE_GZIP);
@@ -3008,8 +3013,7 @@ function page_set_cache() {
       // The remaining case is 'gzip' which means the data is already
       // compressed and nothing left to do but to store it.
     }
-    ob_end_flush();
-    if ($cache && $data) {
+    if (page_cache_allowed() && $data) {
       cache_set($base_root . request_uri(), $data, 'cache_page', CACHE_TEMPORARY, drupal_get_headers());
     }
   }
Index: modules/simpletest/tests/bootstrap.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/bootstrap.test,v
retrieving revision 1.11
diff -u -p -r1.11 bootstrap.test
--- modules/simpletest/tests/bootstrap.test	22 Jan 2009 03:05:18 -0000	1.11
+++ modules/simpletest/tests/bootstrap.test	23 Jan 2009 05:21:06 -0000
@@ -80,6 +80,9 @@ class BootstrapIPAddressTestCase extends
   }
 }
 
+/**
+ * Test page caching.
+ */
 class BootstrapPageCacheTestCase extends DrupalWebTestCase {
 
   function getInfo() {
@@ -90,12 +93,18 @@ class BootstrapPageCacheTestCase extends
     );
   }
 
+  function setUp() {
+    parent::setUp('system_test');
+
+    // Enable caching and clear the page cache.
+    variable_set('cache', CACHE_NORMAL);
+    cache_clear_all('*', 'cache_page', TRUE);
+  }
+
   /**
    * Enable cache and examine HTTP headers.
    */
   function testPageCache() {
-    variable_set('cache', CACHE_NORMAL);
-
     // Fill the cache.
     $this->drupalGet('');
 
@@ -128,6 +137,69 @@ class BootstrapPageCacheTestCase extends
     $this->assertFalse($this->drupalGetHeader('ETag'), t('An ETag header was not sent, indicating that page was not cached.'));
   }
 
+  /**
+   * Test that pages with messages are not cached.
+   */
+  function testNoCacheMessages() {
+    // View the front page with a message on it and test it was not cached.
+    variable_set('front_page_output', 1);
+    $this->drupalGet('');
+    $this->assertText(t('On front page.'), t('Message found.'));
+    $this->assertPageNotCached();
+
+    // View the front page without a message on it and test it was cached.
+    variable_set('front_page_output', 0);
+    $this->drupalGet('');
+    $this->assertNoText(t('On front page.'), t('Message not found.'));
+    $this->assertPageCached();
+  }
+
+  /**
+   * Test that pages viewed by logged in users are not cached.
+   */
+  function testNoCacheLoggedIn() {
+    // Create a user, log in, and test that the request was not cached.
+    $cache_user = $this->drupalCreateUser(array('access content'));
+    $this->drupalLogin($cache_user);
+    $this->drupalGet('');
+    $this->assertPageNotCached();
+
+    // Logout and check that the next request is cached.
+    $this->drupalLogout();
+    $this->drupalGet('');
+    $this->assertPageCached();
+  }
+
+  /**
+   * Test that GET and HEAD requests are cached, while POST requests are not.
+   */
+  function testCacheMethods() {
+    $this->drupalGet('');
+    $this->assertPageCached();
+
+    // Clear the page from the cache for the POST test.
+    cache_clear_all('*', 'cache_page', TRUE);
+
+    $this->drupalPost(NULL, array(), t('Log in'));
+    $this->assertPageNotCached();
+
+    $this->drupalHead('');
+    $this->assertPageCached();
+  }
+
+  /**
+   * Test that a page has been cached.
+   */
+  private function assertPageCached($url = '') {
+    $this->assertTrue(cache_get(url($url, array('absolute' => TRUE)), 'cache_page'), t('Page has been cached.'));
+  }
+
+  /**
+   * Test that a page has not been cached.
+   */
+  private function assertPageNotCached($url = '') {
+    $this->assertFalse(cache_get(url($url, array('absolute' => TRUE)), 'cache_page'), t('Page has been cached.'));
+  }
 }
 
 class BootstrapVariableTestCase extends DrupalWebTestCase {
@@ -180,7 +252,7 @@ class HookBootExitTestCase extends Drupa
   }
 
   function setUp() {
-    parent::setUp('system_test', 'dblog');
+    parent::setUp('dblog', 'system_test');
   }
 
   /**
@@ -190,32 +262,46 @@ class HookBootExitTestCase extends Drupa
     // Test with cache disabled. Boot and exit should always fire.
     variable_set('cache', CACHE_DISABLED);
     $this->drupalGet('');
-    $calls = 1;
-    $this->assertEqual(db_query("SELECT COUNT(*) FROM {watchdog} WHERE type = 'system_test' AND message = 'hook_boot'")->fetchField(), $calls, t('hook_boot called with disabled cache.'));
-    $this->assertEqual(db_query("SELECT COUNT(*) FROM {watchdog} WHERE type = 'system_test' AND message = 'hook_exit'")->fetchField(), $calls, t('hook_exit called with disabled cache.'));
+    $this->assertHookFired('hook_boot', 'disabled cache');
+    $this->assertHookFired('hook_exit', 'disabled cache');
+
+    // Test with a HEAD request. Boot and exit should always fire.
+    $this->drupalHead('');
+    $this->assertHookFired('hook_boot', 'on HEAD request');
+    $this->assertHookFired('hook_exit', 'on HEAD request');
 
     // Test with normal cache. Boot and exit should be called.
     variable_set('cache', CACHE_NORMAL);
     $this->drupalGet('');
-    $calls++;
-    $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.'));
+    $this->assertHookFired('hook_boot', 'normal cache');
+    $this->assertHookFired('hook_exit', '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.'));
     $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.'));
+    $this->assertHookNotFired('hook_boot', 'agressive cache and a cached page');
+    $this->assertHookNotFired('hook_exit', 'agressive cache and a cached page');
 
     // Test with aggressive cache and page cache cleared. Boot and exit should
     // be called.
-    $this->assertTrue(db_delete('cache_page')->execute(), t('Page cache cleared.'));
+    cache_clear_all('*', 'cache_page', TRUE);
     $this->drupalGet('');
-    $calls++;
-    $this->assertEqual(db_query("SELECT COUNT(*) FROM {watchdog} WHERE type = 'system_test' AND message = 'hook_boot'")->fetchField(), $calls, t('hook_boot called with agressive cache and no cached page.'));
-    $this->assertEqual(db_query("SELECT COUNT(*) FROM {watchdog} WHERE type = 'system_test' AND message = 'hook_exit'")->fetchField(), $calls, t('hook_exit called with agressive cache and no cached page.'));
+    $this->assertHookFired('hook_boot', 'agressive cache and no cached page');
+    $this->assertHookFired('hook_exit', 'agressive cache and no cached page');
   }
-}
 
+  private function assertHookFired($hook, $condition) {
+    $fired = db_query("SELECT COUNT(*) FROM {watchdog} WHERE type = 'system_test' AND message = :hook", array(':hook' => $hook))->fetchField();
+    $this->assertEqual($fired, 1, t('@hook called with @condition', array('@hook' => $hook, '@condition' => $condition)));
+    db_delete('watchdog')
+      ->condition('type', 'system_test')
+      ->condition('message', $hook)
+      ->execute();
+   }
+
+  private function assertHookNotFired($hook, $condition) {
+    $this->assertEqual(db_query("SELECT COUNT(*) FROM {watchdog} WHERE type = 'system_test' AND message = :hook", array(':hook' => $hook))->fetchField(), 0, t('@hook not called with @condition.', array('@hook' => $hook, '@condition' => $condition)));
+  }
+}
Index: modules/simpletest/tests/cache.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/cache.test,v
retrieving revision 1.3
diff -u -p -r1.3 cache.test
--- modules/simpletest/tests/cache.test	8 Dec 2008 21:41:54 -0000	1.3
+++ modules/simpletest/tests/cache.test	23 Jan 2009 05:21:06 -0000
@@ -29,7 +29,7 @@ class CacheTestCase extends DrupalWebTes
   }
 
   /**
-   * Assert or a cache entry exists.
+   * Assert that a cache entry exists.
    *
    * @param $message
    *   Message to display.
@@ -55,7 +55,7 @@ class CacheTestCase extends DrupalWebTes
   }
 
   /**
-   * Assert or a cache entry has been removed.
+   * Assert that a cache entry has been removed.
    *
    * @param $message
    *   Message to display.
@@ -224,4 +224,4 @@ class CacheClearCase extends CacheTestCa
                       || $this->checkCacheExists('test_cid_clear2', $this->default_value),
                       t('Two caches removed after clearing cid substring with wildcard true.'));
   }
-}
\ No newline at end of file
+}
