/* * @(#)Counter.java 1.43 97/07/17 * * Copyright (c) 1996-1997 Sun Microsystems, Inc. All Rights Reserved. * * This software is the confidential and proprietary information of Sun * Microsystems, Inc. ("Confidential Information"). You shall not * disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into * with Sun. * * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING * THIS SOFTWARE OR ITS DERIVATIVES. * * CopyrightVersion 1.0 */ import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; //import sun.servlet.http.Cookie; /** * Simple servlet to demonstrate the "Cookie" API. It uses a cookie to * serve as a counter that increments each time this web page is visited * during a user session. That counter, along with some other data, is * shown on an HTML page dynamically generated by this servlet. * *

Of course, other kinds of data can be stored using cookies. You * should look at the privacy and security guidelines in RFC 2109 before * you start to use cookies, and be clear to your customers what value * your cookies are providing to them. * * @version 1.43 * @author David Brownell * @author Pavani Diwanji */ public class Counter extends HttpServlet { // // Name of the main cookie saved by this servlet. // private static final String counterName = "counter"; // // Default initial value of session cookies maintained by counter // servlets. May be overriden by an instance's init parameter. // static final int defaultInitialValue = 10; // // Actual initial value used by this servlet instance. There could // be several such instances, for different parts of the web site's // URL namespace, with different initial values. // // User agents maintain "live" counter values in cookies which are // presented with requests, and the servlet increments such values // in its responses. // private int initialValue; /** * Initializes the servlet. Session counters normally start at ten, * but that may be overridden by providing an initialization parameter * named "initial" with a value which is a decimal number. This lets * different "counter" servlets have different initial values, as well * as letting different user sessions have different actual values. */ public void init(ServletConfig conf) throws ServletException { String s; super.init(conf); if ((s = getInitParameter ("initial")) == null) initialValue = defaultInitialValue; else { try { initialValue = Integer.parseInt (s); } catch (NumberFormatException e) { initialValue = defaultInitialValue; log ("** Non-numeric format for 'initial' parameter: " + s); } } } /** * Handles a request. It does this by updating a per-request "counter" * cookie from the request, and storing it via the response. Output of * the servlet is a simple web page showing the original value of the * session's counter, and some other data. */ protected void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { int counter = initialValue; Cookie cookies [], c = null; boolean hadCookies = false, hadCounter = false; // // We do all the cookie work before we start writing output, // since once we start writing data the headers (with or // without cookies) can get flushed at any time. // if ((cookies = req.getCookies ()) != null) { hadCookies = true; for (int i = 0; i < cookies.length; i++) { if (cookies [i].getName ().equals (counterName)) { try { // clone this cookie to keep using the browser's // version of the cookie protocol c = (Cookie) cookies [i].clone (); counter = Integer.parseInt (c.getValue ()); c.setValue (Integer.toString (counter + 1)); hadCounter = true; } catch (NumberFormatException e) { // should never happen ... c = null; } break; } } } // // Always save a "counter" cookie, taking care to set the // attributes that weren't settable by cloning the original. // if (c == null) c = new Cookie (counterName, Integer.toString (counter)); c.setComment ("Supports Cookie Counter Demo Servlet"); // c.setMaxAge (2 * 24 * 60 * 60); // 2 days // c.setPath ("/"); res.addCookie (c); if (false) { // add a new cookie, discarded on browser exit, to see // how multiple cookies are dealt with c = new Cookie ( "gensym-" + (System.currentTimeMillis () & 0x0ff), new Date().toString ()); c.setComment ("Show multi-cookie support"); res.addCookie(c) ; } // // TRY THIS: // // (A) Design a simple form for letting people create new cookies. // Generate that form in the HTML below. Use the POST action, and // create the new cookie before generating output below. // // (B) Do something similar for letting users delete one or more // of the cookies reported by the user agent ... including the // counter itself, as one way to reinitialize a session! // // (C) Offer form controls over cookies' paths and maximum ages. // // (D) Experiment to see how different web browsers handle version // zero cookies. Which features are handled inconsistently? // // (E) See how this page reacts to HTTP's "HEAD" methods. // // (F) Normally, pages used to set cookies will not be cached. // This will probably be true of most dynamically generated web // content. Are there other pages in your website which should // not be widely cached by proxies and browsers? Why? // // // Generate the response message ... an HTML page that shows all // cookies, their values, and any attributes, plus some random // data about the session that may be interesting. We buffer the // whole response so that HTTP keepalive can be used. // ByteArrayOutputStream bytes; PrintStream out; bytes = new ByteArrayOutputStream (4096); out = new PrintStream (bytes); out.println (""); out.println ("Cookie Counter"); out.println (""); out.println ("

Cookie Counter

"); if (hadCounter) { out.println ("
"); out.println ("

Your session's counter was "); out.println (counter); out.println (" before you visited this page."); out.println ("

The counter has been incremented."); out.println ("

"); } else { out.println ("

You presented no session cookie. A new"); out.println ("cookie was created, with an initial counter"); out.println ("holding the value " + counter + "."); } if (hadCookies) { out.println ("

You presented these cookies:

    "); for (int i = 0; i < cookies.length; i++) { String temp; out.println ("
  1. Name = "); out.println (cookies [i].getName ()); out.println (", Value = "); out.println (cookies [i].getValue ()); // // IETF standard cookies expose these attributes, but // the original (and still most common) style cookies // hide this data on the client side. // if ((temp = cookies [i].getDomain ()) != null) { out.println (", Domain = "); out.println (cookies [i].getDomain ()); } if ((temp = cookies [i].getPath ()) != null) { out.println (", Path = "); out.println (cookies [i].getPath ()); } } out.println ("
"); } out.println ("

Watch the value of the counter change as you"); out.println ("reload this page! The counter is updated by the"); out.println ("servlet which dynamically generates this web page."); out.println ("

Try comparing how different browsers work with"); out.println ("cookies set using these two URLs on this server: "); out.println ("/counter.html, and"); out.println ("/servlet/Counter."); out.println ("These URLs refer to different 'counter' servlets,"); out.println ("which initialize their counts to different values."); String temp = req.getHeader ("User-Agent"); out.println ("

Your browser is " + ((temp != null) ? temp : "not known!") + "."); // XXX // This time printing crashes IIS!!!!! /* out.println ("

The cookie server's time is now " + new Date () + "."); */ out.println (""); out.flush (); // // Now that we've buffered up the entire message: write all our // header fields, then the body. We buffered it up so we can set // content length ... ensuring we can use connection keep-alive, // for the best networking performance. // // With HTTP/1.1 clients guaranteed, we could set the headers // and just write to the output stream (using chunked encoding) // with no worries about preventing keep-alive. // res.setContentType("text/html"); // ;charset=us-ascii res.setContentLength (bytes.size ()); // ... Last-Modified: right now! bytes.writeTo (res.getOutputStream ()); } /** * Describes what this servlet does. */ public String getServletInfo() { return "Demonstrates the 'Cookie' API for user sessions"; } }