start page | rating of books | rating of authors | reviews | copyrights

Book HomeApache: The Definitive GuideSearch this book

4.2. Writing and Executing Scripts

Bear in mind that the CGI script must be executable in the opinion of your operating system. In order to test it, you can run it from the console with the same login that Apache uses. If you cannot, you have a problem that's signaled by disagreeable messages at the client end, plus equivalent stories in the log files on the server, such as:

You don't have permission to access /cgi-bin/mycgi on this server

You need to do either of the following:

If you have not used ScriptAlias, then Options ExecCGI must be on. It will normally be on by default. See the section Section 4.5, "Debugging Scripts", later in this chapter, for more information on fixing scripts.

To experiment, we have a simple test script, mycgi.cgi, in two locations: .../cgi-bin to test the first method above, and .../site.cgi/htdocs to test the second. When it works, we would write the script properly in C or Perl or whatever.

Figure 4.2 The script mycgi.cgi looks like this:

#!/bin/sh
echo "content-type: text/plain"
echo
echo "Have a nice day"

Figure 4.2 Under Win32, providing you want to run your script under COMMAND.COM and call it mycgi.bat, the script can be a little simpler than the Unix version -- it doesn't need the line that specifies the shell:

@echo off
echo "content-type: text/plain"
echo.
echo "Have a nice day"

Figure 4.2 The @echo off command turns off command-line echoing, which would otherwise completely destroy the output of the batch file. The slightly weird-looking "echo." gives a blank line (a plain echo without a dot prints "ECHO is off").

Figure 4.2 If you are running a more exotic shell, like bash or perl, you need the `shebang' line at the top of the script to invoke it:

#!shell path
...

A CGI script consists of headers and a body. Everything up to the first blank line (strictly speaking, CRLF CRLF, but Apache will tolerate LF LF) is header, and everything else is body. The lines of the header are separated by LF or CRLF. A list of possible headers is to be found in the draft CGI 1.1 specification, from which this is a quotation:

The CGI 
header fields have the generic syntax:
   
    generic-header = field-name ":" [ field-value ] NL
    field-name     = 1*<any CHAR, excluding CTLs, SP and ":">
    field-value    = *( field-content | LWSP )
    field-content  = *( token | tspecial | quoted-string )
   The field-name is not case sensitive; a NULL field value is equivalent to
   the header field not being sent.
   
   Content-Type
          The Internet Media Type [9] of the entity body, which is to
          be sent unmodified to the client.
          
    Content-Type = "Content-Type" ":" media-type NL
          This is actually an HTTP-Header rather than a CGI-header
          field, but it is listed here because of its importance in the
          CGI dialogue as a member of the "one of these is required"
          set of header fields.
          
   Location
          This is used to specify to the server that the script is
          returning a reference to a document rather than an actual
          document.
          
    Location         = "Location" ":"
                       ( fragment-URI | rel-URL-abs-path ) NL
    fragment-URI     = URI [ # fragmentid ]
    URI              = scheme ":" *qchar
    fragmentid       = *qchar
    rel-URL-abs-path = "/" [ hpath ] [ "?" query-string ]
    hpath            = fpsegment *( "/" psegment )
    fpsegment        = 1*hchar
    psegment         = *hchar
    hchar            = alpha | digit | safe | extra
                     | ":" | "@" | "& | "="

Our little script first tells Apache to use the sh shell and then specifies what type of data the content is, using the Content-Type header. This must be specified because:

So, the script must send at least one header line: Content-Type. We set it to text/plain to get a nicely formatted output screen. Failure to include it results in an error message on the client, plus equivalent entries in the server log files:

The server encountered an internal error or misconfiguration and was unable to complete your request

Headers must be terminated by a blank line, hence the second echo.

We are going to call our script from one of the Butterthlies forms: form_summer.html. Depending on which location and calling method we use for the script, we need slightly different invocations in the form.

4.2.1. Script in cgi-bin

To steer incoming demands for the script to the right place (.../cgi-bin ), we need to edit our ... /site.cgi/conf/httpd.conf file so it looks like this:

User webuser
Group webgroup
ServerName www.butterthlies.com
DocumentRoot /usr/www/site.cgi/htdocs
ScriptAlias /cgi-bin /usr/www/cgi-bin

We need to edit the form .../site.cgi/htdocs/form_summmer.html so that the relevant line reads:

<!-- UNIX -->
<FORM METHOD=POST ACTION="cgi-bin/mycgi.cgi">
<!-- Win32 -->
<FORM METHOD=POST ACTION="cgi-bin/mycgi.bat">

Since CGI processing is on by default, this should work. When you submit the Butterthlies order form, and thereby invoke the CGI script named by ACTION, you are sent the message "Have a nice day."

You would probably want to proceed in this way, that is, putting the script in the cgi-bin directory, if you were offering a web site to the outside world and wanted to maximize your security.

4.2.2. Script in DocumentRoot

The other method is to put scripts in amongst the HTML files. You should only do this if you trust the authors of the site to write safe scripts (or not write them at all) since security is much reduced. Generally speaking, it is safer to use a separate directory for scripts, as explained previously. First, it means that people writing HTML can't accidentally or deliberately cause security breaches by including executable code in the web tree. Second, it makes life harder for the Bad Guys: often it is necessary to allow fairly wide access to the nonexecutable part of the tree, but more careful control can be exercised on the CGI directories.

But regardless of these good intentions, we put mycgi.cgi in .../site.cgi/htdocs. The Config file is now:

User webuser
Group webgroup
ServerName www.butterthlies.com
DocumentRoot /usr/www/site.cgi/htdocs
AddHandler cgi-script cgi

The AddHandler directive means that any document Apache comes across with the extension .cgi will be taken to be an executable script. We need the corresponding line in the form:

<!-- UNIX -->
<FORM METHOD=POST ACTION="mycgi.cgi">
<!-- WIN32 -->
<FORM METHOD=POST ACTION="mycgi.bat">

Again, if we access http://www.butterthlies.com/form_summer.html, we get the result described.



Library Navigation Links

Copyright © 2001 O'Reilly & Associates. All rights reserved.