home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  

CGI Programming on the World Wide Web

Previous Chapter 12
Debugging and Testing CGI Applications

12.5 CGI Lint--A Debugging/Testing Tool

CGI Lint greatly simplifies the process of testing and debugging CGI applications. Appendix E, Applications, Modules, Utilities, and Documentation, lists where you can get CGI Lint.

Depending on the type of request (either GET or POST), either one or two auxiliary files are required by CGI Lint. The first is a configuration file, which should contain a list of the environment variables in the following format:

QUERY_STRING       =   name=John Surge&company=ABC Corporation!
HTTP_ACCEPT        =   image/gif, image/x-xbitmap, image/jpeg, */*
REMOTE_ADDR        =
SERVER_ROOT        =   /usr/local/bin/httpd_1.4.2
DOCUMENT_ROOT      =   /usr/local/bin/httpd_1.4.2/public
SCRIPT_NAME        =   /cgi-bin/abc.pl
REMOTE_HOST        =   gateway.cgi.com

This format has an advantage over the previous one: You do not need to encode the query string. However, if you have either %, &, or = characters in the query string, you need to escape them by placing a "\" before them:

QUERY_STRING       =   name=Joe\=Joseph&company=JP \& Play&percentage=50\%

Or you can just use the encoded values of %25, %26, and %3d to represent the "%," "&," and "=" characters, respectively. Now, you are ready to test out your CGI program:

% CGI_Lint get.cfg

CGI Lint executes the script that is pointed to by the environment variables SCRIPT_NAME and SERVER_ROOT. In addition, you can use a data file to store query information. Here is an example:

% CGI_Lint form.cfg form.data

The format for the data file should be:

name = Joe\=Joseph
company = JP \& Play
percentage = 50\%

If you already have data stored in QUERY_STRING, CGI Lint will process the data from both sources. In the case of POST requests, all you have to do is change the REQUEST_METHOD to "POST" and run it in the same exact way as before:

% CGI_Lint form.cfg form.data

In addition, you can test the multipart/form-data encoding scheme (see Appendix D, CGI Lite), which is a new addition to the Web. For multipart MIME data, you need to add the following line to the configuration file:

CONTENT_TYPE = multipart/form-data

Normally, multipart data contains boundary strings between fields, but you do not have to go to the trouble of inserting the numerous multipart headers. CGI Lint takes care of all that for you. Now, here is the format for the data file:

name = Joe = Joseph
company = JP & Play
percentage = 50%
review = */usr/shishir/rev.dat

You would execute the script in the same way as you did all the others. CGI Lint reads through the fields and creates a multipart MIME body:

Content-disposition: form-data; name="name"
Joe = Joseph
Content-disposition: form-data; name="company"
JP & Play
Content-disposition: form-data; name="percentage"
Content-disposition: form-data; name="review"; filename="/usr/ shishir/rev.dat"
(contents of the file /home/shishir/rev.dat)

One thing to note here is the last line of the data file. The asterisk instructs the tool to include the information stored in the file /usr/shishir/review.dat. That is one of the powerful features of multipart messages: it allows users to upload files to the server.

In addition to simulating the server data streams, CGI Lint also checks a number of attributes and properties before running the script.

CGI Lint in Action

Let's take a simple CGI program and run it through CGI Lint, and see what happens. Here is the program-it should be familiar to you, as it was introduced at the end of Chapter 7, Advanced Form Applications:

$user = $simple{'user'};
print "Content-type: text/plain", "\n\n";
print "Here are the results of your query: ", "\n";
print `/usr/ucb/finger $user`;
print "\n";
exit (0);

This program outputs finger information about the specified user. Here is the form that is associated with the program:

<FORM ACTION="/cgi-bin/finger.pl" METHOD="POST">
<INPUT TYPE="text" NAME="user" SIZE=40>
<INPUT TYPE="submit" VALUE="Get Information">

Now, let's create the configuration and data files, to be used with CGI Lint. The configuration file must contain the following lines:

SERVER_ROOT = /usr/local/bin/httpd_1.4.2
    SCRIPT_NAME = /cgi-bin/finger.pl

Since the form passes the information to the program using POST, we need to create a data file to hold the post data. It needs to consist of only one line:

user = shishir

This is equivalent to the user entering "shishir" in the user field in the form. That is all that needs to be done. Here is how you would execute CGI Lint (assuming that the configuration file is called finger.cfg, and the data file is called finger.dat):

% CGI_Lint finger.cfg finger.dat

CGI Lint will output the following information:

While looking at your Perl script for possible security holes and
"open" commands, I came across the following statements that *might*
constitute a security breach:
Check the *backtics* on line: print `/usr/ucb/finger $user`;
Variable(s) *may* not be secure!

It looks as though your script has no bugs (at least, on the surface),
so here is the output you have been waiting for:
Here are the results of your query: <BR><HR>
Login name: shishir                     In real life: Shishir Gundavaram
Directory: /home/shishir                Shell: /usr/local/bin/tcsh
On since Oct 26 23:11:27 on ttyp0 from nmrc.bu.edu
Mail last read Mon Oct 27 00:03:54 1995
No Plan.

It will display the output generated by the CGI program. It also outputs various other information, including possible security holes. Here is a list of the exact informational messages that CGI Lint outputs:

  • The configuration file (that holds the environment variable data) could not be found. This file is needed to run this program. Please check and try again.

  • The NCSA server resource map configuration file (srm.conf) could not be found. This might be due to the way your server is set up. In order to rectify the situation, define a variable called SERVER_ROOT (with the correct server root directory) in the configuration file, and try again.

  • Sorry, either the file extension or the path to your CGI script is not valid. Check both of these to make sure they are configured in the NCSA server resource map configuration (srm.conf) file.

  • You do not have the necessary privileges to run the specified script. Use the chmod command to change the permissions, and try again.

  • The CGI program that is specified in the configuration file does not exist. Please check the path, and try again.

  • The CGI program that is specified could not be opened. Please check the permissions and try again.

  • The interpreter you specified either does not exist, is not readable, or is not a binary file. Please check the path, and try again.

  • The script you specified does not have a header line that points to a interpreter that will execute the script. The header line should be something like this:


  • Oops! The script you wrote had errors. I will list all the bugs here. Please fix them and try again. Here they are:

  • While looking at your Perl script for possible security holes and "open" commands, I came across the following *errors*:

  • While looking at your Perl script for possible security holes and "open" commands, I came across the following statements that *might* constitute a security breach:

  • The data file (that holds the potential form data) could not be found. Please check the file specification and try again.

  • A data file to store the simulated POST data cannot be created. Please check to see if you have privileges to write to the /tmp directory.

  • One of the filenames that you listed in the simulated multipart data file does not exist. Be sure to check all possible fields, and try again.

  • The CONTENT_TYPE variable in your data file is not set correctly. You do not have to set a value for this, as I will default it to:


    But, if you do set a value for this variable, it has to be either the one mentioned above, or:


    If you specify an encoding type of multipart/form-data in the configuration file, I will create a random boundary, and set the CONTENT_TYPE to the following:

    multipart/form-data; boundary=--------------Some Random Boundary

  • The REQUEST_METHOD variable in your data file is not set correctly. It has to have a value of either GET or POST.

  • Your NPH (Non-Parsed-Header) script does not output the correct HTTP response. The first line has to be something like:

    HTTP/1.0 200 OK

  • A serious error! Either you are not outputting a **BLANK** line after the HTTP headers, *OR* you are trying to send invalid (or undefined) HTTP headers. Please check the output of your script and try again.

  • It looks as though your script has no bugs (at least, on the surface), so here is the output you have been waiting for:

  • The *system* command was detected in your script. Make sure to turn output buffering off by adding the following line to your script:

    $| = 1;

Previous Home Next
Logging and Simulation Book Index Set UID/GID Wrapper

HTML: The Definitive Guide CGI Programming JavaScript: The Definitive Guide Programming Perl WebMaster in a Nutshell