/* * 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. Load more
/* * 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 javadoc import 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. * *