001: /*
002: * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/Cookie.java,v 1.44 2004/06/05 16:49:20 olegk Exp $
003: * $Revision: 531354 $
004: * $Date: 2007-04-23 08:53:20 +0200 (Mon, 23 Apr 2007) $
005: *
006: * ====================================================================
007: *
008: * Licensed to the Apache Software Foundation (ASF) under one or more
009: * contributor license agreements. See the NOTICE file distributed with
010: * this work for additional information regarding copyright ownership.
011: * The ASF licenses this file to You under the Apache License, Version 2.0
012: * (the "License"); you may not use this file except in compliance with
013: * the License. You may obtain a copy of the License at
014: *
015: * http://www.apache.org/licenses/LICENSE-2.0
016: *
017: * Unless required by applicable law or agreed to in writing, software
018: * distributed under the License is distributed on an "AS IS" BASIS,
019: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
020: * See the License for the specific language governing permissions and
021: * limitations under the License.
022: * ====================================================================
023: *
024: * This software consists of voluntary contributions made by many
025: * individuals on behalf of the Apache Software Foundation. For more
026: * information on the Apache Software Foundation, please see
027: * <http://www.apache.org/>.
028: *
029: */
030:
031: package org.apache.commons.httpclient;
032:
033: import java.io.Serializable;
034: import java.util.Comparator;
035: import java.util.Date;
036:
037: import org.apache.commons.httpclient.cookie.CookiePolicy;
038: import org.apache.commons.httpclient.cookie.CookieSpec;
039: import org.apache.commons.httpclient.util.LangUtils;
040: import org.apache.commons.logging.Log;
041: import org.apache.commons.logging.LogFactory;
042:
043: /**
044: * <p>
045: * HTTP "magic-cookie" represents a piece of state information
046: * that the HTTP agent and the target server can exchange to maintain
047: * a session.
048: * </p>
049: *
050: * @author B.C. Holmes
051: * @author <a href="mailto:jericho@thinkfree.com">Park, Sung-Gu</a>
052: * @author <a href="mailto:dsale@us.britannica.com">Doug Sale</a>
053: * @author Rod Waldhoff
054: * @author dIon Gillard
055: * @author Sean C. Sullivan
056: * @author <a href="mailto:JEvans@Cyveillance.com">John Evans</a>
057: * @author Marc A. Saegesser
058: * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
059: * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
060: *
061: * @version $Revision: 531354 $ $Date: 2007-04-23 08:53:20 +0200 (Mon, 23 Apr 2007) $
062: */
063: public class Cookie extends NameValuePair implements Serializable,
064: Comparator {
065:
066: // ----------------------------------------------------------- Constructors
067:
068: /**
069: * Default constructor. Creates a blank cookie
070: */
071:
072: public Cookie() {
073: this (null, "noname", null, null, null, false);
074: }
075:
076: /**
077: * Creates a cookie with the given name, value and domain attribute.
078: *
079: * @param name the cookie name
080: * @param value the cookie value
081: * @param domain the domain this cookie can be sent to
082: */
083: public Cookie(String domain, String name, String value) {
084: this (domain, name, value, null, null, false);
085: }
086:
087: /**
088: * Creates a cookie with the given name, value, domain attribute,
089: * path attribute, expiration attribute, and secure attribute
090: *
091: * @param name the cookie name
092: * @param value the cookie value
093: * @param domain the domain this cookie can be sent to
094: * @param path the path prefix for which this cookie can be sent
095: * @param expires the {@link Date} at which this cookie expires,
096: * or <tt>null</tt> if the cookie expires at the end
097: * of the session
098: * @param secure if true this cookie can only be sent over secure
099: * connections
100: * @throws IllegalArgumentException If cookie name is null or blank,
101: * cookie name contains a blank, or cookie name starts with character $
102: *
103: */
104: public Cookie(String domain, String name, String value,
105: String path, Date expires, boolean secure) {
106:
107: super (name, value);
108: LOG
109: .trace("enter Cookie(String, String, String, String, Date, boolean)");
110: if (name == null) {
111: throw new IllegalArgumentException(
112: "Cookie name may not be null");
113: }
114: if (name.trim().equals("")) {
115: throw new IllegalArgumentException(
116: "Cookie name may not be blank");
117: }
118: this .setPath(path);
119: this .setDomain(domain);
120: this .setExpiryDate(expires);
121: this .setSecure(secure);
122: }
123:
124: /**
125: * Creates a cookie with the given name, value, domain attribute,
126: * path attribute, maximum age attribute, and secure attribute
127: *
128: * @param name the cookie name
129: * @param value the cookie value
130: * @param domain the domain this cookie can be sent to
131: * @param path the path prefix for which this cookie can be sent
132: * @param maxAge the number of seconds for which this cookie is valid.
133: * maxAge is expected to be a non-negative number.
134: * <tt>-1</tt> signifies that the cookie should never expire.
135: * @param secure if <tt>true</tt> this cookie can only be sent over secure
136: * connections
137: */
138: public Cookie(String domain, String name, String value,
139: String path, int maxAge, boolean secure) {
140:
141: this (domain, name, value, path, null, secure);
142: if (maxAge < -1) {
143: throw new IllegalArgumentException("Invalid max age: "
144: + Integer.toString(maxAge));
145: }
146: if (maxAge >= 0) {
147: setExpiryDate(new Date(System.currentTimeMillis() + maxAge
148: * 1000L));
149: }
150: }
151:
152: /**
153: * Returns the comment describing the purpose of this cookie, or
154: * <tt>null</tt> if no such comment has been defined.
155: *
156: * @return comment
157: *
158: * @see #setComment(String)
159: */
160: public String getComment() {
161: return cookieComment;
162: }
163:
164: /**
165: * If a user agent (web browser) presents this cookie to a user, the
166: * cookie's purpose will be described using this comment.
167: *
168: * @param comment
169: *
170: * @see #getComment()
171: */
172: public void setComment(String comment) {
173: cookieComment = comment;
174: }
175:
176: /**
177: * Returns the expiration {@link Date} of the cookie, or <tt>null</tt>
178: * if none exists.
179: * <p><strong>Note:</strong> the object returned by this method is
180: * considered immutable. Changing it (e.g. using setTime()) could result
181: * in undefined behaviour. Do so at your peril. </p>
182: * @return Expiration {@link Date}, or <tt>null</tt>.
183: *
184: * @see #setExpiryDate(java.util.Date)
185: *
186: */
187: public Date getExpiryDate() {
188: return cookieExpiryDate;
189: }
190:
191: /**
192: * Sets expiration date.
193: * <p><strong>Note:</strong> the object returned by this method is considered
194: * immutable. Changing it (e.g. using setTime()) could result in undefined
195: * behaviour. Do so at your peril.</p>
196: *
197: * @param expiryDate the {@link Date} after which this cookie is no longer valid.
198: *
199: * @see #getExpiryDate
200: *
201: */
202: public void setExpiryDate(Date expiryDate) {
203: cookieExpiryDate = expiryDate;
204: }
205:
206: /**
207: * Returns <tt>false</tt> if the cookie should be discarded at the end
208: * of the "session"; <tt>true</tt> otherwise.
209: *
210: * @return <tt>false</tt> if the cookie should be discarded at the end
211: * of the "session"; <tt>true</tt> otherwise
212: */
213: public boolean isPersistent() {
214: return (null != cookieExpiryDate);
215: }
216:
217: /**
218: * Returns domain attribute of the cookie.
219: *
220: * @return the value of the domain attribute
221: *
222: * @see #setDomain(java.lang.String)
223: */
224: public String getDomain() {
225: return cookieDomain;
226: }
227:
228: /**
229: * Sets the domain attribute.
230: *
231: * @param domain The value of the domain attribute
232: *
233: * @see #getDomain
234: */
235: public void setDomain(String domain) {
236: if (domain != null) {
237: int ndx = domain.indexOf(":");
238: if (ndx != -1) {
239: domain = domain.substring(0, ndx);
240: }
241: cookieDomain = domain.toLowerCase();
242: }
243: }
244:
245: /**
246: * Returns the path attribute of the cookie
247: *
248: * @return The value of the path attribute.
249: *
250: * @see #setPath(java.lang.String)
251: */
252: public String getPath() {
253: return cookiePath;
254: }
255:
256: /**
257: * Sets the path attribute.
258: *
259: * @param path The value of the path attribute
260: *
261: * @see #getPath
262: *
263: */
264: public void setPath(String path) {
265: cookiePath = path;
266: }
267:
268: /**
269: * @return <code>true</code> if this cookie should only be sent over secure connections.
270: * @see #setSecure(boolean)
271: */
272: public boolean getSecure() {
273: return isSecure;
274: }
275:
276: /**
277: * Sets the secure attribute of the cookie.
278: * <p>
279: * When <tt>true</tt> the cookie should only be sent
280: * using a secure protocol (https). This should only be set when
281: * the cookie's originating server used a secure protocol to set the
282: * cookie's value.
283: *
284: * @param secure The value of the secure attribute
285: *
286: * @see #getSecure()
287: */
288: public void setSecure(boolean secure) {
289: isSecure = secure;
290: }
291:
292: /**
293: * Returns the version of the cookie specification to which this
294: * cookie conforms.
295: *
296: * @return the version of the cookie.
297: *
298: * @see #setVersion(int)
299: *
300: */
301: public int getVersion() {
302: return cookieVersion;
303: }
304:
305: /**
306: * Sets the version of the cookie specification to which this
307: * cookie conforms.
308: *
309: * @param version the version of the cookie.
310: *
311: * @see #getVersion
312: */
313: public void setVersion(int version) {
314: cookieVersion = version;
315: }
316:
317: /**
318: * Returns true if this cookie has expired.
319: *
320: * @return <tt>true</tt> if the cookie has expired.
321: */
322: public boolean isExpired() {
323: return (cookieExpiryDate != null && cookieExpiryDate.getTime() <= System
324: .currentTimeMillis());
325: }
326:
327: /**
328: * Returns true if this cookie has expired according to the time passed in.
329: *
330: * @param now The current time.
331: *
332: * @return <tt>true</tt> if the cookie expired.
333: */
334: public boolean isExpired(Date now) {
335: return (cookieExpiryDate != null && cookieExpiryDate.getTime() <= now
336: .getTime());
337: }
338:
339: /**
340: * Indicates whether the cookie had a path specified in a
341: * path attribute of the <tt>Set-Cookie</tt> header. This value
342: * is important for generating the <tt>Cookie</tt> header because
343: * some cookie specifications require that the <tt>Cookie</tt> header
344: * should only include a path attribute if the cookie's path
345: * was specified in the <tt>Set-Cookie</tt> header.
346: *
347: * @param value <tt>true</tt> if the cookie's path was explicitly
348: * set, <tt>false</tt> otherwise.
349: *
350: * @see #isPathAttributeSpecified
351: */
352: public void setPathAttributeSpecified(boolean value) {
353: hasPathAttribute = value;
354: }
355:
356: /**
357: * Returns <tt>true</tt> if cookie's path was set via a path attribute
358: * in the <tt>Set-Cookie</tt> header.
359: *
360: * @return value <tt>true</tt> if the cookie's path was explicitly
361: * set, <tt>false</tt> otherwise.
362: *
363: * @see #setPathAttributeSpecified
364: */
365: public boolean isPathAttributeSpecified() {
366: return hasPathAttribute;
367: }
368:
369: /**
370: * Indicates whether the cookie had a domain specified in a
371: * domain attribute of the <tt>Set-Cookie</tt> header. This value
372: * is important for generating the <tt>Cookie</tt> header because
373: * some cookie specifications require that the <tt>Cookie</tt> header
374: * should only include a domain attribute if the cookie's domain
375: * was specified in the <tt>Set-Cookie</tt> header.
376: *
377: * @param value <tt>true</tt> if the cookie's domain was explicitly
378: * set, <tt>false</tt> otherwise.
379: *
380: * @see #isDomainAttributeSpecified
381: */
382: public void setDomainAttributeSpecified(boolean value) {
383: hasDomainAttribute = value;
384: }
385:
386: /**
387: * Returns <tt>true</tt> if cookie's domain was set via a domain
388: * attribute in the <tt>Set-Cookie</tt> header.
389: *
390: * @return value <tt>true</tt> if the cookie's domain was explicitly
391: * set, <tt>false</tt> otherwise.
392: *
393: * @see #setDomainAttributeSpecified
394: */
395: public boolean isDomainAttributeSpecified() {
396: return hasDomainAttribute;
397: }
398:
399: /**
400: * Returns a hash code in keeping with the
401: * {@link Object#hashCode} general hashCode contract.
402: * @return A hash code
403: */
404: public int hashCode() {
405: int hash = LangUtils.HASH_SEED;
406: hash = LangUtils.hashCode(hash, this .getName());
407: hash = LangUtils.hashCode(hash, this .cookieDomain);
408: hash = LangUtils.hashCode(hash, this .cookiePath);
409: return hash;
410: }
411:
412: /**
413: * Two cookies are equal if the name, path and domain match.
414: * @param obj The object to compare against.
415: * @return true if the two objects are equal.
416: */
417: public boolean equals(Object obj) {
418: if (obj == null)
419: return false;
420: if (this == obj)
421: return true;
422: if (obj instanceof Cookie) {
423: Cookie that = (Cookie) obj;
424: return LangUtils.equals(this .getName(), that.getName())
425: && LangUtils.equals(this .cookieDomain,
426: that.cookieDomain)
427: && LangUtils.equals(this .cookiePath,
428: that.cookiePath);
429: } else {
430: return false;
431: }
432: }
433:
434: /**
435: * Return a textual representation of the cookie.
436: *
437: * @return string.
438: */
439: public String toExternalForm() {
440: CookieSpec spec = null;
441: if (getVersion() > 0) {
442: spec = CookiePolicy.getDefaultSpec();
443: } else {
444: spec = CookiePolicy.getCookieSpec(CookiePolicy.NETSCAPE);
445: }
446: return spec.formatCookie(this );
447: }
448:
449: /**
450: * <p>Compares two cookies to determine order for cookie header.</p>
451: * <p>Most specific should be first. </p>
452: * <p>This method is implemented so a cookie can be used as a comparator for
453: * a SortedSet of cookies. Specifically it's used above in the
454: * createCookieHeader method.</p>
455: * @param o1 The first object to be compared
456: * @param o2 The second object to be compared
457: * @return See {@link java.util.Comparator#compare(Object,Object)}
458: */
459: public int compare(Object o1, Object o2) {
460: LOG.trace("enter Cookie.compare(Object, Object)");
461:
462: if (!(o1 instanceof Cookie)) {
463: throw new ClassCastException(o1.getClass().getName());
464: }
465: if (!(o2 instanceof Cookie)) {
466: throw new ClassCastException(o2.getClass().getName());
467: }
468: Cookie c1 = (Cookie) o1;
469: Cookie c2 = (Cookie) o2;
470: if (c1.getPath() == null && c2.getPath() == null) {
471: return 0;
472: } else if (c1.getPath() == null) {
473: // null is assumed to be "/"
474: if (c2.getPath().equals(CookieSpec.PATH_DELIM)) {
475: return 0;
476: } else {
477: return -1;
478: }
479: } else if (c2.getPath() == null) {
480: // null is assumed to be "/"
481: if (c1.getPath().equals(CookieSpec.PATH_DELIM)) {
482: return 0;
483: } else {
484: return 1;
485: }
486: } else {
487: return c1.getPath().compareTo(c2.getPath());
488: }
489: }
490:
491: /**
492: * Return a textual representation of the cookie.
493: *
494: * @return string.
495: *
496: * @see #toExternalForm
497: */
498: public String toString() {
499: return toExternalForm();
500: }
501:
502: // ----------------------------------------------------- Instance Variables
503:
504: /** Comment attribute. */
505: private String cookieComment;
506:
507: /** Domain attribute. */
508: private String cookieDomain;
509:
510: /** Expiration {@link Date}. */
511: private Date cookieExpiryDate;
512:
513: /** Path attribute. */
514: private String cookiePath;
515:
516: /** My secure flag. */
517: private boolean isSecure;
518:
519: /**
520: * Specifies if the set-cookie header included a Path attribute for this
521: * cookie
522: */
523: private boolean hasPathAttribute = false;
524:
525: /**
526: * Specifies if the set-cookie header included a Domain attribute for this
527: * cookie
528: */
529: private boolean hasDomainAttribute = false;
530:
531: /** The version of the cookie specification I was created from. */
532: private int cookieVersion = 0;
533:
534: // -------------------------------------------------------------- Constants
535:
536: /** Log object for this class */
537: private static final Log LOG = LogFactory.getLog(Cookie.class);
538:
539: }
|