001: /*
002: * CookieSessionHandler.java
003: *
004: * Brazil project web application Framework,
005: * export version: 1.1
006: * Copyright (c) 1999-2000 Sun Microsystems, Inc.
007: *
008: * Sun Public License Notice
009: *
010: * The contents of this file are subject to the Sun Public License Version
011: * 1.0 (the "License"). You may not use this file except in compliance with
012: * the License. A copy of the License is included as the file "license.terms",
013: * and also available at http://www.sun.com/
014: *
015: * The Original Code is from:
016: * Brazil project web application Framework release 1.1.
017: * The Initial Developer of the Original Code is: suhler.
018: * Portions created by suhler are Copyright (C) Sun Microsystems, Inc.
019: * All Rights Reserved.
020: *
021: * Contributor(s): cstevens, suhler.
022: *
023: * Version: 1.12
024: * Created by suhler on 99/06/28
025: * Last modified by suhler on 00/12/11 13:28:46
026: */
027:
028: package sunlabs.brazil.handler;
029:
030: import sunlabs.brazil.server.Handler;
031: import sunlabs.brazil.server.Request;
032: import sunlabs.brazil.server.Server;
033: import sunlabs.brazil.session.SessionManager;
034: import sunlabs.brazil.util.http.MimeHeaders;
035: import sunlabs.brazil.util.regexp.Regexp;
036:
037: import java.util.Hashtable;
038: import java.util.Properties;
039: import java.util.Random;
040: import java.io.IOException;
041:
042: /**
043: * Handler for creating browser sessions using cookies.
044: * This handler provides a single cookie-id that may be used by
045: * other handlers.
046: *
047: * The intent is to require only one cookie per server.
048: * (See also {@link sunlabs.brazil.filter.SessionFilter}, which
049: * manages sessions with or without cookies).
050: *
051: * The following server properties are used:
052: * <dl class=props>
053: * <dt> prefix
054: * <dd> url prefix
055: *
056: * <dt> cookie
057: * <dd> the name of the cookie to use (defaults to "cookie").
058: *
059: * <dt> <code>map</code>
060: * <dd> If specified, the <code>ident</code> argument to
061: * {@link SessionManager#getSession} to get the table of valid
062: * cookies, used to map the cookie value to a Session ID. By default,
063: * the Session ID stored in the request is the cookie value itself.
064:
065: * <dt> <code>exist</code>
066: * <dd> If specified, this means that the Session ID corresponding to the
067: * cookie value must already exist in the <code>SessionManager</code>.
068: * Normally, if the cookie was not present, a new cookie is
069: * automatically created.
070: *
071: * <dt>persist <dd> If set, cookies persist across browser sessions
072: *
073: * <dt> <code>session</code>
074: * <dd> The name of the request property that the Session ID will be stored
075: * in, to be passed to downstream handler. The default value is
076: * "SessionID".
077:
078: * </dl>
079: * If a cookie was returned from the browser, the property:
080: * <code>gotCookie</code> is set to the cookie name. Otherwise it is left unset.
081: *
082: * @author Stephen Uhler
083: * @version 1.12, 00/12/11
084: */
085:
086: public class CookieSessionHandler implements Handler {
087: private static final String PREFIX = "prefix";
088: private static final String COOKIE = "cookie";
089: private static final String MAP = "map";
090: private static final String EXIST = "exist";
091: private static final String PERSIST = "persist";
092: private static final String PROPERTY = "session";
093:
094: private static Random random = new Random();
095:
096: public String prefix = "/";
097: public String cookieName = "cookie";
098: public String ident = "";
099: public boolean mustExist = false;
100: public boolean persist = false;
101: public String session = "SessionID";
102:
103: String propsPrefix;
104: Regexp cookie;
105:
106: public boolean init(Server server, String propsPrefix) {
107: this .propsPrefix = propsPrefix;
108:
109: Properties props = server.props;
110:
111: prefix = props.getProperty(propsPrefix + PREFIX, prefix);
112: cookieName = props
113: .getProperty(propsPrefix + COOKIE, cookieName);
114: ident = props.getProperty(propsPrefix + MAP, ident);
115: mustExist = props.getProperty(propsPrefix + EXIST) != null;
116: persist = props.getProperty(propsPrefix + PERSIST) != null;
117: session = props.getProperty(propsPrefix + PROPERTY, session);
118:
119: cookie = new Regexp("(^|; *)" + cookieName + "=([^;]*)");
120: return true;
121: }
122:
123: public boolean respond(Request request) throws IOException {
124: if (request.url.startsWith(prefix) == false) {
125: return false;
126: }
127:
128: /*
129: * Get the cookie out of the http header. Cookies can be on separate
130: * lines or all combined on one line. When multiple cookies are on
131: * one line, they are separated by ';' characters.
132: */
133:
134: String value = null;
135: String[] subs = new String[3];
136: MimeHeaders headers = request.headers;
137: for (int i = headers.size(); --i >= 0;) {
138: if (headers.getKey(i).equalsIgnoreCase("Cookie") == false) {
139: continue;
140: }
141: if (cookie.match(headers.get(i), subs)) {
142: value = subs[2];
143: if (value.length() == 0) {
144: value = null;
145: }
146: break;
147: }
148: }
149:
150: /* existing session, client can handle sessions */
151:
152: if (value != null) {
153: request.props.put("gotCookie", "true");
154: }
155:
156: /*
157: * If present, map cookie to Session ID. Otherwise, Session ID is
158: * cookie.
159: */
160: String id = value;
161: if (id != null) {
162: Hashtable h = (Hashtable) SessionManager.getSession(null,
163: ident, Hashtable.class);
164: id = (String) h.get(id);
165: if (id == null) {
166: id = value;
167: }
168: }
169:
170: /*
171: * Check if Session ID corresponds to an existing session.
172: */
173:
174: if ((id != null) && mustExist) {
175: if (SessionManager.getSession(id, null, null) == null) {
176: id = null;
177: }
178: }
179:
180: /*
181: * If Session ID was missing or wasn't known, make a new cookie.
182: */
183:
184: // System.out.println("must exist " + mustExist);
185: if (id != null) {
186: request.log(Server.LOG_INFORMATIONAL, propsPrefix,
187: "Using cookie: " + value);
188: } else if (mustExist == false) {
189: String expire = "";
190: if (persist) {
191: expire = "; EXPIRES=Fri, 01-Jan-10 00:00:00 GMT";
192: }
193: if (value == null) {
194: value = Long.toHexString(random.nextLong());
195: request.log(Server.LOG_INFORMATIONAL, propsPrefix,
196: "Creating new cookie: " + value);
197: request.addHeader("Set-Cookie", cookieName + "="
198: + value + "; PATH=" + prefix + expire);
199: }
200: id = value;
201: }
202:
203: if (id != null) {
204: request.props.put(session, id);
205: }
206: return false;
207: }
208:
209: /**
210: * Seed the random number generator.
211: */
212:
213: static {
214: }
215: }
|