php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #42362 PHP should not send GZIP empty data after a 304 response
Submitted: 2007-08-21 14:51 UTC Modified: 2009-03-24 02:01 UTC
Votes:5
Avg. Score:4.8 ± 0.4
Reproduced:4 of 4 (100.0%)
Same Version:1 (25.0%)
Same OS:2 (50.0%)
From: ob dot php at daevel dot net Assigned:
Status: Closed Package: Feature/Change Request
PHP Version: 5.2.8 OS: Debian Etch
Private report: No CVE-ID:
 [2007-08-21 14:51 UTC] ob dot php at daevel dot net
Description:
------------
Hello,

when zlib.output_compression is enabled and the script stop without any contents (case of a 304 page), after all PHP sends contents.
So, if the client use keep-alive, the next request could be "corrupted".

I use php as an Apache 2 module. I reproduced it under PHP 4.4.X too.


Note : if I disable "zlib.output_compression" and use "ob_start( 'gz_handler' )" there is not this problem.

Reproduce code:
---------------
A minimal 304 page :
<?php
header( 'Date: '.gmdate('D, d M Y H:i:s').' GMT' );

header( 'Not Modified', true, 304 );
exit;
?>

A minimal client simulation :
<?php
$sk = fsockopen( 'your-domain.tld', 80 );

$headers = array(
    'GET /test_304.php HTTP/1.1',
    'Host: your-domain.tld',
    'Accept-Encoding: gzip,deflate',
    'Keep-Alive: 300',
    'Connection: keep-alive',
    'If-Modified-Since: Tue, 21 Aug 2007 13:00:54 GMT',
    );

function sock_send( &$sk, $line )
{
    echo '> ', $line, PHP_EOL;
    fputs( $sk, $line . "\r\n" );
}

function sock_gets( &$sk )
{
    $line = fgets( $sk, 4096 );
    echo '< ', rtrim($line), PHP_EOL;
    return $line;
}

for( $i = 1; $i <=2 ; $i++ )
{
    echo "Sending request ", $i, PHP_EOL;

    foreach( $headers as $h )
        sock_send( $sk, $h );
    sock_send( $sk, '' );

    echo "Reading headers only (no contents should be send)", PHP_EOL;

    while( !feof( $sk ) )
    {
        $line = trim(sock_gets( $sk ));
        if( $line === '' )
        {
            break;
        }
    }
}

fclose( $sk );
?>


Expected result:
----------------
Response headers for the second request should be the same as the first.

In my example :
< HTTP/1.1 304 Not Modified
< Date: Tue, 21 Aug 2007 14:45:40 GMT
< Server: Apache/2.2.3 (Debian) PHP/4.4.4-8+etch4
< Connection: Keep-Alive
< Keep-Alive: timeout=60, max=100
< Vary: Accept-Encoding


Actual result:
--------------
Actually there is some "chars" (I suppose the end of compressed data, like checksum ?)
< &#9660;      &#9829;&#9787;     &#9829;         HTTP/1.1 304 Not Modified
< Date: Tue, 21 Aug 2007 14:45:40 GMT
< Server: Apache/2.2.3 (Debian) PHP/4.4.4-8+etch4
< Connection: Keep-Alive
< Keep-Alive: timeout=60, max=99
< Vary: Accept-Encoding
<


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2007-08-21 15:13 UTC] ob dot php at daevel dot net
I add : there is exactly 26 bytes between the 2 requests :

1f 8b 80 00 00 00 00 00 00 30 20 00 00 00 ff ff
30 00 00 00 00 00 00 00 00 00

So it seems to be the "gzip header".
 [2007-08-27 11:07 UTC] jani@php.net
How is this a bug when you tell in your request that you accept gzipped data? Of course you get that header then.
 [2007-09-04 07:04 UTC] ob dot php at daevel dot net
The RFC say :
"The 304 response MUST NOT contain a message-body, and thus is always terminated by the first empty line after the header fields."

Source : http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
(cf 10.3.5 "304 Not Modified" )


Actually PHP sent the "GZIP Magic Header" (I'm not talking about the HTTP headers, but the start of a gzip compressed data).
 [2007-09-04 12:33 UTC] jani@php.net
AFAICT, you're sending the 304 in your script, it's not done by PHP. So in that case, isn't it your script that should turn off the compression?
 [2007-09-05 14:30 UTC] ob dot php at daevel dot net
Yes of course if I disable the compression (with ini_set), there is not the problem. But is it really to the script to check and correct an internal behavior ?
An old script which use ob_start( 'gz_handler' ) doesn't meet this "bug".
 [2007-09-05 17:38 UTC] mike@php.net
Well, the key issue is, zlib.output_compression and ob_gzhandler are not the same thing. Enabling zlib.output_compression starts the output handler without regard whether there's output or not unless you disable it again without sending output. ob_gzhandler is only initialized if there's been output.
 [2009-02-17 19:52 UTC] ezyang@php.net
I'm reopening this bug, under the contention that while PHP is not strictly at fault, it would be nice if it "did the right thing" when it noticed that output was empty, if only because gzipping nothing increases the size, not decrease it!

Either that, or this is a documentation bug, in which case header() and/or zlib.output_compression should warn users that any HTTP status codes which are required to return no output must have zlib.output_compression turned off.
 [2009-03-24 02:01 UTC] scottmac@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.

Will be fixed in 5.3 and may be backported to 5.2
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Sat Apr 19 01:01:59 2014 UTC