package io.craft.atom.protocol.http.model;
import static io.craft.atom.protocol.http.HttpConstants.S_EQUAL_SIGN;
import static io.craft.atom.protocol.http.HttpConstants.S_SEMICOLON;
import static io.craft.atom.protocol.http.HttpConstants.S_SP;
import io.craft.atom.protocol.http.HttpDates;
import java.io.Serializable;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* Represents a token or short packet of state information. <br>
* These header fields can be used by HTTP servers to store state (called cookies) at HTTP user agents,
* letting the servers maintain a stateful session over the mostly stateless HTTP protocol.
* <p>
* Cookie syntax:
* <pre>
* set-cookie-header = "Set-Cookie:" SP set-cookie-string
* set-cookie-string = cookie-pair *( ";" SP cookie-av )
* cookie-pair = cookie-name "=" cookie-value
* cookie-name = token
* cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
* cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
* ; US-ASCII characters excluding CTLs,
* ; whitespace DQUOTE, comma, semicolon,
* ; and backslash
* token = <token, defined in [RFC2616], Section 2.2>
*
* cookie-av = expires-av / max-age-av / domain-av /
* path-av / secure-av / httponly-av /
* extension-av
* expires-av = "Expires=" sane-cookie-date
* sane-cookie-date = <rfc1123-date, defined in [RFC2616], Section 3.3.1>
* max-age-av = "Max-Age=" non-zero-digit *DIGIT
* ; In practice, both expires-av and max-age-av
* ; are limited to dates representable by the
* ; user agent.
* non-zero-digit = %x31-39
* ; digits 1 through 9
* domain-av = "Domain=" domain-value
* domain-value = <subdomain>
* ; defined in [RFC1034], Section 3.5, as
* ; enhanced by [RFC1123], Section 2.1
* path-av = "Path=" path-value
* path-value = <any CHAR except CTLs or ";">
* secure-av = "Secure"
* httponly-av = "HttpOnly"
* extension-av = <any CHAR except CTLs or ";">
*
*
* cookie-header = "Cookie:" OWS cookie-string OWS
* cookie-string = cookie-pair *( ";" SP cookie-pair )
* </pre>
*
* For examples:
* <pre>
* Set-Cookie: SID=31d4d96e407aad42; Domain=example.com; Path=/; HttpOnly; Secure; Expires=Wed, 09 Jun 2021 10:18:14 GMT; Max-Age=86400
* Cookie: SID=31d4d96e407aad42; lang=en-US
* </pre>
*
* More about cookie definition please reference <a href="http://tools.ietf.org/html/rfc6265">rfc6265</a>.
*
* @author mindwind
* @version 1.0, Mar 22, 2013
*/
@ToString(of = { "name", "value", "domain", "path", "httpOnly", "secure", "expires", "maxAge", "extension" })
public class HttpCookie implements Serializable {
private static final long serialVersionUID = 5584804359930330729L;
public static final String DOMAIN = "Domain" ;
public static final String PATH = "Path" ;
public static final String HTTP_ONLY = "HttpOnly" ;
public static final String SECURE = "Secure" ;
public static final String EXPIRES = "Expires" ;
public static final String MAX_AGE = "Max-Age" ;
// ~ ----------------------------------------------------------------------------------------------------------
@Getter @Setter private String name ;
@Getter @Setter private String value ;
@Getter @Setter private String domain ;
@Getter @Setter private String path ;
@Setter private Boolean httpOnly ;
@Setter private Boolean secure ;
@Getter @Setter private Date expires ;
@Getter @Setter private Integer maxAge ;
private Map<String, String> extension = new LinkedHashMap<String, String>();
// ~ ----------------------------------------------------------------------------------------------------------
public HttpCookie() {
super();
}
public HttpCookie(String name, String value) {
if (name == null) {
throw new IllegalArgumentException("Name should not be null");
}
this.name = name;
this.value = value;
}
public HttpCookie(String name, String value, String domain) {
this(name, value);
this.domain = domain;
}
public HttpCookie(String name, String value, String domain, String path) {
this(name, value, domain);
this.path = path;
}
public HttpCookie(String name, String value, String domain, String path, boolean httpOnly) {
this(name, value, domain, path);
}
public HttpCookie(String name, String value, String domain, String path, boolean httpOnly, int maxAge) {
this(name, value, domain, path, httpOnly);
this.maxAge = maxAge;
}
// ~ ----------------------------------------------------------------------------------------------------------
public Boolean isSecure() {
return secure;
}
public Boolean isHttpOnly() {
return httpOnly;
}
public Map<String, String> getExtensionAttributes() {
return Collections.unmodifiableMap(extension);
}
public void addExtensionAttribute(String name, String value) {
this.extension.put(name, value);
}
public void removeExtensionAttribute(String name) {
this.extension.remove(name);
}
public String getExtensionAttribute(String name) {
return this.extension.get(name);
}
public String toHttpString() {
StringBuilder sb = new StringBuilder();
sb.append(getName()).append(S_EQUAL_SIGN).append(getValue());
if (domain != null) {
sb.append(S_SEMICOLON).append(S_SP).append(DOMAIN).append(S_EQUAL_SIGN).append(getDomain());
}
if (path != null) {
sb.append(S_SEMICOLON).append(S_SP).append(PATH).append(S_EQUAL_SIGN).append(getPath());
}
if (httpOnly != null) {
sb.append(S_SEMICOLON).append(S_SP).append(HTTP_ONLY);
}
if (secure != null) {
sb.append(S_SEMICOLON).append(S_SP).append(SECURE);
}
if (expires != null) {
sb.append(S_SEMICOLON).append(S_SP).append(EXPIRES).append(S_EQUAL_SIGN).append(HttpDates.format(getExpires()));
}
if (maxAge != null) {
sb.append(S_SEMICOLON).append(S_SP).append(MAX_AGE).append(S_EQUAL_SIGN).append(getMaxAge());
}
Set<Entry<String, String>> entrys = extension.entrySet();
for (Entry<String, String> entry : entrys) {
String k = entry.getKey();
String v = entry.getValue();
sb.append(S_SEMICOLON).append(S_SP).append(k);
if ( v != null) {
sb.append(S_EQUAL_SIGN).append(v);
}
}
return sb.toString();
}
}