| Why aren't my CGI scripts working?
Here are some common problems encountered with CGI scripts:
1. Your script was uploaded in BINARY mode
instead of ASCII mode. Re-upload the file in ASCII transfer mode
in your FTP program. This means the script must actually upload
as a 'text' file. If your FTP program automatically puts a ".txt" notation at the end
of the script, then simply delete the ".txt" from the file name
after you upload it to the server.
2. The directory your CGI or Perl script lives in is not set to
the proper permission. You do not have the directory permissions
set to 755. ( chmod 755 cgi )
3. CGI's must have permissions of "755" or
they will not execute. ( chmod 755 *.cgi )
Make sure your scripts are in the cgi-bin directory, the path
to PERL and sendmail are correct, and that the permissions are
correctly set.
Location of Perl interpreter: /usr/bin/Perl So you have to put
the following line as the first line in your cgi script if you
want to use Perl:
#!/usr/bin/Perl -w
Absolute path to your Perl/cgi script:
/usr/home/your_account_name/html/cgi-bin/your_script
URL to your Perl/cgi script:
http://www.your_domain_name.com/cgi-bin/your_script
The path to PERL: /usr/bin/Perl
The path to sendmail: /usr/lib/sendmail
You can set permissions with the WS_FTP
program. Click once with the left mouse button to select the
file you want to check/change, then right click on the file and
choose "chmod (UNIX)" (change
mode) from the menu. The standard permissions for a CGI script
are:
Owner: Read Write Execute Group: Read Execute Other: Read Execute
Also check the path to the script in the web page that's attempting
to use the script. Don't forget that the path must include the cgi-bin
directory (i.e.; /cgi-bin/script.cgi).
Make sure that the extension is either .pl or .cgi
Short overview of the CGI calling process
Before you try to find answers to specific problems you have to understand
how CGI programs are executed on the server. There is no magic behind
the Common Gateway Interface, it is just a standardized specification
for interfacing external applications with information servers, such
as HTTP or Web servers. The current version of this specification
is CGI/1.1 and all the information in this article refers to this
version. All recent servers follow this specification and if you
want to get into technical detail (you should sooner or later) you
can find it at http://hoohoo.ncsa.uiuc.edu/cgi/interface.html
This specification is usually called the Standard CGI Interface because it uses
Standard Input (STDIN) and Standard Output (STDOUT) to read and send the data.
There is another form of CGI which is called Win CGI , this is a specification
for the same purpose but tailored to Windows servers. Instead of Standard Input/Output
it uses spooled I/O and originated in 16bit Windows servers but has been pushed
forward since to make use of Win32 features. Visual Basic and Delphi applications
usually make use of the Win CGI interface.
The process is simple: The webserver receives
a request for a document in form of an URL and a method type.
For simplicity's sake we will only talk about the GET and POST
methods but you should be aware that those are not the only methods
(At the time of this writing three other methods are in use,
PUT , DELETE and HEAD ). The URL is mapped internally to a filelocation.
The type of the requested file determines what the webserver
does next. To identify the type of the file the filename suffix
is mapped to a (customizable) table in the server configuration.
If it doesn't find the suffix the server tries to spit out the
requested file on STDOUT and the trouble to identify the filetype
is left to the browser. If the suffix is found but not registered as a CGI
type, the server adds the MIME type that this suffix is mapped to to its output
Header and outputs the file. In this case the method POST is not valid; the
server will complain if the request is a POST, usually with a message like "Method
not implemented". The browser tries to map the MIME type to its own table of
recognized filetypes and determines how to hand the file to the user, i.e.
displaying the content in the browser window or lauching an external application
or plugin.
If the server encounters a file type that it considers to be a handler ( Apache Jargon)
for a CGI program (usually that type would be application/x-httpd-cgi ) it
will execute the file. But before it executes the script, the server usually
does other security checks first, i.e. whether a certain directory is allowed
to contain CGI scripts is entirely up to the person configuring the server.
If everything is fine the server finally tries to execute the script, and along
the way it passes a variety of Environment Variables to the CGI program, like
the method, the content- length of the request, and other useful information
about the server and the client. From this point on any output needs to be
done by the just called CGI application.
At this point there are already a lot of
things that could have gone wrong: The extension must be mapped
to a file-type and this type needs to be associated with CGI.
Many servers also have the possibility to recognize CGI programs
by their location, so you can specify a directory in which every file is considered
to be a CGI script. Administrators often make use of this and keep all CGI
files in a cgi-bin directory. Also, since the server is the one executing the
script it needs to have rights to do that. Finally, the script must actually
execute and do some output. Errors at this stage usually result in that famous
500 Server Error every CGI programmer has encountered often enough. The output
needed consists of a valid Header (the very least you need to output is a MIME
type as the first line of the output like this: Content type: <MIME type> ),
followed by a blank line and finally some data (without any data you will get
an error).

Server Errors
Server errors are pretty general because the server only has an approximate idea
why it couldn't serve the requested script. The most common ones are 500 Internal
Server Error , 501 Method not implemented , 403 Forbidden , 401 File not found
and Document contains no data . If you can't make out the cause right away look
at the server's error log. Chances are you get a more detailed description of
the error. There is unfortunately no sure way to say where the logs are located
but if you can't find them ask the administrator or use search tools (On unix
machines try locate or find , NCSA and Apache logs tend to be named error_log
)
If you have read the previous section , you already should
have a basic idea why and when those errors occur. Let's break them down into
two categories: Errors that occur before the script is invoked and those that
occur while or after execution.Misconfiguration
If you are getting a 401 File not found error but you believe the file to be
in the correct location, i.e. your html directory is at /~yourname and you created
a subdirectory called cgi-bin in this directory, your first guess would be that
files in this directory have the URL /~yourname/cgi-bin/file.cgi , right? That's
usually the case, but as I said earlier, the process of mapping the URL to a
file location is done by the webserver, and it's totally up to the server how
it does the mapping. So don't take anything for granted, it might well be that
a partial URL is mapped to a totally different directory, some virtual servers
often make use of that in conjunction with /cgi-bin URL's to map those automatically
to the same directory for all hosts on the system.
403 Forbidden errors should be rather easy to debug. Somewhere along the way
to the requested file the server was instructed not to serve the file. This
can be either in form of a htaccess directive or a directory along the way
was not readable by the server. Check the permissions of the directories. Keep
in mind that the server runs under its own userid and that is most likely NOT
root but a user with minimal rights. There are ways to run scripts suid meaning
with the ID of the owner of the file but until the server gets to the file
this doesn't matter - all directories up to that point must be readable by
the userid under which the server runs. If you verified the permissions and
can still not figure out why you get this error, chances are the problem lies
in the server configuration in form of an access restriction to certain paths.
We already covered an example when the 501 Method not implemented error occurs.
This error can also occur when the server configuration says not to execute
CGI scripts in this directory. In this case the file is treated as a normal
file but was called with the POST method - for the server this is a No-No,
only cgi-scripts can be called with POST.
Now to the hardest to debug server error, the all-too-generic
500 Internal Server Error : This is basically the servers way of saying "I tried to access
that file and it exists but I either can't execute it or the output wasn't
at all what I expected." There are many reasons for the first possibility (can't
execute the file):
- The userID the server runs under doesn't have permissions to execute the
file, check if you have set the file to be executable.
- The server configuration disallows execution of CGI scripts in this path,
find the configuration files and look if that is the case, best ask the
administrator who set up the server.
- An I/O error occured while reading the file (unlikely), try invoking
the script again.
If the server executes the file but the output isn't what the server expects
(a valid Header followed by a blank line followed by some data) we have another
problem which we will examine next.

Syntax Errors
Let's consider the process
of executing a CGI script written in Perl (on a unix machine), the first
line in the script points to the local Perl interpreter, i.e. #!/usr/bin/perl .
What really happens is the server finds the script, sees it is executable and
trusts that from now on everything will work flawless, it's out of the server's
responsibility. But this is just a textfile, not a compiled program. The so-called
she-bang notation on the first line is part of any shellscript that needs to
invoke an interpreter, in this case it happens to be Perl. What it says is "Start up this program to run the remaining lines." Make
sure that the path in the first line is correct, a common error is to have
the first line point to something like /usr/local/bin while the program actually
resides in /usr/bin, or the other way around.
If the script can't be interpreted because of syntax errors the interpreter
will output some error message and quit. The webserver gets this output and
looks for a correct header, but of course something like "Syntax
error on line 5" isn't
a valid header so the server has no choice but bailing out with a 500 Server
error.
So before you ever test a script via the webserver with your browser, check
it for syntax errors first! In Perl you can do that by invoking the script
with the -c switch from the commandline, i.e. perl -c myscript.cgi . Be
aware that the path to your Perl interpreter has to be right as well, so better
use the same path for testing that you have defined in your script (in our
example /usr/bin/perl -c myscript.cgi ). Whenever
possible test on the same machine your script will be running on, so you'll
notice newbie-mistakes like uploading the script source in binary mode instead
of ascii right away.
Perl scripts on Windows platforms are a different issue,
here we don't have a unix shell that will let us use the she-bang notation,
but still the problem with syntax errors is the same. On Windows it depends
on the webserver how it implements Standard CGI, Microsoft's IIS ® for example needs to have
the info which interpreter to call (and how) in the registry, O'Reilly's WebSite ® on
the other hand just needs the extension to be registered with the Windows Explorer.
(Correction: version 2.0 of WebSite Pro uses its own internal file mapping
which can be set in the Server Properties) So if this information isn't given
or is wrong the interpreter will never be executed or not executed correctly,
resulting in unexpected output and most of the time a standard 500 Server Error.
If you have trouble with CGI on Windows you should definetely check out the
Perl for Win32 FAQ at http://velocity.activestate.com/docs/ActivePerll .
Among other things it contains detailed configuration instructions for all
common Windows webservers.  Logical Errors
| BUGS The -w switch is not mandatory. (from the Perl
manpage) |
Of course apart from syntax errors it is hard to verify that the script does
what you want; running on the commandline is not always an option since the program
flow is often dependant on Environment Variables that are not available when
you run the script from the commandline. In this section we will discuss some
general and some language-specific techniques to help you validate the program-flow.
One option is to add a routine to your program that gets called when the script
runs from the commandline, an easy test for that would be checking for the absence
of the Environment variable REQUEST_METHOD, which is only set when called by
the webserver. In this routine you can initialize your variables to some expected
input, set all Environment variables you need to some basic test data and run
the script on the shell. Of course this is a rather troublesome and not always
suitable method. If you are using Perl there is a better way to accomplish the
same thing, we will get to this later.
What if the script stops execution due to a runtime error? If it does this before
you output a valid header you will get a 500 Server error (optionally with the
information premature end of script headers ), if it bails out after printing
the headers you probably get a Document contains no data error. The problem is
that errors are usually reported to STDERR instead of STDOUT , the CGI interface
doesn't catch that and you won't see the error message in your browser. A simple,
obvious trick helps: redirect STDERR to STDOUT! Make sure that the first thing
your program does is outputting the header and flushing the output, so any output
after that will be valid and you can see the error messages. I'll show an example
in Perl and C later.

Tips for Perl Scripts
- Use the -w switch to enable warnings. add the switch to your first line,
i.e. #!/usr/bin/perl -w
If you are confused about the meaning of some warnings you can always use
diagnostics; - This module extends the terse diagnostics normally emitted
by both the perl compiler and the perl interpeter, augmenting them with the
more explicative and endearing descriptions found in the perldiag manpage.
- Output the header right away and enable autoflushing of the output buffer:
$| = 1; print "Content-type: text/html\n\n";
- Redirect STDERR to STDOUT: open (STDERR, ">&STDOUT");
I recommend to use this only for debugging, don't leave this in your public
script. Not only are other people likely to get confused when being confronted
with Perl's error messages or warnings but also you won't be able to track
down those errors in the server's errorlog - that can really be fatal,
imagine your perfectly fine script breaks one day due to a changed environment
or changed permissions of some files and you don't notice it until weeks
later after finally some visitor complained. Instead use the CGI::Carp
module (see next tip)
- use CGI::Carp; - This neat module takes care that the standard warn(),
die (), croak(), confess() and carp() calls will automagically be replaced
with functions that write out nicely time-stamped messages to the HTTP
server error log. If you want to send fatal (die, confess) errors to the
browser, ask to import the special "fatalsToBrowser" subroutine:
use CGI::Carp qw(fatalsToBrowser);
die "Bad error here";
Fatal errors will now be echoed to the browser as well as to the log. CGI::Carp
arranges to send a minimal HTTP header to the browser so that even errors
that occur in the early compile phase will be seen. Nonfatal errors will
still be directed to the log file only (unless redirected with carpout).
See the CGI::Carp documentation for more detail.
- Always check if I/O or other critical operations were successful, always
include a die statement or write your own error reporting routine with
some HTML formatting (much better for scripts other people will execute).
i.e:
open(FILE,"$filename") or die ("Can't open $filename: $!");
- use strict; !!! Perl is very forgiving, you don't need to declare your
variables, you can use weird bare words and other little tricks which are
certainly nice if you write quick and dirty little 5-liners. You can force
Perl to do a stricter syntax checking by including the standard module
strict . This requires you to declare every variable before you use it,
and kind of forces you to think about the scope of the variables too. You
would be surprised how many silly mistakes or otherwise hard-to-track typos
can be avoided that way.
- use CGI; Even if you don't use the CGI.pm module in your script this
is a very useful debugging tool. Running scripts on the commandline that
use CGI.pm are put in an interactive mode which allows you to enter input
to the script by hand. You can set Environment variables, pass POST or
GET data and your script will behave as if called via the CGI interface.
The module is part of the standard distribution in the current Perl version,
earlier versions can pick up a copy at http://www.genome.wi.mit.edu/ftp/pub/software/WWW/cgi_docs.html or
your nearest CPAN mirror .
Tips for C Scripts
- Plan debugging ahead of time, define a bunch of macros that will make it
easy to print out Environment variables and other critical variables, or
to open a textfile to print out input and output.
- Turn off buffering on the STDOUT stream. If you mix methods of writing
to STDOUT while buffering is turned on, you may end up with jumbled output.
Use
setvbuf(stdout,NULL,_IONBF,0);
to turn off buffering before you output anything else.
- Output the header right away:
printf("Content-type: text/html\n\n");
Flushing the output buffer shouldn't be neccessary if you use the stdio library,
it will flush the output automatically after every newline. If you suspect
that something is going wrong there or you are reading from a file or socket
you can force flushing of the output with fflush(stdout);
- Redirect stderr to a file or stdout:
char *errorfile = "error.txt";
if (!freopen(errorfile,"a+",stderr)) {
printf("Error redirecting STDERR.\n"); exit(1);
}
Where to go from here
If you have read this paper and still aren't able to find the problem there are
a few things you can do.
|