MSc-IT Study Material
June 2010 Edition

Computer Science Department, University of Cape Town

Problems with cookies

Cookies are not the only way which can be used to track a user as they move between the different pages of a Web application. Cookies are convenient because they can be set up so that a user can completely leave the Web application, later return to it, and continue what they were doing without any loss of information. However, the user may have disabled cookies on their browser, causing any Web application using only cookies to track its users to no longer function correctly. Two other methods that can be used are “URL rewriting” (which keeps track of a user by modifying the query string at the end of an URL) and using hidden form fields to store user data.

However, to ease Web application development, the Servlets API provides a unified interface to using Cookies and URL rewriting. This is the Session Tracking API, made available to HTTP Servlets through the HttpSession interface. HttpSession supplies a consistent way of storing and retrieving data about the user, and should generally be used in place of cookies.

Session tracking is easy to use. The first step is to ask for the current session from the HttpServletRequest object, like so:

HttpSession session = request.getSession();
    

This will return the current user's session object. If the user is using the Web application for the first time and no session object currently exists, a new one will be created. If you would like to ensure that a new session object is not created by default, you can use the second form of the method:

HttpSession session = request.getSession(false);
    

If the session does not already exist, getSession(false) returns null. getSession(true) is exactly the same as getSession().

Once you have the session object, you can store arbitrary information about the user, like this:

session.setAttribute(“name”, value);
    

“name” can be an arbitrary string that gives a name for the value. The value variable itself can be any Java object, but in these notes we will only be using strings. The value can be read like so:

String value = (String) session.getAttribue(“name”);
    

Notice that you have to cast the object returned from getAttribute().

This is all there is to using session objects. Below is an updated version of the hit counter Servlet that uses the session tracking API rather than cookies. There are a number of ways that this could be done, including one in which no attribute needs to be set. We will, however, be setting an attribute.

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class Counter extends HttpServlet {

    private final String file_name = "counts.txt";
    private final String attribute_name = "visited";
    private final String attribute_value = "returnSoon";

    public void doGet(HttpServletRequest request,
		      HttpServletResponse response)
    {
	BufferedReader file = null;
	int count = 0;

	synchronized (this) {
	    try {
		file = new BufferedReader(new FileReader(file_name));
		count = Integer.parseInt(file.readLine());
	    }
	    catch(IOException e) {
	    }
	    finally {
		try {
		    if (file != null)
			file.close();
		}
		catch (IOException b) {}
	    }


	    HttpSession session = request.getSession();
	    String value = null;

	    value = (String) session.getAttribute(attribute_name);

	    if (value == null) {
		session.setAttribute(attribute_name, attribute_value);
		session.setMaxInactiveInterval(60 * 60 * 24);
		count += 1; 
	    }
	Writer writer = null;
	    try  {
		writer = new PrintWriter(new FileWriter(file_name));
		writer.println(count);
		writer.close();
		writer = null;
	    }
	    catch (IOException e) {
	    }
	    finally {
		if (writer != null)
		    writer.close();
	    }
	}
	    
	try {   
	    PrintWriter out = response.getWriter();
	    out.println("<html>");
	    out.println("\t<head><title>Hello, visitor number " + count +
			".</title></head>");
	    out.println("<body>");
	    out.println("<p>Hello, visitor number " + count + ".</p>");
	    out.println("</body>");
	    out.println("</html>");
	}
	catch (IOException e) {
	}
    }
}

	    PrintWriter writer = null;
	    try  {
		writer = new PrintWriter(new FileWriter(file_name));
		writer.println(count);
		writer.close();
		writer = null;
	    }
	    catch (IOException e) {
	    }
	    finally {
		if (writer != null)
		    writer.close();
	    }
	}
	    
	try {   
	    PrintWriter out = response.getWriter();
	    out.println("<html>");
	    out.println("\t<head><title>Hello, visitor number " + count +
			".</title></head>");
	    out.println("<body>");
	    out.println("<p>Hello, visitor number " + count + ".</p>");
	    out.println("</body>");
	    out.println("</html>");
	}
	catch (IOException e) {
	}
    }
}
    

Notice how, in the trivial case, the session tracking API is easier to use than Cookies. There are some important differences between this version and the cookie version, however: you cannot easily invalidate session tracking by simply deleting a cookie, since that cookie may not even exist; setMaxInactiveInterval() sets the time, in seconds, from which the user last accessed the page to when the session should be invalidated(). In contrast, setMaxAge() is the time in seconds from the cookie's creation. To get identical behaviour you would have to use the session object's getCreationTime() (which returns time in seconds) and getLastAccessedTime() (which returns the time in seconds since the user last accessed the Web application) methods. If the difference between those two times is larger than a full 24 hours, then the session should be manually invalidated.