Index: trunk/phase3/includes/resourceloader/ResourceLoader.php |
— | — | @@ -287,6 +287,15 @@ |
288 | 288 | */ |
289 | 289 | public function respond( ResourceLoaderContext $context ) { |
290 | 290 | global $wgResourceLoaderMaxage, $wgCacheEpoch; |
| 291 | + |
| 292 | + // Buffer output to catch warnings. Normally we'd use ob_clean() on the |
| 293 | + // top-level output buffer to clear warnings, but that breaks when ob_gzhandler |
| 294 | + // is used: ob_clean() will clear the GZIP header in that case and it won't come |
| 295 | + // back for subsequent output, resulting in invalid GZIP. So we have to wrap |
| 296 | + // the whole thing in our own output buffer to be sure the active buffer |
| 297 | + // doesn't use ob_gzhandler. |
| 298 | + // See http://bugs.php.net/bug.php?id=36514 |
| 299 | + ob_start(); |
291 | 300 | |
292 | 301 | wfProfileIn( __METHOD__ ); |
293 | 302 | |
— | — | @@ -353,6 +362,19 @@ |
354 | 363 | if ( $ims !== false ) { |
355 | 364 | $imsTS = strtok( $ims, ';' ); |
356 | 365 | if ( $mtime <= wfTimestamp( TS_UNIX, $imsTS ) ) { |
| 366 | + // There's another bug in ob_gzhandler (see also the comment at |
| 367 | + // the top of this function) that causes it to gzip even empty |
| 368 | + // responses, meaning it's impossible to produce a truly empty |
| 369 | + // response (because the gzip header is always there). This is |
| 370 | + // a problem because 304 responses have to be completely empty |
| 371 | + // per the HTTP spec, and Firefox behaves buggily when they're not. |
| 372 | + // See also http://bugs.php.net/bug.php?id=51579 |
| 373 | + // To work around this, we tear down all output buffering before |
| 374 | + // sending the 304. |
| 375 | + while ( ob_get_level() > 0 ) { |
| 376 | + ob_end_clean(); |
| 377 | + } |
| 378 | + |
357 | 379 | header( 'HTTP/1.0 304 Not Modified' ); |
358 | 380 | header( 'Status: 304 Not Modified' ); |
359 | 381 | wfProfileOut( __METHOD__ ); |
— | — | @@ -363,13 +385,14 @@ |
364 | 386 | // Generate a response |
365 | 387 | $response = $this->makeModuleResponse( $context, $modules, $missing ); |
366 | 388 | |
367 | | - // Tack on PHP warnings as a comment in debug mode |
| 389 | + // Capture any PHP warnings from the output buffer and append them to the |
| 390 | + // response in a comment if we're in debug mode. |
368 | 391 | if ( $context->getDebug() && strlen( $warnings = ob_get_contents() ) ) { |
369 | 392 | $response .= "/*\n$warnings\n*/"; |
370 | 393 | } |
371 | 394 | |
372 | | - // Clear any warnings from the buffer |
373 | | - ob_clean(); |
| 395 | + // Remove the output buffer and output the response |
| 396 | + ob_end_clean(); |
374 | 397 | echo $response; |
375 | 398 | |
376 | 399 | wfProfileOut( __METHOD__ ); |