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?