/* * Sun Public License * * The contents of this file are subject to the Sun Public License Version * 1.0 (the "License"). You may not use this file except in compliance with * the License. A copy of the License is available at http://www.sun.com/ * * The Original Code is the SLAMD Distributed Load Generation Engine. * The Initial Developer of the Original Code is Neil A. Wilson. * Portions created by Neil A. Wilson are Copyright (C) 2004-2010. * Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc. * All Rights Reserved. * * Contributor(s): Neil A. Wilson */ package com.slamd.http; import java.net.URL; import java.text.SimpleDateFormat; import java.util.HashMap; import java.util.StringTokenizer; /** * This class defines a cookie that may be used to help retain state information * between requests. * * * @author Neil A. Wilson */ public class HTTPCookie { /** * The date formatter that will be used to parse dates from cookies. */ public static final SimpleDateFormat EXPIRATION_DATE_FORMAT = new SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss z"); // Indicates whether this cookie should only be returned for secure // connections. private boolean secure; // The hash map of all extra (unrecognized) properties included in the cookie. private HashMap<String,String> extraProperties; // The version for this cookie. private int version; // The time that this cookie should expire. private long expirationDate; // The comment for this cookie; private String comment; // The domain with which this cookie should be used. private String domain; // The name of the data associated with this cookie. private String name; // The path of the request document with which this cookie should be used. private String path; // The value of the data associated with this cookie. private String value; /** * Creates a new cookie by parsing it from the provided string. * * @param requestURL The URL of the request with which the cookie is * associated. * @param cookieString The string to be parsed to create the cookie. * * @throws HTTPException If a problem occurs while attempting to parse the * provided string as a cookie. */ public HTTPCookie(URL requestURL, String cookieString) throws HTTPException { // Set default values for all the elements. name = null; value = null; domain = null; path = null; expirationDate = -1; secure = false; version = -1; comment = null; extraProperties = new HashMap<String,String>(); // Parse the cookie string into the individual elements. StringTokenizer tokenizer = new StringTokenizer(cookieString, ";"); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken().trim(); String tokenName; String lowerName; String tokenValue; int equalPos = token.indexOf('='); if (equalPos < 0) { tokenName = token; lowerName = tokenName.toLowerCase(); tokenValue = ""; } else { tokenName = token.substring(0, equalPos); lowerName = tokenName.toLowerCase(); tokenValue = token.substring(equalPos+1); } if (name == null) { // This must be the first element in the cookie, which must be the name. name = tokenName; value = tokenValue; } else if (lowerName.equals("secure")) { secure = true; } else if (lowerName.equals("domain")) { domain = tokenValue.toLowerCase(); } else if (lowerName.equals("path")) { path = tokenValue; } else if (lowerName.equals("expires")) { try { expirationDate = EXPIRATION_DATE_FORMAT.parse(token.substring(8)).getTime(); } catch (Exception e) { throw new HTTPException("Unable to parse cookie expiration date: " + e, e); } } else if (lowerName.equals("max-age")) { try { expirationDate = System.currentTimeMillis() + (1000 * Integer.parseInt(tokenValue)); } catch (Exception e) { throw new HTTPException("Unable to parse cookie max-age: " + e, e); } } else if (lowerName.equals("comment")) { comment = tokenValue; } else if (lowerName.equals("version")) { try { version = Integer.parseInt(token.substring(8)); } catch (Exception e) { throw new HTTPException("Unable to parse cookie version: " + e, e); } } else { extraProperties.put(lowerName, tokenValue); } } // Make sure that a name and value were available. If not, then this was an // invalid cookie. if (name == null) { throw new HTTPException("Unable to parse the cookie: no name provided"); } else if (value == null) { throw new HTTPException("Unable to parse the cookie: no value provided"); } // See if a domain was provided. If not, then set it to the address used // for the request. if (domain == null) { domain = requestURL.getHost(); } // See if a path was provided. If not, then set it to the path for the // request. if (path == null) { path = requestURL.getPath(); } } /** * Creates a new cookie with the provided information. * * @param name The name of the data associated with this cookie. * @param value The value of the data associated with this cookie. * @param domain The domain with which this cookie should be used. * @param path The path for which this cookie should be used. * @param expirationDate The time that this cookie should expire, or -1 if * there should be no expiration date. * @param secure Indicates whether this cookie should only be * provided over a secure connection. */ public HTTPCookie(String name, String value, String domain, String path, long expirationDate, boolean secure) { this.name = name; this.value = value; this.domain = domain; this.path = path; this.expirationDate = expirationDate; this.secure = secure; extraProperties = new HashMap<String,String>(0); comment = null; version = -1; } /** * Creates a new cookie with the provided information. * * @param name The name of the data associated with this cookie. * @param value The value of the data associated with this cookie. * @param domain The domain with which this cookie should be used. * @param path The path for which this cookie should be used. * @param expirationDate The time that this cookie should expire, or -1 if * there should be no expiration date. * @param secure Indicates whether this cookie should only be * provided over a secure connection. * @param comment The comment for this cookie. * @param version The version for this cookie, or -1 if there is no * version. */ public HTTPCookie(String name, String value, String domain, String path, long expirationDate, boolean secure, String comment, int version) { this.name = name; this.value = value; this.domain = domain; this.path = path; this.expirationDate = expirationDate; this.secure = secure; this.comment = comment; this.version = version; extraProperties = new HashMap<String,String>(0); } /** * Retrieves the name for this cookie. * * @return The name for this cookie. */ public String getName() { return name; } /** * Retrieves the value for this cookie. * * @return The value for this cookie. */ public String getValue() { return value; } /** * Retrieves the domain associated with this cookie. * * @return The domain associated with this cookie. */ public String getDomain() { return domain; } /** * Retrieves the path associated with this cookie. * * @return The path associated with this cookie. */ public String getPath() { return path; } /** * Retrieves the expiration date for this cookie. * * @return The expiration date for this cookie. */ public long getExpirationDate() { return expirationDate; } /** * Indicates whether this cookie should be only provided over secure * connections. * * @return <CODE>true</CODE> if this cookie should only be provided over * secure connections, or <CODE>false</CODE> if not. */ public boolean getSecure() { return secure; } /** * Retrieves the comment for this cookie. * * @return The comment for this cookie, or <CODE>null</CODE> if there is * none. */ public String getComment() { return comment; } /** * Retrieves the version for this cookie. * * @return The version for this cookie, or -1 if there is none. */ public int getVersion() { return version; } /** * Retrieves the set of all "extra" unrecognized properties that have been * set for this cookie, mapped from the property name (in all lowercase * characters) to the property value. * * @return The set of "extra" unrecognized properties for this cookie. */ public HashMap getProperties() { return extraProperties; } /** * Retrieves the value of the requested "extra" unrecognized property from * this cookie. * * @param lowerName The name of the property to retrieve, in all lowercase * characters. * * @return The value for the requested "extra" property, or <CODE>null</CODE> * if no such property has been set. */ public String getProperty(String lowerName) { return extraProperties.get(lowerName); } /** * Indicates whether this cookie applies to the provided request. * * @param requestURL The request for which to make the determination. * @param currentTime The time to use when determining whether the cookie * is expired. * * @return <CODE>true</CODE> if this cookie should be included in the given * request, or <CODE>false</CODE> if not. */ public boolean appliesToRequest(URL requestURL, long currentTime) { // See if the cookie has expired. if ((expirationDate > 0) && (expirationDate < currentTime)) { return false; } // If this cookie requires a secure connection, verify that the request uses // such a connection. if (secure) { if (! requestURL.getProtocol().equalsIgnoreCase("https")) { return false; } } // See if the domain is applicable to the request. String host = requestURL.getHost().toLowerCase(); if (! host.endsWith(domain)) { return false; } // See if the path is applicable to the request. if (! requestURL.getPath().startsWith(path)) { return false; } // If we've gotten here, then the cookie should be included in the request. return true; } }