You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl-cvs@perl.apache.org by fd...@hyperreal.org on 1999/04/27 22:14:59 UTC
cvs commit: modperl-site/faq mod_perl_cgi.pod
fdc 99/04/27 13:14:59
Modified: faq mod_perl_cgi.pod
Log:
Added a section about header parsing with PerlSendHeader.
Suggest using lynx for testing.
Revision Changes Path
1.2 +91 -16 modperl-site/faq/mod_perl_cgi.pod
Index: mod_perl_cgi.pod
===================================================================
RCS file: /export/home/cvs/modperl-site/faq/mod_perl_cgi.pod,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- mod_perl_cgi.pod 1998/03/23 04:04:39 1.1
+++ mod_perl_cgi.pod 1999/04/27 20:14:59 1.2
@@ -1,6 +1,6 @@
=head1 NAME
-Mod_perl_cgi - running CGI scripts under mod_perl ($Date: 1998/03/23 04:04:39 $)
+Mod_perl_cgi - running CGI scripts under mod_perl ($Date: 1999/04/27 20:14:59 $)
=head1 DESCRIPTION
@@ -40,6 +40,48 @@
says it is OK, you have probably used __END__ or __DATA__. Sorry.
Mod_perl's Apache::Registry can't deal with that.
+=head1 The script runs but the headers are mangled
+
+You have a script that works fine under mod_cgi but the browser
+displays "Content-Type: text/html" or similar headers at the top of
+the page when it is run under mod_perl. There are two possible
+causes.
+
+Something, either your script or mod_perl or CGI.pm (if you are using
+it) has to trigger Apache to send the response header. This happens
+when you call the CGI.pm $q->header method or mod_perl's
+$r->send_http_header. But if your script just prints out one or more
+header lines followed by a blank line and the page content, you need
+to set "PerlSendHeader On" in the configuration for the location of
+the script. This tells mod_perl to parse the stuff that the script
+prints and call $r->send_http_header for you when it sees the blank
+line.
+
+This parsing only happens if PerlSendHeader is on and the header has
+not been sent yet. Even so, it is costly and mod_perl makes the
+assumption that individual headers are not split across print
+statements, to simplify the parser and avoid having to retain
+fragments of headers between calls to print(). So the following does
+not work:
+
+ print "Content-type: text/html\n";
+ print "Set-Cookie: iscookietext\; ";
+ print "expires=Wednesday, 09-Nov-1999 00:00:00 GMT\; ";
+ print "path=\/\; domain=\.mmyserver.com\; \n\n";
+ print "hello";
+
+because the Set-Cookie header is split across multiple print's.
+
+You need to print each header (or group of headers) in one go,
+possibly after building it up in a temporary variable.
+
+ print "Content-type: text/html\n";
+ my $cookie = "Set-Cookie: iscookietext; ";
+ $cookie .= "expires=Wednesday, 09-Nov-1999 00:00:00 GMT; ";
+ $cookie .= "path=/; domain=.mmyserver.com; \n\n";
+ print $cookie;
+ print "hello";
+
=head1 My CGI script behaves strangely under mod_perl. Why?
Remember that a conventional CGI script always starts up a fresh perl
@@ -56,21 +98,35 @@
The command
# ./httpd -X
+
+will start a single-process server with its default configuration.
+You can specify a different configuration with the C<-f> flag (and
+thus use a different port number for testing, for instance).
+
+Now try executing your script from a browser. A non-graphical browser
+is often much better for diagnosing low-level problems. Install lynx
+(http://lynx.browser.org/) if you haven't already got it and use
+
+ lynx -mime_header http://localhost/perl/myscript
+
+to see the response that the web server produces when it GETs your
+script, and
-will start a single-process server with its default configuration. You
-can specify a different configuration with the -f flag (and thus use a
-different port number for testing, for instance).
+ lynx -head -dump http://localhost/perl/myscript
-Now try executing your script from a browser or with a tool such a wget.
+to see the response to a HEAD request. The GET and HEAD commands that
+come with libwww-perl are similar but slower.
+
Here are some of the effects that you might see.
=head2 The server terminates after processing the first request
-Your script is calling the perl C<exit()> function. That is not a problem
-in a conventional CGI script, provided that query processing is complete.
-But you almost certainly don't want to exit in a mod_perl script. It
-kills the server process that handled the request, meaning that the
-advantage of using mod_perl to avoid startup overhead is lost.
+Your script is calling the CORE perl C<exit()> function. That is not
+a problem in a conventional CGI script, provided that query processing
+is complete. But you almost certainly don't want to exit in a
+mod_perl script. It kills the server process that handled the
+request, meaning that the advantage of using mod_perl to avoid startup
+overhead is lost.
The best way to avoid calling C<exit()> is to restructure the script so
that all execution paths return to a common point at the end of the
@@ -78,8 +134,13 @@
placing a label after the last executable statement and replacing calls to
C<exit()> with C<goto label;>
-There may be exceptional circumstances in which an exit is required in a
-mod_perl script, in which case C<Apache-E<gt>exit()> should be used.
+See also what mod_perl_traps says about C<Apache::exit()> and the way
+that Apache::Registry causes it to terminate the script but not the
+httpd child.
+
+There may be exceptional circumstances in which you explicitly want to
+terminate the httpd child at the end of the current request. In this
+case C<Apache-E<gt>exit(-2)> should be used.
=head2 Variables retain their value from one request to the next
@@ -126,9 +187,9 @@
print($q->end_html());
}
-Because you remembered to put the -w switch on the first line, the error
-log will tell you that "Variable $q will not stay shared" (provided you
-are using perl5.004 or higher).
+Because you remembered to put the C<-w> switch on the first line, the
+error log will tell you that "Variable $q will not stay shared"
+(provided you are using perl5.004 or higher).
You must either pass the variable to the subroutine as a parameter,
@@ -143,6 +204,12 @@
use vars qw($q);
$q = CGI->new();
+The reason why Perl works this way is explained in a news posting by
+Mike Guy that is included with this FAQ (mjtg-news.txt).
+
+=for html
+ <a href="mjtg-news.txt">mjtg-news.txt</a>
+
=head2 Variables B<still> retain their value from one request to the next
CGI.pm must pull some extra tricks when it is being used via
@@ -154,8 +221,16 @@
for an environment variable. This test can fail if C<use CGI> is
evaluated too early, before the environment has been set up. That can
happen if you have C<use CGI> in a script and pull the script in with
-a C<PerlScript> directive in httpd.conf. Replacing C<use CGI> with
+a C<PerlRequire> directive in httpd.conf. Replacing C<use CGI> with
C<require CGI> will fix it.
+
+=head2 Do I have to rewrite my legacy code for mod_perl?
+
+If you have CGI code that seems to be fundamentally at odds with
+mod_perl's "compile once, run many" environment, you may be find that
+it will work if run under the module C<Apache::PerlRun>. See the
+documentation of that module, which is included with recent versions
+of mod_perl.
=head1 How can my script continue running after sending the response?