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
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.
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). If any of your clients might not accept cookies,
you have to fall back to the solutions discussed earlier in this
chapter.
 |  |  |
| 7.3. URL Rewriting |  | 7.5. The Session Tracking API |

Copyright © 2001 O'Reilly & Associates. All rights reserved.
|
|