/*
 * $HeadURL: https://svn.apache.org/repos/asf/jakarta/httpcomponents/oac.hc3x/tags/HTTPCLIENT_3_1/src/java/org/apache/commons/httpclient/cookie/RFC2965Spec.java $
 * $Revision: 507134 $
 * $Date: 2007-02-13 19:18:05 +0100 (Tue, 13 Feb 2007) $
 * 
 * ====================================================================
 *
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */

package org.apache.commons.httpclient.cookie;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.apache.commons.httpclient.Cookie;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HeaderElement;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.util.ParameterFormatter;

RFC 2965 specific cookie management functions.

Author:jain.samit@gmail.com (Samit Jain)
Since:3.1
/** * <p>RFC 2965 specific cookie management functions.</p> * * @author jain.samit@gmail.com (Samit Jain) * * @since 3.1 */
public class RFC2965Spec extends CookieSpecBase implements CookieVersionSupport { private static final Comparator PATH_COMPOARATOR = new CookiePathComparator();
Cookie Response Header name for cookies processed by this spec.
/** * Cookie Response Header name for cookies processed * by this spec. */
public final static String SET_COOKIE2_KEY = "set-cookie2";
used for formatting RFC 2956 style cookies
/** * used for formatting RFC 2956 style cookies */
private final ParameterFormatter formatter;
Stores the list of attribute handlers
/** * Stores the list of attribute handlers */
private final List attribHandlerList;
Stores attribute name -> attribute handler mappings
/** * Stores attribute name -> attribute handler mappings */
private final Map attribHandlerMap;
Fallback cookie spec (RFC 2109)
/** * Fallback cookie spec (RFC 2109) */
private final CookieSpec rfc2109;
Default constructor
/** * Default constructor * */
public RFC2965Spec() { super(); this.formatter = new ParameterFormatter(); this.formatter.setAlwaysUseQuotes(true); this.attribHandlerMap = new HashMap(10); this.attribHandlerList = new ArrayList(10); this.rfc2109 = new RFC2109Spec(); registerAttribHandler(Cookie2.PATH, new Cookie2PathAttributeHandler()); registerAttribHandler(Cookie2.DOMAIN, new Cookie2DomainAttributeHandler()); registerAttribHandler(Cookie2.PORT, new Cookie2PortAttributeHandler()); registerAttribHandler(Cookie2.MAXAGE, new Cookie2MaxageAttributeHandler()); registerAttribHandler(Cookie2.SECURE, new CookieSecureAttributeHandler()); registerAttribHandler(Cookie2.COMMENT, new CookieCommentAttributeHandler()); registerAttribHandler(Cookie2.COMMENTURL, new CookieCommentUrlAttributeHandler()); registerAttribHandler(Cookie2.DISCARD, new CookieDiscardAttributeHandler()); registerAttribHandler(Cookie2.VERSION, new Cookie2VersionAttributeHandler()); } protected void registerAttribHandler( final String name, final CookieAttributeHandler handler) { if (name == null) { throw new IllegalArgumentException("Attribute name may not be null"); } if (handler == null) { throw new IllegalArgumentException("Attribute handler may not be null"); } if (!this.attribHandlerList.contains(handler)) { this.attribHandlerList.add(handler); } this.attribHandlerMap.put(name, handler); }
Finds an attribute handler CookieAttributeHandler for the given attribute. Returns null if no attribute handler is found for the specified attribute.
Params:
  • name – attribute name. e.g. Domain, Path, etc.
Returns:an attribute handler or null
/** * Finds an attribute handler {@link CookieAttributeHandler} for the * given attribute. Returns <tt>null</tt> if no attribute handler is * found for the specified attribute. * * @param name attribute name. e.g. Domain, Path, etc. * @return an attribute handler or <tt>null</tt> */
protected CookieAttributeHandler findAttribHandler(final String name) { return (CookieAttributeHandler) this.attribHandlerMap.get(name); }
Gets attribute handler CookieAttributeHandler for the given attribute.
Params:
  • name – attribute name. e.g. Domain, Path, etc.
Throws:
/** * Gets attribute handler {@link CookieAttributeHandler} for the * given attribute. * * @param name attribute name. e.g. Domain, Path, etc. * @throws IllegalStateException if handler not found for the * specified attribute. */
protected CookieAttributeHandler getAttribHandler(final String name) { CookieAttributeHandler handler = findAttribHandler(name); if (handler == null) { throw new IllegalStateException("Handler not registered for " + name + " attribute."); } else { return handler; } } protected Iterator getAttribHandlerIterator() { return this.attribHandlerList.iterator(); }
Parses the Set-Cookie2 value into an array of Cookies.

The syntax for the Set-Cookie2 response header is:

set-cookie      =    "Set-Cookie2:" cookies
cookies         =    1#cookie
cookie          =    NAME "=" VALUE * (";" cookie-av)
NAME            =    attr
VALUE           =    value
cookie-av       =    "Comment" "=" value
                |    "CommentURL" "=" <"> http_URL <">
                |    "Discard"
                |    "Domain" "=" value
                |    "Max-Age" "=" value
                |    "Path" "=" value
                |    "Port" [ "=" <"> portlist <"> ]
                |    "Secure"
                |    "Version" "=" 1*DIGIT
portlist        =       1#portnum
portnum         =       1*DIGIT
Params:
  • host – the host from which the Set-Cookie2 value was received
  • port – the port from which the Set-Cookie2 value was received
  • path – the path from which the Set-Cookie2 value was received
  • secure – true when the Set-Cookie2 value was received over secure conection
  • header – the Set-Cookie2 Header received from the server
Throws:
Returns:an array of Cookies parsed from the Set-Cookie2 value
/** * Parses the Set-Cookie2 value into an array of <tt>Cookie</tt>s. * * <P>The syntax for the Set-Cookie2 response header is: * * <PRE> * set-cookie = "Set-Cookie2:" cookies * cookies = 1#cookie * cookie = NAME "=" VALUE * (";" cookie-av) * NAME = attr * VALUE = value * cookie-av = "Comment" "=" value * | "CommentURL" "=" <"> http_URL <"> * | "Discard" * | "Domain" "=" value * | "Max-Age" "=" value * | "Path" "=" value * | "Port" [ "=" <"> portlist <"> ] * | "Secure" * | "Version" "=" 1*DIGIT * portlist = 1#portnum * portnum = 1*DIGIT * </PRE> * * @param host the host from which the <tt>Set-Cookie2</tt> value was * received * @param port the port from which the <tt>Set-Cookie2</tt> value was * received * @param path the path from which the <tt>Set-Cookie2</tt> value was * received * @param secure <tt>true</tt> when the <tt>Set-Cookie2</tt> value was * received over secure conection * @param header the <tt>Set-Cookie2</tt> <tt>Header</tt> received from the server * @return an array of <tt>Cookie</tt>s parsed from the Set-Cookie2 value * @throws MalformedCookieException if an exception occurs during parsing */
public Cookie[] parse( String host, int port, String path, boolean secure, final Header header) throws MalformedCookieException { LOG.trace("enter RFC2965.parse(" + "String, int, String, boolean, Header)"); if (header == null) { throw new IllegalArgumentException("Header may not be null."); } if (header.getName() == null) { throw new IllegalArgumentException("Header name may not be null."); } if (header.getName().equalsIgnoreCase(SET_COOKIE2_KEY)) { // parse cookie2 cookies return parse(host, port, path, secure, header.getValue()); } else if (header.getName().equalsIgnoreCase(RFC2109Spec.SET_COOKIE_KEY)) { // delegate parsing of old-style cookies to rfc2109Spec return this.rfc2109.parse(host, port, path, secure, header.getValue()); } else { throw new MalformedCookieException("Header name is not valid. " + "RFC 2965 supports \"set-cookie\" " + "and \"set-cookie2\" headers."); } }
See Also:
  • parse(String, int, String, boolean, Header)
/** * @see #parse(String, int, String, boolean, org.apache.commons.httpclient.Header) */
public Cookie[] parse(String host, int port, String path, boolean secure, final String header) throws MalformedCookieException { LOG.trace("enter RFC2965Spec.parse(" + "String, int, String, boolean, String)"); // before we do anything, lets check validity of arguments if (host == null) { throw new IllegalArgumentException( "Host of origin may not be null"); } if (host.trim().equals("")) { throw new IllegalArgumentException( "Host of origin may not be blank"); } if (port < 0) { throw new IllegalArgumentException("Invalid port: " + port); } if (path == null) { throw new IllegalArgumentException( "Path of origin may not be null."); } if (header == null) { throw new IllegalArgumentException("Header may not be null."); } if (path.trim().equals("")) { path = PATH_DELIM; } host = getEffectiveHost(host); HeaderElement[] headerElements = HeaderElement.parseElements(header.toCharArray()); List cookies = new LinkedList(); for (int i = 0; i < headerElements.length; i++) { HeaderElement headerelement = headerElements[i]; Cookie2 cookie = null; try { cookie = new Cookie2(host, headerelement.getName(), headerelement.getValue(), path, null, false, new int[] {port}); } catch (IllegalArgumentException ex) { throw new MalformedCookieException(ex.getMessage()); } NameValuePair[] parameters = headerelement.getParameters(); // could be null. In case only a header element and no parameters. if (parameters != null) { // Eliminate duplicate attribues. The first occurence takes precedence Map attribmap = new HashMap(parameters.length); for (int j = parameters.length - 1; j >= 0; j--) { NameValuePair param = parameters[j]; attribmap.put(param.getName().toLowerCase(), param); } for (Iterator it = attribmap.entrySet().iterator(); it.hasNext(); ) { Map.Entry entry = (Map.Entry) it.next(); parseAttribute((NameValuePair) entry.getValue(), cookie); } } cookies.add(cookie); // cycle through the parameters } return (Cookie[]) cookies.toArray(new Cookie[cookies.size()]); }
Parse RFC 2965 specific cookie attribute and update the corresponsing Cookie properties.
Params:
  • attribute – NameValuePair cookie attribute from the Set-Cookie2 header.
  • cookie – Cookie to be updated
Throws:
/** * Parse RFC 2965 specific cookie attribute and update the corresponsing * {@link org.apache.commons.httpclient.Cookie} properties. * * @param attribute {@link org.apache.commons.httpclient.NameValuePair} cookie attribute from the * <tt>Set-Cookie2</tt> header. * @param cookie {@link org.apache.commons.httpclient.Cookie} to be updated * @throws MalformedCookieException if an exception occurs during parsing */
public void parseAttribute( final NameValuePair attribute, final Cookie cookie) throws MalformedCookieException { if (attribute == null) { throw new IllegalArgumentException("Attribute may not be null."); } if (attribute.getName() == null) { throw new IllegalArgumentException("Attribute Name may not be null."); } if (cookie == null) { throw new IllegalArgumentException("Cookie may not be null."); } final String paramName = attribute.getName().toLowerCase(); final String paramValue = attribute.getValue(); CookieAttributeHandler handler = findAttribHandler(paramName); if (handler == null) { // ignore unknown attribute-value pairs if (LOG.isDebugEnabled()) LOG.debug("Unrecognized cookie attribute: " + attribute.toString()); } else { handler.parse(cookie, paramValue); } }
Performs RFC 2965 compliant Cookie validation
Params:
  • host – the host from which the Cookie was received
  • port – the port from which the Cookie was received
  • path – the path from which the Cookie was received
  • secure – true when the Cookie was received using a secure connection
  • cookie – The cookie to validate
Throws:
/** * Performs RFC 2965 compliant {@link org.apache.commons.httpclient.Cookie} validation * * @param host the host from which the {@link org.apache.commons.httpclient.Cookie} was received * @param port the port from which the {@link org.apache.commons.httpclient.Cookie} was received * @param path the path from which the {@link org.apache.commons.httpclient.Cookie} was received * @param secure <tt>true</tt> when the {@link org.apache.commons.httpclient.Cookie} was received using a * secure connection * @param cookie The cookie to validate * @throws MalformedCookieException if an exception occurs during * validation */
public void validate(final String host, int port, final String path, boolean secure, final Cookie cookie) throws MalformedCookieException { LOG.trace("enter RFC2965Spec.validate(String, int, String, " + "boolean, Cookie)"); if (cookie instanceof Cookie2) { if (cookie.getName().indexOf(' ') != -1) { throw new MalformedCookieException("Cookie name may not contain blanks"); } if (cookie.getName().startsWith("$")) { throw new MalformedCookieException("Cookie name may not start with $"); } CookieOrigin origin = new CookieOrigin(getEffectiveHost(host), port, path, secure); for (Iterator i = getAttribHandlerIterator(); i.hasNext(); ) { CookieAttributeHandler handler = (CookieAttributeHandler) i.next(); handler.validate(cookie, origin); } } else { // old-style cookies are validated according to the old rules this.rfc2109.validate(host, port, path, secure, cookie); } }
Return true if the cookie should be submitted with a request with given attributes, false otherwise.
Params:
  • host – the host to which the request is being submitted
  • port – the port to which the request is being submitted (ignored)
  • path – the path to which the request is being submitted
  • secure – true if the request is using a secure connection
Returns:true if the cookie matches the criterium
/** * Return <tt>true</tt> if the cookie should be submitted with a request * with given attributes, <tt>false</tt> otherwise. * @param host the host to which the request is being submitted * @param port the port to which the request is being submitted (ignored) * @param path the path to which the request is being submitted * @param secure <tt>true</tt> if the request is using a secure connection * @return true if the cookie matches the criterium */
public boolean match(String host, int port, String path, boolean secure, final Cookie cookie) { LOG.trace("enter RFC2965.match(" + "String, int, String, boolean, Cookie"); if (cookie == null) { throw new IllegalArgumentException("Cookie may not be null"); } if (cookie instanceof Cookie2) { // check if cookie has expired if (cookie.isPersistent() && cookie.isExpired()) { return false; } CookieOrigin origin = new CookieOrigin(getEffectiveHost(host), port, path, secure); for (Iterator i = getAttribHandlerIterator(); i.hasNext(); ) { CookieAttributeHandler handler = (CookieAttributeHandler) i.next(); if (!handler.match(cookie, origin)) { return false; } } return true; } else { // old-style cookies are matched according to the old rules return this.rfc2109.match(host, port, path, secure, cookie); } } private void doFormatCookie2(final Cookie2 cookie, final StringBuffer buffer) { String name = cookie.getName(); String value = cookie.getValue(); if (value == null) { value = ""; } this.formatter.format(buffer, new NameValuePair(name, value)); // format domain attribute if (cookie.getDomain() != null && cookie.isDomainAttributeSpecified()) { buffer.append("; "); this.formatter.format(buffer, new NameValuePair("$Domain", cookie.getDomain())); } // format path attribute if ((cookie.getPath() != null) && (cookie.isPathAttributeSpecified())) { buffer.append("; "); this.formatter.format(buffer, new NameValuePair("$Path", cookie.getPath())); } // format port attribute if (cookie.isPortAttributeSpecified()) { String portValue = ""; if (!cookie.isPortAttributeBlank()) { portValue = createPortAttribute(cookie.getPorts()); } buffer.append("; "); this.formatter.format(buffer, new NameValuePair("$Port", portValue)); } }
Return a string suitable for sending in a "Cookie" header as defined in RFC 2965
Params:
  • cookie – a Cookie to be formatted as string
Returns:a string suitable for sending in a "Cookie" header.
/** * Return a string suitable for sending in a <tt>"Cookie"</tt> header as * defined in RFC 2965 * @param cookie a {@link org.apache.commons.httpclient.Cookie} to be formatted as string * @return a string suitable for sending in a <tt>"Cookie"</tt> header. */
public String formatCookie(final Cookie cookie) { LOG.trace("enter RFC2965Spec.formatCookie(Cookie)"); if (cookie == null) { throw new IllegalArgumentException("Cookie may not be null"); } if (cookie instanceof Cookie2) { Cookie2 cookie2 = (Cookie2) cookie; int version = cookie2.getVersion(); final StringBuffer buffer = new StringBuffer(); this.formatter.format(buffer, new NameValuePair("$Version", Integer.toString(version))); buffer.append("; "); doFormatCookie2(cookie2, buffer); return buffer.toString(); } else { // old-style cookies are formatted according to the old rules return this.rfc2109.formatCookie(cookie); } }
Create a RFC 2965 compliant "Cookie" header value containing all Cookies suitable for sending in a "Cookie" header
Params:
  • cookies – an array of Cookies to be formatted
Returns:a string suitable for sending in a Cookie header.
/** * Create a RFC 2965 compliant <tt>"Cookie"</tt> header value containing all * {@link org.apache.commons.httpclient.Cookie}s suitable for * sending in a <tt>"Cookie"</tt> header * @param cookies an array of {@link org.apache.commons.httpclient.Cookie}s to be formatted * @return a string suitable for sending in a Cookie header. */
public String formatCookies(final Cookie[] cookies) { LOG.trace("enter RFC2965Spec.formatCookieHeader(Cookie[])"); if (cookies == null) { throw new IllegalArgumentException("Cookies may not be null"); } // check if cookies array contains a set-cookie (old style) cookie boolean hasOldStyleCookie = false; int version = -1; for (int i = 0; i < cookies.length; i++) { Cookie cookie = cookies[i]; if (!(cookie instanceof Cookie2)) { hasOldStyleCookie = true; break; } if (cookie.getVersion() > version) { version = cookie.getVersion(); } } if (version < 0) { version = 0; } if (hasOldStyleCookie || version < 1) { // delegate old-style cookie formatting to rfc2109Spec return this.rfc2109.formatCookies(cookies); } // Arrange cookies by path Arrays.sort(cookies, PATH_COMPOARATOR); final StringBuffer buffer = new StringBuffer(); // format cookie version this.formatter.format(buffer, new NameValuePair("$Version", Integer.toString(version))); for (int i = 0; i < cookies.length; i++) { buffer.append("; "); Cookie2 cookie = (Cookie2) cookies[i]; // format cookie attributes doFormatCookie2(cookie, buffer); } return buffer.toString(); }
Retrieves valid Port attribute value for the given ports array. e.g. "8000,8001,8002"
Params:
  • ports – int array of ports
/** * Retrieves valid Port attribute value for the given ports array. * e.g. "8000,8001,8002" * * @param ports int array of ports */
private String createPortAttribute(int[] ports) { StringBuffer portValue = new StringBuffer(); for (int i = 0, len = ports.length; i < len; i++) { if (i > 0) { portValue.append(","); } portValue.append(ports[i]); } return portValue.toString(); }
Parses the given Port attribute value (e.g. "8000,8001,8002") into an array of ports.
Params:
  • portValue – port attribute value
Throws:
Returns:parsed array of ports
/** * Parses the given Port attribute value (e.g. "8000,8001,8002") * into an array of ports. * * @param portValue port attribute value * @return parsed array of ports * @throws MalformedCookieException if there is a problem in * parsing due to invalid portValue. */
private int[] parsePortAttribute(final String portValue) throws MalformedCookieException { StringTokenizer st = new StringTokenizer(portValue, ","); int[] ports = new int[st.countTokens()]; try { int i = 0; while(st.hasMoreTokens()) { ports[i] = Integer.parseInt(st.nextToken().trim()); if (ports[i] < 0) { throw new MalformedCookieException ("Invalid Port attribute."); } ++i; } } catch (NumberFormatException e) { throw new MalformedCookieException ("Invalid Port " + "attribute: " + e.getMessage()); } return ports; }
Gets 'effective host name' as defined in RFC 2965.

If a host name contains no dots, the effective host name is that name with the string .local appended to it. Otherwise the effective host name is the same as the host name. Note that all effective host names contain at least one dot.

Params:
  • host – host name where cookie is received from or being sent to.
Returns:
/** * Gets 'effective host name' as defined in RFC 2965. * <p> * If a host name contains no dots, the effective host name is * that name with the string .local appended to it. Otherwise * the effective host name is the same as the host name. Note * that all effective host names contain at least one dot. * * @param host host name where cookie is received from or being sent to. * @return */
private static String getEffectiveHost(final String host) { String effectiveHost = host.toLowerCase(); if (host.indexOf('.') < 0) { effectiveHost += ".local"; } return effectiveHost; }
Performs domain-match as defined by the RFC2965.

Host A's name domain-matches host B's if

      their host name strings string-compare equal; or
      A is a HDN string and has the form NB, where N is a non-empty name string, B has the form .B', and B' is a HDN string. (So, x.y.com domain-matches .Y.com but not Y.com.)
Params:
  • host – host name where cookie is received from or being sent to.
  • domain – The cookie domain attribute.
Returns:true if the specified host matches the given domain.
/** * Performs domain-match as defined by the RFC2965. * <p> * Host A's name domain-matches host B's if * <ol> * <ul>their host name strings string-compare equal; or</ul> * <ul>A is a HDN string and has the form NB, where N is a non-empty * name string, B has the form .B', and B' is a HDN string. (So, * x.y.com domain-matches .Y.com but not Y.com.)</ul> * </ol> * * @param host host name where cookie is received from or being sent to. * @param domain The cookie domain attribute. * @return true if the specified host matches the given domain. */
public boolean domainMatch(String host, String domain) { boolean match = host.equals(domain) || (domain.startsWith(".") && host.endsWith(domain)); return match; }
Returns true if the given port exists in the given ports list.
Params:
  • port – port of host where cookie was received from or being sent to.
  • ports – port list
Returns:true returns true if the given port exists in the given ports list; false otherwise.
/** * Returns <tt>true</tt> if the given port exists in the given * ports list. * * @param port port of host where cookie was received from or being sent to. * @param ports port list * @return true returns <tt>true</tt> if the given port exists in * the given ports list; <tt>false</tt> otherwise. */
private boolean portMatch(int port, int[] ports) { boolean portInList = false; for (int i = 0, len = ports.length; i < len; i++) { if (port == ports[i]) { portInList = true; break; } } return portInList; }
"Path" attribute handler for RFC 2965 cookie spec.
/** * <tt>"Path"</tt> attribute handler for RFC 2965 cookie spec. */
private class Cookie2PathAttributeHandler implements CookieAttributeHandler {
Parse cookie path attribute.
/** * Parse cookie path attribute. */
public void parse(final Cookie cookie, final String path) throws MalformedCookieException { if (cookie == null) { throw new IllegalArgumentException("Cookie may not be null"); } if (path == null) { throw new MalformedCookieException( "Missing value for path attribute"); } if (path.trim().equals("")) { throw new MalformedCookieException( "Blank value for path attribute"); } cookie.setPath(path); cookie.setPathAttributeSpecified(true); }
Validate cookie path attribute. The value for the Path attribute must be a prefix of the request-URI (case-sensitive matching).
/** * Validate cookie path attribute. The value for the Path attribute must be a * prefix of the request-URI (case-sensitive matching). */
public void validate(final Cookie cookie, final CookieOrigin origin) throws MalformedCookieException { if (cookie == null) { throw new IllegalArgumentException("Cookie may not be null"); } if (origin == null) { throw new IllegalArgumentException("Cookie origin may not be null"); } String path = origin.getPath(); if (path == null) { throw new IllegalArgumentException( "Path of origin host may not be null."); } if (cookie.getPath() == null) { throw new MalformedCookieException("Invalid cookie state: " + "path attribute is null."); } if (path.trim().equals("")) { path = PATH_DELIM; } if (!pathMatch(path, cookie.getPath())) { throw new MalformedCookieException( "Illegal path attribute \"" + cookie.getPath() + "\". Path of origin: \"" + path + "\""); } }
Match cookie path attribute. The value for the Path attribute must be a prefix of the request-URI (case-sensitive matching).
/** * Match cookie path attribute. The value for the Path attribute must be a * prefix of the request-URI (case-sensitive matching). */
public boolean match(final Cookie cookie, final CookieOrigin origin) { if (cookie == null) { throw new IllegalArgumentException("Cookie may not be null"); } if (origin == null) { throw new IllegalArgumentException("Cookie origin may not be null"); } String path = origin.getPath(); if (cookie.getPath() == null) { LOG.warn("Invalid cookie state: path attribute is null."); return false; } if (path.trim().equals("")) { path = PATH_DELIM; } if (!pathMatch(path, cookie.getPath())) { return false; } return true; } }
"Domain" cookie attribute handler for RFC 2965 cookie spec.
/** * <tt>"Domain"</tt> cookie attribute handler for RFC 2965 cookie spec. */
private class Cookie2DomainAttributeHandler implements CookieAttributeHandler {
Parse cookie domain attribute.
/** * Parse cookie domain attribute. */
public void parse(final Cookie cookie, String domain) throws MalformedCookieException { if (cookie == null) { throw new IllegalArgumentException("Cookie may not be null"); } if (domain == null) { throw new MalformedCookieException( "Missing value for domain attribute"); } if (domain.trim().equals("")) { throw new MalformedCookieException( "Blank value for domain attribute"); } domain = domain.toLowerCase(); if (!domain.startsWith(".")) { // Per RFC 2965 section 3.2.2 // "... If an explicitly specified value does not start with // a dot, the user agent supplies a leading dot ..." // That effectively implies that the domain attribute // MAY NOT be an IP address of a host name domain = "." + domain; } cookie.setDomain(domain); cookie.setDomainAttributeSpecified(true); }
Validate cookie domain attribute.
/** * Validate cookie domain attribute. */
public void validate(final Cookie cookie, final CookieOrigin origin) throws MalformedCookieException { if (cookie == null) { throw new IllegalArgumentException("Cookie may not be null"); } if (origin == null) { throw new IllegalArgumentException("Cookie origin may not be null"); } String host = origin.getHost().toLowerCase(); if (cookie.getDomain() == null) { throw new MalformedCookieException("Invalid cookie state: " + "domain not specified"); } String cookieDomain = cookie.getDomain().toLowerCase(); if (cookie.isDomainAttributeSpecified()) { // Domain attribute must start with a dot if (!cookieDomain.startsWith(".")) { throw new MalformedCookieException("Domain attribute \"" + cookie.getDomain() + "\" violates RFC 2109: domain must start with a dot"); } // Domain attribute must contain atleast one embedded dot, // or the value must be equal to .local. int dotIndex = cookieDomain.indexOf('.', 1); if (((dotIndex < 0) || (dotIndex == cookieDomain.length() - 1)) && (!cookieDomain.equals(".local"))) { throw new MalformedCookieException( "Domain attribute \"" + cookie.getDomain() + "\" violates RFC 2965: the value contains no embedded dots " + "and the value is not .local"); } // The effective host name must domain-match domain attribute. if (!domainMatch(host, cookieDomain)) { throw new MalformedCookieException( "Domain attribute \"" + cookie.getDomain() + "\" violates RFC 2965: effective host name does not " + "domain-match domain attribute."); } // effective host name minus domain must not contain any dots String effectiveHostWithoutDomain = host.substring( 0, host.length() - cookieDomain.length()); if (effectiveHostWithoutDomain.indexOf('.') != -1) { throw new MalformedCookieException("Domain attribute \"" + cookie.getDomain() + "\" violates RFC 2965: " + "effective host minus domain may not contain any dots"); } } else { // Domain was not specified in header. In this case, domain must // string match request host (case-insensitive). if (!cookie.getDomain().equals(host)) { throw new MalformedCookieException("Illegal domain attribute: \"" + cookie.getDomain() + "\"." + "Domain of origin: \"" + host + "\""); } } }
Match cookie domain attribute.
/** * Match cookie domain attribute. */
public boolean match(final Cookie cookie, final CookieOrigin origin) { if (cookie == null) { throw new IllegalArgumentException("Cookie may not be null"); } if (origin == null) { throw new IllegalArgumentException("Cookie origin may not be null"); } String host = origin.getHost().toLowerCase(); String cookieDomain = cookie.getDomain(); // The effective host name MUST domain-match the Domain // attribute of the cookie. if (!domainMatch(host, cookieDomain)) { return false; } // effective host name minus domain must not contain any dots String effectiveHostWithoutDomain = host.substring( 0, host.length() - cookieDomain.length()); if (effectiveHostWithoutDomain.indexOf('.') != -1) { return false; } return true; } }
"Port" cookie attribute handler for RFC 2965 cookie spec.
/** * <tt>"Port"</tt> cookie attribute handler for RFC 2965 cookie spec. */
private class Cookie2PortAttributeHandler implements CookieAttributeHandler {
Parse cookie port attribute.
/** * Parse cookie port attribute. */
public void parse(final Cookie cookie, final String portValue) throws MalformedCookieException { if (cookie == null) { throw new IllegalArgumentException("Cookie may not be null"); } if (cookie instanceof Cookie2) { Cookie2 cookie2 = (Cookie2) cookie; if ((portValue == null) || (portValue.trim().equals(""))) { // If the Port attribute is present but has no value, the // cookie can only be sent to the request-port. // Since the default port list contains only request-port, we don't // need to do anything here. cookie2.setPortAttributeBlank(true); } else { int[] ports = parsePortAttribute(portValue); cookie2.setPorts(ports); } cookie2.setPortAttributeSpecified(true); } }
Validate cookie port attribute. If the Port attribute was specified in header, the request port must be in cookie's port list.
/** * Validate cookie port attribute. If the Port attribute was specified * in header, the request port must be in cookie's port list. */
public void validate(final Cookie cookie, final CookieOrigin origin) throws MalformedCookieException { if (cookie == null) { throw new IllegalArgumentException("Cookie may not be null"); } if (origin == null) { throw new IllegalArgumentException("Cookie origin may not be null"); } if (cookie instanceof Cookie2) { Cookie2 cookie2 = (Cookie2) cookie; int port = origin.getPort(); if (cookie2.isPortAttributeSpecified()) { if (!portMatch(port, cookie2.getPorts())) { throw new MalformedCookieException( "Port attribute violates RFC 2965: " + "Request port not found in cookie's port list."); } } } }
Match cookie port attribute. If the Port attribute is not specified in header, the cookie can be sent to any port. Otherwise, the request port must be in the cookie's port list.
/** * Match cookie port attribute. If the Port attribute is not specified * in header, the cookie can be sent to any port. Otherwise, the request port * must be in the cookie's port list. */
public boolean match(final Cookie cookie, final CookieOrigin origin) { if (cookie == null) { throw new IllegalArgumentException("Cookie may not be null"); } if (origin == null) { throw new IllegalArgumentException("Cookie origin may not be null"); } if (cookie instanceof Cookie2) { Cookie2 cookie2 = (Cookie2) cookie; int port = origin.getPort(); if (cookie2.isPortAttributeSpecified()) { if (cookie2.getPorts() == null) { LOG.warn("Invalid cookie state: port not specified"); return false; } if (!portMatch(port, cookie2.getPorts())) { return false; } } return true; } else { return false; } } }
"Max-age" cookie attribute handler for RFC 2965 cookie spec.
/** * <tt>"Max-age"</tt> cookie attribute handler for RFC 2965 cookie spec. */
private class Cookie2MaxageAttributeHandler implements CookieAttributeHandler {
Parse cookie max-age attribute.
/** * Parse cookie max-age attribute. */
public void parse(final Cookie cookie, final String value) throws MalformedCookieException { if (cookie == null) { throw new IllegalArgumentException("Cookie may not be null"); } if (value == null) { throw new MalformedCookieException( "Missing value for max-age attribute"); } int age = -1; try { age = Integer.parseInt(value); } catch (NumberFormatException e) { age = -1; } if (age < 0) { throw new MalformedCookieException ("Invalid max-age attribute."); } cookie.setExpiryDate(new Date(System.currentTimeMillis() + age * 1000L)); }
validate cookie max-age attribute.
/** * validate cookie max-age attribute. */
public void validate(final Cookie cookie, final CookieOrigin origin) { }
See Also:
  • match.match(Cookie, String)
/** * @see CookieAttributeHandler#match(org.apache.commons.httpclient.Cookie, String) */
public boolean match(final Cookie cookie, final CookieOrigin origin) { return true; } }
"Secure" cookie attribute handler for RFC 2965 cookie spec.
/** * <tt>"Secure"</tt> cookie attribute handler for RFC 2965 cookie spec. */
private class CookieSecureAttributeHandler implements CookieAttributeHandler { public void parse(final Cookie cookie, final String secure) throws MalformedCookieException { cookie.setSecure(true); } public void validate(final Cookie cookie, final CookieOrigin origin) throws MalformedCookieException { } public boolean match(final Cookie cookie, final CookieOrigin origin) { if (cookie == null) { throw new IllegalArgumentException("Cookie may not be null"); } if (origin == null) { throw new IllegalArgumentException("Cookie origin may not be null"); } return cookie.getSecure() == origin.isSecure(); } }
"Commant" cookie attribute handler for RFC 2965 cookie spec.
/** * <tt>"Commant"</tt> cookie attribute handler for RFC 2965 cookie spec. */
private class CookieCommentAttributeHandler implements CookieAttributeHandler { public void parse(final Cookie cookie, final String comment) throws MalformedCookieException { cookie.setComment(comment); } public void validate(final Cookie cookie, final CookieOrigin origin) throws MalformedCookieException { } public boolean match(final Cookie cookie, final CookieOrigin origin) { return true; } }
"CommantURL" cookie attribute handler for RFC 2965 cookie spec.
/** * <tt>"CommantURL"</tt> cookie attribute handler for RFC 2965 cookie spec. */
private class CookieCommentUrlAttributeHandler implements CookieAttributeHandler { public void parse(final Cookie cookie, final String commenturl) throws MalformedCookieException { if (cookie instanceof Cookie2) { Cookie2 cookie2 = (Cookie2) cookie; cookie2.setCommentURL(commenturl); } } public void validate(final Cookie cookie, final CookieOrigin origin) throws MalformedCookieException { } public boolean match(final Cookie cookie, final CookieOrigin origin) { return true; } }
"Discard" cookie attribute handler for RFC 2965 cookie spec.
/** * <tt>"Discard"</tt> cookie attribute handler for RFC 2965 cookie spec. */
private class CookieDiscardAttributeHandler implements CookieAttributeHandler { public void parse(final Cookie cookie, final String commenturl) throws MalformedCookieException { if (cookie instanceof Cookie2) { Cookie2 cookie2 = (Cookie2) cookie; cookie2.setDiscard(true); } } public void validate(final Cookie cookie, final CookieOrigin origin) throws MalformedCookieException { } public boolean match(final Cookie cookie, final CookieOrigin origin) { return true; } }
"Version" cookie attribute handler for RFC 2965 cookie spec.
/** * <tt>"Version"</tt> cookie attribute handler for RFC 2965 cookie spec. */
private class Cookie2VersionAttributeHandler implements CookieAttributeHandler {
Parse cookie version attribute.
/** * Parse cookie version attribute. */
public void parse(final Cookie cookie, final String value) throws MalformedCookieException { if (cookie == null) { throw new IllegalArgumentException("Cookie may not be null"); } if (cookie instanceof Cookie2) { Cookie2 cookie2 = (Cookie2) cookie; if (value == null) { throw new MalformedCookieException( "Missing value for version attribute"); } int version = -1; try { version = Integer.parseInt(value); } catch (NumberFormatException e) { version = -1; } if (version < 0) { throw new MalformedCookieException("Invalid cookie version."); } cookie2.setVersion(version); cookie2.setVersionAttributeSpecified(true); } }
validate cookie version attribute. Version attribute is REQUIRED.
/** * validate cookie version attribute. Version attribute is REQUIRED. */
public void validate(final Cookie cookie, final CookieOrigin origin) throws MalformedCookieException { if (cookie == null) { throw new IllegalArgumentException("Cookie may not be null"); } if (cookie instanceof Cookie2) { Cookie2 cookie2 = (Cookie2) cookie; if (!cookie2.isVersionAttributeSpecified()) { throw new MalformedCookieException( "Violates RFC 2965. Version attribute is required."); } } } public boolean match(final Cookie cookie, final CookieOrigin origin) { return true; } } public int getVersion() { return 1; } public Header getVersionHeader() { ParameterFormatter formatter = new ParameterFormatter(); StringBuffer buffer = new StringBuffer(); formatter.format(buffer, new NameValuePair("$Version", Integer.toString(getVersion()))); return new Header("Cookie2", buffer.toString(), true); } }