google-chromecginph

How to tell modern browsers to display lines as they arrive


In the early days of web browsers and servers, it was possible to create scripts that would send data to the browser and the browser would display it as it arrived.

For example, the traditional NPH test script:

#!/usr/local/bin/perl

$server_protocol = $ENV{'SERVER_PROTOCOL'};
$server_software = $ENV{'SERVER_SOFTWARE'};
$|=1;

print "$server_protocol 200 OK", "\n";
print "Server: $server_software", "\n";
print "Content-type: text/plain", "\n\n";

print "OK, Here I go. I am going to count from 1 to 5 !", "\n";

for ($loop=1; $loop <= 5; $loop++) {
    print $loop, "\n";
    sleep (2);
}

print "All Done!", "\n";

exit (0);

Back in the old Netscape days the browser would display the 1, 2, 3, 4, 5 as they arrived with 2 seconds between them.

In a modern browser, such as Chrome, you don't see anything until the script terminates and all 5 lines are displayed in one go.

I can see the script works as expected by telneting to the server and running a manual GET command; the output is received every 2 seconds.

Is there anyway of telling modern browsers (maybe via headers?) to act the old way and display the line as it arrives?


Solution

  • It turns out that chunked mode works... but you need to send a bunch of data first, before the browser starts to stream.

    This describes the pre-chunk data, determined through testing:

    Using "transfer-encoding: chunked", how much data must be sent before browsers start rendering it?

    So the resulting code would be something like:

    #!/usr/local/bin/perl
    
    $server_protocol = $ENV{'SERVER_PROTOCOL'};
    $server_software = $ENV{'SERVER_SOFTWARE'};
    
    $|=1;
    
    print "$server_protocol 200 OK", "\n";
    print "Server: $server_software", "\n";
    print "Transfer-Encoding: chunked", "\n";
    print "Content-type: text/plain", "\n\n";
    
    sub chunk {
        my ($chunk)=@_;
        printf("%x\n%s\n", length($chunk), $chunk);  
    }
    
    # Send 1K of spaces to convince browsers to display data as it comes
    chunk(" " x 1024);
    
    chunk("OK, Here I go. I am going to count from 1 to 5 !\r\n");
    
    for ($loop=1; $loop <= 5; $loop++) {
        chunk($loop . "\r\n");
        sleep (2);
    }
    
    chunk("All Done!\r\n");
    
    # We need this to tell the client chunking has ended
    chunk("");
    

    (Thanks to a non-SO user for helping me with this)