Cookies

Terence Parr

The problem

Request/response model does not allow for tracking users as it is stateless.

How do you know when you're generating a page requested from the same user?

  1. URL encoding
  2. cookies

Cookies

A cookie is a named piece of data (string) maintained by the browser that is sent to the server with every page request. The server can use that as a key to retrieve data associated with that user.

Cookies also can have URI path info and lifetime attributes. Cookie names are not unique as you can have multiple paths associated with a name. A path of /news means the cookie is returned for any URI at /news or below.

It is a way to persist data across multiple page views as well as multiple sessions across days or months. See class javax.servlet.http.Cookie.

Cookies affect page caching. Can't cache a page if you need to send cookies back to the browser.

Can I, as a server, ask for another server's cookies (such as amazon.com's)? No! Security breach! If another server can get my server's cookies, the other server/person can log in as me on my server. Heck, my cookies might even store credit card numbers (bad idea).

The solution

Do we know this person?

When a person visits your site for the first time, your server can store a cookie on their disk. When they return, their browser automatically sends this data along with each page request. Your server can ask for the cookie(s) and use it to associate that person with a larger chunk of data (such as their preferences, credit card, ...) in a database or wherever.

Sessions

How do you handle "sessions" where someone is logged in for only a short period? For example, you might only want to hold data in memory for that person while they are actively using your site.

Web servers know how to use cookies to simulate sessions. Subject of next lecture.

Mechanics

Create cookie

  1. set type of response to text/html
  2. create Cookie
  3. setMaxAge(interval-in-sec)
    1. positive=num secs to live
    2. negative = kill with browser
    3. 0 = kill now
  4. add to response
        /** Set a cookie by name */
        public static void setCookieValue(HttpServletResponse response,
                                          String name,
                                          String value)
        {
            Cookie c = new Cookie(name,value);
            c.setMaxAge( 3 * 30 * 24 * 60 * 60 );
            c.setPath( "/" );
            response.addCookie( c );
        }
    

Do example. Show where it is in the netscape browser.

Fetch cookies

The API provides only a method to get all cookies. Have to search for correct one:

/** Find a cookie by name; return first found */
public static Cookie getCookie(HttpServletRequest request, String name) {
    Cookie[] allCookies;

    if ( name==null ) {
        throw new IllegalArgumentException("cookie name is null");
    }

    allCookies = request.getCookies();
    if (allCookies != null) {
        for (int i=0; i < allCookies.length; i++) {
            Cookie candidate = allCookies[i];
            if (name.equals(candidate.getName()) ) {
                return candidate;
            }
        }
    }
    return null;
}

Kill cookie

private void killCookie(HttpServletResponse response, String name) {
    Cookie c = new Cookie(name,"false");
    c.setMaxAge( 0 ); // An age of 0 is defined to mean "delete cookie"
    c.setPath( "/" ); // for all subdirs
    response.addCookie( c );
}

Do a login, logout cookie example + user ID.

Detect and set cookie

The following servlet prints the old value of the "user" cookie and sets it to "parrt" if not already set.

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

public class CookieServlet extends HttpServlet {
    public void doGet(HttpServletRequest request,
		      HttpServletResponse response)
	throws ServletException, IOException
    {
	response.setContentType("text/html");
	String old = CookieMonster.getCookieValue(request, "user");

	PrintWriter out = response.getWriter();
	out.println("<html>");
	out.println("<body>");
	out.println("old cookie: "+old);
	String user = request.getParameter("user");
	if ( user==null ) {
	    user = "parrt";
	}
	CookieMonster.setCookieValue(response, "user", user);
	out.println("<p>Set cookie to "+user);
	out.println("</body>");
	out.println("</html>");
    }
}

Autologin logic

public static final String COOKIE_AUTOLOGIN = "auto_login";
public static final String COOKIE_HASH = "unique_id";

/** Attempt an autologin.  The person's unique hash must match
  *  a record in our Person table.  Return true if routine
  *  succeeds in autologging in that person.  Do a guest login
  *  if autologin fails; i.e., session is always initialized
  *  after this routine.
  */
public static boolean autologin(HttpServletRequest request,
				HttpServletResponse response,
				HttpSession session)
    throws Exception
{
    String autologin = getCookieValue(request, COOKIE_AUTOLOGIN);
    // If they want to be autologged in but they have not yet logged in
    // try to log them in.
    if ( autologin!=null && autologin.equals("true") &&
	 !userIsLoggedIn(session) )
	{
	    // Get the unique key that identifies a user
	    String hash = getCookieValue(request, COOKIE_HASH);
	    // System.out.println("got cookie hash "+hash);
	    if ( login(request, response, session, hash) ) {
		return true;
	    }
	    else {
		guestlogin(request, response, session);
		return false;
	    }
	}
    else {
	guestlogin(request, response, session);
	return false;
    }
}