hc-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ol...@apache.org
Subject svn commit: r1646864 [1/2] - in /httpcomponents/httpclient/trunk/httpclient/src: main/java/org/apache/http/client/protocol/ main/java/org/apache/http/cookie/ main/java/org/apache/http/impl/cookie/ test/java/org/apache/http/client/protocol/ test/java/or...
Date Fri, 19 Dec 2014 20:59:43 GMT
Author: olegk
Date: Fri Dec 19 20:59:42 2014
New Revision: 1646864

URL: http://svn.apache.org/r1646864
Log:
RFC 6265 compliant cookie spec

Added:
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/CookiePriorityComparator.java
      - copied, changed from r1646863, httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/CookiePathComparator.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/LaxExpiresHandler.java   (with props)
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/LaxMaxAgeHandler.java
      - copied, changed from r1646863, httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecBase.java   (with props)
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecProvider.java   (with props)
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265LaxSpec.java
      - copied, changed from r1646863, httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265StrictSpec.java
      - copied, changed from r1646863, httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicExpiresHandler.java
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/cookie/TestCookiePriorityComparator.java   (with props)
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/cookie/TestLaxCookieAttribHandlers.java   (with props)
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/cookie/TestRFC6265CookieSpecBase.java   (with props)
Removed:
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/cookie/TestAbstractCookieSpec.java
Modified:
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/RequestAddCookies.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/Cookie.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/CookieOrigin.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/CookiePathComparator.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicClientCookie.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicDomainHandler.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicExpiresHandler.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicPathHandler.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/DefaultCookieSpecProvider.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDomainHandler.java
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109Spec.java
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestAddCookies.java
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/cookie/TestBasicCookieAttribHandlers.java

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/RequestAddCookies.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/RequestAddCookies.java?rev=1646864&r1=1646863&r2=1646864&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/RequestAddCookies.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/client/protocol/RequestAddCookies.java Fri Dec 19 20:59:42 2014
@@ -156,10 +156,11 @@ public class RequestAddCookies implement
         }
         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 class RequestAddCookies implement
                 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);

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/Cookie.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/Cookie.java?rev=1646864&r1=1646863&r2=1646864&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/Cookie.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/Cookie.java Fri Dec 19 20:59:42 2014
@@ -133,5 +133,7 @@ public interface Cookie {
      */
     boolean isExpired(final Date date);
 
+    //TODO: RFC 6265 requires cookies to track their creation time; add #getCreationDate()
+
 }
 

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/CookieOrigin.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/CookieOrigin.java?rev=1646864&r1=1646863&r2=1646864&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/CookieOrigin.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/CookieOrigin.java Fri Dec 19 20:59:42 2014
@@ -30,6 +30,7 @@ import java.util.Locale;
 
 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 final class CookieOrigin {
         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 = "/";

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/CookiePathComparator.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/CookiePathComparator.java?rev=1646864&r1=1646863&r2=1646864&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/CookiePathComparator.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/CookiePathComparator.java Fri Dec 19 20:59:42 2014
@@ -50,6 +50,8 @@ import org.apache.http.annotation.Immuta
 @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) {

Copied: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/CookiePriorityComparator.java (from r1646863, httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/CookiePathComparator.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/CookiePriorityComparator.java?p2=httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/CookiePriorityComparator.java&p1=httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/CookiePathComparator.java&r1=1646863&r2=1646864&rev=1646864&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/CookiePathComparator.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/cookie/CookiePriorityComparator.java Fri Dec 19 20:59:42 2014
@@ -27,56 +27,43 @@
 
 package org.apache.http.cookie;
 
-import java.io.Serializable;
 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 multiple cookies satisfying
- * a common criteria are ordered in the {@code Cookie} header such
- * that those with more specific Path attributes precede those with
- * less specific.
+ * 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
  *
- * <p>
- * This comparator assumes that Path attributes of two cookies
- * path-match a commmon request-URI. Otherwise, the result of the
- * comparison is undefined.
- * </p>
- *
- *
- * @since 4.0
+ * @since 4.4
  */
 @Immutable
-public class CookiePathComparator implements Serializable, Comparator<Cookie> {
+public class CookiePriorityComparator implements Comparator<Cookie> {
 
-    private static final long serialVersionUID = 7523645369616405818L;
+    public static final CookiePriorityComparator INSTANCE = new CookiePriorityComparator();
 
-    private String normalizePath(final Cookie cookie) {
-        String path = cookie.getPath();
-        if (path == null) {
-            path = "/";
-        }
-        if (!path.endsWith("/")) {
-            path = path + '/';
-        }
-        return path;
+    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 String path1 = normalizePath(c1);
-        final String path2 = normalizePath(c2);
-        if (path1.equals(path2)) {
-            return 0;
-        } else if (path1.startsWith(path2)) {
-            return -1;
-        } else if (path2.startsWith(path1)) {
-            return 1;
-        } else {
-            // Does not really matter
-            return 0;
+        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;
     }
 
 }

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicClientCookie.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicClientCookie.java?rev=1646864&r1=1646863&r2=1646864&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicClientCookie.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicClientCookie.java Fri Dec 19 20:59:42 2014
@@ -304,6 +304,20 @@ public class BasicClientCookie implement
             && 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 class BasicClientCookie implement
     /** The version of the cookie specification I was created from. */
     private int cookieVersion;
 
+    private Date creationDate;
+
 }
 

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicDomainHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicDomainHandler.java?rev=1646864&r1=1646863&r2=1646864&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicDomainHandler.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicDomainHandler.java Fri Dec 19 20:59:42 2014
@@ -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.CookieRest
 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 class BasicDomainHandler implemen
     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;
+        }
+        String domain = value;
+        if (domain.startsWith(".")) {
+            domain = domain.substring(1);
         }
-        cookie.setDomain(value);
+        domain = domain.toLowerCase(Locale.ROOT);
+        cookie.setDomain(domain);
     }
 
     @Override
@@ -71,32 +81,32 @@ public class BasicDomainHandler implemen
         // 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.equals(domain) && !domainMatch(domain, host)) {
+            throw new CookieRestrictionViolationException(
+                    "Illegal 'domain' attribute \"" + domain + "\". Domain of origin: \"" + host + "\"");
         }
-        if (host.contains(".")) {
-            // Not required to have at least two dots.  RFC 2965.
-            // A Set-Cookie2 with Domain=ajax.com will be accepted.
-
-            // 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 class BasicDomainHandler implemen
         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

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicExpiresHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicExpiresHandler.java?rev=1646864&r1=1646863&r2=1646864&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicExpiresHandler.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicExpiresHandler.java Fri Dec 19 20:59:42 2014
@@ -56,11 +56,11 @@ public class BasicExpiresHandler extends
             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);

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java?rev=1646864&r1=1646863&r2=1646864&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java Fri Dec 19 20:59:42 2014
@@ -51,17 +51,17 @@ public class BasicMaxAgeHandler extends
             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));

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicPathHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicPathHandler.java?rev=1646864&r1=1646863&r2=1646864&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicPathHandler.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicPathHandler.java Fri Dec 19 20:59:42 2014
@@ -60,32 +60,38 @@ public class BasicPathHandler implements
             throws MalformedCookieException {
         if (!match(cookie, origin)) {
             throw new CookieRestrictionViolationException(
-                "Illegal path attribute \"" + cookie.getPath()
+                "Illegal 'path' attribute \"" + cookie.getPath()
                 + "\". Path of origin: \"" + origin.getPath() + "\"");
         }
     }
 
-    @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 = "/";
+    static boolean pathMatch(final String uriPath, final String cookiePath) {
+        String normalizedCookiePath = cookiePath;
+        if (normalizedCookiePath == null) {
+            normalizedCookiePath = "/";
         }
-        if (topmostPath.length() > 1 && topmostPath.endsWith("/")) {
-            topmostPath = topmostPath.substring(0, topmostPath.length() - 1);
+        if (normalizedCookiePath.length() > 1 && normalizedCookiePath.endsWith("/")) {
+            normalizedCookiePath = normalizedCookiePath.substring(0, normalizedCookiePath.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()) == '/');
+        if (uriPath.startsWith(normalizedCookiePath)) {
+            if (normalizedCookiePath.equals("/")) {
+                return true;
+            }
+            if (uriPath.length() == normalizedCookiePath.length()) {
+                return true;
+            }
+            if (uriPath.charAt(normalizedCookiePath.length()) == '/') {
+                return true;
             }
         }
-        return match;
+        return false;
+    }
+
+    @Override
+    public boolean match(final Cookie cookie, final CookieOrigin origin) {
+        Args.notNull(cookie, "Cookie");
+        Args.notNull(origin, "Cookie origin");
+        return pathMatch(origin.getPath(), cookie.getPath());
     }
 
     @Override

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/DefaultCookieSpecProvider.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/DefaultCookieSpecProvider.java?rev=1646864&r1=1646863&r2=1646864&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/DefaultCookieSpecProvider.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/DefaultCookieSpecProvider.java Fri Dec 19 20:59:42 2014
@@ -38,7 +38,7 @@ import org.apache.http.protocol.HttpCont
 
 /**
  * {@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

Added: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/LaxExpiresHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/LaxExpiresHandler.java?rev=1646864&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/LaxExpiresHandler.java (added)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/LaxExpiresHandler.java Fri Dec 19 20:59:42 2014
@@ -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;
+    }
+
+}

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/LaxExpiresHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/LaxExpiresHandler.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/LaxExpiresHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Copied: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/LaxMaxAgeHandler.java (from r1646863, httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/LaxMaxAgeHandler.java?p2=httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/LaxMaxAgeHandler.java&p1=httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java&r1=1646863&r2=1646864&rev=1646864&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/LaxMaxAgeHandler.java Fri Dec 19 20:59:42 2014
@@ -27,6 +27,8 @@
 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;
@@ -34,37 +36,39 @@ import org.apache.http.cookie.CommonCook
 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
+ * @since 4.4
  */
 @Immutable
-public class BasicMaxAgeHandler extends AbstractCookieAttributeHandler implements CommonCookieAttributeHandler {
+public class LaxMaxAgeHandler extends AbstractCookieAttributeHandler implements CommonCookieAttributeHandler {
 
-    public BasicMaxAgeHandler() {
+    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 {
+    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");
-        }
-        final int age;
-        try {
-            age = Integer.parseInt(value);
-        } catch (final NumberFormatException e) {
-            throw new MalformedCookieException ("Invalid max-age attribute: "
-                    + value);
+        if (TextUtils.isBlank(value)) {
+            return;
         }
-        if (age < 0) {
-            throw new MalformedCookieException ("Negative max-age attribute: "
-                    + value);
+        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);
         }
-        cookie.setExpiryDate(new Date(System.currentTimeMillis() + age * 1000L));
     }
 
     @Override

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDomainHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDomainHandler.java?rev=1646864&r1=1646863&r2=1646864&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDomainHandler.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/NetscapeDomainHandler.java Fri Dec 19 20:59:42 2014
@@ -30,30 +30,45 @@ import java.util.Locale;
 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 class NetscapeDomainHandler exten
        return host.endsWith(domain);
    }
 
+    @Override
+    public String getAttributeName() {
+        return ClientCookie.DOMAIN_ATTR;
+    }
+
 }

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109Spec.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109Spec.java?rev=1646864&r1=1646863&r2=1646864&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109Spec.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC2109Spec.java Fri Dec 19 20:59:42 2014
@@ -59,8 +59,6 @@ import org.apache.http.util.CharArrayBuf
 @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 class RFC2109Spec extends 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;
         }

Added: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecBase.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecBase.java?rev=1646864&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecBase.java (added)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecBase.java Fri Dec 19 20:59:42 2014
@@ -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;
+    }
+
+}

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecBase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecBase.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecBase.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecProvider.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecProvider.java?rev=1646864&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecProvider.java (added)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecProvider.java Fri Dec 19 20:59:42 2014
@@ -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;
+    }
+
+}

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecProvider.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265CookieSpecProvider.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Copied: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265LaxSpec.java (from r1646863, httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265LaxSpec.java?p2=httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265LaxSpec.java&p1=httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java&r1=1646863&r2=1646864&rev=1646864&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicMaxAgeHandler.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265LaxSpec.java Fri Dec 19 20:59:42 2014
@@ -24,52 +24,38 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.http.impl.cookie;
 
-import java.util.Date;
+package org.apache.http.impl.cookie;
 
-import org.apache.http.annotation.Immutable;
-import org.apache.http.cookie.ClientCookie;
+import org.apache.http.annotation.ThreadSafe;
 import org.apache.http.cookie.CommonCookieAttributeHandler;
-import org.apache.http.cookie.MalformedCookieException;
-import org.apache.http.cookie.SetCookie;
-import org.apache.http.util.Args;
 
 /**
+ * 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.0
+ * @since 4.4
  */
-@Immutable
-public class BasicMaxAgeHandler extends AbstractCookieAttributeHandler implements CommonCookieAttributeHandler {
+@ThreadSafe
+public class RFC6265LaxSpec extends RFC6265CookieSpecBase {
 
-    public BasicMaxAgeHandler() {
-        super();
+    public RFC6265LaxSpec() {
+        super(new BasicPathHandler(),
+                new BasicDomainHandler(),
+                new LaxMaxAgeHandler(),
+                new BasicSecureHandler(),
+                new LaxExpiresHandler());
     }
 
-    @Override
-    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");
-        }
-        final int age;
-        try {
-            age = Integer.parseInt(value);
-        } catch (final NumberFormatException e) {
-            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));
+    RFC6265LaxSpec(final CommonCookieAttributeHandler... handlers) {
+        super(handlers);
     }
 
     @Override
-    public String getAttributeName() {
-        return ClientCookie.MAX_AGE_ATTR;
+    public String toString() {
+        return "rfc6265-lax";
     }
 
 }

Copied: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265StrictSpec.java (from r1646863, httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicExpiresHandler.java)
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265StrictSpec.java?p2=httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265StrictSpec.java&p1=httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicExpiresHandler.java&r1=1646863&r2=1646864&rev=1646864&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/BasicExpiresHandler.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/RFC6265StrictSpec.java Fri Dec 19 20:59:42 2014
@@ -24,51 +24,44 @@
  * <http://www.apache.org/>.
  *
  */
-package org.apache.http.impl.cookie;
 
-import java.util.Date;
+package org.apache.http.impl.cookie;
 
-import org.apache.http.annotation.Immutable;
+import org.apache.http.annotation.ThreadSafe;
 import org.apache.http.client.utils.DateUtils;
-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;
 
 /**
+ * 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.0
+ * @since 4.4
  */
-@Immutable
-public class BasicExpiresHandler extends AbstractCookieAttributeHandler implements CommonCookieAttributeHandler {
+@ThreadSafe
+public class RFC6265StrictSpec extends RFC6265CookieSpecBase {
 
-    /** Valid date patterns */
-    private final String[] datepatterns;
-
-    public BasicExpiresHandler(final String[] datepatterns) {
-        Args.notNull(datepatterns, "Array of date patterns");
-        this.datepatterns = datepatterns;
+    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));
     }
 
-    @Override
-    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");
-        }
-        final Date expiry = DateUtils.parseDate(value, this.datepatterns);
-        if (expiry == null) {
-            throw new MalformedCookieException("Unable to parse expires attribute: "
-                    + value);
-        }
-        cookie.setExpiryDate(expiry);
+    RFC6265StrictSpec(final CommonCookieAttributeHandler... handlers) {
+        super(handlers);
     }
 
     @Override
-    public String getAttributeName() {
-        return ClientCookie.EXPIRES_ATTR;
+    public String toString() {
+        return "rfc6265-strict";
     }
 
 }

Modified: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestAddCookies.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestAddCookies.java?rev=1646864&r1=1646863&r2=1646864&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestAddCookies.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/client/protocol/TestRequestAddCookies.java Fri Dec 19 20:59:42 2014
@@ -57,6 +57,7 @@ import org.apache.http.protocol.HttpCore
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mockito;
 
 public class TestRequestAddCookies {
 
@@ -371,10 +372,13 @@ public class TestRequestAddCookies {
         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 class TestRequestAddCookies {
         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 class TestRequestAddCookies {
         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

Added: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/cookie/TestCookiePriorityComparator.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/cookie/TestCookiePriorityComparator.java?rev=1646864&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/cookie/TestCookiePriorityComparator.java (added)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/cookie/TestCookiePriorityComparator.java Fri Dec 19 20:59:42 2014
@@ -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);
+    }
+
+}
+

Propchange: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/cookie/TestCookiePriorityComparator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/cookie/TestCookiePriorityComparator.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/cookie/TestCookiePriorityComparator.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/cookie/TestBasicCookieAttribHandlers.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/cookie/TestBasicCookieAttribHandlers.java?rev=1646864&r1=1646863&r2=1646864&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/cookie/TestBasicCookieAttribHandlers.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/cookie/TestBasicCookieAttribHandlers.java Fri Dec 19 20:59:42 2014
@@ -35,6 +35,7 @@ import java.util.Locale;
 
 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 class TestBasicCookieAttribHandle
         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 class TestBasicCookieAttribHandle
         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");
@@ -163,6 +166,28 @@ public class TestBasicCookieAttribHandle
     }
 
     @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();
         try {



Mime
View raw message