View Javadoc

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