Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

how to indicate progress on long run CGI 1

Status
Not open for further replies.

goBoating

Programmer
Feb 8, 2000
1,606
US
fedora core 3
apache 2
perl/CGI

I have a CGI application that accepts inputs from a user, passes those inputs to a piece of java which takes 30-45 seconds to build their results, and then redirects the browser the output which has been built by the java run. Because the java stuff takes so long, I'd like to give my users some indication that their request has been submitted and it will take a few seconds to deliver their results. In the following, for simplicity sake, I have substituted a simple piece of Perl(spoon.pl) to emulate the long java process.

I have been able to make a this work in mozilla and firefox browsers using a fork, but, I can't get it to work for IE.

Driver.cgi
Code:
#!/usr/bin/perl
use strict;
use CGI;#  qw('fatalsToBrowser', 'warngingsToBrowser');
my $http = new CGI;
my $pid;
my $time = localtime;   
$| = 1;
if ($pid = fork) { # this is the parent
    print $http->header(-title=>"Process Monitor"),
	qq(<body bgcolor="#0000FF"
        onload="location.href='[URL unfurl="true"]http://localhost/'">[/URL]
	<font color="#FFFFFF"><p>Working...);
	}
else { # this is the child   
	close (STDOUT);
	# java writes stuff to a db - but I'm playing 
        # with a simple text file for now
    system ("/usr/bin/perl", "/path/to/spoon.pl");
    exit(0);
    }

# This is parent process again.  
# Check to see if the text file is there.
while (!(-e '/var/[URL unfurl="true"]www/cache/junk.txt'))[/URL] {
    sleep(1);
    print ".";
    }
print qq(</p><p>$time Done! </p></font>), 
    $http->end_html;

Since mozilla and family render the page as it is delivered (to some degree), the above code shows 'Working...' with more dots slowly appearing until the child process completes. This is just what I want, but, IE will not render any of the page until it has the complete page. So, IE shows a blank page until, the child (java) finishes and then immediately does the redirect.

spoon.pl - this is a spoon since the other is a 'fork' ;-)
Code:
#!/usr/bin/perl
use strict;
# emulate a long java run before writing the text file.sleep(5); 
my $time = localtime();
open(OPF,">/var/[URL unfurl="true"]www/cache/junk.txt")[/URL] 
	or die "Failed to open OPF: $!\n";
print OPF "spoon.pl ran at $time\n";
close OPF;

Ideas?

'hope this helps

If you are new to Tek-Tips, please use descriptive titles, check the FAQs, and beware the evil typo.
 
I'd cheat here, and show an animated gif or png, and then redirect to the results when they're ready.

Have you tried this in a few IE browsers, it might just be a settings thing, as I've seen perl generated javascript slow to load render in IE comparably to Moz et al.

Just a thought
--Paul

cigless ...
 
Hey Paul,
thanks for the note. I tried an animated gif and it worked well in mozilla and family, but not in IE (several versions). Recent version of mozilla and firefox render the page parts much earlier in the process than IE.

I played with IE some and I could not get anything to render in the browser until the body tag closed. That got me to thinking that since a frame has a body tag........


This is slightly contrived, but, it works in every browser I can find to test.

The solution employs frames and a little javascript. There is an input page (firstPage.html) which submits to 'Driver.cgi'. 'Driver.cgi' immediately creates a page with two frames. The frames are sufficiently independent of each other in the various browsers that each frame renders as it gets it's input. The src for the upper frame is a call to a long running piece of CGI which emulates my long running piece of java. I set the row size to zero and the border to zero so the user has no idea the frame is there. The src for the lower frame is a message to the user that their process is running. The upper frame has an 'onload' javascript event handler in the body tag so that when the long running process returns, the body tag closes and the 'onload' fires. The called javascript function forwards the parent (the browser) to the results page.

I had hoped to find a more concise solution, but, this works, and it has taken too long already. So, I shall proceed with this verbose ugliness. ;-)

Note that I have neglected using taint mode while I proto-typed this. If anyone uses this code, you need enforce taint mode (add a ' -T' to the top line of each script).

firstPage.html
Code:
<html>
<head><title>bare bones architecture</title>
</head>
<body>
<form method="POST" action="/cgi-bin/Driver.cgi">
<select name="run_id">
	<option>1</option>
	<option>2</option>
	<option>3</option>
	<option>4</option>
</select>
<input type="submit" />
</form>
</body>
</html>

Driver.cgi - build a two frame page with an invisible top frame and user message in the lower frame.
Code:
#!/usr/bin/perl
use strict;
use CGI;#  qw('fatalsToBrowser', 'warngingsToBrowser');
my $http = new CGI;
my $run_id = $http->param('run_id');

print qq(
<HTML>
<HEAD>
<TITLE>playing with frames</TITLE>
</HEAD>
<!-- hide with size and border = 0 --> 
<FRAMESET rows="0,*" border="0"> 
  <FRAME name="topFrame"    
    src="/cgi-bin/tarry.cgi?run_id=$run_id" />
  <FRAME name="bottomFrame" src="/cgi-bin/lowerF.cgi" />
</FRAMESET>
</HTML>);


tarry.cgi - my long running process
Code:
#!/usr/bin/perl
use strict;
use CGI;
my $http = new CGI;
my $run_id = $http->param('run_id');
print $http->header,
	qq(	<script langauge="JavaScript">
		function goNext() {	parent.location.href='/cgi-bin/report.cgi?run_id=$run_id';
	}
	</script>
	<body onload="goNext()">);
sleep(8); # emulate a long running process 
print qq(</body></html>);

lowerF.cgi - my message to user
Code:
#!/usr/bin/perl
use strict;
use CGI;
my $http = new CGI;
print $http->header,
  $http->start_html(-bgcolor=>"#0C0099"),
	qq(<div align="center">
	<font color="#FFFFFF">
	<p>Your request is in process and may 
           20-30 seconds or more.<br />
	   You will be forwarded to your results 
           shortly.  </p>
	</font>
        <!-- an animated progress bar -->
	<img src="/loadData.gif" /> 
	</div>),
	$http->end_html;

report.cgi - results
Code:
#!/usr/bin/perl
use strict;
use CGI;
my $http = new CGI;
my $run_id = $http->param('run_id');
print $http->header;
print $http->start_html, qq(<p>Run_ID: $run_id</p>), $http->end_html;

'hope this helps

If you are new to Tek-Tips, please use descriptive titles, check the FAQs, and beware the evil typo.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top