Fall 2001 CSCI 363 Homework 6

This assignment is due Thursday, 15 November.

The task

Your assignment is to write three CGI fairly simple scripts, or programs. Each of these illustrate an aspect of CGI programming.

Introduction to the programs

Sample versions of these CGI scripts have already been written. The URL's shown below can be used to access them.

Industrial strength CGI scripts process information from forms. However, since CSCI 363 is not an HTML class, we're going to invoke our CGI scripts in a very simple way. We're putting the CGI arguments after the question mark at the end of the URL. Consequently, in the above three examples, the CGI scripts are invoked with the arguments 15+23, +29, and +37.

CGI and the HTTP server

We're assuming that you will be using an Apache HTTP server for this assignment. There's a good chance, any Unix-based server will work with the method we describe in this section.

Reading the query

If you give your browser a URL that uses a CGI script, Apache will involve your program with several environment variables. One of these environment variables is QUERY_STRING. It will contain the argument, that is, the string after the question mark, to your CGI script. In C++, you can obtain the value of QUERY_STRING with the following statement:

A careful programmer will test the value returned by getenv to make sure it isn't the null pointer.

Reading the cookies

If your browser has stored cookies for your URL, it will provide them in an environment variable called HTTP_COOKIE. Cookies are provided in a semi-colon separated list similar to:

If your program wishes to retrieve a cookie, it will have to test for the existence of the HTTP_COOKIE environment variable and, if it is present, parse it to find the needed cookie. By the way, just because the browser has provided some cookies, do not assume that it has provided the cookie for which you are searching. It may just be giving you cookie deposited by other web sites within your domain.

Generally, programmers use special CGI libraries that provide cookie-parsing routines. I this assignment we'll provide you with an embarrassingly simple cookie parser.

Returning the result

Your CGI script must write to standard output the contents of a page to display to the browser making the CGI request. If you are not storing cookies on the remote browser, this page should be in standard HTML format, but it must be preceded by the following two lines, where the second line is blank:

The format of the script's output is similar to that shown in Figure 2.8 of your textbook, except that it does provide the initial state line. The Apache server does that task.

Note that these lines must be separated by carriage return-line feed characters and that a blank line must proceed your HTML-formatted message.

By the way, when C++ write to cout, they are writing to standard output. In C, stdout is standard output.

Setting the cookie

When you wish to set a cookie on the browser, your script writes three lines of output before the HTML. These lines resemble:

If you want your cookie to live beyond one session, you also need to attach an expires field to it. In this case, your Set-Cookie line will resemble:

The three CGI scripts

The three scripts utilize different notions of state. The first is a completely stateless CGI script. It received two numbers expressed as N+M, adds them modulo 1000000, and returns a page containing the result of the addition.

The second script uses a cookie to store a running sum. The script installs a cookie named C, where you choose your own C, with the value N in the user's browser. When the user make a CGI query for +M, the script computers the sum of N and M modulo 1000000, and returns a page containing the addition along with a Set-Cookie to set C to this new sum.

The third script keeps a running sum, but in a file stored on the server rather than within a cookie. This way several browser sessions can modify the same running sum.

Obviously a real CGI script is not this simple. However, most are some combination of the second and third scripts. Databases on the server maintain information that is accessed by a key derived from a cookie. Think about how your CGI scripts could be used to implement a shopping cart application. Your scripts would identify each customer with a unique cookie value and databases on your server would store customer choices.

Compiling and running the scripts

The Apache server on www.cs.unca.edu allows you to run your program anywhere inside your public_html directory. You should create a protected directory called csci/363/home06 to store your source files using the following commands:

After your scripts are compiled, you should copy them into the following three files within your public_html directory.

Testing the CGI scripts

Testing the CGI scripts through your browser would be painful. Instead, use your shell to set the environment variables, QUERY_STRING or HTTP_COOKIE, used by the script and then run the script. Here's an example of how to do this, using the C-shell for the first CGI script:

% setenv QUERY_STRING "17+13"
% try1.cgi
Content-type: text/html

<title>Dean's cookie 1</title>
<h1>Dean's cookie 1</h1>
<p>Number one is <kbd>000017</kbd>.</p>
<p>Number two is <kbd>000013</kbd>.</p>
<p>Number sum is <kbd>000030</kbd>.</p>

For the second CGI script, you'll have to also need to set an environment variable for the cookie.

% setenv QUERY_STRING "+15"
% setenv HTTP_COOKIE "deanscookie=000023"
% try2.cgi
Content-type: text/html
Set-Cookie: deanscookie=000038; domain=cs.unca.edu ; path=/~brock/classes/Fall2001/363/ ; expires=Sat, 01-Dec-2001 05:00:00 GMT

<title>Dean's cookie 2</title>
<h1>Dean's cookie 2</h1>
<p>Old Cookie is <kbd>000023</kbd>.</p>
<p>Add Number is <kbd>000015</kbd>.</p>
<p>New Cookie is <kbd>000038</kbd>.</p>

CGI protection

Pay attention! This is a tricky part. Also, don't try this until you have tested your CGI script by setting environment variables from the shell as explained in the preceding section.

When CGI scripts are involved by the woodfin Apache server, they run as a special user called nobody. This is considered a safe way to run scripts, since the user nobody typically "owns" no files on the system.

However, nobody does cause some problems. If you CGI script gets into a loop and is running as nobody, you can't cancel it. Also, nobody could not rewrite the file needed for the third CGI script unless you make the file writable to all users.

But there is a solution. You can set the permissions of your CGI script so that it runs as your own user-id. You do this by turning on the set-uid bit. Generally, it's a bad idea to turn on the CGI script, but if you write your script carefully there should be no security problems. For this assignment, the main thing you need to do is to be careful when you open files. If you always open the file by its full path name, you should be safe.

Don't open a file for writing as:

Do open a file for writing as:

And better yet, don't open any files at all! After all, it's only the third script that needs to do I/O.

Getting started

You don't have to completely reinvent the wheel. You could go out on the Internet and find many examples of CGI scripts; however, fill-in-the-blank C++ skeletons follow:

You should need to modify only one routine in each of these three programs. I'll let you figure out which one.

These program were compiled under Linux. Minor modifications may be required for other Unix platforms. If you try Windows, you are on your own.

You don't have to write your scripts in C++. C would be just as easy. Java would require a shell script to invoke the java program, but that's a minor problem. If you Perl, you'll find the job easier, but you'll need a CGI wrap facility to handle the set-UID part of the assignment.

However you program, leave your source code in your csci/363/home06.