Invoking a CGI method in external program trashes form params

U

usenet

Greetings. Kindly consider this simplified CGI script which
illustrates my question:

#!/usr/bin/perl
use strict; use warnings;
use CGI qw{ :standard };

system('/var/www/cgi-bin/do_nothing.pl');

print(
header(),
start_html(),
start_form(),
h2(param('xxx')),
textfield({-name => 'xxx'}),
submit(),
end_form(),
end_html()
);
__END__

As you can see, the CGI first runs an external perl program. OK,
fine. Here is the external program:

#!/usr/bin/perl
use strict; use warnings;
use CGI qw{ header };

open (my $file, '>', '/tmp/junk.xxx') or die "oops - $!\n";

my $test_mode = 0;

print $file $test_mode ? header()
: "Content-Type: text/html;
charset=ISO-8859-1\n\n",
__END__

This external program simply prints an HTML content declaration to a
junk file. But it has the option to use CGI.pm's header() method, or
to just print hardcoded text. Either way, the resulting junk file is
identical (same md5sum).

When I run the CGI (in a browser), I should be able to type something
in the textbox and it will be shown to me when I click submit. And if
I run everything as posted, that's exactly what happens.

But if I change $test_mode to non-zero then the value of the CGI
parameter 'xxx' is no longer carried. I can type something in the
textfield and hit submit, but I won't see the value of the param.
Changing $test_mode back to zero causes the form to again work as
expected.

Somehow invoking the CGI.pm header method() in the external program is
causing my CGI form parameters to be lost between form invocations!

That's strange! Does anyone have any idea why?

Thanks!
 
B

Ben Morrow

Quoth (e-mail address removed):
Greetings. Kindly consider this simplified CGI script which
illustrates my question:

#!/usr/bin/perl
use strict; use warnings;
use CGI qw{ :standard };

system('/var/www/cgi-bin/do_nothing.pl');

print(
header(),
start_html(),
start_form(),
h2(param('xxx')),
textfield({-name => 'xxx'}),
submit(),
end_form(),
end_html()
);
__END__

As you can see, the CGI first runs an external perl program. OK,
fine. Here is the external program:

#!/usr/bin/perl
use strict; use warnings;
use CGI qw{ header };

open (my $file, '>', '/tmp/junk.xxx') or die "oops - $!\n";

my $test_mode = 0;

print $file $test_mode ? header()
: "Content-Type: text/html;
charset=ISO-8859-1\n\n",
__END__

This external program simply prints an HTML content declaration to a
junk file. But it has the option to use CGI.pm's header() method, or
to just print hardcoded text. Either way, the resulting junk file is
identical (same md5sum).

When I run the CGI (in a browser), I should be able to type something
in the textbox and it will be shown to me when I click submit. And if
I run everything as posted, that's exactly what happens.

But if I change $test_mode to non-zero then the value of the CGI
parameter 'xxx' is no longer carried. I can type something in the
textfield and hit submit, but I won't see the value of the param.
Changing $test_mode back to zero causes the form to again work as
expected.

Somehow invoking the CGI.pm header method() in the external program is
causing my CGI form parameters to be lost between form invocations!

That's strange! Does anyone have any idea why?

You are using POST, yes? POST parameters are passed on STDIN; when a CGI
object is created (with the function interface, the first time you call
a CGI.pm function) it reads the whole of STDIN and extracts the
information. The second script shares its STDIN with the first; the
first call to a CGI function occurs in the second. This call reads the
whole of STDIN, so when you get back to the first script there's nothing
left there to read, and the CGI object in that script ends up empty.

There are many solutions:

Explicitly create a CGI object, or perhaps just call 'header()' and
throw it away, before calling the second script.

'do' the second script instead of executing it with system: you will
lose some separation, but save a fork, and the two will share the
same implicit default CGI object.

Execute the second script with STDIN redirected from /dev/null (or
File::Spec->devnull for portability).

Refactor both scripts (I presume they're not really this trivial) so
that you don't need to invoke the second at all; put the important
stuff in modules, and call the right bits at the right times.

Ben
 
U

usenet

The second script shares its STDIN with the first; the
first call to a CGI function occurs in the second. This call reads the
whole of STDIN, so when you get back to the first script there's nothing
left there to read, and the CGI object in that script ends up empty.

Thanks, Ben, for your great explanation and plethora of solutions!
This was exactly what I needed to know to solve this problem!

FWIW, in the "real" application, I'm using HTML::Template, but I build
the template with Perl using the CGI module (because I hate to write
raw HTML). As I'm developing the program, the template-generating
program is changing constantly, so I want to rebuild the template each
time the CGI is invoked.

Thanks again, Ben!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top