Cookie Examples

Introduction

Cookies are a way of storing data on the client side. They have been used extensively for personalization of portal sites, user preference tracking, and logging into web sites. For enterprise customers using cookies in their web sites, cookie support in Java Plug-in and Java Web Start facilitates deployment of client-side Java.

Cookie support allows a Java application to pass a cookie back to a web server if that cookie originated from the web server. This provides the server with information about the state of the client.
Cookie Support in Java Plug-in and Java Web Start

There are two main types of cookies: Session Cookies and Permanent Cookies.
Session Cookies

Session cookies are stored in memory during the applet or application session. Session cookies expire when the applet or application exits and are automatically deleted. These cookies usually store a session ID that is not personally identifiable to users, allowing the user to move from page to page without having to log-in repeatedly. They are widely used by commercial web sites (for example, to keep track of items that a consumer has added to a shopping cart.)
Permanent Cookies

Permanent cookies are stored in persistent storage and are not deleted when the application exits. They are deleted when they expire. They can retain user preferences for a particular web site, allowing those preferences to be used in future sessions. Permanent cookies can be used to identify individual users, so they may be used by web sites to analyze users’ surfing behavior within the web site. These cookies can also be used to provide information about the numbers of visitors, the average time spent on a particular page, and the general performance of the web site. They are usually configured to keep track of users for a prolonged period of time, in some cases many years into the future.
Support

Java Plug-in and Java Web Start support handling of both types of cookie on all platforms.

Java Plug-in provides permanent cookie support using the underlying browser cookie store. When it runs in Internet Explorer, the cookie store in IE is used; when it runs in Mozilla, the cookie store in Mozilla is used.

Java Web Start provides permanent cookie support on Windows using the cookie store in Internet Explorer. On Linux/Solaris, Java Web Start provides permanent cookie support using its own cookie store implementation.
Programmatic Access to Cookies

There are several ways for an application to override the default cookie handling. Four are outlined below.
void URLConnection.setRequestProperty(String key, String value)

This approach allows the application to set a custom cookie header in URLConnection before making a connection.

URL url = new URL( “http://java.sun.com/” );
URLConnection conn = url.openConnection();
conn.setRequestProperty(“Cookie”, “foo=bar”);
InputStream is = conn.getInputStream();
…..

When the connection is made, the custom cookie would be sent to the server in the HTTP/HTTPS request headers.
Map<String, List<String>> URLConnection.getHeaderFields()

After a connection is made, the server may return a cookie in the HTTP/HTTPS response headers. The approach outlined below allows the application to retrieve the cookie value through URLConnection.

URL url = new URL( “http://java.sun.com/” );
URLConnection conn = url.openConnection();
conn.connect();
…..
Map> headers = conn.getHeaderFields();
List values = headers.get(“Set-Cookie”);

String cookieValue = null;
for (Iterator iter = values.iterator(); iter.hasNext(); ) {
String v = values.next();
if (cookieValue == null)
cookieValue = v;
else
cookieValue = cookieValue + “;” + v;
}

After the connection is made, the server may return the cookie in the HTTP/HTTPS response headers.
Map> CookieHandler.get(URI uri, Map> requestHeaders)

This approach allows the application to retrieve session/permanent cookies for a given URL:

String retrieveCookie(URL url)
{
String cookieValue = null;

CookieHandler handler = CookieHandler.getDefault();
if (handler != null) {
Map> headers = handler.get(url.toURI(), new HashMap>());
List values = headers.get(“Cookie”);
for (Iterator iter=values.iterator(); iter.hasNext();) {
String v = iter.next();

if (cookieValue == null)
cookieValue = v;
else
cookieValue = cookieValue + “;” + v;
}
}
return cookieValue;
}

CookieHandler is an abstraction of the browser/system cookie storage, so additional security permission is required for execution; the above code will be executed successfully only if the application is trusted.
void CookieHandler.put(URI uri, Map<String,List<String>> responseHeaders)

This approach allows the application to set a session/permanent cookie for a given URL:

void setCookie(URL url, String value)
{
CookieHandler handler = CookieHandler.getDefault();
if (handler != null) {
Map> headers= new HashMap>();
List values = new Vector();
values.add(value);
headers.put(“Cookie”, values);

handler.put(url.toURI(), headers);
}
}

CookieHandler is an abstraction of the browser/system cookie storage, so additional security permission is required for execution; the above code will be executed successfully only if the application is trusted.

Persistent Cookies

A fourth technique to perform session tracking involves persistent cookies. A cookie is a bit of information sent by a web server to a browser that can later be read back from that browser. When a browser receives a cookie, it saves the cookie and thereafter sends the cookie back to the server each time it accesses a page on that server, subject to certain rules. Because a cookie’s value can uniquely identify a client, cookies are often used for session tracking.

Cookies were first introduced in Netscape Navigator. Although they were not part of the official HTTP specification, cookies quickly became a de facto standard supported in all the popular browsers including Netscape 0.94 Beta and up and Microsoft Internet Explorer 2 and up. Currently the HTTP Working Group of the Internet Engineering Task Force (IETF) is in the process of making cookies an official standard as written in RFC 2109. For more information on cookies see Netscape’s Cookie Specification at
Working with Cookies

Version 2.0 of the Servlet API provides the javax.servlet.http.Cookie class for working with cookies. The HTTP header details for the cookies are handled by the Servlet API. You create a cookie with the Cookie() constructor:

public Cookie(String name, String value)

This creates a new cookie with an initial name and value. The rules for valid names and values are given in Netscape’s Cookie Specification and RFC 2109.

A servlet can send a cookie to the client by passing a Cookie object to the addCookie() method of HttpServletResponse:

public void HttpServletResponse.addCookie(Cookie cookie)

This method adds the specified cookie to the response. Additional cookies can be added with subsequent calls to addCookie() . Because cookies are sent using HTTP headers, they should be added to the response before you send any content. Browsers are only required to accept 20 cookies per site, 300 total per user, and they can limit each cookie’s size to 4096 bytes.

The code to set a cookie looks like this:

Cookie cookie = new Cookie(“ID”, “123″);
res.addCookie(cookie);

A servlet retrieves cookies by calling the getCookies() method of HttpServlet- Request:

public Cookie[] HttpServletRequest.getCookies()

This method returns an array of Cookie objects that contains all the cookies sent by the browser as part of the request or null if no cookies were sent. The code to fetch cookies looks like this:

Cookie[] cookies = req.getCookies();
if (cookies != null) {
for (int i = 0; i < cookies.length; i++) {
String name = cookies[i].getName();
String value = cookies[i].getValue();
}
}

You can set a number of attributes for a cookie in addition to its name and value. The following methods are used to set these attributes. As you can see in Appendix B, “HTTP Servlet API Quick Reference”, there is a corresponding get method for each set method. The get methods are rarely used, however, because when a cookie is sent to the server, it contains only its name, value, and version.

public void Cookie.setVersion(int v)

Sets the version of a cookie. Servlets can send and receive cookies formatted to match either Netscape persistent cookies (Version 0) or the newer, somewhat experimental, RFC 2109 cookies (Version 1). Newly constructed cookies default to Version to maximize interoperability.
public void Cookie.setDomain(String pattern)

Specifies a domain restriction pattern. A domain pattern specifies the servers that should see a cookie. By default, cookies are returned only to the host that saved them. Specifying a domain name pattern overrides this. The pattern must begin with a dot and must contain at least two dots. A pattern matches only one entry beyond the initial dot. For example, “.foo.com” is valid and matches www.foo.com and upload.foo.combut not www.upload.foo.com. For details on domain patterns, see Netscape’s Cookie Specification and RFC 2109.
public void Cookie.setMaxAge(int expiry)

Specifies the maximum age of the cookie in seconds before it expires. A negative value indicates the default, that the cookie should expire when the browser exits. A zero value tells the browser to delete the cookie immediately.
public void Cookie.setPath(String uri)

Specifies a path for the cookie, which is the subset of URIs to which a cookie should be sent. By default, cookies are sent to the page that set the cookie and to all the pages in that directory or under that directory. For example, if /servlet/CookieMonster sets a cookie, the default path is “/servlet”. That path indicates the cookie should be sent to /servlet/Elmo and to /servlet/subdir/BigBird–but not to the /Oscar.html servlet alias or to any CGI programs under /cgi-bin. A path set to “/” causes a cookie to be sent to all the pages on a server. A cookie’s path must be such that it includes the servlet that set the cookie.
public void Cookie.setSecure(boolean flag)

Indicates whether the cookie should be sent only over a secure channel, such as SSL. By default, its value is false.
public void Cookie.setComment(String comment)

Sets the comment field of the cookie. A comment describes the intended purpose of a cookie. Web browsers may choose to display this text to the user. Comments are not supported by Version cookies.
public void Cookie.setValue(String newValue)

Assigns a new value to a cookie. With Version cookies, values should not contain the following: whitespace, brackets and parentheses, equals signs, commas, double quotes, slashes, question marks, at signs, colons, and semicolons. Empty values may not behave the same way on all browsers.

Shopping Using Persistent Cookies

shows a version of our shopping cart viewer that has been modified to maintain the shopping cart using persistent cookies.
Session tracking using persistent cookies

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

public class ShoppingCartViewerCookie extends HttpServlet {

public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res.setContentType(“text/html”);
PrintWriter out = res.getWriter();

// Get the current session ID by searching the received cookies.
String sessionid = null;
Cookie[] cookies = req.getCookies();
if (cookies != null) {
for (int i = 0; i < cookies.length; i++) {
if (cookies[i].getName().equals(“sessionid”)) {
sessionid = cookies[i].getValue();
break;
}
}
}

// If the session ID wasn’t sent, generate one.
// Then be sure to send it to the client with the response.
if (sessionid == null) {
sessionid = generateSessionId();
Cookie c = new Cookie(“sessionid”, sessionid);
res.addCookie(c);
}

out.println(“Current Shopping Cart Items;”);
out.println(“;”);

// Cart items are associated with the session ID
String[] items = getItemsFromCart(sessionid);

// Print the current cart items.
out.println(“You currently have the following items in your cart:
“);
if (items == null) {
out.println(“None“);
}
else {
out.println(”

    “);
    for (int i = 0; i
    out.println(”

  • ” + items[i]);
    }
    out.println(“

“);
}

// Ask if they want to add more items or check out.
out.println(”

“);
out.println(“Would you like to
“);
out.println(“< input type=”submit” value=” submit ;” / >”);
out.println(“< input type=”submit” value=” submit ;” / >”);
out.println(“< / form>”);

// Offer a help page.
out.println(“For help, click
“?topic=ShoppingCartViewerCookie\”>here”);

out.println(“”);
}

private static String generateSessionId() {
String uid = new java.rmi.server.UID().toString();  // guaranteed unique
return java.net.URLEncoder.encode(uid);  // encode any special chars
}

private static String[] getItemsFromCart(String sessionid) {
// Not implemented
}
}

This servlet first tries to fetch the client’s session ID by iterating through the cookies it received as part of the request. If no cookie contains a session ID, the servlet generates a new one using generateSessionId() and adds a cookie containing the new session ID to the response. The rest of this servlet matches the URL rewriting version, except that this version doesn’t perform any rewriting.

Persistent cookies offer an elegant, efficient, easy way to implement session tracking. Cookies provide as automatic an introduction for each request as you could hope for. For each request, a cookie can automatically provide a client’s session ID or perhaps a list of the client’s preferences. In addition, the ability to customize cookies gives them extra power and versatility.

The biggest problem with cookies is that browsers don’t always accept cookies. Sometimes this is because the browser doesn’t support cookies. More often, it’s because the user has specifically configured the browser to refuse cookies (out of privacy concerns, perhaps). If any of your clients might not accept cookies, you have to fall back to the solutions discussed earlier in this chapter.

Leave a Reply