A Recipe for Making Cookies

Cookies are an excellent way of keeping track of users who visit a web site. Here's how to use them.
How Browsers See Cookies

The Set-cookie header becomes obvious if we use telnet to look at the output sent by the program. From my computer running Red Hat Linux 4.2, I type:

telnet localhost 80

which opens a connection to the Apache HTTP server running on my computer. I then type:

GET /cgi-bin/cookie-test.pl HTTP/1.0
followed by two line-feed characters, which indicates the end of my request. As in the example above, my server knows that anything in /cgi-bin is actually supposed to execute cookie-test.pl and to send the output from that program to the user's browser. When I enter the above request and press the return key twice (once to end the request line and another to indicate that we have finished the entire request), I get the following:
HTTP/1.1 200 OK
  Date: Tue, 23 Sep 1997 09:15:42 GMT
  Server: Apache/1.2.4
  Set-cookie: counter=1; path=/cgi-bin/
  Connection: close
  Content-Type: text/html
  <HTML><HEAD><TITLE>Cookie set</TITLE>
  </HEAD><BODY><P>The cookie named "counter" has
  been set to 1.</P>
  </BODY></HTML>Connection closed by foreign host.
The above response is a bit more detailed than the skeleton response that we looked at above, but its contents should still be fairly clear. We get a 200 (“OK”) message from the web server, the date at which the document was created, the server that produced the response, the connection type and the content type.

The Set-cookie header tells our browser that we should now hold onto a cookie named counter, whose value should be 1. In the future, every time my browser asks for a document in the cgi-bin path from this host, it will send the value of the counter cookie, which will still be set to 1. Listing 2 is a short CGI program that prints the names and values of all cookies sent to it.

Note that our program only sees a single cookie, while I know that my browser has held onto far more cookies that this. I do not have to enter my password when entering certain sites at which I have registered, and there are a large number of cookies in ~/.netscape/cookies, the file in which the Netscape's browsers place cookies. Why does only one cookie appear?

The answer is that when a browser visits a site, it only sends those cookies that were created by that site. Thus, when I am accessing my local web server, only those cookies created by my local web server are available to CGI programs there. If I were to access The New York Times, only those cookies set by the nytimes.com domain would be available to their system. One of the cornerstones of the cookie specification is that the cookie name and value pair should only be sent to the hosts or domains that created them.

Those of you worried that information about your web browsing interests is shared among sites (and thus violate your privacy) might still be right—but this cannot happen automatically with cookies unless all of the sites you visit are within the same domain. Indeed, HotWired used to have several sites with a shared password system that relied on cookies. Because the sites all had different domain names, however, I had to have a separate cookie on my system for each sub-site. The result was that I had to enter my user name and password the first time I visited each of these sites.

Storing Useful Values

Now we know how to create cookies. Our CGI program uses CGI.pm's cookie method to create one with a name and value, and then puts it into the header returned to the browser. We also know how to write programs that can grab cookies' values. To get a list of all cookies, use the same cookie method, then iterate through the list of names that it returns. Once we have those names, we can retrieve the values with the cookie method, giving it an argument of a particular cookie name.

Storing a value isn't of much use unless we can also change it. Our next task is to combine parts of cookie-test.pl and show-cookies.pl into a single program which increments the counter cookie value each time we visit the site, displaying its value each time. The first time we visit this CGI program, it sets the cookie's value to 1, the second time we visit, it will set the value to 2 and so on.

You can see a bare-bones attempt at this sort of program in Listing 3. As you can see, the code is fairly straightforward. We create an instance of CGI and use the cookie method to extract the value of the counter cookie. We increment that value by 1, create a new counter cookie with the updated value and send that value back as part of the header to the program's response. The body of the response contains a short listing of the names and values of each cookie in the system.

Each time we invoke update-counter.pl, the user's browser recognizes counter as a cookie with the appropriate host or domain name and path, and thus sends counter as a cookie with its request. Update-counter.pl grabs the value of the cookie if it exists and sets it to 0 if it does not. It then increments the value of the cookie and creates a new (outgoing) cookie with the counter name and the updated value. This new cookie is included in the headers which update-counter.pl sends to the user's browser, and the value of the cookie is displayed in the body of the response which contains HTML-formatted text.

This program may not seem very useful, but with a few small variations, it could be useful in a plethora of situations. For example, you could ensure that users only enter a questionnaire once or keep track of how many times they have requested technical support via the Web rather than by telephone. Another possibility might be a web-based quiz game which presented questions one at a time. You could keep track of a user's score with cookies. Alternatively, you could keep track of which questions the user had already seen, so as not to ask the same question twice. You could even keep track of the user's high score, giving a special message if and when the user achieves a new high.