/***********************************************************************
*
* $CVSHeader$
*
* This file is part of WebScarab, an Open Web Application Security
* Project utility. For details, please see http://www.owasp.org/
*
* Copyright (c) 2002 - 2004 Rogan Dawes
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Getting Source
* ==============
*
* Source for this application is maintained at Sourceforge.net, a
* repository for free software projects.
*
* For details, please see http://www.sourceforge.net/projects/owasp
*
*/
/*
* Cookie.java
*
* Created on September 10, 2003, 11:01 PM
*/
package org.owasp.webscarab.model;
import java.util.Date;
import java.util.logging.Logger;
/**
* Represents a cookie received from a web server
*
* From rfc 2109
*
* The syntax for the Set-Cookie response header is
*
* set-cookie = "Set-Cookie:" cookies
* cookies = 1#cookie
* cookie = NAME "=" VALUE *(";" cookie-av)
* NAME = attr
* VALUE = value
* cookie-av = "Comment" "=" value
* | "Domain" "=" value
* | "Max-Age" "=" value
* | "Path" "=" value
* | "Secure"
* | "Version" "=" 1*DIGIT
*
*
* added support for Microsoft's new httponly flag - untested, and largely unused!
*
* @author rdawes
*/
public class Cookie {
private Date _date = null;
private String _name = null;
private String _value = null;
private String _key = null;
private String _comment = null;
private String _domain = null;
private String _path = null;
private String _maxage = null;
private boolean _secure = false;
private String _version = null;
private boolean _httponly = false;
private Logger _logger = Logger.getLogger(getClass().getName());
/**
* Creates a new instance of Cookie
* @param date the date the cookie was created/received
* @param url the URL the the cookie was sent back from
* @param setHeader the actual "Set-Cookie" header value
*/
public Cookie(Date date, HttpUrl url, String setHeader) {
_date = date;
_domain = url.getHost();
_path = url.getPath();
int index = _path.lastIndexOf("/");
if (index > 0) {
_path = _path.substring(0,index);
} else {
_path = "/";
}
parseHeader(setHeader);
_key = _domain + _path + " " + _name;
}
/**
* This variant of the constuctor should only be called when we are sure that the
* Set-Cookie header already contains the domain and path.
* e.g. when we are reading the cookies from disk
* @param date The date the cookie was created or received
* @param setHeader a complete Set-Cookie header
*/
public Cookie(Date date, String setHeader) {
_date = date;
parseHeader(setHeader);
_key = _domain + _path + " " + _name;
}
private void parseHeader(String setHeader) {
if (setHeader == null) {
throw new NullPointerException("You may not pass a null value for setHeader");
}
String[] parts = setHeader.split(" *; *");
if (parts.length < 1) {
throw new IllegalArgumentException("The setHeader must have at least one part to it!");
}
String[] av = parts[0].split("=",2);
if (av.length != 2) {
throw new IllegalArgumentException("The header passed in must at least contain the name and value '" +parts[0] + "'");
}
_name = av[0];
_value = av[1];
for (int i=1; i<parts.length; i++) {
if (parts[i].equalsIgnoreCase("secure")) {
_secure = true;
} else if (parts[i].equalsIgnoreCase("httponly")) {
_httponly = true;
} else {
av = parts[i].split("=", 2);
if (av.length != 2) {
_logger.warning("Unknown cookie attribute '" + parts[i] + "'");
} else if (av[0].equalsIgnoreCase("Comment")) {
_comment = av[1];
} else if (av[0].equalsIgnoreCase("Domain")) {
_domain = av[1];
} else if (av[0].equalsIgnoreCase("Path")) {
_path = av[1];
} else if (av[0].equalsIgnoreCase("Max-Age")) {
_maxage = av[1];
} else if (av[0].equalsIgnoreCase("Version")) {
_version = av[1];
}
}
}
}
/**
* an identifier for the cookie "name", made up of the domain, the path, and the name of the cookie
* @return the identifier
*/
public String getKey() {
return _key;
}
/**
* returns the date/time the cookie was created
* @return the Date
*/
public Date getDate() {
return _date;
}
/**
* returns the name of the cookie
* @return the name of the cookie
*/
public String getName() {
return _name;
}
/**
* returns the value of the cookie
* @return the value of the cookie
*/
public String getValue() {
return _value;
}
/**
* returns the domain of the cookie
* @return the domain of the cookie
*/
public String getDomain() {
return _domain;
}
/**
* returns the maximum age of the cookie
* @return the maximum age of the cookie
*/
public String getMaxAge() {
return _maxage;
}
/**
* returns the path of the cookie
* @return the path of the cookie
*/
public String getPath() {
return _path;
}
/**
* indicates whether this cookie had the "secure" flag set
* @return true if the "secure" flag was set
*/
public boolean getSecure() {
return _secure;
}
/**
* indicates whther this cookie had MS's "httpOnly" flag set
* @return true if the "httpOnly" flag was set
*/
public boolean getHTTPOnly() {
return _httponly;
}
/**
* returns the version of the cookie
* @return the version of the cookie
*/
public String getVersion() {
return _version;
}
/**
* returns the comment of the cookie
* @return the comment of the cookie
*/
public String getComment() {
return _comment;
}
/**
* returns a string equivalent to the complete "Set-Cookie" header that would have been sent.
* @return a string equivalent to the complete "Set-Cookie" header that would have been sent.
*/
public String setCookie() {
StringBuffer buf = new StringBuffer();
buf.append(_name + "=" + _value);
if (_comment != null) {
buf.append("; Comment=" + _comment);
}
if (_domain != null) {
buf.append("; Domain=" + _domain);
}
if (_maxage != null) {
buf.append("; Max-Age=" + _maxage);
}
if (_path != null) {
buf.append("; Path=" + _path);
}
if (_secure) {
buf.append("; Secure");
}
if (_httponly) {
buf.append("; httponly");
}
if (_version != null) {
buf.append("; Version=" + _version);
}
return buf.toString();
}
/**
*
*/
public String toString() {
StringBuffer buff = new StringBuffer();
buff.append(_date.getTime()).append(" ");
buff.append(setCookie());
return buff.toString();
}
}