tags:

views:

316

answers:

5

I have this Perl script sitting in the cgi-bin folder of my Apache server:

#!/usr/bin/perl 
use strict;
use warnings;

$| = 1;

print "Content-type: text/html\r\n\r\n";
print "Hello there!<br />\nJust testing .<br />\n";

my $top = 5;
foreach (1..$top) {
    print "i = $_<br />\n";
    sleep 1;
}

What I want to achieve here is a gradual update of the web page to show the user an updated status. However, what I'm actually getting is the entire output at once, after a delay of 5 secs.

Is there any way I can write a script that is able to continuously inform the user of its progress? I have a script that takes a long time to finish and I would like to be able to see its progress in real time rather than the whole script to finish.

I have also tried to set autoflush mode to off ($| = 0), but even that doesn't do any thing.

+3  A: 

What you are wanting to achieve is possible -- browsers generally render what it has received so far, even if it is not the complete document, provided there is sufficient markup to be able to render anything at all. I'm wondering however why you use \r\n for some output and just \n for others -- you should be consistent and use \n throughout. Additionally, you are specifying a content type of text/html, but not providing any html headers (<html><title></title><body>) before your content.

However, the "modern" way to do this is to return the page output immediately, but leave the part you want to update later as an empty <div> element. Then you can update the content of that element with javascript (via an AJAX request).

Ether
tried outputting a valid HTML page, still the same response...
Asad Jibran Ahmed
A: 

Does it do what you expect when you set the content-type to text/plain? Perhaps the HTML parsing in your browser is causing the delay in the output, since you're not actually outputting valid HTML? (no <html> or <body> tags)

zigdon
tried setting the output type to text/plain, still nothing... output is still delayed.
Asad Jibran Ahmed
What browser are you using? If the browser does content sniffing, it will simply ignore your content-type if you send html anyway.
innaM
+2  A: 

Assuming you are using a version of Apache newer than 1.3, this should work. otherwise, You'll have to make your script into an NPH (No Parsed Headers) CGI, meaning its filename should be prefixed with nph- and it should output complete HTTP headers, eg.

HTTP/1.1 200 OK\n
Content-type: text/html\n\n

see the (somewhat old)Apache FAQ for more info

Hasturkun
+4  A: 

Randal Schwartz shows a better way in Watching long processes through CGI.

That said, lying about the content type will not help. The following script does exactly what you seem to want it to do on Windows XP with Apache 2.2 (in that it takes ten seconds for the last line of output to appear):

#!/usr/bin/perl

use strict;
use warnings;

use CGI qw(:cgi);

print header('text/plain');

$| = 1;

print "Job started\n";

for ( 1 .. 10 ) {
    print "$_\n";
    sleep 1;
}

Now, if you are sending HTML, you cannot avoid the fact that most browsers will wait until they what they believe is enough of the page to begin rendering.

Sinan Ünür
+1  A: 

To see if your script is working, try using a command line tool to avoid any confusion with your browser. curl, for example, will output as soon as it receives data.

If what you are doing is for an important purpose, I wouldn't use your current approach, though. If the script takes a long time to run, fork it off into the background (info here) and update a file or database with progress. You can then use an auto-refreshing (JavaScript or META-REFRESH) iFrame to display the progress. You could also use AJAX, but that is a bit more involved.

Jack M.