This month I had a client who needed to implement a "shopping cart" type of application which enables customers to order items from his web site. Handling the order for one item is pretty straightforward using the CGI techniques discussed in the December, 1996 column. (Unless you are pretty familiar with CGI programming, I would suggest that you look at that article before continuing with this one.)
If you want to process an order that contains multiple items, things can get a little tricky. If the catalog is not too large, then you can put all of it on one page and let the customer check off multiple items and process them all in one submission to your CGI script. If the catalog is too large though, that method won't work because the page will take too long to download and be unwieldy to use. If you must break the catalog up into separate pages then you run into the problem of HTTP being a stateless protocol. Stateless simply means that there is no inherent connection between one access of a web server and another. If you call a CGI program twice, there is no way of connecting the results of the two accesses. With HTTP, a client makes a request of the server which the server satisfies in some way, and then the connection is broken. Obviously this presents a problem if you want people to be able to browse through a multiple page catalog and check off multiple items to be ordered. How can the server know what was previously ordered?
If you use Netscape Navigator, open the file cookies.txt in your Netscape directory with a text editor like OS/2's Enhanced Editor (EPM). It will have entries that look like this:
www.netscape.com FALSE / FALSE 942189160 NGUserID cc98a714-18593-893105250-3For what we're doing, the format of the cookies.txt file is not important. But what you can see is that a cookie is associated with a particular web server and only that web server can retrieve the contents of the cookie. A cookie has a name (NGUserID above) and a value (cc98a714-18593-893105250-3). In our case of needing to identify a person across multiple submissions to our CGI program, we used a cookie called SESSION_ID and made it a 12 digit random number.
So, how is the cookie created in the first place? It's really pretty simple, you simply return a line in the header of your response to the client of the form
Set-Cookie name=value; path=/somepath; expires=date and time; domain=domain_namewhere name is the name of your cookie (case-sensitive) and value is the value associated with the cookie. The path is the path on the web server to be associated with the cookie. This could be a file (e.g. /catalog/page1.html or just / if it is to be associated with all paths on the server). And expires is a date and time (GMT) for the cookie to expire and be removed by the browser. If you do not specify an expiration date, the cookie expires when the client closes their web browser. Finally, domain is the domain to be associated with the cookie. This must contain at least two dots to prevent the possibility of someone's using ".com" for example, and getting all of your cookies from any site with ".com" in the address. A valid value might be ".os2ezine.com" or "www.os2ezine.com". You can leave off the domain and it will default to the address of the server setting the cookie. Here is a concrete example:
Set-Cookie: SESSION_ID=54635397865; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT path=/ domain=.os2ezine.comThe code to send back the header of the response to the web browser might look like:
Say 'Set-Cookie: SESSION_ID='||Session_ID||'; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT path=/ domain=.os2ezine.com' Say "Content-type: text/html" Say Say Say "CGI Results:<P>"Once you have created a cookie on the client end, that cookie will be passed to your server anytime a request is made and the path in the cookie matches the requested document. The cookie will be passed in the environment variable HTTP_COOKIE. You will recall that in the first article we wrote our Rexx code so that it would run under OS/2 and Unix, which have different ways of retrieving the contents of environment variables. Under OS/2 Rexx, you use the value() function and under Unix you use the getenv() function. So, modifying our previous code a little bit, we can get the contents of any cookies that the client browser sends to us:
Select When OperatingSystem="OS/2" then do method = value("REQUEST_METHOD",,env) cookie = value("HTTP_COOKIE",,env) len = value("CONTENT_LENGTH",,env) if (method == "GET") Then Do query_string = value("QUERY_STRING",,env) end End Otherwise /* We're on a Unix machine */ method=getenv("REQUEST_METHOD") cookie=getenv("HTTP_COOKIE") len = getenv("CONTENT_LENGTH") if (method=="GET") then do query_string=getenv("QUERY_STRING") end If (method == "POST") & (len \= "") Then Do /* use POST method to pass parameters */ post_string = charin(,,len) query_string = post_string End End /* Select */After executing the above code, the variable cookie will contain the contents of any cookies that are appropriate to the current query by the browser. You can then parse the contents to get the values stored in the cookie. In my program, I needed to know if the client had been assigned a session ID and if not, to assign one. Here is the code I used:
If Pos("SESSION_ID",Cookie)<>0 then Do /* SESSION_ID exists in the cookie, so parse for its value */ Parse Var Cookie . "SESSION_ID=" Session_ID . If Session_ID="SESSION_ID" then /* just in case we assigned a session ID before creating it */ Session_ID=Left(Random(1,100000),6,"0")||Left(Random(1,100000),6,"0") End Else Do /* There was no SESSION_ID in the cookie so create one */ Session_ID=Right(Random(1,99999),5,"0")||Right(Random(1,99999),5,"0") EndWhat this code does is check to see if there is a SESSION_ID in the cookie. If so, it parses the contents of the cookie to get the value stored in SESSION_ID. Then it checks to make sure that it doesn't have the value SESSION_ID which would result if we set the cookie before defining a value for our Rexx variable. If the cookie doesn't contain a value for SESSION_ID, then we create one. The value for the session ID is generated using the Random() function. Right() is used to tack zeroes onto the random number to make it have a length of five digits. Performing those calls twice and concatenating the results gives us a session ID that has twelve digits. You could, of course, generate the numbers in many other ways.
Dr. Dirk Terrell is an astronomer at the University of Florida specializing in interacting binary stars. His hobbies include cave diving, martial arts, painting and writing OS/2 software such as HTML Wizard.
|Copyright © 1998 - Falcon Networking||ISSN 1203-5696|