Table of Contents
Previous | Next
Apache Server Survival Guide

Appendix A: Un-CGI Version 1.7 Documentation


Un-CGI Version 1.7 Documentation


The Un-CGI documentation was reprinted, with minor alterations, with kind permission from its author, Steven Grimm. The most recent version of this software and its documentation are available via the Web at http://www.hyperion.com/~koreth/uncig.html.

Introduction


This is Un-CGI, a frontend for processing queries and forms from the Web on UNIX systems. You can get it via anonymous File Transfer Protocol (FTP) from ftp.hyperion.com or, depending on your browser, by following this link:

http://www.hyperion.com/~koreth/uncgi.html.

If you wanted to process a form without this program, you would have to either write or dig up routines to translate the values of the form's fields from URL encoding to whichever your program required. This was a hassle in C and a real pain in the shell, and you had to do things differently for GET and POST queries.

This is where uncgi comes in. It decodes all the form fields and sticks them into environment variables for easy peruse by a shell script, a C program, a Perl script, or whatever you like. Then it executes whichever program you specify. (Actually, Un-CGI is something of a misnomer because the weird URL syntax is from the HTML forms specification, not from CGI itself.)

Installation


Let's assume that you have at least a passing familiarity with compiling and installing programs from the Internet. You know how to unpack a compressed tarfile and use make, and are familiar with the operation of your HTTP server. If you don't, you're probably not the right person to install Un-CGI; ask your system administrator to set it up for you.

To install, edit the makefile. Change the following settings:
CC The name of your system's C compiler—typically cc or gcc.
SCRIPT_DIR The directory where you want Un-CGI to look for your programs. This doesn't have to be the same as your server's CGI directory. Note that you cannot use a tilde (~) here to signify a home directory; you have to use the entire path, beginning with /.
DESTDIR The directory where you want the Un-CGI executable to be installed. If your server has a cgi-bin directory, it is generally what you'll need to put here because the server needs to know to run Un-CGI as a CGI program. Often that can only happen for programs that are located in the server's cgi-bin directory.

Note that you cannot just make a directory called cgi-bin in your account and expect Un-CGI to be run from it. The HTTP server needs to be configured to know where to look for executable programs. If you don't manage the HTTP server on your system, you probably cannot install Un-CGI in the right place. (On some servers, you can put CGI programs anywhere if you give them a certain file extension; talk to your system administrator to find out if this is the case on your system. If so, see the next item.)
EXTENSION If your server allows CGI programs to be run from anywhere as long as they have a particular filename extension (typically .cgi), you should set this to that extension, including the period (.). In that case, you can set DESTDIR to point into any directory that the server has access to (for example, your public_html directory).

You don't need to follow any particular naming rules for the programs you're going to ask Un-CGI to run. As long as they're in the SCRIPT_DIR directory, you can name them any way you see fit.

Once you're done editing the makefile, run make install and your system will build and install Un-CGI into the directory you specified as DESTDIR. If you get an error message like make: Command not found or cc: Command not found, talk to your system administrator. There's no way of magically knowing where your system happens to put its compiler tools.

Make sure the file permissions on the Un-CGI binary (and the directory it's in) are set so that the HTTP server can execute it. On most systems the HTTP server runs as user nobody or www. You may want to make Un-CGI a setuid program if you want to manipulate private files with your back-end scripts because they will ordinarily be run under the same user ID as the HTTP server. Consult your system administrator to find out your site's policy on setuid programs; they are frowned upon in some places.

Usage


An example is the easiest way to demonstrate Un-CGI's use. Suppose you have the following in an HTML file:

<form method=POST action="/cgi-bin/uncgi/myscript">
What's your name?
<input type=text size=30 name=name>
<p>
Type some comments.
<br>
<textarea name=_comments rows=10 cols=60></textarea>
What problem are you having? <select name=problem multiple>
<option> Sleeplessness
<option> Unruly goat
<option> Limousine overcrowding
</select>
<p>
<input type=submit value=" Send 'em in! ">
</form>

When the user selects the Send 'em in! button, the HTTP server will run Un-CGI. Un-CGI will set three environment variables—WWW_name, WWW_comments, and WWW_problem—to the values of the name, comments, and problem fields in the form, respectively. Then it will execute myscript in the SCRIPT_DIR directory.

All the usual CGI environment variables (PATH_INFO, QUERY_STRING, and so on) are available to the script or program you tell Un-CGI to run. A couple of them (PATH_INFO and PATH_TRANSLATED) are tweaked by Un-CGI to the values they would have if your program were being executed directly by the server. PATH_INFO is, in case you haven't read up on CGI, set to all the path elements after the script name in your URL (if there is any). This is an easy way to specify additional parameters to your script without resorting to hidden fields.

myscript might be as simple as this:

#!/bin/sh
echo 'Content-type: text/html'
echo ''
mail webmaster << __EOF__
$WWW_name is having $WWW_problem problems and said:
$WWW_comments
__EOF__
cat /my/home/directory/htmlfiles/thanks.html

With Un-CGI, that's all you need to write a script to send your mail from a form and print a prewritten file as a response. It's the same whether you want to use GET or POST queries.

If you're using Perl, $ENV{"WWW_xyz"} will look up the value of the xyz form field.

If more than one problem is selected in the previous example, the values will all be placed in WWW_comments and separated by hash marks (#). You can use the library function strtok() to separate and replace the hash marks with newlines using tr. Type the following:

echo $WWW_problem | tr '#' \\012 | while read value; do
echo $value 'selected.'
done

A useful learning tool is to point your form at a script that just prints the contents of the environment. On most systems there is a program to do that, called either env or printenv. You can write a little script that runs it:

#!/bin/sh
echo 'Content-type: text/plain'
echo ''
env

This script will print all the CGI environment variables set by the server.

Special Processing


You eagle-eyed readers may have noticed that the text area in the previous example had an underscore (_) at the beginning of its name. When Un-CGI sees a form field whose name begins with an underscore, it strips whitespace from the beginning and end of the value and makes sure that all the end-of-line characters in the value are UNIX-style newlines (as opposed to DOS-style CR-LF pairs or Macintosh-style CRs, both of which are sent by some browsers). This makes processing text easier because your program doesn't have to worry about the browser's end-of-line conventions. Note that if a form field is named _xyz, you still get an environment variable called WWW_xyz. The extra underscore doesn't show up in the environment variable name.

Un-CGI also modifies variable names containing periods. The major source of which is <input type=image>. Shell scripts have trouble coping with periods in environment variable names, so Un-CGI converts periods to underscores. This is only done to variable names; periods in values will remain untouched.

Other Features


If you compile with -DNO_MAIN, you can use Un-CGI as a library function in a C program of your own. Just call uncgi() at the start of your program. Follow this example.

Un-CGI will handle hybrid GET/POST requests. Specify a method of POST in the form, and add a GET-style query string to the action An example of this is as follows:

<from method=POST action="/cgi-bin/uncgi/myscript?form id=feedback">

When your script is run, WWW_form_id will be set to feedback. This will only work if your HTTP server supports it (NCSA's does, for now anyway).

Un-CGI is freeware. If you want to include it in a commercial product, please send me mail. I'll probably just ask you to include a pointer to this page with your product. If you want to pay me for Un-CGI, send me a picture postcard to help decorate my wall! My address is

Steven Grimm
Hyperion
173 Sherland Ave.
Mountain View, CA 94043

Frequently Asked Questions


As with any kind of program, many questions arise regarding its use. What follows is a compilation of the most frequently asked questions about Un-CGI.

I Get an Error About sys_errlist When I Compile


Some UNIX variants' standard-include files contain a declaration for the list of system error codes, and some don't. For the latter, I need to include the declaration in uncgi.c. If you get an error about a previous declaration of sys_errlist, edit uncgi.c and remove the line:

extern char *sys_errlist[];

Then recompile and everything should work.

Where Do I Put Everything?


Short answer: Look in the makefile.

Long answer: When you edit Un-CGI's makefile, you'll see two macro definitions relating to paths. The first, SCRIPT_DIR, tells Un-CGI where to look for your scripts or programs. It must be set to the name of an existing directory; you can set it to any directory you like.

Sometimes it is set to the location of your server's cgi-bin directory, although that's not necessary. The second, DESTDIR, tells the makefile where to install Un-CGI. It must point to your server's cgi-bin directory, if your server has one.

Note that you can't just create a directory called cgi-bin in your account and expect it to work. The server has configuration files that tell it where to look for scripts and programs. Talk to your system administrator if you aren't the person in charge of the server on your machine.

An additional makefile setting, EXTENSION, should be of help if your server allows you to put CGI programs anywhere on the system. Again, consult your system administrator to see if this is the case.

Why Does Un-CGI Tell Me It Can't Run My Script?


First, make sure your script is in the right place; see the preceding section. Second, make sure your script can be executed by the server. Remember, Un-CGI is run by the server, which is probably using a system user ID, not your user ID. You need to set the permissions on your script so that it can be run by any user. Usually, you can say "chmod 755 scriptname" (replacing scriptname with the name of your script) to set the permissions properly.

If you're still having trouble, edit the makefile, uncomment the DEBUG_PATH line, and rebuild. This will instruct Un-CGI to include the full path to where it thinks your script should be in its error message.

What Do I Do in My Forms?


The <form> tag has two attributes, METHOD and ACTION. METHOD must be set to either GET or POST. Un-CGI will handle either one, but POST is preferred if you have text area fields or are expecting a lot of information from the client. Note that the attribute name (METHOD) can be upper or lowercase, but the value must be all caps.

ACTION should have the following components:

So, if you wanted to tell Un-CGI to run sendmemail with no additional parameters, you'd put sendmemail in the directory you specified as the value of CGI_BIN in Un-CGI's makefile, and use the following tag to begin your form:

<form method=POST action="/cgi-bin/uncgi/sendmemail">

I Get an Error 403 when I Submit My Form


The usual cause of this is that your server requires a special filename extension on CGI programs. (Most often it's .cgi.) You need to give Un-CGI a name that will identify it as a CGI program to the Web server. There is nothing special about Un-CGI from the Web server's point of view; it's just another program that gets run like any other, and your installation of it has to obey the same rules as other programs.

I Get an Error Code 500 From the Server


This usually means your script isn't specifying a content type to the server. The first thing your script needs to output is Content-type: text/html followed by a blank line. Note that the blank line following the header is not optional, and it has to be completely empty—no whitespace. (See Chapter 5, "CGI (Common Gateway Interface) Programming," for more information.) If you're writing a shell script, for instance, you'll need the following:

echo Content-type: text/html
echo ""

The empty quotes on the second line are necessary; otherwise, echo won't print anything, not even a blank line. Of course, if your script is outputting something other than HTML, adjust the content type accordingly.

My Script Doesn't See the Form Variables


There are a few common causes for this:


The Browser Just Sits There When I Submit My Form


The most common cause of hangs like that is from trying to convert an old CGI-compliant program or script to run under Un-CGI. Your script is detecting that the form was submitted with the POST method and is trying to read form results from the browser. Unfortunately, by the time your script is run, Un-CGI has already read the results, so your program sits there waiting forever for bytes that have already been consumed.

Remove the part of your code that reads a query from the standard input. It'll generally be located somewhere around the word POST, which is easy to search for. Replace it with code that fills your program's internal variables via getenv() calls (assuming that your program is in C) on the WWW_ variables defined by Un-CGI.

How Do I Parse Check Box Results?


Un-CGI puts hash marks (#) between check box selections if there are several of them. How you parse depends entirely on which language you're using. In C, use strtok(). In Python, use string.splitfields(). In Perl, use split(). In Bourne shell, use something like the following:

echo $WWW_whatever | tr \# \\012 | while read result;
 do echo User picked $result
done

Do I Need to Make a Directory Called uncgi?


No. You're probably assuming that because your form has an ACTION like /cgi-bin/uncgi/xyz, there must be an uncgi directory under cgi-bin. That's not how it works.

The parts of a URL between the slashes are not directory names. They are symbols that tell the server where to find a particular document. In most cases, the server will look for a directory with the same name as the symbol in question. If there is one, go in that directory and proceed to the next symbol. However, that isn't always what happens. If the server sees that a particular symbol matches the name of a program, it will typically run that program and pass the rest of the URL to the program as an argument. And that's exactly what's happening here.

There's no uncgi directory. You can think of /cgi-bin/uncgi/xyz as /cgi-bin/uncgi xyz if that helps. (Strictly speaking, it's not accurate, but that's the concept.) Un-CGI sees the xyz argument and looks in its SCRIPT_BIN directory to find a program by that name.

If you're still not sure what all this means, just try it out and see what happens!

Does Un-CGI Strip Out Special Shell Characters that Might Cause Security Problems?


No, it doesn't for the simple reason that Un-CGI isn't tied to any one shell or any shell at all, for that matter. Un-CGI sits in front of C programs just as easily as Bourne shell scripts, Perl scripts, or Python scripts. (All of which, incidentally, are used in conjunction with Un-CGI at Hyperion.)

In most of those languages, there aren't any special characters that are inherently security problems, so having Un-CGI strip characters that cause problems for a particular shell would just end up pointlessly mangling the input to other kinds of scripts and programs. People using shells with different special characters would still have to specially handle them anyway.

On most UNIXes, you can use the tr -d command to strip out characters that your shell processes. For example, to strip out dollar signs from a Bourne shell variable, you would type:

WWW_puppycount="`echo $WWW_puppy | tr -d \$`"

Summary


Un-CGI can be a key piece of software when you are developing quick shell-based CGIs to handle output from forms. However, you should keep in mind that Un-CGI doesn't perform any sort of security checks on the submitted values it processes. For more information on security issues that you should address on your CGI, please refer to Chapter 16, "Web Server Security Issues."