From 02f47c30271647609d1e9c5277ea818921fded6c Mon Sep 17 00:00:00 2001 From: Roan Kattouw Date: Fri, 10 Dec 2010 17:06:00 +0000 Subject: [PATCH] (bug 26130) ob_start( 'ob_gzhandler' ) in LocalSettings.php broke gzip output from load.php . This is caused by http://bugs.php.net/bug.php?id=36514 (ob_clean() removes GZIP header). Also noticed that load.php is affected by http://bugs.php.net/bug.php?id=51579 (ob_gzhandler generates non-empty 304s, invalid HTTP, triggers a Firefox bug) as well and fixed that too while I was at it. --- includes/resourceloader/ResourceLoader.php | 29 +++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/includes/resourceloader/ResourceLoader.php b/includes/resourceloader/ResourceLoader.php index e4677d0552..834acedf1a 100644 --- a/includes/resourceloader/ResourceLoader.php +++ b/includes/resourceloader/ResourceLoader.php @@ -287,6 +287,15 @@ class ResourceLoader { */ public function respond( ResourceLoaderContext $context ) { global $wgResourceLoaderMaxage, $wgCacheEpoch; + + // Buffer output to catch warnings. Normally we'd use ob_clean() on the + // top-level output buffer to clear warnings, but that breaks when ob_gzhandler + // is used: ob_clean() will clear the GZIP header in that case and it won't come + // back for subsequent output, resulting in invalid GZIP. So we have to wrap + // the whole thing in our own output buffer to be sure the active buffer + // doesn't use ob_gzhandler. + // See http://bugs.php.net/bug.php?id=36514 + ob_start(); wfProfileIn( __METHOD__ ); @@ -353,6 +362,19 @@ class ResourceLoader { if ( $ims !== false ) { $imsTS = strtok( $ims, ';' ); if ( $mtime <= wfTimestamp( TS_UNIX, $imsTS ) ) { + // There's another bug in ob_gzhandler (see also the comment at + // the top of this function) that causes it to gzip even empty + // responses, meaning it's impossible to produce a truly empty + // response (because the gzip header is always there). This is + // a problem because 304 responses have to be completely empty + // per the HTTP spec, and Firefox behaves buggily when they're not. + // See also http://bugs.php.net/bug.php?id=51579 + // To work around this, we tear down all output buffering before + // sending the 304. + while ( ob_get_level() > 0 ) { + ob_end_clean(); + } + header( 'HTTP/1.0 304 Not Modified' ); header( 'Status: 304 Not Modified' ); wfProfileOut( __METHOD__ ); @@ -363,13 +385,14 @@ class ResourceLoader { // Generate a response $response = $this->makeModuleResponse( $context, $modules, $missing ); - // Tack on PHP warnings as a comment in debug mode + // Capture any PHP warnings from the output buffer and append them to the + // response in a comment if we're in debug mode. if ( $context->getDebug() && strlen( $warnings = ob_get_contents() ) ) { $response .= "/*\n$warnings\n*/"; } - // Clear any warnings from the buffer - ob_clean(); + // Remove the output buffer and output the response + ob_end_clean(); echo $response; wfProfileOut( __METHOD__ ); -- 2.20.1