diff options
Diffstat (limited to 'simple/simple-http/src/main/java/org/simpleframework/http/Cookie.java')
-rw-r--r-- | simple/simple-http/src/main/java/org/simpleframework/http/Cookie.java | 527 |
1 files changed, 527 insertions, 0 deletions
diff --git a/simple/simple-http/src/main/java/org/simpleframework/http/Cookie.java b/simple/simple-http/src/main/java/org/simpleframework/http/Cookie.java new file mode 100644 index 0000000..a9ab422 --- /dev/null +++ b/simple/simple-http/src/main/java/org/simpleframework/http/Cookie.java @@ -0,0 +1,527 @@ +/* + * Cookie.java February 2001 + * + * Copyright (C) 2001, Niall Gallagher <niallg@users.sf.net> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package org.simpleframework.http; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.SimpleTimeZone; +import java.util.TimeZone; + +/** + * This class is used to represent a generic cookie. This exposes + * the fields that a cookie can have. By default the version of the + * <code>Cookie</code> is set to 1. The version can be configured + * using the <code>setVersion</code> method. The domain, path, + * security, and expiry of the cookie can also be set using their + * respective set methods. + * <p> + * The <code>toString</code> method allows the <code>Cookie</code> + * to be converted back into text form. This text form converts the + * cookie according to the Set-Cookie header form. This is done so + * that a created <code>Cookie</code> instance can be converted + * to a string which can be used as a a HTTP header. + * + * @author Niall Gallagher + */ +public class Cookie { + + /** + * This is used to set the expiry date for the cookie. + */ + private CookieDate date; + + /** + * The name attribute of this cookie instance. + */ + private String name; + + /** + * The value attribute of this cookie instance. + */ + private String value; + + /** + * Represents the value of the path for this cookie. + */ + private String path; + + /** + * Represents the value of the domain attribute. + */ + private String domain; + + /** + * Determines whether the cookie should be secure. + */ + private boolean secure; + + /** + * Determines whether the cookie should be protected. + */ + private boolean protect; + + /** + * This is used to determine the the cookie is new. + */ + private boolean created; + + /** + * Represents the value of the version attribute. + */ + private int version; + + /** + * Represents the duration in seconds of the cookie. + */ + private int expiry; + + /** + * Constructor of the <code>Cookie</code> that uses a default + * version of 1, which is used by RFC 2109. This contains none + * of the optional attributes, such as domain and path. These + * optional attributes can be set using the set methods. + * <p> + * The name must conform to RFC 2109, which means that it can + * contain only ASCII alphanumeric characters and cannot have + * commas, white space, or semicolon characters. + * + * @param name this is the name of this cookie instance + * @param value this is the value of this cookie instance + */ + public Cookie(String name, String value) { + this(name, value, "/"); + } + + /** + * Constructor of the <code>Cookie</code> that uses a default + * version of 1, which is used by RFC 2109. This contains none + * of the optional attributes, such as domain and path. These + * optional attributes can be set using the set methods. + * <p> + * The name must conform to RFC 2109, which means that it can + * contain only ASCII alphanumeric characters and cannot have + * commas, white space, or semicolon characters. + * + * @param name this is the name of this cookie instance + * @param value this is the value of this cookie instance + * @param created this determines if the cookie is new + */ + public Cookie(String name, String value, boolean created) { + this(name, value, "/", created); + } + + /** + * Constructor of the <code>Cookie</code> that uses a default + * version of 1, which is used by RFC 2109. This allows the + * path attribute to be specified for on construction. Other + * attributes can be set using the set methods provided. + * <p> + * The name must conform to RFC 2109, which means that it can + * contain only ASCII alphanumeric characters and cannot have + * commas, white space, or semicolon characters. + * + * @param name this is the name of this cookie instance + * @param value this is the value of this cookie instance + * @param path the path attribute of this cookie instance + */ + public Cookie(String name, String value, String path) { + this(name, value, path, false); + } + + /** + * Constructor of the <code>Cookie</code> that uses a default + * version of 1, which is used by RFC 2109. This allows the + * path attribute to be specified for on construction. Other + * attributes can be set using the set methods provided. + * <p> + * The name must conform to RFC 2109, which means that it can + * contain only ASCII alphanumeric characters and cannot have + * commas, white space, or semicolon characters. + * + * @param name this is the name of this cookie instance + * @param value this is the value of this cookie instance + * @param path the path attribute of this cookie instance + * @param created this determines if the cookie is new + */ + public Cookie(String name, String value, String path, boolean created) { + this.date = new CookieDate(); + this.created = created; + this.value = value; + this.name = name; + this.path = path; + this.version = 1; + this.expiry = -1; + } + + /** + * This is used to determine if the cookie is new. A cookie is + * considered new if it has just been created on the server. A + * cookie is considered not new if it has been received by the + * client in a request. This allows the server to determine if + * the cookie needs to be delivered to the client. + * + * @return this returns true if the cookie was just created + */ + public boolean isNew() { + return created; + } + + /** + * This returns the version for this cookie. The version is + * not optional and so will always return the version this + * cookie uses. If no version number is specified this will + * return a version of 1, to comply with RFC 2109. + * + * @return the version value from this cookie instance + */ + public int getVersion() { + return version; + } + + /** + * This enables the version of the <code>Cookie</code> to be + * set. By default the version of the <code>Cookie</code> is + * set to 1. It is not advisable to set the version higher + * than 1, unless it is known that the client will accept it. + * <p> + * Some old browsers can only handle cookie version 0. This + * can be used to comply with the original Netscape cookie + * specification. Version 1 complies with RFC 2109. + * + * @param version this is the version number for the cookie + */ + public void setVersion(int version) { + this.version = version; + } + + /** + * This returns the name for this cookie. The name and value + * attributes of a cookie define what the <code>Cookie</code> + * is for, these values will always be present. These are + * mandatory for both the Cookie and Set-Cookie headers. + * <p> + * Because the cookie may be stored by name, the cookie name + * cannot be modified after the creation of the cookie object. + * + * @return the name from this cookie instance object + */ + public String getName() { + return name; + } + + /** + * This returns the value for this cookie. The name and value + * attributes of a cookie define what the <code>Cookie</code> + * is for, these values will always be present. These are + * mandatory for both the Cookie and Set-Cookie headers. + * + * @return the value from this cookie instance object + */ + public String getValue() { + return value; + } + + /** + * This enables the value of the cookie to be changed. This + * can be set to any value the server wishes to send. Cookie + * values can contain space characters as they are transmitted + * in quotes. For example a value of <code>some value</code> + * is perfectly legal. However for maximum compatibility + * across the different plaforms such as PHP, JavaScript and + * others, quotations should be avoided. If quotations are + * required they must be added to the string. For example a + * quoted value could be created as <code>"some value"</code>. + * + * @param value this is the new value of this cookie object + */ + public void setValue(String value) { + this.value = value; + } + + /** + * This determines whether the cookie is secure. The cookie + * is secure if it has the "secure" token set, as defined + * by RFC 2109. If this token is set then the cookie is only + * sent over secure channels such as SSL and TLS and ensures + * that a third party cannot intercept and spoof the cookie. + * + * @return this returns true if the "secure" token is set + */ + public boolean isSecure() { + return secure; + } + + /** + * This is used to determine if the client browser should send + * this cookie over a secure protocol. If this is true then + * the client browser should only send the cookie over secure + * channels such as SSL and TLS. This ensures that the value + * of the cookie cannot be intercepted by a third party. + * + * @param secure if true then the cookie should be secure + */ + public void setSecure(boolean secure) { + this.secure = secure; + } + + /** + * This is used to determine if the cookie is protected against + * cross site scripting. It sets the <code>HttpOnly</code> value + * for the cookie. Setting this value ensures that the cookie + * is not available to some scripting attacks. + * + * @return this returns true if the cookie is protected + */ + public boolean isProtected() { + return protect; + } + + /** + * This is used to protect the cookie from cross site scripting + * vulnerabilities. If this is set to true the cookie will be + * protected by setting the <code>HttpOnly</code> value for the + * cookie. See RFC 6265 for more details on this value. + * + * @param protect this determines if the cookie is protected + */ + public void setProtected(boolean protect) { + this.protect = protect; + } + + /** + * This returns the number of seconds a cookie lives for. This + * determines how long the cookie will live on the client side. + * If the expiry is less than zero the cookie lifetime is the + * duration of the client browser session, if it is zero then + * the cookie will be deleted from the client browser. + * + * @return returns the duration in seconds the cookie lives + */ + public int getExpiry() { + return expiry; + } + + /** + * This allows a lifetime to be specified for the cookie. This + * will make use of the "max-age" token specified by RFC 2109 + * the specifies the number of seconds a browser should keep + * a cookie for. This is useful if the cookie is to be kept + * beyond the lifetime of the client session. If the value of + * this is zero then this will remove the client cookie, if + * it is less than zero then the "max-age" field is ignored. + * + * @param expiry the duration in seconds the cookie lives + */ + public void setExpiry(int expiry){ + this.expiry = expiry; + } + + /** + * This returns the path for this cookie. The path is in both + * the Cookie and Set-Cookie headers and so may return null + * if there is no domain value. If the <code>toString</code> + * or <code>toClientString</code> is invoked the path will + * not be present if the path attribute is null. + * + * @return this returns the path value from this cookie + */ + public String getPath() { + return path; + } + + /** + * This is used to set the cookie path for this cookie. This + * is set so that the cookie can specify the directories that + * the cookie is sent with. For example if the path attribute + * is set to <code>/pub/bin</code>, then requests for the + * resource <code>http://hostname:port/pub/bin/README</code> + * will be issued with this cookie. The cookie is issued for + * all resources in the path and all subdirectories. + * + * @param path this is the path value for this cookie object + */ + public void setPath(String path) { + this.path = path; + } + + /** + * This returns the domain for this cookie. The domain is in + * both the Cookie and Set-Cookie headers and so may return + * null if there is no domain value. If either the + * <code>toString</code> or <code>toClientString</code> is + * invoked the domain will not be present if this is null. + * + * @return this returns the domain value from this cookie + */ + public String getDomain() { + return domain; + } + + /** + * This enables the domain for this <code>Cookie</code> to be + * set. The form of the domain is specified by RFC 2109. The + * value can begin with a dot, like <code>.host.com</code>. + * This means that the cookie is visible within a specific + * DNS zone like <code>www.host.com</code>. By default this + * value is null which means it is sent back to its origin. + * + * @param domain this is the domain value for this cookie + */ + public void setDomain(String domain) { + this.domain = domain; + } + + /** + * This will give the correct string value of this cookie. This + * will generate the cookie text with only the values that were + * given with this cookie. If there are no optional attributes + * like $Path or $Domain these are left blank. This returns the + * encoding as it would be for the HTTP Cookie header. + * + * @return this returns the Cookie header encoding of this + */ + public String toClientString(){ + return "$Version="+version+"; "+name+"="+ + value+ (path==null?"":"; $Path="+ + path)+ (domain==null? "":"; $Domain="+ + domain); + } + + /** + * The <code>toString</code> method converts the cookie to the + * Set-Cookie value. This can be used to send the HTTP header + * to a client browser. This uses a format that has been tested + * with various browsers. This is required as some browsers + * do not perform flexible parsing of the Set-Cookie value. + * <p> + * Netscape and IE-5.0 can't or wont handle <code>Path</code> + * it must be <code>path</code> also Netscape can not handle + * the path in quotations such as <code>"/path"</code> it must + * be <code>/path</code>. This value is never in quotations. + * <p> + * For maximum compatibility cookie values are not transmitted + * in quotations. This is done to ensure that platforms like + * PHP, JavaScript and various others that don't comply with + * RFC 2109 can transparently access the sent cookies. + * <p> + * When setting the expiry time for the cookie it is important + * to set the <code>max-age</code> and <code>expires</code> + * attributes so that IE-5.0 and up can understand them. Old + * versions of IE do not understand <code>max-age</code>. + * + * @return this returns a Set-Cookie encoding of the cookie + */ + public String toString(){ + return name+"="+value+"; version="+ + version +(path ==null ?"":"; path="+path)+ + (domain ==null ?"": "; domain="+domain)+ + (expiry< 0?"":"; expires="+date.format(expiry))+ + (expiry < 0 ? "" : "; max-age="+expiry)+ + (secure ? "; secure" : "") + + (protect ? "; httponly" : ""); + + } + + /** + * The <code>CookieDate</code> complies with the date format + * used by older browsers such as Internet Explorer and + * Netscape Navigator. The format of the date is not the same + * as other HTTP date headers. It takes the form. + * <pre> + * + * DAY, DD-MMM-YYYY HH:MM:SS GMT + * + * </pre> + * Support for this format is required as many browsers do + * not support <code>max-age</code> and so cookies will not + * expire for these browsers. + */ + private static class CookieDate { + + /** + * This is the format that is required for the date. + */ + private static final String FORMAT = "EEE, dd-MMM-yyyy HH:mm:ss z"; + + /** + * The cookie date must be returned in the GMT zone. + */ + private static final String ZONE = "GMT"; + + /** + * This is the date formatter used to build the string. + */ + private final DateFormat format; + + /** + * This is the GMT time zone which must be used. + */ + private final TimeZone zone; + + /** + * Constructor for the <code>CookieDate</code> formatter. + * This creates the time zone and date formatting tools + * that are need to convert the expiry in seconds to the + * correct text format for older browsers to understand. + */ + public CookieDate() { + this.format = new SimpleDateFormat(FORMAT); + this.zone = new SimpleTimeZone(0, ZONE); + } + + /** + * This takes the number of seconds the cookie will live + * for. In order for this to be respected by older browsers + * such as IE-5.0 to IE-9.0 this must return a string in + * the original cookie specification by Netscape. + * + * @param seconds the number of seconds from now + * + * @return a date formatted for used with old browsers + */ + public String format(int seconds) { + Calendar calendar = Calendar.getInstance(zone); + Date date = convert(seconds); + + calendar.setTime(date); + format.setCalendar(calendar); + + return format.format(date); + } + + /** + * This method is used to convert the provided time to + * a date that can be formatted. The time returned is the + * current time plus the number of seconds provided. + * + * @param seconds the number of seconds from now + * + * @return a date representing some time in the future + */ + private Date convert(int seconds) { + long now = System.currentTimeMillis(); + long duration = seconds * 1000L; + long time = now + duration; + + return new Date(time); + } + } +} |