/*
* COMSAT
* Copyright (c) 2013-2014, Parallel Universe Software Co. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 3.0
* as published by the Free Software Foundation.
*/
package co.paralleluniverse.comsat.webactors;
/**
* A HTTP cookie
*/
public class Cookie {
/**
* Constructs a cookie with the specified name and value.
*
* <p>The name must conform to RFC 2109. However, vendors may
* provide a configuration option that allows cookie names conforming
* to the original Netscape Cookie Specification to be accepted.
*
* <p>The name of a cookie cannot be changed once the cookie has been created.
*
* <p>The value can be anything the server chooses to send.
* Its value is probably of interest only to the server.
*
* <p>By default, cookies are created according to the Netscape cookie specification.
* The version can be changed with the {@link Builder#setVersion(int) setVersion} method.
*
* @param name the name of the cookie
* @param value the value of the cookie
* @return a new {@link Cookie.Builder}
*/
public static Builder cookie(String name, String value) {
return new Builder(name, value);
}
public static class Builder {
private final String name;
private final String value;
private String path;
private String domain;
private int maxAge = -1;
private String comment;
private int version;
private boolean httpOnly;
private boolean secure;
private Builder(String name, String value) {
this.name = name;
this.value = value;
}
/**
* 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 2109 (available on the Internet) for more
* information on setting path names for cookies.
*
* @param uri a {@code String} specifying a path
*
* @see Cookie#getPath
*/
public Builder setPath(String uri) {
this.path = uri;
return this;
}
/**
*
* Specifies the domain within which this cookie should be presented.
*
* <p>The form of the domain name is specified by RFC 2109.
* A domain name begins with a dot ({@code .foo.com}) and means that
* the cookie is visible to servers in a specified Domain Name System
* (DNS) zone (for example,
* {@code www.foo.com}, but not {@code a.b.foo.com}).
* By default, cookies are only returned to the server that sent them.
*
* @param domain the domain name within which this cookie is visible;
* form is according to RFC 2109
*
* @see Cookie#getDomain
*/
public Builder setDomain(String domain) {
this.domain = domain;
return this;
}
/**
* Sets the maximum age in seconds for this Cookie.
*
* <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 maxAge an integer specifying the maximum age of the
* cookie in seconds; if negative, means
* the cookie is not stored; if zero, deletes the cookie
*
* @see Cookie#getMaxAge
*/
public Builder setMaxAge(int maxAge) {
this.maxAge = maxAge;
return this;
}
/**
* 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 comment a {@code String} specifying the comment to display to the user
*
* @see Cookie#getComment
*/
public Builder setComment(String comment) {
this.comment = comment;
return this;
}
/**
* Sets the version of the cookie protocol that this Cookie complies with.
*
* <p>Version 0 complies with the original Netscape cookie specification.
* Version 1 complies with RFC 2109.
*
* <p>Since RFC 2109 is still somewhat new, consider
* version 1 as experimental; do not use it yet on production sites.
*
* @param version 0 if the cookie should comply with the original Netscape
* specification; 1 if the cookie should comply with RFC 2109
*
* @see Cookie#getVersion
*/
public Builder setVersion(int version) {
this.version = version;
return this;
}
/**
* Marks or unmarks this Cookie as <i>HttpOnly</i>.
*
* <p>If {@code httpOnly} is set to {@code true}, this cookie is
* marked as <i>HttpOnly</i>, by adding the {@code HttpOnly} attribute to it.
*
* <p><i>HttpOnly</i> cookies are not supposed to be exposed to
* client-side scripting code, and may therefore help mitigate certain
* kinds of cross-site scripting attacks.
*
* @param httpOnly {@code true} if this cookie is to be marked as <i>HttpOnly</i>, {@code false} otherwise
*
* @see Cookie#isHttpOnly()
*/
public Builder setHttpOnly(boolean httpOnly) {
this.httpOnly = httpOnly;
return this;
}
/**
* Indicates to the browser whether the cookie should only be sent
* using a secure protocol, such as HTTPS or SSL.
*
* <p>The default value is {@code false}.
*
* @param flag if {@code true}, sends the cookie from the browser
* to the server only when using a secure protocol;
* if {@code false}, sent on any protocol
*
* @see Cookie#isSecure
*/
public Builder setSecure(boolean flag) {
this.secure = flag;
return this;
}
/**
* Instantiates a new immutable {@link Cookie} based on the values set in this builder.
*
* @return a new {@link Cookie}
*/
public Cookie build() {
return new Cookie(this);
}
}
private final String name;
private final String value;
private final String path;
private final String domain;
private final int maxAge;
private final String comment;
private final int version;
private final boolean httpOnly;
private final boolean secure;
private Cookie(Builder builder) {
this.name = builder.name;
this.value = builder.value;
this.path = builder.path;
this.domain = builder.domain;
this.maxAge = builder.maxAge;
this.comment = builder.comment;
this.version = builder.version;
this.httpOnly = builder.httpOnly;
this.secure = builder.secure;
}
/**
* The name of the cookie.
*
* @see #cookie(String, String)
*/
public String getName() {
return name;
}
/**
* The value of this Cookie.
*
* @see #cookie(String, String)
*/
public String getValue() {
return value;
}
/**
* Returns the path on the server to which the browser returns this cookie.
* The cookie is visible to all subpaths on the server.
*
* @return a {@code String} specifying a path that contains a servlet name, for example, <i>/catalog</i>
*
* @see Builder#setPath
*/
public String getPath() {
return path;
}
/**
* The domain name of this Cookie.
*
* <p>Domain names are formatted according to RFC 2109.
*
* @see Builder#setDomain
*/
public String getDomain() {
return domain;
}
/**
* The maximum age in seconds of this Cookie.
*
* <p>By default, {@code -1} is returned, which indicates that the cookie will persist until browser shutdown.
*
* @return an integer specifying the maximum age of the cookie in seconds;
* if negative, means the cookie persists until browser shutdown
*
* @see Builder#setMaxAge
*/
public int getMaxAge() {
return maxAge;
}
/**
* The comment describing the purpose of this cookie, or {@code null} if the cookie has no comment.
*
* @see Builder#setComment
*/
public String getComment() {
return comment;
}
/**
* The version of the protocol this cookie complies with.
* Version 1 complies with RFC 2109,
* and version 0 complies with the original cookie specification drafted by Netscape.
* Cookies provided by a browser use and identify the browser's cookie version.
*
* @return {@code 0} if the cookie complies with the original Netscape specification;
* {@code 1} if the cookie complies with RFC 2109
*
* @see Builder#setVersion
*/
public int getVersion() {
return version;
}
/**
* Whether this Cookie has been marked as <i>HttpOnly</i>.
*
* @return {@code true} if this Cookie has been marked as <i>HttpOnly</i>, {@code false} otherwise
*/
public boolean isHttpOnly() {
return httpOnly;
}
/**
* Returns {@code true} if the browser is sending cookies only over a secure protocol,
* or {@code false} if the browser can send cookies using any protocol.
*
* @return {@code true} if the browser uses a secure protocol, {@code false} otherwise
*
* @see Builder#setSecure
*/
public boolean isSecure() {
return secure;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Cookie[");
sb.append("name: ").append(name);
sb.append(" value: ").append(value);
if (path != null)
sb.append(" path: ").append(path);
if (domain != null)
sb.append(" domain: ").append(domain);
sb.append(" maxAge: ").append(maxAge);
if (comment != null)
sb.append(" comment: ").append(comment);
sb.append(" version: ").append(version);
if (httpOnly)
sb.append(" httpOnly: ").append(httpOnly);
sb.append(" secure: ").append(secure);
sb.append(']');
return sb.toString();
}
}