Work-around for exceptions on broken webservers
authorAlexander Ebert <ebert@woltlab.com>
Wed, 28 Mar 2018 10:31:02 +0000 (12:31 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Wed, 28 Mar 2018 10:31:02 +0000 (12:31 +0200)
wcfsetup/install/files/lib/system/WCF.class.php

index f292150e330de0f9441b9d693f1bcb2e3e7b4339..dfcc4ee1e106472a26f64f68485ee6b6987ac988 100644 (file)
@@ -262,11 +262,33 @@ class WCF {
                        // ob_get_level() can return values > 1, if the PHP setting `output_buffering` is on
                        while (ob_get_level()) ob_end_clean();
                        
-                       // `identity` is the default "encoding" and basically means that the client
-                       // must treat the content as if the header did not appear in first place, this
-                       // also overrules the gzip header if present
-                       @header('Content-Encoding: identity');
-                       HeaderUtil::exceptionDisableGzip();
+                       // Some webservers are broken and will apply gzip encoding at all cost, but they fail
+                       // to set a proper `Content-Encoding` HTTP header and mess things up even more.
+                       // Especially the `identity` value appears to be unrecognized by some of them, hence
+                       // we'll just gzip the output of the exception to prevent them from tampering.
+                       // This part is copied from `HeaderUtil` in order to isolate the exception handler!
+                       if (HTTP_ENABLE_GZIP && !defined('HTTP_DISABLE_GZIP')) {
+                               if (function_exists('gzcompress') && !@ini_get('zlib.output_compression') && !@ini_get('output_handler') && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) {
+                                       if (strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'x-gzip')) {
+                                               @header('Content-Encoding: x-gzip');
+                                       }
+                                       else {
+                                               @header('Content-Encoding: gzip');
+                                       }
+                                       
+                                       ob_start(function($output) {
+                                               $size = strlen($output);
+                                               $crc = crc32($output);
+                                               
+                                               $newOutput = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff";
+                                               $newOutput .= substr(gzcompress($output, 1), 2, -4);
+                                               $newOutput .= pack('V', $crc);
+                                               $newOutput .= pack('V', $size);
+                                               
+                                               return $newOutput;
+                                       });
+                               }
+                       }
                }
                
                // backwards compatibility