KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > matuschek > http > cookie > Cookie


1 package net.matuschek.http.cookie;
2
3 import java.net.URL JavaDoc;
4 import java.util.Date JavaDoc;
5 import java.util.Locale JavaDoc;
6 import java.util.StringTokenizer JavaDoc;
7 /*********************************************
8     Copyright (c) 2001 by Daniel Matuschek
9 *********************************************/

10                                          
11
12 /**
13  * This object represents an HTTP cookie for a browser.
14  * It can interpret both Netscape and RFC cookies
15  *
16  * @author Daniel Matuschek
17  * @version $Id $
18  */

19 public class Cookie
20 {
21   /** HTTP Set-Cookie response header (not case sensitive) */
22   final static String JavaDoc HEADER_SETCOOKIE="Set-Cookie:";
23
24   /** HTTP cookie response header (not case sensitive) */
25   final static String JavaDoc HEADER_COOKIE="Cookie:";
26
27   /** Cookie name */
28   private String JavaDoc name;
29
30   /** Cookie value */
31   private String JavaDoc value=null;
32
33   /**
34    * Life time in seconds, -1 means "expire, if browser exits" <br />
35    * this is only useful for RFC 2109 cookie, because Netscape cookies
36    * do not have a maxAge field. This value will only be used to
37    * create the internal expireDate value.
38    */

39   private long maxAge=-1;
40
41   /** Comment */
42   private String JavaDoc comment="";
43
44   /** Domain */
45   private String JavaDoc domain=null;
46
47   /** Path */
48   private String JavaDoc path="/";
49
50   /** Secure ? */
51   private boolean secure=false;
52
53   /**
54    * expire date, default is "never" for cookies without explicit
55    * exipration date
56    */

57   private Date JavaDoc expireDate=new Date JavaDoc(Long.MAX_VALUE);
58
59   /**
60    * Cookie version <br />
61    * version=0 refers to the Netscape cookie specification <br />
62    * version=1 refers to the RFC 2109 Cookie specification <br />
63    * <br />
64    * @see <a HREF="http://home.netscape.com/newsref/std/cookie_spec.html">
65    * Netscape Cookie specification</a><br />
66    */

67   private int version=0;
68
69
70   /**
71    * Default constructor, creates an empty cookie
72    */

73   public Cookie() {
74   }
75
76
77   /**
78    * Constructor that initializes a cookie from a HTTP Set-Cookie: header
79    * @param setCookie a HTTP Set-Cookie: header line (including Set-Cookie)
80    * @param u there URL of the HTTP document where this cookie was set from
81    * this is needed, if no "domain" field is given in the cookie.
82    * It will be ignored otherwise
83    * @exception CookieException if the given setCookie String is not a valid
84    * HTTP Set-Cookie response header
85    */

86   public Cookie(String JavaDoc setCookie, URL JavaDoc u)
87     throws CookieException
88   {
89     this();
90
91     String JavaDoc cookieHeader = null;
92     String JavaDoc host = "";
93     StringTokenizer JavaDoc tokens = null;
94
95     // does is start with "Set-Cookie" ?
96
if (setCookie.substring(0,HEADER_SETCOOKIE.length()).equalsIgnoreCase(HEADER_SETCOOKIE)) {
97       cookieHeader = setCookie.substring(HEADER_SETCOOKIE.length());
98     } else {
99       throw new CookieException("Not a Set-Cookie header");
100     }
101
102     // set defaults from the URL
103
if (u != null) {
104       this.domain = u.getHost().toLowerCase();
105       host = this.domain;
106     } else {
107         this.domain = "";
108     }
109
110     // tokenize setcookie request
111
tokens = new StringTokenizer JavaDoc(cookieHeader,";");
112
113     // there must be at least ONE token (name=value)
114
if (tokens.countTokens() < 1) {
115       throw new CookieException("Cookie contains no data");
116     } else {
117       String JavaDoc field = tokens.nextToken();
118       int pos = field.indexOf('=');
119       if (pos <= 0) {
120     throw new CookieException("First field not in the format NAME=VALUE"
121                   +" but got "+field);
122       } else {
123     name = field.substring(0,pos).trim();
124     value = field.substring(pos+1);
125       }
126     }
127
128     // parse all other fields
129
while (tokens.hasMoreTokens()) {
130       String JavaDoc field = tokens.nextToken();
131       String JavaDoc fieldname="";
132       String JavaDoc fieldvalue="";
133
134       int pos = field.indexOf('=');
135       if (pos <= 0) {
136     fieldname = field.trim();
137     fieldvalue="";
138       } else {
139     fieldname = field.substring(0,pos).trim();
140     fieldvalue = field.substring(pos+1).trim();
141       }
142
143       if (fieldname.equalsIgnoreCase("comment")) {
144     //
145
// COMMENT
146
//
147
this.comment = fieldvalue;
148       } else if (fieldname.equalsIgnoreCase("domain")) {
149     //
150
// DOMAIN
151
//
152
String JavaDoc domainvalue = fieldvalue.toLowerCase();
153     // check if the domain is allowed for the current URL !
154
if ((host.equals(""))
155         || (host.endsWith(domain))) {
156       this.domain=domainvalue;
157     } else {
158       throw new CookieException("Not allowed to set a cookie for domain "
159                     +domainvalue+" from host "+host);
160     }
161       } else if (fieldname.equalsIgnoreCase("jmfdomain")) {
162     //
163
// JMFDOMAIN
164
//
165
String JavaDoc domainvalue = fieldvalue.toLowerCase();
166     // check if the domain is allowed for the current URL !
167
if ((host.equals(""))
168         || (host.endsWith(domain))) {
169       this.domain=domainvalue;
170     } else {
171       throw new CookieException("Not allowed to set a cookie for domain "
172                     +domainvalue+" from host "+host);
173     }
174       } else if (fieldname.equalsIgnoreCase("path")) {
175     //
176
// PATH
177
//
178
this.path=fieldvalue;
179       } else if (fieldname.equalsIgnoreCase("secure")) {
180     //
181
// SECURE
182
//
183
this.secure = true;
184       } else if (fieldname.equalsIgnoreCase("max-age")) {
185     //
186
// MAX-AGE
187
//
188
try {
189       this.maxAge = Integer.parseInt(fieldvalue);
190     } catch (NumberFormatException JavaDoc e) {
191       throw new CookieException("max-age must be integer, but is "
192                     +fieldvalue);
193     }
194     
195     if (maxAge >= 0) {
196       this.expireDate = new Date JavaDoc(System.currentTimeMillis()
197                      +maxAge*1000);
198     } else {
199       this.expireDate = new Date JavaDoc(Long.MAX_VALUE);
200     }
201       } else if (fieldname.equalsIgnoreCase("expires")) {
202     //
203
// EXPIRES
204
//
205
String JavaDoc dateStr = null;
206     java.text.SimpleDateFormat JavaDoc[] df = new java.text.SimpleDateFormat JavaDoc[2];
207
208     // possible date formats
209
// thanks to Scott Woodson for the feedback
210
df[0] = new java.text.SimpleDateFormat JavaDoc("dd-MMM-yyyy HH:mm:ss z",
211                            Locale.US);
212     df[1] = new java.text.SimpleDateFormat JavaDoc("dd MMM yyyy HH:mm:ss z",
213                            Locale.US);
214     
215     int commapos = fieldvalue.indexOf(",");
216     if (commapos < 0) {
217       throw new CookieException("Expires field does not contain "
218                     +"a comma, value is "+fieldvalue);
219     }
220     dateStr = fieldvalue.substring(commapos+1).trim();
221     boolean foundDate = false;
222
223     for (int i=0; i<df.length; i++) {
224       try {
225         this.expireDate = df[i].parse(dateStr);
226         // if we got no exception, jump out of the loop
227
foundDate=true;
228         continue;
229       } catch (java.text.ParseException JavaDoc e) {};
230     }
231     
232     // found a valid date ?
233
if (! foundDate) {
234       throw new CookieException("Can't parse expires field as date, "
235                     +"value is "+dateStr);
236     }
237
238       } else if (fieldname.equalsIgnoreCase("version")) {
239     //
240
// VERSION
241
//
242
try {
243       this.version=Integer.parseInt(fieldvalue);
244     } catch (NumberFormatException JavaDoc e) {
245       throw new CookieException("Version must be integer, but is "
246                     +fieldvalue);
247     }
248
249     if (version > 1) {
250       throw new CookieException("Only version 0 and 1 supported yet, "
251                     +"but cookie used version "+version);
252     }
253       }
254     }
255
256   }
257
258   /**
259    * Initializes a cookie from an name-value pair and additional
260    * information. This constructor is useful to create cookies
261    * by yourself.
262    */

263   public Cookie(String JavaDoc name, String JavaDoc value, String JavaDoc domain, String JavaDoc path) {
264     this.name=name;
265     this.value=value;
266     this.domain=domain;
267     this.path=path;
268   }
269   
270
271   /**
272    * Is this cookie valid ?
273    * @return true if the cookie is valid, false if it is expired
274    */

275   public boolean isValid() {
276     Date JavaDoc current = new Date JavaDoc();
277     return current.before(expireDate);
278   }
279
280
281   /**
282    * Is this cookie valid for the given URL ?
283    * That means, it is not expired and host and path matches the given URL
284    * @return true if this cookie is valid for the given URL, false otherwise
285    */

286   public boolean isValid(URL JavaDoc u) {
287     String JavaDoc urlhost = u.getHost().toLowerCase();
288     String JavaDoc urlpath = u.getPath();
289
290     return (isValid()
291         && urlhost.endsWith(this.domain)
292         && urlpath.startsWith(path));
293   }
294
295   /**
296    * Does this Cookie overwrite another cookie ?
297    * A Cookie overwrites another one, if they have the same
298    * name, domain and path. It doesn't matter, if expireDate or value of
299    * the cookie are different !
300    */

301   public boolean overwrites(Cookie c) {
302     return (this.domain.equals(c.domain)
303         && this.path.equals(c.path)
304         && this.name.equals(c.name));
305   }
306
307
308   /**
309    * Gets the cookie name and value as NAME=VALUE pair
310    * @return a string in the format NAME=VALUE
311    */

312   public String JavaDoc getNameValuePair() {
313     return this.name+"="+this.value;
314   }
315
316
317   /**
318    * Convert the cookie to a String. Format is not defined and may change
319    * without notice. Use it for debugging and logging purposes only !
320    * @return a String representation of this cookie
321    */

322   public String JavaDoc toString() {
323     return this.name+"="+this.value+" (Comment="+this.comment
324       +", Version="+this.version+", domain="+this.domain
325       +", path="+this.path
326       +", expires "
327       +java.text.DateFormat.getDateTimeInstance().format(this.expireDate)+")";
328   }
329   
330   
331   /**
332    */

333   public static Cookie[] cookieStringToCookies(String JavaDoc cookieStr, String JavaDoc domain) throws CookieException {
334     String JavaDoc cookieHeader;
335     
336     // does is start with "Cookie" ?
337
if (cookieStr.substring(0,HEADER_COOKIE.length()).equalsIgnoreCase(HEADER_COOKIE)) {
338       cookieHeader = cookieStr.substring(HEADER_COOKIE.length());
339     } else {
340       throw new CookieException("Not a Cookie header");
341     }
342     
343     // tokenize setcookie request
344
StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(cookieHeader,";");
345     Cookie[] cookies= new Cookie[tokens.countTokens()];
346     int i=0;
347     
348     while (tokens.hasMoreTokens()) {
349         cookies[i]=null;
350         String JavaDoc field = tokens.nextToken();
351         int pos = field.indexOf('=');
352         if (pos <= 0) {
353             throw new CookieException("Cookie field not in the format NAME=VALUE"
354                   +" but got "+field);
355         } else {
356             cookies[i]=new Cookie();
357             cookies[i].name = field.substring(0,pos).trim();
358             cookies[i].value = field.substring(pos+1);
359             // we do not know this from a "Cookie" header, but from the
360
// argument of this function
361
cookies[i].domain = "."+domain;
362         }
363         i++;
364     }
365
366     return cookies;
367
368   }
369
370
371 public boolean isSecure() {
372     return secure;
373 }
374
375 }
376
Popular Tags