Maintaining State Using Cookies

Review

What is State?

In case you skipped over the last tutorial, state – in the context of web development – means that the same URL and query string may return a different web page, depending on the state of the server.

For example, I visit my Gmail inbox. The url is:

http://mail.google.com/mail/#inbox

When I log into my Gmail account, I ony have to do it once; I don’t have to log in over and over again every time I change pages. Between requests, Gmail ‘remembers’ me, without my changing the URL.

Likewise, when I browse to the page, sometimes I’ve received a new email and the page is different. Likewise, when I delete or move an email from my inbox, the next time I return, it hasn’t moved back to my inbox. Gmail ‘remembers’ the state of my inbox from one request to the next.

Maintaining state is essentially a technical way of saying "the web site remembers things."

Why Is It "Hard" To Maintain State?

HTTP is a stateless protocol; there is no mechanism is the protocol which defines a relationship between one request and another.

So how do web sites like Gmail accomplish this statefulness?

How To Maintain State

Generally speaking, a web application accomplishes this by assigning the browser an identifier. When the request is over, the CGI script persists state-related information; the state could be persisted in a file for example. When the client makes another request, they include their identifier in the request. The CGI script uses this identification to find the persisted data, and proceeds with the transaction.

This is why I always put "remember" in quotation marks: while the server has to "remember" stateful information, its just as important that the client reminds the server with its identifier…

We are going to refer to a series of request-response interactions between a server and a specific client during which we maintain state a session. We are going to call the identifier that the browser includes with every request as a session ID.

There are two ways of passing the session ID between the client and the server: using a parameter in the query string to identify the client, and using cookies. We will see how to do this with a cookies in this tutorial.

What Are Cookies?

Cookies are key-value pairs stored on a machine for use by a web browser. An individual cookie is associated with a doman (google.com, leguen.ca etc) and when the browser sends a request to that domain, it includes all the cookies for that domain in a special ‘Cookie’ HTTP header.

A web server can include – in its HTTP response – a ‘Set-Cookie’ header. The ‘Set-Cookie’ header tells the browser to create a cookie, specifying the cookie’s name and value. The cookie can also have an expiration date. Here is an example, where the server instructs the browser to create a cookie ‘MyFirstCookie’ with a value of ‘BlahBlahBlah’; the cookie will expire (meaning the browser will discard it) on the 31st of December, 2010, just before midnight. Any requests until then (or until the browser is closed) which the browser sends to "www.richard-jp-leguen.ca/tutoring" should include this cookie in the ‘Cookie’ header.

Maintaining State Using Cookies

So how can we use cookies to maintain state? In the same way that we included a SESSIONID in the query string, we re now going to specify a SESSIONID cookie.

The Sample Application – BlackJack

We’re going to re-do the sample BlackJack application, but this time we will use a Cookie we’ll call "SESSIONID" to maintain state.

Session information will be in a file in the /tmp directory. That file will contain four lists: one for the cards in the deck, one for cards in the player’s hand, one for cards in the dealer’s hand, and one for cards in the discard pile.

The Rules (Again)

Again, to make the game of Blackjack simpler, we’re going to remove the Aces from our deck, and only give the player the option to "Hit" and "Stay". We won’t bother keeping track of the player’s score, and the player can "Hit" as much as they want.

What we do want to keep track of is the cards. We going to deal cards out of the deck to the two players, and those cards have to be valid across requests. Additionally, when there are no more cards, we shuffle the discard pile, and start using it as a deck.

The Basics

Ignoring anything about the rules of Blackjack, our script will look like this in the end:

We now initialize the deck, the player’s card, the dealer’s cards, and the discard pile. They are all arrays.

@deck = ();
@player = ();
@dealer = ();
@discard = ();

We now have to load our session data. We have two situations: if the request included session information, and when the request did not include session information. If the request did not include session information we initialize everything and create a random SESSIONID:

(if you’re wondering why the names of the cards are so strange, it’s because we’re going to be hotlinking to Wikimedia Commons… meaning we’re stealing images from someone else’s web site…)

If a SESSIONID cookie was provided though, we need to load our state out of a file. In the following code, change ‘r_leguen’ to your ENCS username:

else { # if a session ID is provided, we initialize session data.
$sessionID = $cookies{"SESSIONID"};
open("SESSION", "</tmp/r_leguen.cgi_blackjack.".$sessionID);
# we read the first line,
# which is the list of cards in the deck
# seperated by commas
$cards = <SESSION>;
chomp($cards);
@deck = split(/,/, $cards);
# we read the second line,
# which is the list of cards in the hand
# seperated by commas
$cards = <SESSION>;
chomp($cards);
@player = split(/,/, $cards);
# we read the third line,
# which is the list of cards in the computer's hand
# seperated by commas
$cards = <SESSION>;
chomp($cards);
@dealer = split(/,/, $cards);
# we read the fourth line,
# which is the list of cards in the deck
# seperated by commas
$cards = <SESSION>;
chomp($cards);
@discard = split(/,/, $cards);
close(SESSION);
}

If neither the payer nor the dealer have any cards, it means we’re playing a new game and need to deal cards to them:

We will now output the dealer’s hand. We are going to hotlink to images on wikimedia commons, such as this playing card clipart:
Take note that only the first card of the dealer’s hand is revealed until the player chooses to ‘Stand’.