RFC 6265 compliant cookie spec

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1646864 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2014-12-19 20:59:42 +00:00
parent 88b56ddb3f
commit 70489c4bb0
25 changed files with 1824 additions and 205 deletions

View File

@ -156,10 +156,11 @@ public void process(final HttpRequest request, final HttpContext context)
}
final CookieSpec cookieSpec = provider.create(clientContext);
// Get all cookies available in the HTTP state
final List<Cookie> cookies = new ArrayList<Cookie>(cookieStore.getCookies());
final List<Cookie> cookies = cookieStore.getCookies();
// Find cookies matching the given origin
final List<Cookie> matchedCookies = new ArrayList<Cookie>();
final Date now = new Date();
boolean expired = false;
for (final Cookie cookie : cookies) {
if (!cookie.isExpired(now)) {
if (cookieSpec.match(cookie, cookieOrigin)) {
@ -172,8 +173,15 @@ public void process(final HttpRequest request, final HttpContext context)
if (this.log.isDebugEnabled()) {
this.log.debug("Cookie " + cookie + " expired");
}
expired = true;
}
}
// Per RFC 6265, 5.3
// The user agent must evict all expired cookies if, at any time, an expired cookie
// exists in the cookie store
if (expired) {
cookieStore.clearExpired(now);
}
// Generate Cookie request headers
if (!matchedCookies.isEmpty()) {
final List<Header> headers = cookieSpec.formatCookies(matchedCookies);

View File

@ -133,5 +133,7 @@ public interface Cookie {
*/
boolean isExpired(final Date date);
//TODO: RFC 6265 requires cookies to track their creation time; add #getCreationDate()
}

View File

@ -30,6 +30,7 @@
import org.apache.http.annotation.Immutable;
import org.apache.http.util.Args;
import org.apache.http.util.TextUtils;
/**
* CookieOrigin class encapsulates details of an origin server that
@ -52,7 +53,7 @@ public CookieOrigin(final String host, final int port, final String path, final
Args.notNull(path, "Path");
this.host = host.toLowerCase(Locale.ROOT);
this.port = port;
if (!path.trim().isEmpty()) {
if (!TextUtils.isBlank(path)) {
this.path = path;
} else {
this.path = "/";

View File

@ -50,6 +50,8 @@
@Immutable
public class CookiePathComparator implements Serializable, Comparator<Cookie> {
public static final CookiePathComparator INSTANCE = new CookiePathComparator();
private static final long serialVersionUID = 7523645369616405818L;
private String normalizePath(final Cookie cookie) {

View File

@ -0,0 +1,69 @@
/*
* ====================================================================
* 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.http.cookie;
import java.util.Comparator;
import java.util.Date;
import org.apache.http.annotation.Immutable;
import org.apache.http.impl.cookie.BasicClientCookie;
/**
* This cookie comparator ensures that cookies with longer paths take precedence over
* cookies with shorter path. Among cookies with equal path length cookies with ealier
* creation time take precedence over cookies with later creation time
*
* @since 4.4
*/
@Immutable
public class CookiePriorityComparator implements Comparator<Cookie> {
public static final CookiePriorityComparator INSTANCE = new CookiePriorityComparator();
private int getPathLength(final Cookie cookie) {
final String path = cookie.getPath();
return path != null ? path.length() : 1;
}
@Override
public int compare(final Cookie c1, final Cookie c2) {
final int l1 = getPathLength(c1);
final int l2 = getPathLength(c2);
//TODO: update this class once Cookie interface has been expended with #getCreationTime method
final int result = l2 - l1;
if (result == 0 && c1 instanceof BasicClientCookie && c2 instanceof BasicClientCookie) {
final Date d1 = ((BasicClientCookie) c1).getCreationDate();
final Date d2 = ((BasicClientCookie) c2).getCreationDate();
if (d1 != null && d2 != null) {
return (int) (d1.getTime() - d2.getTime());
}
}
return result;
}
}

View File

@ -304,6 +304,20 @@ public boolean isExpired(final Date date) {
&& cookieExpiryDate.getTime() <= date.getTime());
}
/**
* @since 4.4
*/
public Date getCreationDate() {
return creationDate;
}
/**
* @since 4.4
*/
public void setCreationDate(final Date creationDate) {
this.creationDate = creationDate;
}
public void setAttribute(final String name, final String value) {
this.attribs.put(name, value);
}
@ -385,5 +399,7 @@ public String toString() {
/** The version of the cookie specification I was created from. */
private int cookieVersion;
private Date creationDate;
}

View File

@ -26,7 +26,10 @@
*/
package org.apache.http.impl.cookie;
import java.util.Locale;
import org.apache.http.annotation.Immutable;
import org.apache.http.conn.util.InetAddressUtils;
import org.apache.http.cookie.ClientCookie;
import org.apache.http.cookie.CommonCookieAttributeHandler;
import org.apache.http.cookie.Cookie;
@ -35,6 +38,7 @@
import org.apache.http.cookie.MalformedCookieException;
import org.apache.http.cookie.SetCookie;
import org.apache.http.util.Args;
import org.apache.http.util.TextUtils;
/**
*
@ -51,13 +55,19 @@ public BasicDomainHandler() {
public void parse(final SetCookie cookie, final String value)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
if (value == null) {
throw new MalformedCookieException("Missing value for domain attribute");
if (TextUtils.isBlank(value)) {
throw new MalformedCookieException("Blank or null value for domain attribute");
}
if (value.trim().isEmpty()) {
throw new MalformedCookieException("Blank value for domain attribute");
// Ignore domain attributes ending with '.' per RFC 6265, 4.1.2.3
if (value.endsWith(".")) {
return;
}
cookie.setDomain(value);
String domain = value;
if (domain.startsWith(".")) {
domain = domain.substring(1);
}
domain = domain.toLowerCase(Locale.ROOT);
cookie.setDomain(domain);
}
@Override
@ -71,32 +81,32 @@ public void validate(final Cookie cookie, final CookieOrigin origin)
// request-host and domain must be identical for the cookie to sent
// back to the origin-server.
final String host = origin.getHost();
String domain = cookie.getDomain();
final String domain = cookie.getDomain();
if (domain == null) {
throw new CookieRestrictionViolationException("Cookie domain may not be null");
throw new CookieRestrictionViolationException("Cookie 'domain' may not be null");
}
if (host.contains(".")) {
// Not required to have at least two dots. RFC 2965.
// A Set-Cookie2 with Domain=ajax.com will be accepted.
if (!host.equals(domain) && !domainMatch(domain, host)) {
throw new CookieRestrictionViolationException(
"Illegal 'domain' attribute \"" + domain + "\". Domain of origin: \"" + host + "\"");
}
}
// domain must match host
if (!host.endsWith(domain)) {
if (domain.startsWith(".")) {
domain = domain.substring(1, domain.length());
}
if (!host.equals(domain)) {
throw new CookieRestrictionViolationException(
"Illegal domain attribute \"" + domain
+ "\". Domain of origin: \"" + host + "\"");
}
static boolean domainMatch(final String domain, final String host) {
if (InetAddressUtils.isIPv4Address(host) || InetAddressUtils.isIPv6Address(host)) {
return false;
}
final String normalizedDomain = domain.startsWith(".") ? domain.substring(1) : domain;
if (host.endsWith(normalizedDomain)) {
final int prefix = host.length() - normalizedDomain.length();
// Either a full match or a prefix endidng with a '.'
if (prefix == 0) {
return true;
}
} else {
if (!host.equals(domain)) {
throw new CookieRestrictionViolationException(
"Illegal domain attribute \"" + domain
+ "\". Domain of origin: \"" + host + "\"");
if (prefix > 1 && host.charAt(prefix - 1) == '.') {
return true;
}
}
return false;
}
@Override
@ -108,13 +118,19 @@ public boolean match(final Cookie cookie, final CookieOrigin origin) {
if (domain == null) {
return false;
}
if (domain.startsWith(".")) {
domain = domain.substring(1);
}
domain = domain.toLowerCase(Locale.ROOT);
if (host.equals(domain)) {
return true;
}
if (!domain.startsWith(".")) {
domain = '.' + domain;
if (cookie instanceof ClientCookie) {
if (((ClientCookie) cookie).containsAttribute(ClientCookie.DOMAIN_ATTR)) {
return domainMatch(domain, host);
}
}
return host.endsWith(domain) || host.equals(domain.substring(1));
return false;
}
@Override

View File

@ -56,11 +56,11 @@ public void parse(final SetCookie cookie, final String value)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
if (value == null) {
throw new MalformedCookieException("Missing value for expires attribute");
throw new MalformedCookieException("Missing value for 'expires' attribute");
}
final Date expiry = DateUtils.parseDate(value, this.datepatterns);
if (expiry == null) {
throw new MalformedCookieException("Unable to parse expires attribute: "
throw new MalformedCookieException("Invalid 'expires' attribute: "
+ value);
}
cookie.setExpiryDate(expiry);

View File

@ -51,17 +51,17 @@ public void parse(final SetCookie cookie, final String value)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
if (value == null) {
throw new MalformedCookieException("Missing value for max-age attribute");
throw new MalformedCookieException("Missing value for 'max-age' attribute");
}
final int age;
try {
age = Integer.parseInt(value);
} catch (final NumberFormatException e) {
throw new MalformedCookieException ("Invalid max-age attribute: "
throw new MalformedCookieException ("Invalid 'max-age' attribute: "
+ value);
}
if (age < 0) {
throw new MalformedCookieException ("Negative max-age attribute: "
throw new MalformedCookieException ("Negative 'max-age' attribute: "
+ value);
}
cookie.setExpiryDate(new Date(System.currentTimeMillis() + age * 1000L));

View File

@ -60,32 +60,38 @@ public void validate(final Cookie cookie, final CookieOrigin origin)
throws MalformedCookieException {
if (!match(cookie, origin)) {
throw new CookieRestrictionViolationException(
"Illegal path attribute \"" + cookie.getPath()
"Illegal 'path' attribute \"" + cookie.getPath()
+ "\". Path of origin: \"" + origin.getPath() + "\"");
}
}
static boolean pathMatch(final String uriPath, final String cookiePath) {
String normalizedCookiePath = cookiePath;
if (normalizedCookiePath == null) {
normalizedCookiePath = "/";
}
if (normalizedCookiePath.length() > 1 && normalizedCookiePath.endsWith("/")) {
normalizedCookiePath = normalizedCookiePath.substring(0, normalizedCookiePath.length() - 1);
}
if (uriPath.startsWith(normalizedCookiePath)) {
if (normalizedCookiePath.equals("/")) {
return true;
}
if (uriPath.length() == normalizedCookiePath.length()) {
return true;
}
if (uriPath.charAt(normalizedCookiePath.length()) == '/') {
return true;
}
}
return false;
}
@Override
public boolean match(final Cookie cookie, final CookieOrigin origin) {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
final String targetpath = origin.getPath();
String topmostPath = cookie.getPath();
if (topmostPath == null) {
topmostPath = "/";
}
if (topmostPath.length() > 1 && topmostPath.endsWith("/")) {
topmostPath = topmostPath.substring(0, topmostPath.length() - 1);
}
boolean match = targetpath.startsWith (topmostPath);
// if there is a match and these values are not exactly the same we have
// to make sure we're not matcing "/foobar" and "/foo"
if (match && targetpath.length() != topmostPath.length()) {
if (!topmostPath.endsWith("/")) {
match = (targetpath.charAt(topmostPath.length()) == '/');
}
}
return match;
return pathMatch(origin.getPath(), cookie.getPath());
}
@Override

View File

@ -38,7 +38,7 @@
/**
* {@link org.apache.http.cookie.CookieSpecProvider} implementation that provides an instance of
* {@link BestMatchSpec}. The instance returned by this factory can
* {@link org.apache.http.impl.cookie.DefaultCookieSpec}. The instance returned by this factory can
* be shared by multiple threads.
*
* @since 4.4

View File

@ -0,0 +1,220 @@
/*
* ====================================================================
* 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.http.impl.cookie;
import java.util.BitSet;
import java.util.Calendar;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.http.annotation.Immutable;
import org.apache.http.cookie.ClientCookie;
import org.apache.http.cookie.CommonCookieAttributeHandler;
import org.apache.http.cookie.MalformedCookieException;
import org.apache.http.cookie.SetCookie;
import org.apache.http.message.ParserCursor;
import org.apache.http.util.Args;
/**
*
* @since 4.4
*/
@Immutable
public class LaxExpiresHandler extends AbstractCookieAttributeHandler implements CommonCookieAttributeHandler {
static final TimeZone UTC = TimeZone.getTimeZone("UTC");
private static final BitSet DELIMS;
static {
final BitSet bitSet = new BitSet();
bitSet.set(0x9);
for (int b = 0x20; b <= 0x2f; b++) {
bitSet.set(b);
}
for (int b = 0x3b; b <= 0x40; b++) {
bitSet.set(b);
}
for (int b = 0x5b; b <= 0x60; b++) {
bitSet.set(b);
}
for (int b = 0x7b; b <= 0x7e; b++) {
bitSet.set(b);
}
DELIMS = bitSet;
}
private static final Map<String, Integer> MONTHS;
static {
final ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String, Integer>(12);
map.put("jan", Calendar.JANUARY);
map.put("feb", Calendar.FEBRUARY);
map.put("mar", Calendar.MARCH);
map.put("apr", Calendar.APRIL);
map.put("may", Calendar.MAY);
map.put("jun", Calendar.JUNE);
map.put("jul", Calendar.JULY);
map.put("aug", Calendar.AUGUST);
map.put("sep", Calendar.SEPTEMBER);
map.put("oct", Calendar.OCTOBER);
map.put("nov", Calendar.NOVEMBER);
map.put("dec", Calendar.DECEMBER);
MONTHS = map;
}
private final static Pattern TIME_PATTERN = Pattern.compile(
"^([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})([^0-9].*)?$");
private final static Pattern DAY_OF_MONTH_PATTERN = Pattern.compile(
"^([0-9]{1,2})([^0-9].*)?$");
private final static Pattern MONTH_PATTERN = Pattern.compile(
"^(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)(.*)?$", Pattern.CASE_INSENSITIVE);
private final static Pattern YEAR_PATTERN = Pattern.compile(
"^([0-9]{2,4})([^0-9].*)?$");
public LaxExpiresHandler() {
super();
}
@Override
public void parse(final SetCookie cookie, final String value) throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
final ParserCursor cursor = new ParserCursor(0, value.length());
final StringBuilder content = new StringBuilder();
int second = 0, minute = 0, hour = 0, day = 0, month = 0, year = 0;
boolean foundTime = false, foundDayOfMonth = false, foundMonth = false, foundYear = false;
try {
while (!cursor.atEnd()) {
skipDelims(value, cursor);
content.setLength(0);
copyContent(value, cursor, content);
if (content.length() == 0) {
break;
}
if (!foundTime) {
final Matcher matcher = TIME_PATTERN.matcher(content);
if (matcher.matches()) {
foundTime = true;
hour = Integer.parseInt(matcher.group(1));
minute = Integer.parseInt(matcher.group(2));
second =Integer.parseInt(matcher.group(3));
continue;
}
}
if (!foundDayOfMonth) {
final Matcher matcher = DAY_OF_MONTH_PATTERN.matcher(content);
if (matcher.matches()) {
foundDayOfMonth = true;
day = Integer.parseInt(matcher.group(1));
continue;
}
}
if (!foundMonth) {
final Matcher matcher = MONTH_PATTERN.matcher(content);
if (matcher.matches()) {
foundMonth = true;
month = MONTHS.get(matcher.group(1).toLowerCase(Locale.ROOT));
continue;
}
}
if (!foundYear) {
final Matcher matcher = YEAR_PATTERN.matcher(content);
if (matcher.matches()) {
foundYear = true;
year = Integer.parseInt(matcher.group(1));
continue;
}
}
}
} catch (NumberFormatException ignore) {
throw new MalformedCookieException("Invalid 'expires' attribute: " + value);
}
if (!foundTime || !foundDayOfMonth || !foundMonth || !foundYear) {
throw new MalformedCookieException("Invalid 'expires' attribute: " + value);
}
if (year >= 70 && year <= 99) {
year = 1900 + year;
}
if (year >= 0 && year <= 69) {
year = 2000 + year;
}
if (day < 1 || day > 31 || year < 1601 || hour > 23 || minute > 59 || second > 59) {
throw new MalformedCookieException("Invalid 'expires' attribute: " + value);
}
final Calendar c = Calendar.getInstance();
c.setTimeZone(UTC);
c.setTimeInMillis(0L);
c.set(Calendar.SECOND, second);
c.set(Calendar.MINUTE, minute);
c.set(Calendar.HOUR_OF_DAY, hour);
c.set(Calendar.DAY_OF_MONTH, day);
c.set(Calendar.MONTH, month);
c.set(Calendar.YEAR, year);
cookie.setExpiryDate(c.getTime());
}
private void skipDelims(final CharSequence buf, final ParserCursor cursor) {
int pos = cursor.getPos();
final int indexFrom = cursor.getPos();
final int indexTo = cursor.getUpperBound();
for (int i = indexFrom; i < indexTo; i++) {
final char current = buf.charAt(i);
if (DELIMS.get(current)) {
pos++;
} else {
break;
}
}
cursor.updatePos(pos);
}
private void copyContent(final CharSequence buf, final ParserCursor cursor, final StringBuilder dst) {
int pos = cursor.getPos();
final int indexFrom = cursor.getPos();
final int indexTo = cursor.getUpperBound();
for (int i = indexFrom; i < indexTo; i++) {
final char current = buf.charAt(i);
if (DELIMS.get(current)) {
break;
} else {
pos++;
dst.append(current);
}
}
cursor.updatePos(pos);
}
@Override
public String getAttributeName() {
return ClientCookie.MAX_AGE_ATTR;
}
}

View File

@ -0,0 +1,79 @@
/*
* ====================================================================
* 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.http.impl.cookie;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.http.annotation.Immutable;
import org.apache.http.cookie.ClientCookie;
import org.apache.http.cookie.CommonCookieAttributeHandler;
import org.apache.http.cookie.MalformedCookieException;
import org.apache.http.cookie.SetCookie;
import org.apache.http.util.Args;
import org.apache.http.util.TextUtils;
/**
*
* @since 4.4
*/
@Immutable
public class LaxMaxAgeHandler extends AbstractCookieAttributeHandler implements CommonCookieAttributeHandler {
private final static Pattern MAX_AGE_PATTERN = Pattern.compile("^\\-?[0-9]+$");
public LaxMaxAgeHandler() {
super();
}
@Override
public void parse(final SetCookie cookie, final String value) throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
if (TextUtils.isBlank(value)) {
return;
}
final Matcher matcher = MAX_AGE_PATTERN.matcher(value);
if (matcher.matches()) {
final int age;
try {
age = Integer.parseInt(value);
} catch (final NumberFormatException e) {
return;
}
final Date expiryDate = age >= 0 ? new Date(System.currentTimeMillis() + age * 1000L) :
new Date(Long.MIN_VALUE);
cookie.setExpiryDate(expiryDate);
}
}
@Override
public String getAttributeName() {
return ClientCookie.MAX_AGE_ATTR;
}
}

View File

@ -30,30 +30,45 @@
import java.util.StringTokenizer;
import org.apache.http.annotation.Immutable;
import org.apache.http.cookie.ClientCookie;
import org.apache.http.cookie.CommonCookieAttributeHandler;
import org.apache.http.cookie.Cookie;
import org.apache.http.cookie.CookieOrigin;
import org.apache.http.cookie.CookieRestrictionViolationException;
import org.apache.http.cookie.MalformedCookieException;
import org.apache.http.cookie.SetCookie;
import org.apache.http.util.Args;
import org.apache.http.util.TextUtils;
/**
*
* @since 4.0
*/
@Immutable
public class NetscapeDomainHandler extends BasicDomainHandler {
public class NetscapeDomainHandler implements CommonCookieAttributeHandler {
public NetscapeDomainHandler() {
super();
}
@Override
public void parse(final SetCookie cookie, final String value) throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
if (TextUtils.isBlank(value)) {
throw new MalformedCookieException("Blank or null value for domain attribute");
}
cookie.setDomain(value);
}
@Override
public void validate(final Cookie cookie, final CookieOrigin origin)
throws MalformedCookieException {
super.validate(cookie, origin);
// Perform Netscape Cookie draft specific validation
final String host = origin.getHost();
final String domain = cookie.getDomain();
if (!host.equals(domain) && !BasicDomainHandler.domainMatch(domain, host)) {
throw new CookieRestrictionViolationException(
"Illegal domain attribute \"" + domain + "\". Domain of origin: \"" + host + "\"");
}
if (host.contains(".")) {
final int domainParts = new StringTokenizer(domain, ".").countTokens();
@ -103,4 +118,9 @@ public boolean match(final Cookie cookie, final CookieOrigin origin) {
return host.endsWith(domain);
}
@Override
public String getAttributeName() {
return ClientCookie.DOMAIN_ATTR;
}
}

View File

@ -59,8 +59,6 @@
@ThreadSafe
public class RFC2109Spec extends CookieSpecBase {
private final static CookiePathComparator PATH_COMPARATOR = new CookiePathComparator();
final static String[] DATE_PATTERNS = {
DateUtils.PATTERN_RFC1123,
DateUtils.PATTERN_RFC1036,
@ -127,7 +125,7 @@ public List<Header> formatCookies(final List<Cookie> cookies) {
if (cookies.size() > 1) {
// Create a mutable copy and sort the copy.
cookieList = new ArrayList<Cookie>(cookies);
Collections.sort(cookieList, PATH_COMPARATOR);
Collections.sort(cookieList, CookiePathComparator.INSTANCE);
} else {
cookieList = cookies;
}

View File

@ -0,0 +1,276 @@
/*
* ====================================================================
* 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.http.impl.cookie;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.http.FormattedHeader;
import org.apache.http.Header;
import org.apache.http.annotation.ThreadSafe;
import org.apache.http.cookie.ClientCookie;
import org.apache.http.cookie.CommonCookieAttributeHandler;
import org.apache.http.cookie.Cookie;
import org.apache.http.cookie.CookieAttributeHandler;
import org.apache.http.cookie.CookieOrigin;
import org.apache.http.cookie.CookiePriorityComparator;
import org.apache.http.cookie.CookieSpec;
import org.apache.http.cookie.MalformedCookieException;
import org.apache.http.cookie.SM;
import org.apache.http.message.BufferedHeader;
import org.apache.http.message.ParserCursor;
import org.apache.http.message.TokenParser;
import org.apache.http.util.Args;
import org.apache.http.util.CharArrayBuffer;
/**
* Cookie management functions shared by RFC C6265 compliant specification.
*
* @since 4.4
*/
@ThreadSafe
class RFC6265CookieSpecBase implements CookieSpec {
private final static char PARAM_DELIMITER = ';';
private final static char COMMA_CHAR = ',';
private final static char EQUAL_CHAR = '=';
private final static char DQUOTE_CHAR = '"';
private final static char ESCAPE_CHAR = '\\';
// IMPORTANT!
// These private static variables must be treated as immutable and never exposed outside this class
private static final BitSet TOKEN_DELIMS = TokenParser.INIT_BITSET(EQUAL_CHAR, PARAM_DELIMITER);
private static final BitSet VALUE_DELIMS = TokenParser.INIT_BITSET(PARAM_DELIMITER);
private static final BitSet SPECIAL_CHARS = TokenParser.INIT_BITSET(' ',
DQUOTE_CHAR, COMMA_CHAR, PARAM_DELIMITER, ESCAPE_CHAR);
private final CookieAttributeHandler[] attribHandlers;
private final Map<String, CookieAttributeHandler> attribHandlerMap;
private final TokenParser tokenParser;
RFC6265CookieSpecBase(final CommonCookieAttributeHandler... handlers) {
super();
this.attribHandlers = handlers.clone();
this.attribHandlerMap = new ConcurrentHashMap<String, CookieAttributeHandler>(handlers.length);
for (CommonCookieAttributeHandler handler: handlers) {
this.attribHandlerMap.put(handler.getAttributeName().toLowerCase(Locale.ROOT), handler);
}
this.tokenParser = TokenParser.INSTANCE;
}
static String getDefaultPath(final CookieOrigin origin) {
String defaultPath = origin.getPath();
int lastSlashIndex = defaultPath.lastIndexOf('/');
if (lastSlashIndex >= 0) {
if (lastSlashIndex == 0) {
//Do not remove the very first slash
lastSlashIndex = 1;
}
defaultPath = defaultPath.substring(0, lastSlashIndex);
}
return defaultPath;
}
static String getDefaultDomain(final CookieOrigin origin) {
return origin.getHost();
}
@Override
public final List<Cookie> parse(final Header header, final CookieOrigin origin) throws MalformedCookieException {
Args.notNull(header, "Header");
Args.notNull(origin, "Cookie origin");
if (!header.getName().equalsIgnoreCase(SM.SET_COOKIE)) {
throw new MalformedCookieException("Unrecognized cookie header: '" + header.toString() + "'");
}
final CharArrayBuffer buffer;
final ParserCursor cursor;
if (header instanceof FormattedHeader) {
buffer = ((FormattedHeader) header).getBuffer();
cursor = new ParserCursor(((FormattedHeader) header).getValuePos(), buffer.length());
} else {
final String s = header.getValue();
if (s == null) {
throw new MalformedCookieException("Header value is null");
}
buffer = new CharArrayBuffer(s.length());
buffer.append(s);
cursor = new ParserCursor(0, buffer.length());
}
final String name = tokenParser.parseToken(buffer, cursor, TOKEN_DELIMS);
if (name.length() == 0) {
throw new MalformedCookieException("Cookie name is invalid: '" + header.toString() + "'");
}
if (cursor.atEnd()) {
throw new MalformedCookieException("Cookie value is invalid: '" + header.toString() + "'");
}
final int valueDelim = buffer.charAt(cursor.getPos());
cursor.updatePos(cursor.getPos() + 1);
if (valueDelim != '=') {
throw new MalformedCookieException("Cookie value is invalid: '" + header.toString() + "'");
}
final String value = tokenParser.parseValue(buffer, cursor, VALUE_DELIMS);
if (!cursor.atEnd()) {
cursor.updatePos(cursor.getPos() + 1);
}
final BasicClientCookie cookie = new BasicClientCookie(name, value);
cookie.setPath(getDefaultPath(origin));
cookie.setDomain(getDefaultDomain(origin));
cookie.setCreationDate(new Date());
final Map<String, String> attribMap = new LinkedHashMap<String, String>();
while (!cursor.atEnd()) {
final String paramName = tokenParser.parseToken(buffer, cursor, TOKEN_DELIMS);
String paramValue = null;
if (!cursor.atEnd()) {
final int paramDelim = buffer.charAt(cursor.getPos());
cursor.updatePos(cursor.getPos() + 1);
if (paramDelim == EQUAL_CHAR) {
paramValue = tokenParser.parseToken(buffer, cursor, VALUE_DELIMS);
if (!cursor.atEnd()) {
cursor.updatePos(cursor.getPos() + 1);
}
}
}
cookie.setAttribute(paramName.toLowerCase(Locale.ROOT), paramValue);
attribMap.put(paramName, paramValue);
}
// Ignore 'Expires' if 'Max-Age' is present
if (attribMap.containsKey(ClientCookie.MAX_AGE_ATTR)) {
attribMap.remove(ClientCookie.EXPIRES_ATTR);
}
for (Map.Entry<String, String> entry: attribMap.entrySet()) {
final String paramName = entry.getKey();
final String paramValue = entry.getValue();
final CookieAttributeHandler handler = this.attribHandlerMap.get(paramName);
if (handler != null) {
handler.parse(cookie, paramValue);
}
}
return Collections.<Cookie>singletonList(cookie);
}
@Override
public final void validate(final Cookie cookie, final CookieOrigin origin)
throws MalformedCookieException {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
for (final CookieAttributeHandler handler: this.attribHandlers) {
handler.validate(cookie, origin);
}
}
@Override
public final boolean match(final Cookie cookie, final CookieOrigin origin) {
Args.notNull(cookie, "Cookie");
Args.notNull(origin, "Cookie origin");
for (final CookieAttributeHandler handler: this.attribHandlers) {
if (!handler.match(cookie, origin)) {
return false;
}
}
return true;
}
@Override
public List<Header> formatCookies(final List<Cookie> cookies) {
Args.notEmpty(cookies, "List of cookies");
final List<? extends Cookie> sortedCookies;
if (cookies.size() > 1) {
// Create a mutable copy and sort the copy.
sortedCookies = new ArrayList<Cookie>(cookies);
Collections.sort(sortedCookies, CookiePriorityComparator.INSTANCE);
} else {
sortedCookies = cookies;
}
final CharArrayBuffer buffer = new CharArrayBuffer(20 * sortedCookies.size());
buffer.append(SM.COOKIE);
buffer.append(": ");
for (int n = 0; n < sortedCookies.size(); n++) {
final Cookie cookie = sortedCookies.get(n);
if (n > 0) {
buffer.append(PARAM_DELIMITER);
buffer.append(' ');
}
buffer.append(cookie.getName());
final String s = cookie.getValue();
if (s != null) {
buffer.append(EQUAL_CHAR);
if (containsSpecialChar(s)) {
buffer.append(DQUOTE_CHAR);
for (int i = 0; i < s.length(); i++) {
final char ch = s.charAt(i);
if (ch == DQUOTE_CHAR || ch == ESCAPE_CHAR) {
buffer.append(ESCAPE_CHAR);
}
buffer.append(ch);
}
buffer.append(DQUOTE_CHAR);
} else {
buffer.append(s);
}
}
}
final List<Header> headers = new ArrayList<Header>(1);
headers.add(new BufferedHeader(buffer));
return headers;
}
boolean containsSpecialChar(final CharSequence s) {
return containsChars(s, SPECIAL_CHARS);
}
boolean containsChars(final CharSequence s, final BitSet chars) {
for (int i = 0; i < s.length(); i++) {
final char ch = s.charAt(i);
if (chars.get(ch)) {
return true;
}
}
return false;
}
@Override
public final int getVersion() {
return 0;
}
@Override
public final Header getVersionHeader() {
return null;
}
}

View File

@ -0,0 +1,120 @@
/*
* ====================================================================
* 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.http.impl.cookie;
import org.apache.http.annotation.Immutable;
import org.apache.http.conn.util.PublicSuffixMatcher;
import org.apache.http.cookie.Cookie;
import org.apache.http.cookie.CookieOrigin;
import org.apache.http.cookie.CookieSpec;
import org.apache.http.cookie.CookieSpecProvider;
import org.apache.http.cookie.MalformedCookieException;
import org.apache.http.protocol.HttpContext;
/**
* {@link org.apache.http.cookie.CookieSpecProvider} implementation that provides an instance of
* RFC 6265 conformant cookie policy. The instance returned by this factory can be shared by
* multiple threads.
*
* @since 4.4
*/
@Immutable
public class RFC6265CookieSpecProvider implements CookieSpecProvider {
public enum CompatibilityLevel {
STRICT,
RELAXED,
IE_MEDIUM_SECURITY
}
private final CompatibilityLevel compatibilityLevel;
private final PublicSuffixMatcher publicSuffixMatcher;
private volatile CookieSpec cookieSpec;
public RFC6265CookieSpecProvider(
final CompatibilityLevel compatibilityLevel,
final PublicSuffixMatcher publicSuffixMatcher) {
super();
this.compatibilityLevel = compatibilityLevel != null ? compatibilityLevel : CompatibilityLevel.RELAXED;
this.publicSuffixMatcher = publicSuffixMatcher;
}
public RFC6265CookieSpecProvider(final PublicSuffixMatcher publicSuffixMatcher) {
this(CompatibilityLevel.RELAXED, publicSuffixMatcher);
}
public RFC6265CookieSpecProvider() {
this(CompatibilityLevel.RELAXED, null);
}
@Override
public CookieSpec create(final HttpContext context) {
if (cookieSpec == null) {
synchronized (this) {
if (cookieSpec == null) {
switch (this.compatibilityLevel) {
case STRICT:
this.cookieSpec = new RFC6265StrictSpec(
new BasicPathHandler(),
PublicSuffixDomainFilter.decorate(
new BasicDomainHandler(), this.publicSuffixMatcher),
new BasicMaxAgeHandler(),
new BasicSecureHandler(),
new BasicExpiresHandler(RFC6265StrictSpec.DATE_PATTERNS));
case IE_MEDIUM_SECURITY:
this.cookieSpec = new RFC6265LaxSpec(
new BasicPathHandler() {
@Override
public void validate(
final Cookie cookie,
final CookieOrigin origin) throws MalformedCookieException {
// No validation
}
},
PublicSuffixDomainFilter.decorate(
new BasicDomainHandler(), this.publicSuffixMatcher),
new BasicMaxAgeHandler(),
new BasicSecureHandler(),
new BasicExpiresHandler(RFC6265StrictSpec.DATE_PATTERNS));
default:
this.cookieSpec = new RFC6265LaxSpec(
new BasicPathHandler(),
PublicSuffixDomainFilter.decorate(
new BasicDomainHandler(), this.publicSuffixMatcher),
new LaxMaxAgeHandler(),
new BasicSecureHandler(),
new LaxExpiresHandler());
}
}
}
}
return this.cookieSpec;
}
}

View File

@ -0,0 +1,61 @@
/*
* ====================================================================
* 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.http.impl.cookie;
import org.apache.http.annotation.ThreadSafe;
import org.apache.http.cookie.CommonCookieAttributeHandler;
/**
* Standard {@link org.apache.http.cookie.CookieSpec} implementation that enforces a more relaxed
* interpretation of the HTTP state management specification (RFC 6265, section 5)
* for interoprability with existing servers that do not conform to the well behaved profile
* (RFC 6265, section 4).
*
* @since 4.4
*/
@ThreadSafe
public class RFC6265LaxSpec extends RFC6265CookieSpecBase {
public RFC6265LaxSpec() {
super(new BasicPathHandler(),
new BasicDomainHandler(),
new LaxMaxAgeHandler(),
new BasicSecureHandler(),
new LaxExpiresHandler());
}
RFC6265LaxSpec(final CommonCookieAttributeHandler... handlers) {
super(handlers);
}
@Override
public String toString() {
return "rfc6265-lax";
}
}

View File

@ -0,0 +1,67 @@
/*
* ====================================================================
* 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.http.impl.cookie;
import org.apache.http.annotation.ThreadSafe;
import org.apache.http.client.utils.DateUtils;
import org.apache.http.cookie.CommonCookieAttributeHandler;
/**
* Standard {@link org.apache.http.cookie.CookieSpec} implementation that enforces syntax
* and semantics of the well-behaved profile of the HTTP state management specification
* (RFC 6265, section 4).
*
* @since 4.4
*/
@ThreadSafe
public class RFC6265StrictSpec extends RFC6265CookieSpecBase {
final static String[] DATE_PATTERNS = {
DateUtils.PATTERN_RFC1123,
DateUtils.PATTERN_RFC1036,
DateUtils.PATTERN_ASCTIME
};
public RFC6265StrictSpec() {
super(new BasicPathHandler(),
new BasicDomainHandler(),
new BasicMaxAgeHandler(),
new BasicSecureHandler(),
new BasicExpiresHandler(DATE_PATTERNS));
}
RFC6265StrictSpec(final CommonCookieAttributeHandler... handlers) {
super(handlers);
}
@Override
public String toString() {
return "rfc6265-strict";
}
}

View File

@ -57,6 +57,7 @@
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
public class TestRequestAddCookies {
@ -371,10 +372,13 @@ public void testExcludeExpiredCookies() throws Exception {
cookie3.setVersion(1);
cookie3.setDomain("localhost.local");
cookie3.setPath("/");
cookie3.setExpiryDate(new Date(System.currentTimeMillis() - (24 * 60 * 60 * 1000)));
cookie3.setExpiryDate(new Date(System.currentTimeMillis() + 100));
this.cookieStore.addCookie(cookie3);
Assert.assertEquals(3, this.cookieStore.getCookies().size());
this.cookieStore = Mockito.spy(this.cookieStore);
final HttpRoute route = new HttpRoute(this.target, null, false);
final HttpClientContext context = HttpClientContext.create();
@ -383,6 +387,9 @@ public void testExcludeExpiredCookies() throws Exception {
context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
// Make sure the third cookie expires
Thread.sleep(200);
final HttpRequestInterceptor interceptor = new RequestAddCookies();
interceptor.process(request, context);
@ -394,6 +401,8 @@ public void testExcludeExpiredCookies() throws Exception {
final Header[] headers2 = request.getHeaders(SM.COOKIE2);
Assert.assertNotNull(headers2);
Assert.assertEquals(0, headers2.length);
Mockito.verify(this.cookieStore, Mockito.times(1)).clearExpired(Mockito.<Date>any());
}
@Test

View File

@ -0,0 +1,113 @@
/*
* ====================================================================
* 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.http.cookie;
import java.util.Comparator;
import java.util.Date;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* Test cases for {@link org.apache.http.cookie.CookiePriorityComparator}.
*/
public class TestCookiePriorityComparator {
private Comparator<Cookie> comparator;
@Before
public void setup() {
comparator = CookiePriorityComparator.INSTANCE;
}
@Test
public void testUnequality() {
final BasicClientCookie cookie1 = new BasicClientCookie("name1", "value");
cookie1.setPath("/a/b/");
final BasicClientCookie cookie2 = new BasicClientCookie("name1", "value");
cookie2.setPath("/a/");
Assert.assertTrue(comparator.compare(cookie1, cookie2) < 0);
Assert.assertTrue(comparator.compare(cookie2, cookie1) > 0);
}
@Test
public void testEquality() {
final BasicClientCookie cookie1 = new BasicClientCookie("name1", "value");
cookie1.setPath("/a");
final BasicClientCookie cookie2 = new BasicClientCookie("name1", "value");
cookie2.setPath("/a");
Assert.assertTrue(comparator.compare(cookie1, cookie2) == 0);
Assert.assertTrue(comparator.compare(cookie2, cookie1) == 0);
}
@Test
public void testUnequalityTrailingSlash() {
final BasicClientCookie cookie1 = new BasicClientCookie("name1", "value");
cookie1.setPath("/a/");
final BasicClientCookie cookie2 = new BasicClientCookie("name1", "value");
cookie2.setPath("/a");
Assert.assertTrue(comparator.compare(cookie1, cookie2) < 0);
Assert.assertTrue(comparator.compare(cookie2, cookie1) > 0);
}
@Test
public void testEqualityNullPath() {
final BasicClientCookie cookie1 = new BasicClientCookie("name1", "value");
cookie1.setPath(null);
final BasicClientCookie cookie2 = new BasicClientCookie("name1", "value");
cookie2.setPath("/");
Assert.assertTrue(comparator.compare(cookie1, cookie2) == 0);
Assert.assertTrue(comparator.compare(cookie2, cookie1) == 0);
}
@Test
public void testEqualitySameLength() {
final BasicClientCookie cookie1 = new BasicClientCookie("name1", "value");
cookie1.setPath("/this");
final BasicClientCookie cookie2 = new BasicClientCookie("name1", "value");
cookie2.setPath("/that");
Assert.assertTrue(comparator.compare(cookie1, cookie2) == 0);
Assert.assertTrue(comparator.compare(cookie2, cookie1) == 0);
}
@Test
public void testUnequalityCreationDate() {
final BasicClientCookie cookie1 = new BasicClientCookie("name1", "value");
cookie1.setPath("/blah");
cookie1.setCreationDate(new Date(System.currentTimeMillis() - 200000));
final BasicClientCookie cookie2 = new BasicClientCookie("name1", "value");
cookie2.setPath("/blah");
cookie2.setCreationDate(new Date(System.currentTimeMillis()));
Assert.assertTrue(comparator.compare(cookie1, cookie2) < 0);
Assert.assertTrue(comparator.compare(cookie2, cookie1) > 0);
}
}

View File

@ -1,143 +0,0 @@
/*
* ====================================================================
* 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.http.impl.cookie;
import java.util.Iterator;
import java.util.List;
import org.apache.http.Header;
import org.apache.http.cookie.Cookie;
import org.apache.http.cookie.CookieAttributeHandler;
import org.apache.http.cookie.CookieOrigin;
import org.apache.http.cookie.MalformedCookieException;
import org.apache.http.cookie.SetCookie;
import org.junit.Assert;
import org.junit.Test;
public class TestAbstractCookieSpec {
private static class DummyCookieSpec extends AbstractCookieSpec {
@Override
public List<Header> formatCookies(final List<Cookie> cookies) {
return null;
}
@Override
public boolean match(final Cookie cookie, final CookieOrigin origin) {
return true;
}
@Override
public List<Cookie> parse(final Header header, final CookieOrigin origin) throws MalformedCookieException {
return null;
}
@Override
public void validate(final Cookie cookie, final CookieOrigin origin) throws MalformedCookieException {
}
@Override
public int getVersion() {
return 0;
}
@Override
public Header getVersionHeader() {
return null;
}
}
private static class DummyCookieAttribHandler implements CookieAttributeHandler {
@Override
public boolean match(final Cookie cookie, final CookieOrigin origin) {
return true;
}
@Override
public void parse(final SetCookie cookie, final String value) throws MalformedCookieException {
}
@Override
public void validate(final Cookie cookie, final CookieOrigin origin) throws MalformedCookieException {
}
}
@Test
public void testSimpleRegisterAndGet() {
final CookieAttributeHandler h1 = new DummyCookieAttribHandler();
final CookieAttributeHandler h2 = new DummyCookieAttribHandler();
final AbstractCookieSpec cookiespec = new DummyCookieSpec();
cookiespec.registerAttribHandler("this", h1);
cookiespec.registerAttribHandler("that", h2);
cookiespec.registerAttribHandler("thistoo", h1);
cookiespec.registerAttribHandler("thattoo", h2);
Assert.assertTrue(h1 == cookiespec.getAttribHandler("this"));
Assert.assertTrue(h2 == cookiespec.getAttribHandler("that"));
Assert.assertTrue(h1 == cookiespec.getAttribHandler("thistoo"));
Assert.assertTrue(h2 == cookiespec.getAttribHandler("thattoo"));
final Iterator<CookieAttributeHandler> it = cookiespec.getAttribHandlers().iterator();
Assert.assertNotNull(it.next());
Assert.assertNotNull(it.next());
Assert.assertNotNull(it.next());
Assert.assertNotNull(it.next());
Assert.assertFalse(it.hasNext());
}
@Test(expected=IllegalStateException.class)
public void testInvalidHandler() {
final CookieAttributeHandler h1 = new DummyCookieAttribHandler();
final CookieAttributeHandler h2 = new DummyCookieAttribHandler();
final AbstractCookieSpec cookiespec = new DummyCookieSpec();
cookiespec.registerAttribHandler("this", h1);
cookiespec.registerAttribHandler("that", h2);
Assert.assertNull(cookiespec.findAttribHandler("whatever"));
cookiespec.getAttribHandler("whatever");
}
@Test(expected=IllegalArgumentException.class)
public void testBasicPathInvalidInput1() throws Exception {
final AbstractCookieSpec cookiespec = new DummyCookieSpec();
cookiespec.registerAttribHandler(null, null);
}
@Test(expected=IllegalArgumentException.class)
public void testBasicPathInvalidInput2() throws Exception {
final AbstractCookieSpec cookiespec = new DummyCookieSpec();
cookiespec.registerAttribHandler("whatever", null);
}
}

View File

@ -35,6 +35,7 @@
import org.apache.http.client.utils.DateUtils;
import org.apache.http.conn.util.PublicSuffixMatcher;
import org.apache.http.cookie.ClientCookie;
import org.apache.http.cookie.CookieAttributeHandler;
import org.apache.http.cookie.CookieOrigin;
import org.apache.http.cookie.MalformedCookieException;
@ -140,6 +141,7 @@ public void testBasicDomainMatch1() throws Exception {
final CookieAttributeHandler h = new BasicDomainHandler();
cookie.setDomain("somedomain.com");
cookie.setAttribute(ClientCookie.DOMAIN_ATTR, "somedomain.com");
Assert.assertTrue(h.match(cookie, origin));
cookie.setDomain(".somedomain.com");
@ -153,6 +155,7 @@ public void testBasicDomainMatch2() throws Exception {
final CookieAttributeHandler h = new BasicDomainHandler();
cookie.setDomain("somedomain.com");
cookie.setAttribute(ClientCookie.DOMAIN_ATTR, "somedomain.com");
Assert.assertTrue(h.match(cookie, origin));
cookie.setDomain(".somedomain.com");
@ -162,6 +165,28 @@ public void testBasicDomainMatch2() throws Exception {
Assert.assertFalse(h.match(cookie, origin));
}
@Test
public void testBasicDomainMatchOneLetterPrefix() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieOrigin origin = new CookieOrigin("a.somedomain.com", 80, "/", false);
final CookieAttributeHandler h = new BasicDomainHandler();
cookie.setDomain("somedomain.com");
cookie.setAttribute(ClientCookie.DOMAIN_ATTR, "somedomain.com");
Assert.assertTrue(h.match(cookie, origin));
}
@Test
public void testBasicDomainMatchMixedCase() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieOrigin origin = new CookieOrigin("a.SomeDomain.com", 80, "/", false);
final CookieAttributeHandler h = new BasicDomainHandler();
cookie.setDomain("somedoMain.Com");
cookie.setAttribute(ClientCookie.DOMAIN_ATTR, "somedoMain.Com");
Assert.assertTrue(h.match(cookie, origin));
}
@Test
public void testBasicDomainInvalidInput() throws Exception {
final CookieAttributeHandler h = new BasicDomainHandler();

View File

@ -0,0 +1,317 @@
/*
* ====================================================================
* 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.http.impl.cookie;
import java.util.Calendar;
import java.util.Date;
import org.apache.http.cookie.CookieAttributeHandler;
import org.apache.http.cookie.MalformedCookieException;
import org.junit.Assert;
import org.junit.Test;
public class TestLaxCookieAttribHandlers {
@Test
public void testParseMaxAge() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxMaxAgeHandler();
h.parse(cookie, "2000");
Assert.assertNotNull(cookie.getExpiryDate());
}
@Test
public void testParseMaxNegative() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxMaxAgeHandler();
h.parse(cookie, "-2000");
Assert.assertNotNull(cookie.getExpiryDate());
}
@Test
public void testParseMaxZero() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxMaxAgeHandler();
h.parse(cookie, "0000");
Assert.assertNotNull(cookie.getExpiryDate());
}
@Test
public void testBasicMaxAgeParseEmpty() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxMaxAgeHandler();
h.parse(cookie, " ");
Assert.assertNull(cookie.getExpiryDate());
}
@Test
public void testBasicMaxAgeParseInvalid() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxMaxAgeHandler();
h.parse(cookie, "garbage");
Assert.assertNull(cookie.getExpiryDate());
}
@Test
public void testBasicMaxAgeInvalidInput() throws Exception {
final CookieAttributeHandler h = new LaxMaxAgeHandler();
try {
h.parse(null, "stuff");
Assert.fail("IllegalArgumentException must have been thrown");
} catch (final IllegalArgumentException ex) {
// expected
}
}
@Test(expected = MalformedCookieException.class)
public void testExpiryGarbage() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, ";;blah,blah;yada ");
}
@Test
public void testParseExpiry() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, "1:0:12 8-jan-2012");
final Date expiryDate = cookie.getExpiryDate();
Assert.assertNotNull(expiryDate);
final Calendar c = Calendar.getInstance();
c.setTimeZone(LaxExpiresHandler.UTC);
c.setTime(expiryDate);
Assert.assertEquals(2012, c.get(Calendar.YEAR));
Assert.assertEquals(Calendar.JANUARY, c.get(Calendar.MONTH));
Assert.assertEquals(8, c.get(Calendar.DAY_OF_MONTH));
Assert.assertEquals(1, c.get(Calendar.HOUR_OF_DAY));
Assert.assertEquals(0, c.get(Calendar.MINUTE));
Assert.assertEquals(12, c.get(Calendar.SECOND));
Assert.assertEquals(0, c.get(Calendar.MILLISECOND));
}
@Test(expected = MalformedCookieException.class)
public void testParseExpiryInvalidTime1() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, "1:0:122 8 dec 1980");
}
@Test(expected = MalformedCookieException.class)
public void testParseExpiryInvalidTime2() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, "24:00:00 8 dec 1980");
}
@Test(expected = MalformedCookieException.class)
public void testParseExpiryInvalidTime3() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, "23:60:00 8 dec 1980");
}
@Test(expected = MalformedCookieException.class)
public void testParseExpiryInvalidTime4() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, "23:00:60 8 dec 1980");
}
@Test
public void testParseExpiryFunnyTime() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, "1:59:00blah; 8-feb-2000");
final Date expiryDate = cookie.getExpiryDate();
Assert.assertNotNull(expiryDate);
final Calendar c = Calendar.getInstance();
c.setTimeZone(LaxExpiresHandler.UTC);
c.setTime(expiryDate);
Assert.assertEquals(2000, c.get(Calendar.YEAR));
Assert.assertEquals(Calendar.FEBRUARY, c.get(Calendar.MONTH));
Assert.assertEquals(8, c.get(Calendar.DAY_OF_MONTH));
Assert.assertEquals(1, c.get(Calendar.HOUR_OF_DAY));
Assert.assertEquals(59, c.get(Calendar.MINUTE));
Assert.assertEquals(0, c.get(Calendar.SECOND));
Assert.assertEquals(0, c.get(Calendar.MILLISECOND));
}
@Test(expected = MalformedCookieException.class)
public void testParseExpiryInvalidDayOfMonth1() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, "12:00:00 888 mar 1880");
}
@Test(expected = MalformedCookieException.class)
public void testParseExpiryInvalidDayOfMonth2() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, "12:00:00 0 mar 1880");
}
@Test(expected = MalformedCookieException.class)
public void testParseExpiryInvalidDayOfMonth3() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, "12:00:00 32 mar 1880");
}
@Test
public void testParseExpiryFunnyDayOfMonth() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, "12:00:00 8blah;mar;1880");
final Date expiryDate = cookie.getExpiryDate();
Assert.assertNotNull(expiryDate);
final Calendar c = Calendar.getInstance();
c.setTimeZone(LaxExpiresHandler.UTC);
c.setTime(expiryDate);
Assert.assertEquals(1880, c.get(Calendar.YEAR));
Assert.assertEquals(Calendar.MARCH, c.get(Calendar.MONTH));
Assert.assertEquals(8, c.get(Calendar.DAY_OF_MONTH));
Assert.assertEquals(12, c.get(Calendar.HOUR_OF_DAY));
Assert.assertEquals(0, c.get(Calendar.MINUTE));
Assert.assertEquals(0, c.get(Calendar.SECOND));
Assert.assertEquals(0, c.get(Calendar.MILLISECOND));
}
@Test(expected = MalformedCookieException.class)
public void testParseExpiryInvalidMonth() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, "1:00:00 8 dek 80");
}
@Test
public void testParseExpiryFunnyMonth() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, "23:59:59; 1-ApriLLLLL-2008");
final Date expiryDate = cookie.getExpiryDate();
Assert.assertNotNull(expiryDate);
final Calendar c = Calendar.getInstance();
c.setTimeZone(LaxExpiresHandler.UTC);
c.setTime(expiryDate);
Assert.assertEquals(2008, c.get(Calendar.YEAR));
Assert.assertEquals(Calendar.APRIL, c.get(Calendar.MONTH));
Assert.assertEquals(1, c.get(Calendar.DAY_OF_MONTH));
Assert.assertEquals(23, c.get(Calendar.HOUR_OF_DAY));
Assert.assertEquals(59, c.get(Calendar.MINUTE));
Assert.assertEquals(59, c.get(Calendar.SECOND));
Assert.assertEquals(0, c.get(Calendar.MILLISECOND));
}
@Test(expected = MalformedCookieException.class)
public void testParseExpiryInvalidYearTooShort() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, "1:00:00 8 dec 8");
}
@Test(expected = MalformedCookieException.class)
public void testParseExpiryInvalidYearTooLong() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, "1:00:00 8 dec 88888");
}
@Test(expected = MalformedCookieException.class)
public void testParseExpiryInvalidYearTooLongAgo() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, "1:00:00 8 dec 1600");
}
@Test
public void testParseExpiryFunnyYear() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, "23:59:59; 1-Apr-2008blah");
final Date expiryDate = cookie.getExpiryDate();
Assert.assertNotNull(expiryDate);
final Calendar c = Calendar.getInstance();
c.setTimeZone(LaxExpiresHandler.UTC);
c.setTime(expiryDate);
Assert.assertEquals(2008, c.get(Calendar.YEAR));
Assert.assertEquals(Calendar.APRIL, c.get(Calendar.MONTH));
Assert.assertEquals(1, c.get(Calendar.DAY_OF_MONTH));
Assert.assertEquals(23, c.get(Calendar.HOUR_OF_DAY));
Assert.assertEquals(59, c.get(Calendar.MINUTE));
Assert.assertEquals(59, c.get(Calendar.SECOND));
Assert.assertEquals(0, c.get(Calendar.MILLISECOND));
}
@Test
public void testParseExpiryYearTwoDigit1() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, "23:59:59; 1-Apr-70");
final Date expiryDate = cookie.getExpiryDate();
Assert.assertNotNull(expiryDate);
final Calendar c = Calendar.getInstance();
c.setTimeZone(LaxExpiresHandler.UTC);
c.setTime(expiryDate);
Assert.assertEquals(1970, c.get(Calendar.YEAR));
}
@Test
public void testParseExpiryYearTwoDigit2() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, "23:59:59; 1-Apr-99");
final Date expiryDate = cookie.getExpiryDate();
Assert.assertNotNull(expiryDate);
final Calendar c = Calendar.getInstance();
c.setTimeZone(LaxExpiresHandler.UTC);
c.setTime(expiryDate);
Assert.assertEquals(1999, c.get(Calendar.YEAR));
}
@Test
public void testParseExpiryYearTwoDigit3() throws Exception {
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
final CookieAttributeHandler h = new LaxExpiresHandler();
h.parse(cookie, "23:59:59; 1-Apr-00");
final Date expiryDate = cookie.getExpiryDate();
Assert.assertNotNull(expiryDate);
final Calendar c = Calendar.getInstance();
c.setTimeZone(LaxExpiresHandler.UTC);
c.setTime(expiryDate);
Assert.assertEquals(2000, c.get(Calendar.YEAR));
}
}

View File

@ -0,0 +1,337 @@
/*
* ====================================================================
* 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.http.impl.cookie;
import java.util.Arrays;
import java.util.List;
import org.apache.http.Header;
import org.apache.http.cookie.ClientCookie;
import org.apache.http.cookie.CommonCookieAttributeHandler;
import org.apache.http.cookie.Cookie;
import org.apache.http.cookie.CookieOrigin;
import org.apache.http.cookie.MalformedCookieException;
import org.apache.http.cookie.SetCookie;
import org.apache.http.message.BasicHeader;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
public class TestRFC6265CookieSpecBase {
@Test
public void testParseCookieBasics() throws Exception {
final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
Mockito.when(h1.getAttributeName()).thenReturn("this");
final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
Mockito.when(h2.getAttributeName()).thenReturn("that");
final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase(h1, h2);
final Header header = new BasicHeader("Set-Cookie", "name = value ; this = stuff;");
final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
final List<Cookie> cookies = cookiespec.parse(header, origin);
Assert.assertEquals(1, cookies.size());
final Cookie cookie = cookies.get(0);
Assert.assertEquals("name", cookie.getName());
Assert.assertEquals("value", cookie.getValue());
Assert.assertEquals("/path", cookie.getPath());
Assert.assertEquals("host", cookie.getDomain());
Assert.assertTrue(cookie instanceof ClientCookie);
final ClientCookie clientCookie = (ClientCookie) cookie;
Assert.assertEquals("stuff", clientCookie.getAttribute("this"));
Assert.assertEquals(null, clientCookie.getAttribute("that"));
Mockito.verify(h1).parse(Mockito.<SetCookie>any(), Mockito.eq("stuff"));
Mockito.verify(h2, Mockito.never()).parse(Mockito.<SetCookie>any(), Mockito.anyString());
}
@Test
public void testParseCookieQuotedValue() throws Exception {
final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase();
final Header header = new BasicHeader("Set-Cookie", "name = \" one, two, three; four \" ; this = stuff;");
final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
final List<Cookie> cookies = cookiespec.parse(header, origin);
Assert.assertEquals(1, cookies.size());
final Cookie cookie = cookies.get(0);
Assert.assertEquals("name", cookie.getName());
Assert.assertEquals(" one, two, three; four ", cookie.getValue());
Assert.assertTrue(cookie instanceof ClientCookie);
final ClientCookie clientCookie = (ClientCookie) cookie;
Assert.assertEquals("stuff", clientCookie.getAttribute("this"));
}
@Test(expected = MalformedCookieException.class)
public void testParseCookieWrongHeader() throws Exception {
final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase();
final Header header = new BasicHeader("Set-Cookie2", "blah");
final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
cookiespec.parse(header, origin);
}
@Test(expected = MalformedCookieException.class)
public void testParseCookieMissingName() throws Exception {
final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase();
final Header header = new BasicHeader("Set-Cookie", "=blah ; this = stuff;");
final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
cookiespec.parse(header, origin);
}
@Test(expected = MalformedCookieException.class)
public void testParseCookieMissingValue1() throws Exception {
final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase();
final Header header = new BasicHeader("Set-Cookie", "blah");
final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
cookiespec.parse(header, origin);
}
@Test(expected = MalformedCookieException.class)
public void testParseCookieMissingValue2() throws Exception {
final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase();
final Header header = new BasicHeader("Set-Cookie", "blah;");
final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
cookiespec.parse(header, origin);
}
@Test
public void testParseCookieEmptyValue() throws Exception {
final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase();
final Header header = new BasicHeader("Set-Cookie", "blah=;");
final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
final List<Cookie> cookies = cookiespec.parse(header, origin);
Assert.assertEquals(1, cookies.size());
final Cookie cookie = cookies.get(0);
Assert.assertEquals("blah", cookie.getName());
Assert.assertEquals("", cookie.getValue());
}
@Test
public void testParseCookieWithAttributes() throws Exception {
final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
Mockito.when(h1.getAttributeName()).thenReturn("this");
final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
Mockito.when(h2.getAttributeName()).thenReturn("that");
final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase(h1, h2);
final Header header = new BasicHeader("Set-Cookie", "name = value ; p1 = v ; p2 = v,0; p3 ; p4");
final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
final List<Cookie> cookies = cookiespec.parse(header, origin);
Assert.assertEquals(1, cookies.size());
final Cookie cookie = cookies.get(0);
Assert.assertEquals("name", cookie.getName());
Assert.assertEquals("value", cookie.getValue());
Assert.assertTrue(cookie instanceof ClientCookie);
final ClientCookie clientCookie = (ClientCookie) cookie;
Assert.assertEquals("v", clientCookie.getAttribute("p1"));
Assert.assertEquals("v,0", clientCookie.getAttribute("p2"));
Assert.assertTrue(clientCookie.containsAttribute("p3"));
Assert.assertTrue(clientCookie.containsAttribute("p4"));
Assert.assertFalse(clientCookie.containsAttribute("p5"));
}
@Test
public void testParseCookieWithAttributes2() throws Exception {
final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
Mockito.when(h1.getAttributeName()).thenReturn("this");
final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
Mockito.when(h2.getAttributeName()).thenReturn("that");
final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase(h1, h2);
final Header header = new BasicHeader("Set-Cookie", "name = value ; p1 = v");
final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
final List<Cookie> cookies = cookiespec.parse(header, origin);
Assert.assertEquals(1, cookies.size());
final Cookie cookie = cookies.get(0);
Assert.assertEquals("name", cookie.getName());
Assert.assertEquals("value", cookie.getValue());
Assert.assertTrue(cookie instanceof ClientCookie);
final ClientCookie clientCookie = (ClientCookie) cookie;
Assert.assertEquals("v", clientCookie.getAttribute("p1"));
}
@Test
public void testParseCookieWithAttributes3() throws Exception {
final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
Mockito.when(h1.getAttributeName()).thenReturn("this");
final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
Mockito.when(h2.getAttributeName()).thenReturn("that");
final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase(h1, h2);
final Header header = new BasicHeader("Set-Cookie", "name = value ; p1 =");
final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
final List<Cookie> cookies = cookiespec.parse(header, origin);
Assert.assertEquals(1, cookies.size());
final Cookie cookie = cookies.get(0);
Assert.assertEquals("name", cookie.getName());
Assert.assertEquals("value", cookie.getValue());
Assert.assertTrue(cookie instanceof ClientCookie);
final ClientCookie clientCookie = (ClientCookie) cookie;
Assert.assertEquals("", clientCookie.getAttribute("p1"));
}
@Test
public void testValidateCookieBasics() throws Exception {
final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
Mockito.when(h1.getAttributeName()).thenReturn("this");
final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
Mockito.when(h2.getAttributeName()).thenReturn("that");
final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase(h1, h2);
final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
cookiespec.validate(cookie, origin);
Mockito.verify(h1).validate(cookie, origin);
Mockito.verify(h2).validate(cookie, origin);
}
@Test
public void testMatchCookie() throws Exception {
final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
Mockito.when(h1.getAttributeName()).thenReturn("this");
final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
Mockito.when(h2.getAttributeName()).thenReturn("that");
final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase(h1, h2);
final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
Mockito.when(h1.match(cookie, origin)).thenReturn(true);
Mockito.when(h2.match(cookie, origin)).thenReturn(true);
Assert.assertTrue(cookiespec.match(cookie, origin));
Mockito.verify(h1).match(cookie, origin);
Mockito.verify(h2).match(cookie, origin);
}
@Test
public void testMatchCookieNoMatch() throws Exception {
final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
Mockito.when(h1.getAttributeName()).thenReturn("this");
final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
Mockito.when(h2.getAttributeName()).thenReturn("that");
final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase(h1, h2);
final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
final BasicClientCookie cookie = new BasicClientCookie("name", "value");
Mockito.when(h1.match(cookie, origin)).thenReturn(false);
Mockito.when(h2.match(cookie, origin)).thenReturn(false);
Assert.assertFalse(cookiespec.match(cookie, origin));
Mockito.verify(h1).match(cookie, origin);
Mockito.verify(h2, Mockito.never()).match(cookie, origin);
}
@Test
public void testLegacy() throws Exception {
final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase();
Assert.assertEquals(0, cookiespec.getVersion());
Assert.assertEquals(null, cookiespec.getVersionHeader());
}
@Test
public void testFormatCookiesBasics() throws Exception {
final Cookie cookie1 = new BasicClientCookie("name1", "value");
final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase();
final List<Header> headers = cookiespec.formatCookies(Arrays.asList(cookie1));
Assert.assertNotNull(headers);
Assert.assertEquals(1, headers.size());
final Header header = headers.get(0);
Assert.assertEquals("Cookie", header.getName());
Assert.assertEquals("name1=value", header.getValue());
}
@Test
public void testFormatCookiesIllegalCharsInValue() throws Exception {
final Cookie cookie1 = new BasicClientCookie("name1", "value");
final Cookie cookie2 = new BasicClientCookie("name2", "some value");
final Cookie cookie3 = new BasicClientCookie("name3", "\"\\\"");
final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase();
final List<Header> headers = cookiespec.formatCookies(Arrays.asList(cookie1, cookie2, cookie3));
Assert.assertNotNull(headers);
Assert.assertEquals(1, headers.size());
final Header header = headers.get(0);
Assert.assertEquals("Cookie", header.getName());
Assert.assertEquals("name1=value; name2=\"some value\"; name3=\"\\\"\\\\\\\"\"", header.getValue());
}
@Test
public void testParseCookieMultipleAttributes() throws Exception {
final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
Mockito.when(h1.getAttributeName()).thenReturn("this");
final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase(h1);
final Header header = new BasicHeader("Set-Cookie", "name = value ; this = stuff; this = morestuff;");
final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
cookiespec.parse(header, origin);
Mockito.verify(h1).parse(Mockito.<SetCookie>any(), Mockito.eq("morestuff"));
Mockito.verify(h1, Mockito.times(1)).parse(Mockito.<SetCookie>any(), Mockito.anyString());
}
@Test
public void testParseCookieMaxAgeOverExpires() throws Exception {
final CommonCookieAttributeHandler h1 = Mockito.mock(CommonCookieAttributeHandler.class);
Mockito.when(h1.getAttributeName()).thenReturn("Expires");
final CommonCookieAttributeHandler h2 = Mockito.mock(CommonCookieAttributeHandler.class);
Mockito.when(h2.getAttributeName()).thenReturn("Max-Age");
final RFC6265CookieSpecBase cookiespec = new RFC6265CookieSpecBase(h1, h2);
final Header header = new BasicHeader("Set-Cookie", "name = value ; expires = stuff; max-age = otherstuff;");
final CookieOrigin origin = new CookieOrigin("host", 80, "/path/", true);
cookiespec.parse(header, origin);
Mockito.verify(h1, Mockito.never()).parse(Mockito.<SetCookie>any(), Mockito.anyString());
Mockito.verify(h2).parse(Mockito.<SetCookie>any(), Mockito.eq("otherstuff"));
}
}