# Cookie Management

## Introduction

The HTTP state management mechanism specifies a way to create a stateful session with HTTP requests and responses. The specification for it can be found in RFC 2965: HTTP State Management Mechanism at http://www.ietf.org/rfc/rfc2965.txt?number=2965.

## Pre-Tiger support

Prior to Tiger, it was possible to add Cookie management to applications. But the supporting API was somewhat rudimentary. There was no single point of hook up with cookie management. Each application had to handle cookies for each HTTP request/response separately by using the following two methods from java.net.URLConnection class:

`setRequestProperty()
getHeaderFields()`

The first method should be called before sending out a HTTP request in order to set the appropriate cookies for the current URL in the HTTP headers. The second method should be used to retrieve the cookies from the response headers sent by the HTTP server.

Although doable, adding Cookie support in this way results in fragmented code, which is error prone and incurs high maintenance.

## What's new in Tiger?

We have introduced a new callback mechanism via an abstract class to hook up a HTTP state management policy implementation into the HTTP protocol handler. Applications and web containers can introduce Cookie management by providing a concrete subclass of the new API.

The new abstract class is called java.net.CookieHandler. It provides a mechanism to register and retrieve the current CookieHandler for the JVM, as well as methods to retrieve and record relevant cookies for a specific URI.

There are two static methods in CookieHandler getDefault() and setDefault() for retrieving and registering the default CookieHandler in the VM. As well as two instance methods get() and put() for returning a list of cookies based on a URL and stores a list of cookies from the response headers, respectively.

Cookies are represented as Map<String,List<String>>, a Map from the header field name for cookies to a list of cookies represented by Strings. There are two state management headers defined so far, "Set-Cookie2" and "Cookie". The former is used for returning cookies in response headers; while the latter is for setting cookies in HTTP request headers.

Here is an example from RFC2965:

1. User Agent -> Server

POST /acme/login HTTP/1.1
[form data]

2. Server -> User Agent

HTTP/1.1 200 OK
Set-Cookie2: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"

3. User Agent -> Server

POST /acme/pickitem HTTP/1.1
Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"
[form data]

## A simple Example

Here's a simple example of a CookieHandler implementation. Basically there are two methods to implement, given a request URI and request headers (except the cookie headers), retrieve all the relevant cookies from your cookie cache; and record the applicable cookies to your cookie cache given the request URI and the response headers.

    class MyCookieHandler extends CookieHandler {
    	public Map<String, List<String>>
    		get(URI uri, Map<String, List<String>> requestHeaders)
    		throws IOException {
    		// the cookies will be included in request
    		Map<String, List<String>> map = new HashMap<String, List<String>>();
    		List<String> l = retrieveCookies(uri, rqstHdrs);
    		map.put("Cookie",l);
    		return Collections.unmodifiableMap(map);
    	}

    	public void
    		put(URI uri, Map responseHeaders)
    		throws IOException {
    	    // check response has cookies[1]
    		List l = (List)responseHeaders.get("Set-Cookie2");
    	    if (l != null) {
    			// save the cookies in a cookie cache
    		 storeCookies(uri, l);
    	    }
    	}
    }

The methods `retrieveCookies()` and `storeCookies()` are "magic" functions for interacting with a backend cookie management facility, which is omitted in this example.

Once it is registered with the VM, it will take effect when you issue HTTP transactions.

    public static void main(String args[]) throws Exception {
    	......
    	CookieHandler.setDefault(new MyCookieHandler());
    	HttpURLConnection http = (HttpURLConnection)url.openConnection();

    	int respCode = http.getResponseCode();
    	http.disconnect();
    	......
    }

There is no default implementation of a cookie manager in J2SE. However, this may change in the future. Java Plugin and Java WebStart provides a default CookieHandler in their environment.