1206 lines · 39.2 KB · Java
RawDownload
/* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.net; import java.util.List;import java.util.StringTokenizer;import java.util.NoSuchElementException;import java.text.SimpleDateFormat;import java.util.TimeZone;import java.util.Date; import java.lang.NullPointerException;  // for javadocimport java.util.Locale;import java.util.Objects; /** * An HttpCookie object represents an http cookie, which carries state * information between server and user agent. Cookie is widely adopted * to create stateful sessions. * * <p>There are 3 http cookie specifications: * <blockquote> *   Netscape draft<br> *   RFC 2109 - <a href="http://www.ietf.org/rfc/rfc2109.txt"> * <i>http://www.ietf.org/rfc/rfc2109.txt</i></a><br> *   RFC 2965 - <a href="http://www.ietf.org/rfc/rfc2965.txt"> * <i>http://www.ietf.org/rfc/rfc2965.txt</i></a> * </blockquote> * * <p>HttpCookie class can accept all these 3 forms of syntax. * * @author Edward Wang * @since 1.6 */public final class HttpCookie implements Cloneable {    /* ---------------- Fields -------------- */     //    // The value of the cookie itself.    //     private String name;        // NAME= ... "$Name" style is reserved    private String value;       // value of NAME     //    // Attributes encoded in the header's cookie fields.    //     private String comment;     // Comment=VALUE ... describes cookie's use    private String commentURL;  // CommentURL="http URL" ... describes cookie's use    private boolean toDiscard;  // Discard ... discard cookie unconditionally    private String domain;      // Domain=VALUE ... domain that sees cookie    private long maxAge = MAX_AGE_UNSPECIFIED;  // Max-Age=VALUE ... cookies auto-expire    private String path;        // Path=VALUE ... URLs that see the cookie    private String portlist;    // Port[="portlist"] ... the port cookie may be returned to    private boolean secure;     // Secure ... e.g. use SSL    private boolean httpOnly;   // HttpOnly ... i.e. not accessible to scripts    private int version = 1;    // Version=1 ... RFC 2965 style     //    // Hold the creation time (in seconds) of the http cookie for later    // expiration calculation    //    private long whenCreated = 0;      //    // Since the positive and zero max-age have their meanings,    // this value serves as a hint as 'not specify max-age'    //    private final static long MAX_AGE_UNSPECIFIED = -1;      //    // date formats used by Netscape's cookie draft    // as well as formats seen on various sites    //    private final static String[] COOKIE_DATE_FORMATS = {        "EEE',' dd-MMM-yyyy HH:mm:ss 'GMT'",        "EEE',' dd MMM yyyy HH:mm:ss 'GMT'",        "EEE MMM dd yyyy HH:mm:ss 'GMT'Z"    };     //    // constant strings represent set-cookie header token    //    private final static String SET_COOKIE = "set-cookie:";    private final static String SET_COOKIE2 = "set-cookie2:";      /* ---------------- Ctors -------------- */     /**     * Constructs a cookie with a specified name and value.     *     * <p>The name must conform to RFC 2965. That means it can contain     * only ASCII alphanumeric characters and cannot contain commas,     * semicolons, or white space or begin with a $ character. The cookie's     * name cannot be changed after creation.     *     * <p>The value can be anything the server chooses to send. Its     * value is probably of interest only to the server. The cookie's     * value can be changed after creation with the     * <code>setValue</code> method.     *     * <p>By default, cookies are created according to the RFC 2965     * cookie specification. The version can be changed with the     * <code>setVersion</code> method.     *     *     * @param name                      a <code>String</code> specifying the name of the cookie     *     * @param value                     a <code>String</code> specifying the value of the cookie     *     * @throws IllegalArgumentException if the cookie name contains illegal characters     *                                  or it is one of the tokens reserved for use     *                                  by the cookie protocol     * @throws NullPointerException     if <tt>name</tt> is <tt>null</tt>     * @see #setValue     * @see #setVersion     *     */     public HttpCookie(String name, String value) {        name = name.trim();        if (name.length() == 0 || !isToken(name) || isReserved(name)) {            throw new IllegalArgumentException("Illegal cookie name");        }         this.name = name;        this.value = value;        toDiscard = false;        secure = false;         whenCreated = System.currentTimeMillis();        portlist = null;    }      /**     * Constructs cookies from set-cookie or set-cookie2 header string.     * RFC 2965 section 3.2.2 set-cookie2 syntax indicates that one header line     * may contain more than one cookie definitions, so this is a static     * utility method instead of another constructor.     *     * @param header    a <tt>String</tt> specifying the set-cookie header.     *                  The header should start with "set-cookie", or "set-cookie2"     *                  token; or it should have no leading token at all.     * @return          a List of cookie parsed from header line string     * @throws IllegalArgumentException if header string violates the cookie     *                                  specification's syntax, or the cookie     *                                  name contains llegal characters, or     *                                  the cookie name is one of the tokens     *                                  reserved for use by the cookie protocol     * @throws NullPointerException     if the header string is <tt>null</tt>     */    public static List<HttpCookie> parse(String header) {        int version = guessCookieVersion(header);         // if header start with set-cookie or set-cookie2, strip it off        if (startsWithIgnoreCase(header, SET_COOKIE2)) {            header = header.substring(SET_COOKIE2.length());        } else if (startsWithIgnoreCase(header, SET_COOKIE)) {            header = header.substring(SET_COOKIE.length());        }          List<HttpCookie> cookies = new java.util.ArrayList<HttpCookie>();        // The Netscape cookie may have a comma in its expires attribute,        // while the comma is the delimiter in rfc 2965/2109 cookie header string.        // so the parse logic is slightly different        if (version == 0) {            // Netscape draft cookie            HttpCookie cookie = parseInternal(header);            cookie.setVersion(0);            cookies.add(cookie);        } else {            // rfc2965/2109 cookie            // if header string contains more than one cookie,            // it'll separate them with comma            List<String> cookieStrings = splitMultiCookies(header);            for (String cookieStr : cookieStrings) {                HttpCookie cookie = parseInternal(cookieStr);                cookie.setVersion(1);                cookies.add(cookie);            }        }         return cookies;    }        /* ---------------- Public operations -------------- */      /**     * Reports whether this http cookie has expired or not.     *     * @return  <tt>true</tt> to indicate this http cookie has expired;     *          otherwise, <tt>false</tt>     */    public boolean hasExpired() {        if (maxAge == 0) return true;         // if not specify max-age, this cookie should be        // discarded when user agent is to be closed, but        // it is not expired.        if (maxAge == MAX_AGE_UNSPECIFIED) return false;         long deltaSecond = (System.currentTimeMillis() - whenCreated) / 1000;        if (deltaSecond > maxAge)            return true;        else            return false;    }     /**     *     * Specifies a comment that describes a cookie's purpose.     * The comment is useful if the browser presents the cookie     * to the user. Comments     * are not supported by Netscape Version 0 cookies.     *     * @param purpose           a <code>String</code> specifying the comment     *                          to display to the user     *     * @see #getComment     *     */     public void setComment(String purpose) {        comment = purpose;    }        /**     * Returns the comment describing the purpose of this cookie, or     * <code>null</code> if the cookie has no comment.     *     * @return                  a <code>String</code> containing the comment,     *                          or <code>null</code> if none     *     * @see #setComment     *     */     public String getComment() {        return comment;    }      /**     *     * Specifies a comment url that describes a cookie's purpose.     * The comment url is useful if the browser presents the cookie     * to the user. Comment url is RFC 2965 only.     *     * @param purpose           a <code>String</code> specifying the comment url     *                          to display to the user     *     * @see #getCommentURL     *     */     public void setCommentURL(String purpose) {        commentURL = purpose;    }        /**     * Returns the comment url describing the purpose of this cookie, or     * <code>null</code> if the cookie has no comment url.     *     * @return                  a <code>String</code> containing the comment url,     *                          or <code>null</code> if none     *     * @see #setCommentURL     *     */     public String getCommentURL() {        return commentURL;    }      /**     * Specify whether user agent should discard the cookie unconditionally.     * This is RFC 2965 only attribute.     *     * @param discard   <tt>true</tt> indicates to discard cookie unconditionally     *     * @see #getDiscard     */     public void setDiscard(boolean discard) {        toDiscard = discard;    }        /**     * Return the discard attribute of the cookie     *     * @return  a <tt>boolean</tt> to represent this cookie's discard attribute     *     * @see #setDiscard     */     public boolean getDiscard() {        return toDiscard;    }      /**     * Specify the portlist of the cookie, which restricts the port(s)     * to which a cookie may be sent back in a Cookie header.     *     * @param ports     a <tt>String</tt> specify the port list, which is     *                  comma seperated series of digits     * @see #getPortlist     */     public void setPortlist(String ports) {        portlist = ports;    }        /**     * Return the port list attribute of the cookie     *     * @return  a <tt>String</tt> contains the port list     *          or <tt>null</tt> if none     * @see #setPortlist     */     public String getPortlist() {        return portlist;    }     /**     *     * Specifies the domain within which this cookie should be presented.     *     * <p>The form of the domain name is specified by RFC 2965. A domain     * name begins with a dot (<code>.foo.com</code>) and means that     * the cookie is visible to servers in a specified Domain Name System     * (DNS) zone (for example, <code>www.foo.com</code>, but not     * <code>a.b.foo.com</code>). By default, cookies are only returned     * to the server that sent them.     *     *     * @param pattern           a <code>String</code> containing the domain name     *                          within which this cookie is visible;     *                          form is according to RFC 2965     *     * @see #getDomain     *     */     public void setDomain(String pattern) {        if (pattern != null)            domain = pattern.toLowerCase();        else            domain = pattern;    }         /**     * Returns the domain name set for this cookie. The form of     * the domain name is set by RFC 2965.     *     * @return                  a <code>String</code> containing the domain name     *     * @see #setDomain     *     */     public String getDomain() {        return domain;    }      /**     * Sets the maximum age of the cookie in seconds.     *     * <p>A positive value indicates that the cookie will expire     * after that many seconds have passed. Note that the value is     * the <i>maximum</i> age when the cookie will expire, not the cookie's     * current age.     *     * <p>A negative value means     * that the cookie is not stored persistently and will be deleted     * when the Web browser exits. A zero value causes the cookie     * to be deleted.     *     * @param expiry            an integer specifying the maximum age of the     *                          cookie in seconds; if zero, the cookie     *                          should be discarded immediately;     *                          otherwise, the cookie's max age is unspecified.     *     * @see #getMaxAge     *     */    public void setMaxAge(long expiry) {        maxAge = expiry;    }        /**     * Returns the maximum age of the cookie, specified in seconds.     * By default, <code>-1</code> indicating the cookie will persist     * until browser shutdown.     *     *     * @return                  an integer specifying the maximum age of the     *                          cookie in seconds     *     *     * @see #setMaxAge     *     */     public long getMaxAge() {        return maxAge;    }        /**     * Specifies a path for the cookie     * to which the client should return the cookie.     *     * <p>The cookie is visible to all the pages in the directory     * you specify, and all the pages in that directory's subdirectories.     * A cookie's path must include the servlet that set the cookie,     * for example, <i>/catalog</i>, which makes the cookie     * visible to all directories on the server under <i>/catalog</i>.     *     * <p>Consult RFC 2965 (available on the Internet) for more     * information on setting path names for cookies.     *     *     * @param uri               a <code>String</code> specifying a path     *     *     * @see #getPath     *     */     public void setPath(String uri) {        path = uri;    }        /**     * Returns the path on the server     * to which the browser returns this cookie. The     * cookie is visible to all subpaths on the server.     *     *

Lines 1–500 of 1206.