Index: includes/bootstrap.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v
retrieving revision 1.266
diff -u -9 -p -r1.266 bootstrap.inc
--- includes/bootstrap.inc	20 Jan 2009 03:18:40 -0000	1.266
+++ includes/bootstrap.inc	21 Jan 2009 23:00:33 -0000
@@ -793,25 +793,28 @@ function drupal_page_cache_header($cache
 
   // Send appropriate response:
   header("Last-Modified: " . gmdate(DATE_RFC1123, $cache->created));
   header("ETag: $etag");
 
   // The following headers force validation of cache:
   header("Expires: Sun, 19 Nov 1978 05:00:00 GMT");
   header("Cache-Control: must-revalidate");
 
-  if (variable_get('page_compression', TRUE)) {
+  if (variable_get('page_compression', TRUE) && extension_loaded('zlib')) {
     // Determine if the browser accepts gzipped data.
-    if (@strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') === FALSE && function_exists('gzencode')) {
+    if (@strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') === FALSE) {
       // Strip the gzip header and run uncompress.
       $cache->data = gzinflate(substr(substr($cache->data, 10), 0, -8));
     }
-    elseif (function_exists('gzencode')) {
+    else {
+      // $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');
     }
   }
 
   // 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) {
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.852
diff -u -9 -p -r1.852 common.inc
--- includes/common.inc	20 Jan 2009 03:18:40 -0000	1.852
+++ includes/common.inc	21 Jan 2009 23:00:33 -0000
@@ -2965,48 +2965,39 @@ 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;
 
   if (page_get_cache(FALSE)) {
     $cache = TRUE;
     $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;
-      }
-      elseif (zlib_get_coding_type() == FALSE) {
-        $data = gzencode($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 (variable_get('page_compression', TRUE) && extension_loaded('zlib')) {
+      $data = gzencode($data, 9, FORCE_GZIP);
     }
     ob_end_flush();
-    if ($cache && $data) {
+    if ($data) {
       cache_set($base_root . request_uri(), $data, 'cache_page', CACHE_TEMPORARY, drupal_get_headers());
     }
   }
 }
 
 /**
  * Executes a cron run when called
  * @return
  * Returns TRUE if ran successfully
Index: modules/simpletest/drupal_web_test_case.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/drupal_web_test_case.php,v
retrieving revision 1.80
diff -u -9 -p -r1.80 drupal_web_test_case.php
--- modules/simpletest/drupal_web_test_case.php	19 Jan 2009 10:46:51 -0000	1.80
+++ modules/simpletest/drupal_web_test_case.php	21 Jan 2009 23:00:33 -0000
@@ -1172,19 +1172,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.10
diff -u -9 -p -r1.10 bootstrap.test
--- modules/simpletest/tests/bootstrap.test	14 Jan 2009 12:15:38 -0000	1.10
+++ modules/simpletest/tests/bootstrap.test	21 Jan 2009 23:00:33 -0000
@@ -87,23 +87,27 @@ class BootstrapIPAddressTestCase extends
     $this->assertTrue(drupal_valid_http_host(), t('NULL HTTP_HOST is valid'));
   }
 }
 
 class BootstrapPageCacheTestCase extends DrupalWebTestCase {
 
   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 different HTTP requests.'),
       'group' => t('Bootstrap')
     );
   }
 
+  function setUp() {
+    parent::setUp('system_test');
+  }
+
   /**
    * Enable cache and examine HTTP headers.
    */
   function testPageCache() {
     variable_set('cache', CACHE_NORMAL);
 
     // Fill the cache.
     $this->drupalGet('');
 
@@ -130,18 +134,77 @@ class BootstrapPageCacheTestCase extends
     $this->assertTrue($this->drupalGetHeader('ETag'), t('An ETag header was sent, indicating that page was cached.'));
 
     $user = $this->drupalCreateUser();
     $this->drupalLogin($user);
     $this->drupalGet('', array(), array('If-Modified-Since: ' . $last_modified, 'If-None-Match: ' . $etag));
     $this->assertResponse(200, t('Conditional request returned 200 OK for authenticated user.'));
     $this->assertFalse($this->drupalGetHeader('ETag'), t('An ETag header was not sent, indicating that page was not cached.'));
   }
 
+  /**
+   * 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->assertFalse($this->drupalGetHeader('ETag'), t('An ETag header was not sent, indicating that page was not cached.'));
+
+    // Verify that cached output is compressed.
+    $this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate'));
+    $this->assertTrue($this->drupalGetHeader('ETag'), t('An ETag header was sent, indicating that 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->assertTrue($this->drupalGetHeader('ETag'), t('An ETag header was sent, indicating that 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->assertTrue($this->drupalGetHeader('ETag'), t('An ETag header was sent, indicating that 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');
   }
 
   function getInfo() {
Index: modules/simpletest/tests/common.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/common.test,v
retrieving revision 1.22
diff -u -9 -p -r1.22 common.test
--- modules/simpletest/tests/common.test	21 Jan 2009 14:22:32 -0000	1.22
+++ modules/simpletest/tests/common.test	21 Jan 2009 23:00:33 -0000
@@ -490,33 +490,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' => 184,
+      '%line' => 189,
       '%file' => realpath('modules/simpletest/tests/system_test.module'),
     );
     $error_warning = array(
       '%type' => 'Warning',
       '%message' => 'Division by zero',
       '%function' => 'system_test_generate_warnings()',
-      '%line' => 186,
+      '%line' => 191,
       '%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' => 188,
+      '%line' => 193,
       '%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);
@@ -538,26 +538,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' => 197,
+      '%line' => 202,
       '%file' => realpath('modules/simpletest/tests/system_test.module'),
     );
     $error_pdo_exception = array(
       '%type' => 'PDOException',
       '%message' => 'SQLSTATE',
       '%function' => 'system_test_trigger_pdo_exception()',
-      '%line' => 205,
+      '%line' => 210,
       '%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.8
diff -u -9 -p -r1.8 system_test.module
--- modules/simpletest/tests/system_test.module	9 Dec 2008 11:09:26 -0000	1.8
+++ modules/simpletest/tests/system_test.module	21 Jan 2009 23:00:34 -0000
@@ -149,18 +149,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.'));
