Don't do gzip compression if the URL path ends in .gz or .tgz
authorBrion Vibber <brion@users.mediawiki.org>
Thu, 19 Jul 2007 19:06:32 +0000 (19:06 +0000)
committerBrion Vibber <brion@users.mediawiki.org>
Thu, 19 Jul 2007 19:06:32 +0000 (19:06 +0000)
This confuses Safari and triggers a download of the page,
even though it's pretty clearly labeled as viewable HTML.
Bad Safari! Bad!

Bug is still present in Safari 2.0.4/Mac and 3.0.2/Win.

We have had a live hack for this on Wikimedia sites for .gz files;
hadn't noticed the .tgz problem before though.

While I was in there, also made a tweak so wfGzipHandler() makes
sure the Vary: header is there whether the current agent sent us
an Accept-Encoding header or not.

RELEASE-NOTES
includes/OutputHandler.php

index 0b879c5..d37f86c 100644 (file)
@@ -315,6 +315,7 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN
 * Fix several JavaScript bugs under MSIE 5/Macintosh
 * (bug 10591) Use Arabic numerals (0,1,2...) for the Malayam language
 * (bug 10642) Fix shift-click checkbox behavior for Opera 9.0+ and 6.0
+* Work around Safari bug with pages ending in ".gz" or ".tgz"
 
 
 == API changes since 1.10 ==
index 6b19afd..d8ac12b 100644 (file)
@@ -17,31 +17,68 @@ function wfOutputHandler( $s ) {
        return $s;
 }
 
+/**
+ * Get the "file extension" that some client apps will estimate from
+ * the currently-requested URL.
+ * This isn't on WebRequest because we need it when things aren't initialized
+ * @private
+ */
+function wfRequestExtension() {
+       /// @fixme -- this sort of dupes some code in WebRequest::getRequestUrl()
+       if( isset( $_SERVER['REQUEST_URI'] ) ) {
+               // Strip the query string...
+               list( $path ) = explode( '?', $_SERVER['REQUEST_URI'], 2 );
+       } elseif( isset( $_SERVER['SCRIPT_NAME'] ) ) {
+               // Probably IIS. QUERY_STRING appears separately.
+               $path = $_SERVER['SCRIPT_NAME'];
+       } else {
+               // Can't get the path from the server? :(
+               return '';
+       }
+       
+       $period = strrpos( $path, '.' );
+       if( $period !== false ) {
+               return strtolower( substr( $path, $period ) );
+       }
+       return '';
+}
+
 /**
  * Handler that compresses data with gzip if allowed by the Accept header.
  * Unlike ob_gzhandler, it works for HEAD requests too.
  */
 function wfGzipHandler( $s ) {
-       if ( function_exists( 'gzencode' ) && !headers_sent() ) {
-               $tokens = preg_split( '/[,; ]/', $_SERVER['HTTP_ACCEPT_ENCODING'] );
-               if ( in_array( 'gzip', $tokens ) ) {
-                       header( 'Content-Encoding: gzip' );
-                       $s = gzencode( $s, 3 );
-
-                       # Set vary header if it hasn't been set already
-                       $headers = headers_list();
-                       $foundVary = false;
-                       foreach ( $headers as $header ) {
-                               if ( substr( $header, 0, 5 ) == 'Vary:' ) {
-                                       $foundVary = true;
-                                       break;
-                               }
-                       }
-                       if ( !$foundVary ) {
-                               header( 'Vary: Accept-Encoding' );
-                       }
+       if( !function_exists( 'gzencode' ) || headers_sent() ) {
+               return $s;
+       }
+       
+       $ext = wfRequestExtension();
+       if( $ext == '.gz' || $ext == '.tgz' ) {
+               // Don't do gzip compression if the URL path ends in .gz or .tgz
+               // This confuses Safari and triggers a download of the page,
+               // even though it's pretty clearly labeled as viewable HTML.
+               // Bad Safari! Bad!
+               return $s;
+       }
+       
+       $tokens = preg_split( '/[,; ]/', $_SERVER['HTTP_ACCEPT_ENCODING'] );
+       if ( in_array( 'gzip', $tokens ) ) {
+               header( 'Content-Encoding: gzip' );
+               $s = gzencode( $s, 3 );
+       }
+       
+       // Set vary header if it hasn't been set already
+       $headers = headers_list();
+       $foundVary = false;
+       foreach ( $headers as $header ) {
+               if ( substr( $header, 0, 5 ) == 'Vary:' ) {
+                       $foundVary = true;
+                       break;
                }
        }
+       if ( !$foundVary ) {
+               header( 'Vary: Accept-Encoding' );
+       }
        return $s;
 }