Index: includes/bootstrap.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v
retrieving revision 1.277
diff -u -9 -p -r1.277 bootstrap.inc
--- includes/bootstrap.inc	24 Apr 2009 08:15:50 -0000	1.277
+++ includes/bootstrap.inc	24 Apr 2009 16:08:33 -0000
@@ -985,18 +985,21 @@ function drupal_page_cache_header(stdCla
   // that the module knows how to cache the page.
   if (!isset($hook_boot_headers['vary']) && !variable_get('omit_vary_cookie')) {
     header('Vary: Cookie');
   }
 
   if ($page_compression) {
     header('Vary: Accept-Encoding', FALSE);
     // If page_compression is enabled, the cache contains gzipped data.
     if ($return_compressed) {
+      // $cache->data 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');
     }
     else {
       // The client does not support compression, so unzip the data in the
       // cache. Strip the gzip header and run uncompress.
       $cache->data = gzinflate(substr(substr($cache->data, 10), 0, -8));
     }
   }
 
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.879
diff -u -9 -p -r1.879 common.inc
--- includes/common.inc	24 Apr 2009 08:15:50 -0000	1.879
+++ includes/common.inc	24 Apr 2009 16:08:33 -0000
@@ -3001,59 +3001,49 @@ function _drupal_bootstrap_full() {
   // We do not want this while running update.php.
   if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
     module_invoke_all('init');
   }
 }
 
 /**
  * Store the current page in the cache.
  *
- * We try to store a gzipped version of the cache. This requires the
- * PHP zlib extension (http://php.net/manual/en/ref.zlib.php).
- * Presence of the extension is checked by testing for the function
- * gzencode. There are two compression algorithms: gzip and deflate.
- * The majority of all modern browsers support gzip or both of them.
- * We thus only deal with the gzip variant and unzip the cache in case
- * the browser does not accept gzip encoding.
+ * If page_compression is enabled, a gzipped version of the page is stored in
+ * the cache to avoid compressing the output on each request. The cache entry
+ * is unzipped in the relatively rare event that the page is requested by a
+ * client without gzip support.
+ * 
+ * Page compression requires the PHP zlib extension
+ * (http://php.net/manual/en/ref.zlib.php).
  *
  * @see drupal_page_header
  */
 function page_set_cache() {
-  global $user, $base_root;
+  global $base_root;
 
   if (page_get_cache(FALSE)) {
-    $cache_page = TRUE;
     $cache = (object) array(
       'cid' => $base_root . request_uri(),
       'data' => ob_get_clean(),
       'expire' => CACHE_TEMPORARY,
       'created' => REQUEST_TIME,
       'headers' => array(),
     );
     // Restore preferred header names based on the lower-case names returned
     // by drupal_get_header().
     $header_names = _drupal_set_preferred_header_name();
     foreach (drupal_get_header() as $name_lower => $value) {
       $cache->headers[$header_names[$name_lower]] = $value;
     }
-    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_page = FALSE;
-      }
-      elseif (zlib_get_coding_type() == FALSE) {
+    if ($cache->data) {
+      if (variable_get('page_compression', TRUE) && extension_loaded('zlib')) {
         $cache->data = gzencode($cache->data, 9, FORCE_GZIP);
       }
-      // The remaining case is 'gzip' which means the data is already
-      // compressed and nothing left to do but to store it.
-    }
-    if ($cache_page && $cache->data) {
       cache_set($cache->cid, $cache->data, 'cache_page', $cache->expire, $cache->headers);
     }
     drupal_page_cache_header($cache);
   }
   else {
     // If output buffering was enabled during bootstrap, and the headers were
     // not sent in the DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE phase, send them now.
     drupal_page_header();
   }
Index: modules/simpletest/drupal_web_test_case.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/drupal_web_test_case.php,v
retrieving revision 1.96
diff -u -9 -p -r1.96 drupal_web_test_case.php
--- modules/simpletest/drupal_web_test_case.php	22 Apr 2009 09:57:10 -0000	1.96
+++ modules/simpletest/drupal_web_test_case.php	24 Apr 2009 16:08:33 -0000
@@ -1208,19 +1208,19 @@ class DrupalWebTestCase {
   /**
    * Check for meta refresh tag and if found call drupalGet() recursively. This
    * function looks for the http-equiv attribute to be set to "Refresh"
    * and is case-sensitive.
    *
    * @return
    *   Either the new page content or FALSE.
    */
   protected function checkForMetaRefresh() {
-    if ($this->drupalGetContent() != '' && $this->parse()) {
+    if (strpos($this->drupalGetContent(), '<meta ') && $this->parse()) {
       $refresh = $this->xpath('//meta[@http-equiv="Refresh"]');
       if (!empty($refresh)) {
         // Parse the content attribute of the meta tag for the format:
         // "[delay]: URL=[page_to_redirect_to]".
         if (preg_match('/\d+;\s*URL=(?P<url>.*)/i', $refresh[0]['content'], $match)) {
           return $this->drupalGet($this->getAbsoluteUrl(decode_entities($match['url'])));
         }
       }
     }
Index: modules/simpletest/tests/bootstrap.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/bootstrap.test,v
retrieving revision 1.15
diff -u -9 -p -r1.15 bootstrap.test
--- modules/simpletest/tests/bootstrap.test	22 Apr 2009 09:45:03 -0000	1.15
+++ modules/simpletest/tests/bootstrap.test	24 Apr 2009 16:08:33 -0000
@@ -85,19 +85,19 @@ class BootstrapIPAddressTestCase extends
     $this->assertTrue(drupal_valid_http_host('[::1]:80'), t('HTTP_HOST containing IPv6 loopback is valid'));
   }
 }
 
 class BootstrapPageCacheTestCase extends DrupalWebTestCase {
 
   public static function getInfo() {
     return array(
       'name' => t('Page cache test'),
-      'description' => t('Enable the page cache and test it with conditional HTTP requests.'),
+      'description' => t('Enable the page cache and test it with various HTTP requests.'),
       'group' => t('Bootstrap')
     );
   }
 
   function setUp() {
     parent::setUp('system_test');
   }
 
   /**
@@ -171,18 +171,78 @@ class BootstrapPageCacheTestCase extends
     $this->drupalLogin($user);
     $this->drupalGet('system-test/set-header', array('query' => array('name' => 'Foo', 'value' => 'bar')));
     $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'), t('Caching was bypassed.'));
     $this->assertFalse($this->drupalGetHeader('Vary'), t('Vary header was not sent.'));
     $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'no-cache, must-revalidate, post-check=0, pre-check=0', t('Cache-Control header was sent.'));
     $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', t('Expires header was sent.'));
     $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', t('Custom header was sent.'));
 
   }
+
+  /**
+   * Test page compression when zlib.output_compression is disabled. The test
+   * should pass even if zlib.output_compression is enabled in php.ini,
+   * .htaccess or similar, or if compression is done outside PHP, e.g. by the
+   * mod_deflate Apache module.
+   */
+  function testPageCompression() {
+    variable_set('cache', CACHE_NORMAL);
+    // Disable zlib.output_compression in system_test_boot().
+    variable_set('zlib_output_compression', 'O');
+
+    // Fill the cache. The response is not compressed, unless compression is
+    // done outside PHP, e.g. by the mod_deflate Apache module.
+    $this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate'));
+    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', t('Page was cached.'));
+
+    // Verify that cached output is compressed.
+    $this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate'));
+    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', t('Page was cached.'));
+    $this->assertEqual($this->drupalGetHeader('Content-Encoding'), 'gzip', t('A Content-Encoding header was sent.'));
+    $this->assertTrue(strpos(gzinflate(substr($this->drupalGetContent(), 10, -8)), t('Welcome to your new Drupal website!')), t('Page was gzip compressed.'));
+
+    // Verify that a client with compression support gets an uncompressed page.
+    $this->drupalGet('');
+    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', t('Page was cached.'));
+    $this->assertFalse($this->drupalGetHeader('Content-Encoding'), t('A Content-Encoding header was not sent.'));
+    $this->assertText(t('Welcome to your new Drupal website!'), t('Page was not compressed.'));
+
+    // Verify that a client without gzip support gets an uncompressed page.
+    $this->drupalGet('', array(), array('Accept-Encoding: deflate'));
+    $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', t('Page was cached.'));
+    $this->assertFalse($this->drupalGetHeader('Content-Encoding'), t('A Content-Encoding header was not sent.'));
+    $this->assertText(t('Welcome to your new Drupal website!'), t('Page was not compressed.'));
+  }
+
+  /**
+   * Test page compression when zlib.output_compression is enabled. Requires
+   * that zlib.output_compression is enabled in php.ini, .htaccess or similar.
+   */
+  function testPageCompressionWithZlibOutputCompression() {
+    // zlib.output_compression cannot be enabled at runtime, so this test can
+    // only run, if it has been enabled in php.ini, .htaccess or similar. See
+    // http://bugs.php.net/bug.php?id=33653
+    if (!ini_get('zlib.output_compression')) {
+      return;
+    }
+
+    variable_set('cache', CACHE_NORMAL);
+
+    // Fill the cache. Compression is done by zlib.output_compression.
+    $this->drupalGet('', array(), array('Accept-Encoding: deflate'));
+    $this->assertEqual($this->drupalGetHeader('Content-Encoding'), 'deflate', t('A Content-Encoding header was sent.'));
+
+    // Verify that output is gzip'ed, even though the cache was filled when
+    // zlib.output_compression was doing deflate compression.
+    $this->drupalGet('', array(), array('Accept-Encoding: gzip'));
+    $this->assertEqual($this->drupalGetHeader('Content-Encoding'), 'gzip', t('Page was compressed.'));
+    $this->assertTrue(strpos(gzinflate(substr($this->drupalGetContent(), 10, -8)), t('Welcome to your new Drupal website!')), t('Page was compressed.'));
+  }
 }
 
 class BootstrapVariableTestCase extends DrupalWebTestCase {
 
   function setUp() {
     parent::setUp('system_test');
   }
 
   public static function getInfo() {
Index: modules/simpletest/tests/common.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/common.test,v
retrieving revision 1.33
diff -u -9 -p -r1.33 common.test
--- modules/simpletest/tests/common.test	22 Apr 2009 09:45:03 -0000	1.33
+++ modules/simpletest/tests/common.test	24 Apr 2009 16:08:33 -0000
@@ -641,33 +641,33 @@ class DrupalErrorHandlerUnitTest extends
 
   /**
    * Test the error handler.
    */
   function testErrorHandler() {
     $error_notice = array(
       '%type' => 'Notice',
       '%message' => 'Undefined variable: bananas',
       '%function' => 'system_test_generate_warnings()',
-      '%line' => 194,
+      '%line' => 199,
       '%file' => realpath('modules/simpletest/tests/system_test.module'),
     );
     $error_warning = array(
       '%type' => 'Warning',
       '%message' => 'Division by zero',
       '%function' => 'system_test_generate_warnings()',
-      '%line' => 196,
+      '%line' => 201,
       '%file' => realpath('modules/simpletest/tests/system_test.module'),
     );
     $error_user_notice = array(
       '%type' => 'User notice',
       '%message' => 'Drupal is awesome',
       '%function' => 'system_test_generate_warnings()',
-      '%line' => 198,
+      '%line' => 203,
       '%file' => realpath('modules/simpletest/tests/system_test.module'),
     );
 
     // Set error reporting to collect notices.
     variable_set('error_level', 2);
     $this->drupalGet('system-test/generate-warnings');
     $this->assertErrorMessage($error_notice);
     $this->assertErrorMessage($error_warning);
     $this->assertErrorMessage($error_user_notice);
@@ -689,26 +689,26 @@ class DrupalErrorHandlerUnitTest extends
 
   /**
    * Test the exception handler.
    */
   function testExceptionHandler() {
     $error_exception = array(
       '%type' => 'Exception',
       '%message' => 'Drupal is awesome',
       '%function' => 'system_test_trigger_exception()',
-      '%line' => 207,
+      '%line' => 212,
       '%file' => realpath('modules/simpletest/tests/system_test.module'),
     );
     $error_pdo_exception = array(
       '%type' => 'PDOException',
       '%message' => 'SQLSTATE',
       '%function' => 'system_test_trigger_pdo_exception()',
-      '%line' => 215,
+      '%line' => 220,
       '%file' => realpath('modules/simpletest/tests/system_test.module'),
     );
 
     $this->drupalGet('system-test/trigger-exception');
     $this->assertErrorMessage($error_exception);
 
     $this->drupalGet('system-test/trigger-pdo-exception');
     // We cannot use assertErrorMessage() since the extact error reported
     // varies from database to database. Check for the error keyword 'SQLSTATE'.
Index: modules/simpletest/tests/system_test.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/system_test.module,v
retrieving revision 1.9
diff -u -9 -p -r1.9 system_test.module
--- modules/simpletest/tests/system_test.module	22 Apr 2009 09:45:03 -0000	1.9
+++ modules/simpletest/tests/system_test.module	24 Apr 2009 16:08:33 -0000
@@ -159,18 +159,23 @@ function system_test_modules_uninstalled
     drupal_set_message(t('hook_modules_uninstalled fired for aggregator'));
   }
 }
 
 /**
  * Implementation of hook_boot().
  */
 function system_test_boot() {
   watchdog('system_test', 'hook_boot');
+
+  $zlib_output_compression = variable_get('zlib_output_compression', NULL);
+  if ($zlib_output_compression !== NULL) {
+    ini_set('zlib.output_compression', $zlib_output_compression);
+  }
 }
 
 /**
  * Implementation of hook_init().
  */
 function system_test_init() {
   // Used by FrontPageTestCase to get the results of drupal_is_front_page().
   if (variable_get('front_page_output', 0) && drupal_is_front_page()) {
     drupal_set_message(t('On front page.'));
