diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java index bbc1ff88405..eabcc8e9957 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java @@ -80,17 +80,18 @@ import org.eclipse.jetty.util.thread.TimerScheduler; *

{@link HttpClient} also acts as a central configuration point for cookies, via {@link #getCookieStore()}.

*

Typical usage:

*
+ * HttpClient httpClient = new HttpClient();
+ * httpClient.start();
+ *
  * // One liner:
- * new HttpClient().GET("http://localhost:8080/").get().status();
+ * httpClient.GET("http://localhost:8080/").get().status();
  *
  * // Building a request with a timeout
- * HttpClient client = new HttpClient();
- * Response response = client.newRequest("http://localhost:8080").send().get(5, TimeUnit.SECONDS);
+ * Response response = httpClient.newRequest("http://localhost:8080").send().get(5, TimeUnit.SECONDS);
  * int status = response.status();
  *
  * // Asynchronously
- * HttpClient client = new HttpClient();
- * client.newRequest("http://localhost:8080").send(new Response.CompleteListener()
+ * httpClient.newRequest("http://localhost:8080").send(new Response.CompleteListener()
  * {
  *     @Override
  *     public void onComplete(Result result)
@@ -108,17 +109,17 @@ public class HttpClient extends ContainerLifeCycle
     private final ConcurrentMap conversations = new ConcurrentHashMap<>();
     private final List handlers = new CopyOnWriteArrayList<>();
     private final List requestListeners = new CopyOnWriteArrayList<>();
-    private final CookieStore cookieStore = new HttpCookieStore();
     private final AuthenticationStore authenticationStore = new HttpAuthenticationStore();
     private final Set decoderFactories = Collections.newSetFromMap(new ConcurrentHashMap());
     private final SslContextFactory sslContextFactory;
+    private volatile CookieStore cookieStore = new HttpCookieStore();
     private volatile Executor executor;
     private volatile ByteBufferPool byteBufferPool;
     private volatile Scheduler scheduler;
     private volatile SelectorManager selectorManager;
     private volatile String agent = "Jetty/" + Jetty.VERSION;
     private volatile boolean followRedirects = true;
-    private volatile int maxConnectionsPerDestination = 8;
+    private volatile int maxConnectionsPerDestination = 64;
     private volatile int maxRequestsQueuedPerDestination = 1024;
     private volatile int requestBufferSize = 4096;
     private volatile int responseBufferSize = 4096;
@@ -248,6 +249,14 @@ public class HttpClient extends ContainerLifeCycle
         return cookieStore;
     }
 
+    /**
+     * @param cookieStore the cookie store associated with this instance
+     */
+    public void setCookieStore(CookieStore cookieStore)
+    {
+        this.cookieStore = cookieStore;
+    }
+
     /**
      * @return the authentication store associated with this instance
      */
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpCookieStore.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpCookieStore.java
index 43ef9b82a65..2f0b4256df1 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpCookieStore.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpCookieStore.java
@@ -49,6 +49,8 @@ public class HttpCookieStore implements CookieStore
             accumulateCookies(destination, cookies, result);
 
         // Path lookup
+        if (path == null)
+            path = "/";
         String[] split = path.split("/");
         for (int i = 1; i < split.length; i++)
         {
@@ -130,6 +132,17 @@ public class HttpCookieStore implements CookieStore
         return true;
     }
 
+    @Override
+    public boolean removeCookie(Destination destination, HttpCookie cookie)
+    {
+        for (Queue cookies : allCookies.values())
+        {
+            if (cookies.remove(cookie))
+                return true;
+        }
+        return false;
+    }
+
     @Override
     public void clear()
     {
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/CookieStore.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/CookieStore.java
index 7ac798c58b6..e3b222d88b0 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/CookieStore.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/CookieStore.java
@@ -18,6 +18,7 @@
 
 package org.eclipse.jetty.client.api;
 
+import java.util.Collections;
 import java.util.List;
 
 import org.eclipse.jetty.client.HttpClient;
@@ -51,8 +52,46 @@ public interface CookieStore
      */
     boolean addCookie(Destination destination, HttpCookie cookie);
 
+    /**
+     * Removes the given cookie from this store for the given destination.
+     *
+     * @param destination the destination the cookie belongs to
+     * @param cookie the cookie to remove
+     * @return whether the cookie has been removed or not
+     */
+    boolean removeCookie(Destination destination, HttpCookie cookie);
+
     /**
      * Removes all the cookies from this store.
      */
     void clear();
+
+    /**
+     * A {@link CookieStore} that is always empty
+     */
+    public static class Empty implements CookieStore
+    {
+        @Override
+        public List findCookies(Destination destination, String path)
+        {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public boolean addCookie(Destination destination, HttpCookie cookie)
+        {
+            return false;
+        }
+
+        @Override
+        public boolean removeCookie(Destination destination, HttpCookie cookie)
+        {
+            return false;
+        }
+
+        @Override
+        public void clear()
+        {
+        }
+    }
 }