7.4 Persistent Cookies

Java Servlet Programming, 2nd Edition > 7. Session Tracking > 7.4 Persistent Cookies

 
< BACKCONTINUE >

7.4 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 http://home.netscape.com/newsref/std/cookie_spec.html and RFC 2109 at http://www.ietf.org/rfc/rfc2109.txt. Another good site is http://www.cookiecentral.com.

7.4.1 Working with Cookies

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 the response has been committed. 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 HttpServletRequest:

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 an empty array if no cookies were sent. Servlet API versions before 2.1 had getCookies( ) return null if no cookies were sent. For maximum portability it's best to assume either a null or an empty array is legitimate.

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();   } }

Lamentably, there's no method in the standard Servlet API to fetch a cookie value by name. 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, 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. If you set an attribute on a cookie received from the client, you must add it to the response for the change to take effect, and you should take care that all attributes except name, value, and version are reset on the cookie as well.

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 0 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.com but not www.upload.foo.com.[3]

[3] Technically, according to the Netscape cookie specification, two dots are needed for the top-level domains of .com, .edu, .net, .org, .gov, .mil, and .int, while three dots are required for all other domains. This rule keeps a server from accidentally or maliciously setting a cookie for the domain .co.uk and passing the cookie to all companies in the United Kingdom, for example. Unfortunately, nearly all browsers ignore the three-dot rule! See http://homepages.paradise.net.nz/~glineham/cookiemonster.html for more information.

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 0 cookies.

public void Cookie.setValue(String newValue)

assigns a new value to a cookie. With Version 0 cookies, values should not contain the following: whitespace, brackets, 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.

7.4.2 Shopping Using Persistent Cookies

Example 7-3 shows a version of our shopping cart viewer that has been modified to maintain the shopping cart using persistent cookies.

Example 7-3. 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("<HEAD><TITLE>Current Shopping Cart Items</TITLE></HEAD>");     out.println("<BODY>");     // 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:<BR>");     if (items == null) {       out.println("<B>None</B>");     }     else {       out.println("<UL>");       for (int i = 0; i < items.length; i++) {         out.println("<LI>" + items[i]);       }       out.println("</UL>");     }     // Ask if they want to add more items or check out.     out.println("<FORM ACTION=\"/servlet/ShoppingCart\" METHOD=POST>");     out.println("Would you like to<BR>");     out.println("<INPUT TYPE=SUBMIT VALUE=\" Add More Items \">");     out.println("<INPUT TYPE=SUBMIT VALUE=\" Check Out \">");     out.println("</FORM>");     // Offer a help page.     out.println("For help, click <A HREF=\"/servlet/Help" +                 "?topic=ShoppingCartViewerCookie\">here</A>");     out.println("</BODY></HTML>");   }   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). WAP devices also don't currently accept cookies due to limited memory space, and only recently have WAP gateways begun to manage cookies on their devices' behalf. If any of your clients might not accept cookies, you have to fall back to the solutions discussed earlier in this chapter.


Last updated on 3/20/2003
Java Servlet Programming, 2nd Edition, © 2001 O'Reilly

< BACKCONTINUE >


Java servlet programming
Java Servlet Programming (Java Series)
ISBN: 0596000405
EAN: 2147483647
Year: 2000
Pages: 223

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net