diff --git a/module-client/src/main/java/org/apache/http/impl/client/DefaultClientRequestDirector.java b/module-client/src/main/java/org/apache/http/impl/client/DefaultClientRequestDirector.java
index d9b6b9892..0e5299ec6 100644
--- a/module-client/src/main/java/org/apache/http/impl/client/DefaultClientRequestDirector.java
+++ b/module-client/src/main/java/org/apache/http/impl/client/DefaultClientRequestDirector.java
@@ -81,7 +81,6 @@ import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
-import org.apache.http.params.HttpParamsLinker;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
diff --git a/module-client/src/main/java/org/apache/http/impl/cookie/AbstractCookieSpec.java b/module-client/src/main/java/org/apache/http/impl/cookie/AbstractCookieSpec.java
index af723f522..003debf84 100644
--- a/module-client/src/main/java/org/apache/http/impl/cookie/AbstractCookieSpec.java
+++ b/module-client/src/main/java/org/apache/http/impl/cookie/AbstractCookieSpec.java
@@ -31,16 +31,13 @@
package org.apache.http.impl.cookie;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
-import java.util.List;
import java.util.Map;
import org.apache.http.cookie.CookieAttributeHandler;
import org.apache.http.cookie.CookieSpec;
-
/**
* Abstract cookie specification which can delegate the job of parsing,
* validation or matching cookie attributes to a number of arbitrary
@@ -52,11 +49,6 @@ import org.apache.http.cookie.CookieSpec;
*/
public abstract class AbstractCookieSpec implements CookieSpec {
- /**
- * Stores the list of attribute handlers
- */
- private final List attribHandlerList;
-
/**
* Stores attribute name -> attribute handler mappings
*/
@@ -68,7 +60,6 @@ public abstract class AbstractCookieSpec implements CookieSpec {
public AbstractCookieSpec() {
super();
this.attribHandlerMap = new HashMap(10);
- this.attribHandlerList = new ArrayList(10);
}
public void registerAttribHandler(
@@ -79,9 +70,6 @@ public abstract class AbstractCookieSpec implements CookieSpec {
if (handler == null) {
throw new IllegalArgumentException("Attribute handler may not be null");
}
- if (!this.attribHandlerList.contains(handler)) {
- this.attribHandlerList.add(handler);
- }
this.attribHandlerMap.put(name, handler);
}
@@ -116,7 +104,7 @@ public abstract class AbstractCookieSpec implements CookieSpec {
}
protected Iterator getAttribHandlerIterator() {
- return this.attribHandlerList.iterator();
+ return this.attribHandlerMap.values().iterator();
}
}
diff --git a/module-client/src/main/java/org/apache/http/impl/cookie/BasicClientCookie2.java b/module-client/src/main/java/org/apache/http/impl/cookie/BasicClientCookie2.java
index d5579e968..5e78c95a0 100644
--- a/module-client/src/main/java/org/apache/http/impl/cookie/BasicClientCookie2.java
+++ b/module-client/src/main/java/org/apache/http/impl/cookie/BasicClientCookie2.java
@@ -31,6 +31,8 @@
package org.apache.http.impl.cookie;
+import java.util.Date;
+
import org.apache.http.cookie.SetCookie2;
/**
@@ -80,5 +82,9 @@ public class BasicClientCookie2 extends BasicClientCookie implements SetCookie2
return !this.discard && super.isPersistent();
}
+ public boolean isExpired(final Date date) {
+ return this.discard || super.isExpired(date);
+ }
+
}
diff --git a/module-client/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java b/module-client/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java
index e1c0e6981..96d273ce7 100644
--- a/module-client/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java
+++ b/module-client/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java
@@ -56,6 +56,10 @@ public class BasicMaxAgeHandler extends AbstractCookieAttributeHandler {
throw new MalformedCookieException ("Invalid max-age attribute: "
+ value);
}
+ if (age < 0) {
+ throw new MalformedCookieException ("Negative max-age attribute: "
+ + value);
+ }
cookie.setExpiryDate(new Date(System.currentTimeMillis() + age * 1000L));
}
diff --git a/module-client/src/main/java/org/apache/http/impl/cookie/RFC2109Spec.java b/module-client/src/main/java/org/apache/http/impl/cookie/RFC2109Spec.java
index d93e0ef80..3bd00897d 100644
--- a/module-client/src/main/java/org/apache/http/impl/cookie/RFC2109Spec.java
+++ b/module-client/src/main/java/org/apache/http/impl/cookie/RFC2109Spec.java
@@ -186,7 +186,7 @@ public class RFC2109Spec extends CookieSpecBase {
* @param param The parameter.
* @param version The cookie version
*/
- private void formatParamAsVer(final CharArrayBuffer buffer,
+ protected void formatParamAsVer(final CharArrayBuffer buffer,
final String name, final String value, int version) {
buffer.append(name);
buffer.append("=");
@@ -208,7 +208,7 @@ public class RFC2109Spec extends CookieSpecBase {
* @param cookie The {@link Cookie} to be formatted as string
* @param version The version to use.
*/
- private void formatCookieAsVer(final CharArrayBuffer buffer,
+ protected void formatCookieAsVer(final CharArrayBuffer buffer,
final Cookie cookie, int version) {
formatParamAsVer(buffer, cookie.getName(), cookie.getValue(), version);
if (cookie.getPath() != null) {
diff --git a/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965PortAttributeHandler.java b/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965PortAttributeHandler.java
index 265541aee..7743ae8ca 100644
--- a/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965PortAttributeHandler.java
+++ b/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965PortAttributeHandler.java
@@ -78,7 +78,7 @@ public class RFC2965PortAttributeHandler implements CookieAttributeHandler {
}
if (cookie instanceof SetCookie2) {
SetCookie2 cookie2 = (SetCookie2) cookie;
- if (portValue != null && !portValue.equals("")) {
+ if (portValue != null && portValue.trim().length() > 0) {
int[] ports = parsePortAttribute(portValue);
cookie2.setPorts(ports);
}
diff --git a/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965Spec.java b/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965Spec.java
new file mode 100644
index 000000000..669115c02
--- /dev/null
+++ b/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965Spec.java
@@ -0,0 +1,224 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ *
+ * 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
+ * .
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.NameValuePair;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieAttributeHandler;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.CookieVersionSupport;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.cookie.SM;
+import org.apache.http.message.BufferedHeader;
+import org.apache.http.util.CharArrayBuffer;
+
+/**
+ *
RFC 2965 specific cookie management functions.
+ *
+ * @author jain.samit@gmail.com (Samit Jain)
+ * @author Oleg Kalnichevski
+ *
+ * @since 3.1
+ */
+public class RFC2965Spec extends RFC2109Spec implements CookieVersionSupport {
+
+ /**
+ * Default constructor
+ *
+ */
+ public RFC2965Spec() {
+ this(null, false);
+ }
+
+ public RFC2965Spec(final String[] datepatterns, boolean oneHeader) {
+ super(datepatterns, oneHeader);
+ registerAttribHandler(ClientCookie.DOMAIN_ATTR, new RFC2965DomainAttributeHandler());
+ registerAttribHandler(ClientCookie.PORT_ATTR, new RFC2965PortAttributeHandler());
+ registerAttribHandler(ClientCookie.COMMENTURL_ATTR, new RFC2965CommentUrlAttributeHandler());
+ registerAttribHandler(ClientCookie.DISCARD_ATTR, new RFC2965DiscardAttributeHandler());
+ registerAttribHandler(ClientCookie.VERSION_ATTR, new RFC2965VersionAttributeHandler());
+ }
+
+ public Cookie[] parse(
+ final Header header,
+ CookieOrigin origin) throws MalformedCookieException {
+ if (header == null) {
+ throw new IllegalArgumentException("Header may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+
+ origin = adjustEffectiveHost(origin);
+
+ HeaderElement[] elems = header.getElements();
+
+ Cookie[] cookies = new Cookie[elems.length];
+ for (int i = 0; i < elems.length; i++) {
+ HeaderElement headerelement = elems[i];
+
+ String name = headerelement.getName();
+ String value = headerelement.getValue();
+ if (name == null || name.equals("")) {
+ throw new MalformedCookieException("Cookie name may not be empty");
+ }
+
+ BasicClientCookie2 cookie = new BasicClientCookie2(name, value);
+ cookie.setPath(getDefaultPath(origin));
+ cookie.setDomain(getDefaultDomain(origin));
+ cookie.setPorts(new int [] { origin.getPort() });
+
+ // cycle through the parameters
+ NameValuePair[] attribs = headerelement.getParameters();
+
+ // Eliminate duplicate attributes. The first occurrence takes precedence
+ // See RFC2965: 3.2 Origin Server Role
+ Map attribmap = new HashMap(attribs.length);
+ for (int j = attribs.length - 1; j >= 0; j--) {
+ NameValuePair param = attribs[j];
+ attribmap.put(param.getName().toLowerCase(), param);
+ }
+ for (Iterator it = attribmap.entrySet().iterator(); it.hasNext(); ) {
+ Map.Entry entry = (Map.Entry) it.next();
+ NameValuePair attrib = (NameValuePair) entry.getValue();
+ String s = attrib.getName().toLowerCase();
+
+ cookie.setAttribute(s, attrib.getValue());
+
+ CookieAttributeHandler handler = findAttribHandler(s);
+ if (handler != null) {
+ handler.parse(cookie, attrib.getValue());
+ }
+ }
+ cookies[i] = cookie;
+ }
+ return cookies;
+ }
+
+ public void validate(final Cookie cookie, CookieOrigin origin)
+ throws MalformedCookieException {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ origin = adjustEffectiveHost(origin);
+ super.validate(cookie, origin);
+ }
+
+ public boolean match(final Cookie cookie, CookieOrigin origin) {
+ if (cookie == null) {
+ throw new IllegalArgumentException("Cookie may not be null");
+ }
+ if (origin == null) {
+ throw new IllegalArgumentException("Cookie origin may not be null");
+ }
+ origin = adjustEffectiveHost(origin);
+ return super.match(cookie, origin);
+ }
+
+ /**
+ * Adds valid Port attribute value, e.g. "8000,8001,8002"
+ */
+ protected void formatCookieAsVer(final CharArrayBuffer buffer,
+ final Cookie cookie, int version) {
+ super.formatCookieAsVer(buffer, cookie, version);
+ // format port attribute
+ if (cookie instanceof ClientCookie) {
+ // Test if the port attribute as set by the origin server is not blank
+ String s = ((ClientCookie) cookie).getAttribute(ClientCookie.PORT_ATTR);
+ if (s != null) {
+ buffer.append("; $Port");
+ buffer.append("=\"");
+ if (s.trim().length() > 0) {
+ int[] ports = cookie.getPorts();
+ if (ports != null) {
+ for (int i = 0, len = ports.length; i < len; i++) {
+ if (i > 0) {
+ buffer.append(",");
+ }
+ buffer.append(Integer.toString(ports[i]));
+ }
+ }
+ }
+ buffer.append("\"");
+ }
+ }
+ }
+
+ /**
+ * Set 'effective host name' as defined in RFC 2965.
+ *
+ * If a host name contains no dots, the effective host name is
+ * that name with the string .local appended to it. Otherwise
+ * the effective host name is the same as the host name. Note
+ * that all effective host names contain at least one dot.
+ *
+ * @param host host name where cookie is received from or being sent to.
+ * @return
+ */
+ private static CookieOrigin adjustEffectiveHost(final CookieOrigin origin) {
+ String effectiveHost = origin.getHost();
+ if (effectiveHost.indexOf('.') < 0) {
+ effectiveHost += ".local";
+ return new CookieOrigin(
+ effectiveHost,
+ origin.getPort(),
+ origin.getPath(),
+ origin.isSecure());
+ } else {
+ return origin;
+ }
+ }
+
+ public int getVersion() {
+ return 1;
+ }
+
+ public Header getVersionHeader() {
+ CharArrayBuffer buffer = new CharArrayBuffer(40);
+ buffer.append(SM.COOKIE_2);
+ buffer.append(": ");
+ buffer.append("$Version=");
+ buffer.append(Integer.toString(getVersion()));
+ return new BufferedHeader(buffer);
+ }
+
+}
+
diff --git a/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965SpecFactory.java b/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965SpecFactory.java
new file mode 100644
index 000000000..87113cf41
--- /dev/null
+++ b/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965SpecFactory.java
@@ -0,0 +1,57 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ * 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
+ * .
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import org.apache.http.cookie.CookieSpec;
+import org.apache.http.cookie.CookieSpecFactory;
+import org.apache.http.cookie.params.CookieSpecPNames;
+import org.apache.http.params.HttpParams;
+
+/**
+ *
+ * @author Oleg Kalnichevski
+ *
+ * @since 4.0
+ */
+public class RFC2965SpecFactory implements CookieSpecFactory {
+
+ public CookieSpec newInstance(final HttpParams params) {
+ if (params != null) {
+ return new RFC2965Spec(
+ (String []) params.getParameter(CookieSpecPNames.DATE_PATTERNS),
+ params.getBooleanParameter(CookieSpecPNames.SINGLE_COOKIE_HEADER, false));
+ } else {
+ return new RFC2965Spec();
+ }
+ }
+
+}
diff --git a/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965VersionAttributeHandler.java b/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965VersionAttributeHandler.java
index d6e18a5e2..7e4fc1ccd 100644
--- a/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965VersionAttributeHandler.java
+++ b/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965VersionAttributeHandler.java
@@ -50,7 +50,7 @@ public class RFC2965VersionAttributeHandler implements CookieAttributeHandler {
}
if (cookie instanceof ClientCookie) {
if (cookie instanceof ClientCookie
- && ((ClientCookie) cookie).containsAttribute(ClientCookie.VERSION_ATTR)) {
+ && !((ClientCookie) cookie).containsAttribute(ClientCookie.VERSION_ATTR)) {
throw new MalformedCookieException(
"Violates RFC 2965. Version attribute is required.");
}
diff --git a/module-client/src/test/java/org/apache/http/impl/cookie/TestAbstractCookieSpec.java b/module-client/src/test/java/org/apache/http/impl/cookie/TestAbstractCookieSpec.java
index 63b38d65c..f1761ad82 100644
--- a/module-client/src/test/java/org/apache/http/impl/cookie/TestAbstractCookieSpec.java
+++ b/module-client/src/test/java/org/apache/http/impl/cookie/TestAbstractCookieSpec.java
@@ -111,6 +111,8 @@ public class TestAbstractCookieSpec extends TestCase {
Iterator it = cookiespec.getAttribHandlerIterator();
assertNotNull(it.next());
assertNotNull(it.next());
+ assertNotNull(it.next());
+ assertNotNull(it.next());
assertFalse(it.hasNext());
}
diff --git a/module-client/src/test/java/org/apache/http/impl/cookie/TestAllCookieImpl.java b/module-client/src/test/java/org/apache/http/impl/cookie/TestAllCookieImpl.java
index fd690e904..6058a8191 100644
--- a/module-client/src/test/java/org/apache/http/impl/cookie/TestAllCookieImpl.java
+++ b/module-client/src/test/java/org/apache/http/impl/cookie/TestAllCookieImpl.java
@@ -50,6 +50,7 @@ public class TestAllCookieImpl extends TestCase {
suite.addTest(TestBrowserCompatSpec.suite());
suite.addTest(TestCookieNetscapeDraft.suite());
suite.addTest(TestCookieRFC2109Spec.suite());
+ suite.addTest(TestCookieRFC2965Spec.suite());
return suite;
}
diff --git a/module-client/src/test/java/org/apache/http/impl/cookie/TestCookieRFC2965Spec.java b/module-client/src/test/java/org/apache/http/impl/cookie/TestCookieRFC2965Spec.java
new file mode 100644
index 000000000..008519ece
--- /dev/null
+++ b/module-client/src/test/java/org/apache/http/impl/cookie/TestCookieRFC2965Spec.java
@@ -0,0 +1,963 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ * ====================================================================
+ *
+ * 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
+ * .
+ *
+ */
+
+package org.apache.http.impl.cookie;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.util.Date;
+
+import org.apache.http.Header;
+import org.apache.http.cookie.ClientCookie;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.cookie.CookieOrigin;
+import org.apache.http.cookie.CookieSpec;
+import org.apache.http.cookie.MalformedCookieException;
+import org.apache.http.message.BasicHeader;
+
+/**
+ * Test cases for RFC2965 cookie spec
+ *
+ * @author jain.samit@gmail.com (Samit Jain)
+ */
+public class TestCookieRFC2965Spec extends TestCase {
+
+ // ------------------------------------------------------------ Constructor
+
+ public TestCookieRFC2965Spec(String name) {
+ super(name);
+ }
+
+ // ------------------------------------------------------- TestCase Methods
+
+ public static Test suite() {
+ return new TestSuite(TestCookieRFC2965Spec.class);
+ }
+
+ // ------------------------------------------------------- Test Cookie Parsing
+
+ /**
+ * Test parsing cookie "Path" attribute.
+ */
+ public void testParsePath() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Path=/;Version=1;Path=");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ // only the first occurrence of path attribute is considered, others ignored
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ assertEquals("/", cookie.getPath());
+ assertTrue(cookie.containsAttribute(ClientCookie.PATH_ATTR));
+ }
+
+ public void testParsePathDefault() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/path/", false);
+ // Path is OPTIONAL, defaults to the request path
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Version=1");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ assertEquals("/path", cookie.getPath());
+ assertFalse(cookie.containsAttribute(ClientCookie.PATH_ATTR));
+ }
+
+ public void testParseNullPath() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Path=;Version=1");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ assertEquals("/", cookie.getPath());
+ assertTrue(cookie.containsAttribute(ClientCookie.PATH_ATTR));
+ }
+
+ public void testParseBlankPath() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Path=\" \";Version=1");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ assertEquals("/", cookie.getPath());
+ assertTrue(cookie.containsAttribute(ClientCookie.PATH_ATTR));
+ }
+
+ /**
+ * Test parsing cookie "Domain" attribute.
+ */
+ public void testParseDomain() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Domain=.domain.com;Version=1;Domain=");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ // only the first occurrence of domain attribute is considered, others ignored
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ assertEquals(".domain.com", cookie.getDomain());
+ assertTrue(cookie.containsAttribute(ClientCookie.DOMAIN_ATTR));
+
+ // should put a leading dot if there is no dot in front of domain
+ header = new BasicHeader("Set-Cookie2", "name=value;Domain=domain.com;Version=1");
+ parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ cookie = (ClientCookie) parsed[0];
+ assertEquals(".domain.com", cookie.getDomain());
+ }
+
+ public void testParseDomainDefault() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ // Domain is OPTIONAL, defaults to the request host
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Version=1");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ assertEquals("www.domain.com", cookie.getDomain());
+ assertFalse(cookie.containsAttribute(ClientCookie.DOMAIN_ATTR));
+ }
+
+ public void testParseNullDomain() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ // domain cannot be null
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Domain=;Version=1");
+ try {
+ cookiespec.parse(header, origin);
+ fail("MalformedCookieException should have been thrown");
+ } catch (MalformedCookieException ex) {
+ // expected
+ }
+ }
+
+ public void testParseBlankDomain() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Domain=\" \";Version=1");
+ try {
+ cookiespec.parse(header, origin);
+ fail("MalformedCookieException should have been thrown");
+ } catch (MalformedCookieException ex) {
+ // expected
+ }
+ }
+
+ /**
+ * Test parsing cookie "Port" attribute.
+ */
+ public void testParsePort() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Port=\"80,800,8000\";Version=1;Port=nonsense");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ // only the first occurrence of port attribute is considered, others ignored
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ int[] ports = cookie.getPorts();
+ assertNotNull(ports);
+ assertEquals(3, ports.length);
+ assertEquals(80, ports[0]);
+ assertEquals(800, ports[1]);
+ assertEquals(8000, ports[2]);
+ assertTrue(cookie.containsAttribute(ClientCookie.PORT_ATTR));
+ }
+
+ public void testParsePortDefault() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ // Port is OPTIONAL, cookie can be accepted from any port
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Version=1");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ assertFalse(cookie.containsAttribute(ClientCookie.PORT_ATTR));
+ }
+
+ public void testParseNullPort() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ // null port defaults to request port
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Port=;Version=1");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ int[] ports = cookie.getPorts();
+ assertNotNull(ports);
+ assertEquals(1, ports.length);
+ assertEquals(80, ports[0]);
+ assertEquals("", cookie.getAttribute(ClientCookie.PORT_ATTR));
+ }
+
+ public void testParseBlankPort() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ // blank port defaults to request port
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Port=\" \";Version=1");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ int[] ports = cookie.getPorts();
+ assertNotNull(ports);
+ assertEquals(1, ports.length);
+ assertEquals(80, ports[0]);
+ assertEquals(" ", cookie.getAttribute(ClientCookie.PORT_ATTR));
+ }
+
+ public void testParseInvalidPort() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Port=nonsense;Version=1");
+ try {
+ cookiespec.parse(header, origin);
+ fail("MalformedCookieException should have been thrown");
+ } catch (MalformedCookieException ex) {
+ // expected
+ }
+ }
+
+ public void testParseNegativePort() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Port=\"80,-800,8000\";Version=1");
+ try {
+ cookiespec.parse(header, origin);
+ fail("MalformedCookieException should have been thrown");
+ } catch (MalformedCookieException ex) {
+ // expected
+ }
+ }
+
+ /**
+ * test parsing cookie name/value.
+ */
+ public void testParseNameValue() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Version=1;");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ assertEquals("name", cookie.getName());
+ assertEquals("value", cookie.getValue());
+ }
+
+ /**
+ * test parsing cookie "Version" attribute.
+ */
+ public void testParseVersion() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Version=1;");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ assertEquals(1, cookie.getVersion());
+ assertTrue(cookie.containsAttribute(ClientCookie.VERSION_ATTR));
+ }
+
+ public void testParseNullVersion() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ // version cannot be null
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Version=;");
+ try {
+ cookiespec.parse(header, origin);
+ fail("MalformedCookieException should have been thrown");
+ } catch (MalformedCookieException ex) {
+ // expected
+ }
+ }
+
+ public void testParseNegativeVersion() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Version=-1;");
+ try {
+ cookiespec.parse(header, origin);
+ fail("MalformedCookieException should have been thrown");
+ } catch (MalformedCookieException ex) {
+ // expected
+ }
+ }
+ /**
+ * test parsing cookie "Max-age" attribute.
+ */
+ public void testParseMaxage() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Max-age=3600;Version=1;Max-age=nonsense");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ // only the first occurence of max-age attribute is considered, others ignored
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ assertFalse(cookie.isExpired(new Date()));
+ }
+
+ public void testParseMaxageDefault() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ // Max-age is OPTIONAL, defaults to session cookie
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Version=1");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ assertFalse(cookie.isPersistent());
+ }
+
+ public void testParseNullMaxage() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Max-age=;Version=1");
+ try {
+ cookiespec.parse(header, origin);
+ fail("MalformedCookieException should have been thrown");
+ } catch (MalformedCookieException ex) {
+ // expected
+ }
+ }
+
+ public void testParseNegativeMaxage() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Max-age=-3600;Version=1;");
+ try {
+ cookiespec.parse(header, origin);
+ fail("MalformedCookieException should have been thrown");
+ } catch (MalformedCookieException ex) {
+ // expected
+ }
+ }
+
+ /**
+ * test parsing "Secure" attribute.
+ */
+ public void testParseSecure() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Secure;Version=1");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ assertTrue(cookie.isSecure());
+ }
+
+ /**
+ * test parsing "Discard" attribute.
+ */
+ public void testParseDiscard() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Discard;Max-age=36000;Version=1");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ // discard overrides max-age
+ assertFalse(cookie.isPersistent());
+
+ // Discard is OPTIONAL, default behavior is dictated by max-age
+ header = new BasicHeader("Set-Cookie2", "name=value;Max-age=36000;Version=1");
+ parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ cookie = (ClientCookie) parsed[0];
+ assertTrue(cookie.isPersistent());
+ }
+
+ /**
+ * test parsing "Comment", "CommentURL" and
+ * "Secure" attributes.
+ */
+ public void testParseOtherAttributes() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Comment=\"good cookie\";" +
+ "CommentURL=\"www.domain.com/goodcookie/\";Secure;Version=1");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ assertEquals("good cookie", cookie.getComment());
+ assertEquals("www.domain.com/goodcookie/", cookie.getCommentURL());
+ assertTrue(cookie.isSecure());
+
+ // Comment, CommentURL, Secure are OPTIONAL
+ header = new BasicHeader("Set-Cookie2", "name=value;Version=1");
+ parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ cookie = (ClientCookie) parsed[0];
+ assertFalse(cookie.isSecure());
+ }
+
+ /**
+ * Test parsing header with 2 cookies (separated by comma)
+ */
+ public void testCookiesWithComma() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "a=b,c");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(2, parsed.length);
+ assertEquals("a", parsed[0].getName());
+ assertEquals("b", parsed[0].getValue());
+ assertEquals("c", parsed[1].getName());
+ assertEquals(null, parsed[1].getValue());
+ }
+
+ // ------------------------------------------------------- Test Cookie Validation
+
+ /**
+ * Test Domain validation when domain is not specified
+ * in Set-Cookie2 header.
+ */
+ public void testValidateNoDomain() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Version=1");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ for (int i = 0; i < parsed.length; i++) {
+ cookiespec.validate(parsed[i], origin);
+ }
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ // cookie domain must string match request host
+ assertEquals("www.domain.com", cookie.getDomain());
+ }
+
+ /**
+ * Test Domain validation. Cookie domain attribute must have a
+ * leading dot.
+ */
+ public void testValidateDomainLeadingDot() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value;Domain=domain.com;Version=1");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ for (int i = 0; i < parsed.length; i++) {
+ cookiespec.validate(parsed[i], origin);
+ }
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ assertEquals(".domain.com", cookie.getDomain());
+ }
+
+ /**
+ * Test Domain validation. Domain must have at least one embedded dot.
+ */
+ public void testValidateDomainEmbeddedDot() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("b.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value; domain=.com; version=1");
+ try {
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ for (int i = 0; i < parsed.length; i++) {
+ cookiespec.validate(parsed[i], origin);
+ }
+ fail("MalformedCookieException should have been thrown");
+ } catch (MalformedCookieException expected) {}
+
+ origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ header = new BasicHeader("Set-Cookie2", "name=value;Domain=domain.com;Version=1");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ for (int i = 0; i < parsed.length; i++) {
+ cookiespec.validate(parsed[i], origin);
+ }
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ }
+
+ /**
+ * Test local Domain validation. Simple host names
+ * (without any dots) are valid only when cookie domain is specified
+ * as ".local".
+ */
+ public void testValidateDomainLocal() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("simplehost", 80, "/", false);
+ // when domain is specified as .local, simple host names are valid
+ Header header = new BasicHeader("Set-Cookie2", "name=value; domain=.local; version=1");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ for (int i = 0; i < parsed.length; i++) {
+ cookiespec.validate(parsed[i], origin);
+ }
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ assertEquals(".local", cookie.getDomain());
+
+ // when domain is NOT specified as .local, simple host names are invalid
+ header = new BasicHeader("Set-Cookie2", "name=value; domain=domain.com; version=1");
+ try {
+ // since domain is not .local, this must fail
+ parsed = cookiespec.parse(header, origin);
+ for (int i = 0; i < parsed.length; i++) {
+ cookiespec.validate(parsed[i], origin);
+ }
+ fail("MalformedCookieException should have been thrown");
+ } catch (MalformedCookieException expected) {}
+ }
+
+
+ /**
+ * Test Domain validation. Effective host name
+ * must domain-match domain attribute.
+ */
+ public void testValidateDomainEffectiveHost() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+
+ // cookie domain does not domain-match request host
+ Header header = new BasicHeader("Set-Cookie2", "name=value; domain=.domain.com; version=1");
+ try {
+ CookieOrigin origin = new CookieOrigin("www.domain.org", 80, "/", false);
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ for (int i = 0; i < parsed.length; i++) {
+ cookiespec.validate(parsed[i], origin);
+ }
+ fail("MalformedCookieException should have been thrown");
+ } catch (MalformedCookieException expected) {}
+
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ // cookie domain domain-matches request host
+ header = new BasicHeader("Set-Cookie2", "name=value; domain=.domain.com; version=1");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ for (int i = 0; i < parsed.length; i++) {
+ cookiespec.validate(parsed[i], origin);
+ }
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ }
+
+ /**
+ * Test local Domain validation.
+ * Effective host name minus domain must not contain any dots.
+ */
+ public void testValidateDomainIllegal() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("a.b.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie2", "name=value; domain=.domain.com; version=1");
+ try {
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ for (int i = 0; i < parsed.length; i++) {
+ cookiespec.validate(parsed[i], origin);
+ }
+ fail("MalformedCookieException should have been thrown");
+ } catch (MalformedCookieException expected) {}
+ }
+
+ /**
+ * Test cookie Path validation. Cookie path attribute must path-match
+ * request path.
+ */
+ public void testValidatePath() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ Header header = new BasicHeader("Set-Cookie2", "name=value;path=/path;version=1");
+ try {
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ for (int i = 0; i < parsed.length; i++) {
+ cookiespec.validate(parsed[i], origin);
+ }
+ fail("MalformedCookieException exception should have been thrown");
+ } catch (MalformedCookieException expected) {}
+
+ // path-matching is case-sensitive
+ header = new BasicHeader("Set-Cookie2", "name=value;path=/Path;version=1");
+ try {
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/path", false);
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ for (int i = 0; i < parsed.length; i++) {
+ cookiespec.validate(parsed[i], origin);
+ }
+ fail("MalformedCookieException exception should have been thrown");
+ } catch (MalformedCookieException expected) {}
+
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/path/path1", false);
+ header = new BasicHeader("Set-Cookie2", "name=value;path=/path;version=1");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ for (int i = 0; i < parsed.length; i++) {
+ cookiespec.validate(parsed[i], origin);
+ }
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ assertEquals("/path", parsed[0].getPath());
+ }
+
+ /**
+ * Test cookie name validation.
+ */
+ public void testValidateCookieName() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("127.0.0.1", 80, "/", false);
+ // cookie name must not contain blanks
+ Header header = new BasicHeader("Set-Cookie2", "invalid name=value; version=1");
+ try {
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ for (int i = 0; i < parsed.length; i++) {
+ cookiespec.validate(parsed[i], origin);
+ }
+ fail("MalformedCookieException exception should have been thrown");
+ } catch (MalformedCookieException expected) {}
+
+ // cookie name must not start with '$'.
+ header = new BasicHeader("Set-Cookie2", "$invalid_name=value; version=1");
+ try {
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ for (int i = 0; i < parsed.length; i++) {
+ cookiespec.validate(parsed[i], origin);
+ }
+ fail("MalformedCookieException exception should have been thrown");
+ } catch (MalformedCookieException expected) {}
+
+ // valid name
+ header = new BasicHeader("Set-Cookie2", "name=value; version=1");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ assertEquals("name", cookie.getName());
+ assertEquals("value", cookie.getValue());
+ }
+
+ /**
+ * Test cookie Port validation. Request port must be in the
+ * port attribute list.
+ */
+ public void testValidatePort() throws Exception {
+ Header header = new BasicHeader("Set-Cookie2", "name=value; Port=\"80,800\"; version=1");
+ CookieSpec cookiespec = new RFC2965Spec();
+ try {
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 8000, "/", false);
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ for (int i = 0; i < parsed.length; i++) {
+ cookiespec.validate(parsed[i], origin);
+ }
+ fail("MalformedCookieException should have been thrown");
+ } catch (MalformedCookieException e) {}
+
+ // valid port list
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ for (int i = 0; i < parsed.length; i++) {
+ cookiespec.validate(parsed[i], origin);
+ }
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ ClientCookie cookie = (ClientCookie) parsed[0];
+ int[] ports = cookie.getPorts();
+ assertNotNull(ports);
+ assertEquals(2, ports.length);
+ assertEquals(80, ports[0]);
+ assertEquals(800, ports[1]);
+ }
+
+ /**
+ * Test cookie Version validation.
+ */
+ public void testValidateVersion() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ // version attribute is REQUIRED
+ Header header = new BasicHeader("Set-Cookie2", "name=value");
+ try {
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 8000, "/", false);
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ for (int i = 0; i < parsed.length; i++) {
+ cookiespec.validate(parsed[i], origin);
+ }
+ fail("MalformedCookieException should have been thrown");
+ } catch (MalformedCookieException e) {}
+ }
+
+ // ------------------------------------------------------- Test Cookie Matching
+
+ /**
+ * test cookie Path matching. Cookie path attribute must path-match
+ * path of the request URI.
+ */
+ public void testMatchPath() throws Exception {
+ BasicClientCookie2 cookie = new BasicClientCookie2("name", "value");
+ cookie.setDomain(".domain.com");
+ cookie.setPath("/path");
+ cookie.setPorts(new int[] {80});
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin1 = new CookieOrigin("www.domain.com", 80, "/", false);
+ assertFalse(cookiespec.match(cookie, origin1));
+ CookieOrigin origin2 = new CookieOrigin("www.domain.com", 80, "/path/path1", false);
+ assertTrue(cookiespec.match(cookie, origin2));
+ }
+
+ /**
+ * test cookie Domain matching.
+ */
+ public void testMatchDomain() throws Exception {
+ BasicClientCookie2 cookie = new BasicClientCookie2("name", "value");
+ cookie.setDomain(".domain.com");
+ cookie.setPath("/");
+ cookie.setPorts(new int[] {80});
+ CookieSpec cookiespec = new RFC2965Spec();
+ // effective host name minus domain must not contain any dots
+ CookieOrigin origin1 = new CookieOrigin("a.b.domain.com" /* request host */, 80, "/", false);
+ assertFalse(cookiespec.match(cookie, origin1));
+ // The effective host name MUST domain-match the Domain
+ // attribute of the cookie.
+ CookieOrigin origin2 = new CookieOrigin("www.domain.org" /* request host */, 80, "/", false);
+ assertFalse(cookiespec.match(cookie, origin2));
+ CookieOrigin origin3 = new CookieOrigin("www.domain.com" /* request host */, 80, "/", false);
+ assertTrue(cookiespec.match(cookie, origin3));
+ }
+
+ /**
+ * test cookie local Domain matching.
+ */
+ public void testMatchDomainLocal() throws Exception {
+ BasicClientCookie2 cookie = new BasicClientCookie2("name", "value");
+ cookie.setDomain(".local");
+ cookie.setPath("/");
+ cookie.setPorts(new int[] {80});
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin1 = new CookieOrigin("host" /* request host */, 80, "/", false);
+ assertTrue(cookiespec.match(cookie, origin1));
+ CookieOrigin origin2 = new CookieOrigin("host.com" /* request host */, 80, "/", false);
+ assertFalse(cookiespec.match(cookie, origin2));
+ }
+
+ /**
+ * test cookie Port matching.
+ */
+ public void testMatchPort() throws Exception {
+ // cookie can be sent to any port if port attribute not specified
+ BasicClientCookie2 cookie = new BasicClientCookie2("name", "value");
+ cookie.setDomain(".domain.com");
+ cookie.setPath("/");
+ cookie.setPorts(null);
+
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin1 = new CookieOrigin("www.domain.com", 8080 /* request port */, "/", false);
+ assertTrue(cookiespec.match(cookie, origin1));
+ CookieOrigin origin2 = new CookieOrigin("www.domain.com", 323 /* request port */, "/", false);
+ assertTrue(cookiespec.match(cookie, origin2));
+
+ // otherwise, request port must be in cookie's port list
+ cookie = new BasicClientCookie2("name", "value");
+ cookie.setDomain(".domain.com");
+ cookie.setPath("/");
+ cookie.setPorts(new int[] {80, 8080});
+ cookie.setAttribute(ClientCookie.PORT_ATTR, "80, 8080");
+ CookieOrigin origin3 = new CookieOrigin("www.domain.com", 434 /* request port */, "/", false);
+ assertFalse(cookiespec.match(cookie, origin3));
+ CookieOrigin origin4 = new CookieOrigin("www.domain.com", 8080 /* request port */, "/", false);
+ assertTrue(cookiespec.match(cookie, origin4));
+ }
+
+ /**
+ * test cookie expiration.
+ */
+ public void testCookieExpiration() throws Exception {
+ Date now = new Date();
+
+ Date beforeOneHour = new Date(now.getTime() - 3600 * 1000L);
+ BasicClientCookie2 cookie = new BasicClientCookie2("name", "value");
+ cookie.setDomain(".domain.com");
+ cookie.setPath("/");
+ cookie.setPorts(null);
+ cookie.setExpiryDate(beforeOneHour);
+
+ assertTrue(cookie.isExpired(now));
+
+ Date afterOneHour = new Date(now.getTime() + 3600 * 1000L);
+ cookie = new BasicClientCookie2("name", "value");
+ cookie.setDomain(".domain.com");
+ cookie.setPath("/");
+ cookie.setPorts(null);
+ cookie.setExpiryDate(afterOneHour);
+
+ assertFalse(cookie.isExpired(now));
+
+ // discard attributes overrides cookie age, makes it a session cookie.
+ cookie.setDiscard(true);
+ assertFalse(cookie.isPersistent());
+ assertTrue(cookie.isExpired(now));
+ }
+
+ /**
+ * test cookie Secure attribute.
+ */
+ public void testCookieSecure() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ // secure cookie can only be sent over a secure connection
+ BasicClientCookie2 cookie = new BasicClientCookie2("name", "value");
+ cookie.setDomain(".domain.com");
+ cookie.setPath("/");
+ cookie.setSecure(true);
+ CookieOrigin origin1 = new CookieOrigin("www.domain.com", 80, "/", false);
+ assertFalse(cookiespec.match(cookie, origin1));
+ CookieOrigin origin2 = new CookieOrigin("www.domain.com", 80, "/", true);
+ assertTrue(cookiespec.match(cookie, origin2));
+ }
+
+ // ------------------------------------------------------- Test Cookie Formatting
+
+ /**
+ * Tests RFC 2965 compliant cookie formatting.
+ */
+ public void testRFC2965CookieFormatting() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec(null, true);
+ BasicClientCookie2 cookie1 = new BasicClientCookie2("name1", "value");
+ cookie1.setDomain(".domain.com");
+ cookie1.setPath("/");
+ cookie1.setPorts(new int[] {80,8080});
+ cookie1.setVersion(1);
+ // domain, path, port specified
+ cookie1.setAttribute(ClientCookie.DOMAIN_ATTR, ".domain.com");
+ cookie1.setAttribute(ClientCookie.PATH_ATTR, "/");
+ cookie1.setAttribute(ClientCookie.PORT_ATTR, "80,8080");
+
+ Header[] headers = cookiespec.formatCookies(new Cookie[] {cookie1});
+ assertNotNull(headers);
+ assertEquals(1, headers.length);
+ assertEquals("$Version=1; name1=\"value\"; $Path=\"/\"; $Domain=\".domain.com\"; $Port=\"80,8080\"",
+ headers[0].getValue());
+
+
+ BasicClientCookie2 cookie2 = new BasicClientCookie2("name2", "value");
+ cookie2.setDomain(".domain.com");
+ cookie2.setPath("/a/");
+ cookie2.setPorts(new int[] {80,8080});
+ cookie2.setVersion(2);
+ // domain, path specified but port unspecified
+ cookie2.setAttribute(ClientCookie.DOMAIN_ATTR, ".domain.com");
+ cookie2.setAttribute(ClientCookie.PATH_ATTR, "/a/");
+
+ headers = cookiespec.formatCookies(new Cookie[] {cookie2});
+ assertNotNull(headers);
+ assertEquals(1, headers.length);
+ assertEquals("$Version=2; name2=\"value\"; $Path=\"/a/\"; $Domain=\".domain.com\"",
+ headers[0].getValue());
+
+ BasicClientCookie2 cookie3 = new BasicClientCookie2("name3", "value");
+ cookie3.setDomain(".domain.com");
+ cookie3.setPath("/a/b/");
+ cookie3.setPorts(new int[] {80,8080});
+ cookie3.setVersion(1);
+ // path specified, port specified but blank, domain unspecified
+ cookie3.setAttribute(ClientCookie.PATH_ATTR, "/a/b/");
+ cookie3.setAttribute(ClientCookie.PORT_ATTR, " ");
+
+ headers = cookiespec.formatCookies(new Cookie[] {cookie3});
+ assertNotNull(headers);
+ assertEquals(1, headers.length);
+ assertEquals("$Version=1; name3=\"value\"; $Path=\"/a/b/\"; $Port=\"\"",
+ headers[0].getValue());
+
+ headers = cookiespec.formatCookies(new Cookie[] {cookie3, cookie2, cookie1});
+ assertNotNull(headers);
+ assertEquals(1, headers.length);
+ assertEquals("$Version=1; " +
+ "name3=\"value\"; $Path=\"/a/b/\"; $Port=\"\"; " +
+ "name2=\"value\"; $Path=\"/a/\"; $Domain=\".domain.com\"; " +
+ "name1=\"value\"; $Path=\"/\"; $Domain=\".domain.com\"; $Port=\"80,8080\"",
+ headers[0].getValue());
+ }
+
+ /**
+ * Tests RFC 2965 compliant cookies formatting.
+ */
+ public void testRFC2965CookiesFormatting() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec(null, true);
+ BasicClientCookie2 cookie1 = new BasicClientCookie2("name1", "value1");
+ cookie1.setDomain(".domain.com");
+ cookie1.setPath("/");
+ cookie1.setPorts(new int[] {80,8080});
+ cookie1.setVersion(1);
+ // domain, path, port specified
+ cookie1.setAttribute(ClientCookie.DOMAIN_ATTR, ".domain.com");
+ cookie1.setAttribute(ClientCookie.PATH_ATTR, "/");
+ cookie1.setAttribute(ClientCookie.PORT_ATTR, "80,8080");
+
+ BasicClientCookie2 cookie2 = new BasicClientCookie2("name2", "");
+ cookie2.setDomain(".domain.com");
+ cookie2.setPath("/");
+ cookie2.setPorts(new int[] {80,8080});
+ cookie2.setVersion(1);
+ // value null, domain, path specified
+ cookie2.setAttribute(ClientCookie.DOMAIN_ATTR, ".domain.com");
+ cookie2.setAttribute(ClientCookie.PATH_ATTR, "/");
+
+ Header[] headers = cookiespec.formatCookies(new Cookie[] {cookie1, cookie2});
+ assertNotNull(headers);
+ assertEquals(1, headers.length);
+
+ assertEquals("$Version=1; name1=\"value1\"; $Path=\"/\"; $Domain=\".domain.com\"; $Port=\"80,8080\"; " +
+ "name2=\"\"; $Path=\"/\"; $Domain=\".domain.com\"",
+ headers[0].getValue());
+ }
+
+ // ------------------------------------------------------- Backward compatibility tests
+
+ /**
+ * Test backward compatibility with Set-Cookie header.
+ */
+ public void testCompatibilityWithSetCookie() throws Exception {
+ CookieSpec cookiespec = new RFC2965Spec();
+ CookieOrigin origin = new CookieOrigin("www.domain.com", 80, "/", false);
+ Header header = new BasicHeader("Set-Cookie", "name=value; domain=.domain.com; version=1");
+ Cookie[] parsed = cookiespec.parse(header, origin);
+ assertNotNull(parsed);
+ assertEquals(1, parsed.length);
+ assertEquals("name", parsed[0].getName());
+ assertEquals("value", parsed[0].getValue());
+ assertEquals(".domain.com", parsed[0].getDomain());
+ assertEquals("/", parsed[0].getPath());
+ }
+
+}
+