diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/cookie/BasicCookieStore.java b/httpclient5/src/main/java/org/apache/hc/client5/http/cookie/BasicCookieStore.java index d9cc51a89f..01c0901558 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/cookie/BasicCookieStore.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/cookie/BasicCookieStore.java @@ -82,8 +82,18 @@ public void addCookie(final Cookie cookie) { if (cookie != null) { lock.writeLock().lock(); try { - // first remove any old cookie that is equivalent - cookies.remove(cookie); + final Cookie oldCookie = cookies.ceiling(cookie); + if (oldCookie != null && CookieIdentityComparator.INSTANCE.compare(oldCookie, cookie) == 0) { + if (cookie instanceof SetCookie) { + final Instant creationInstant = oldCookie.getCreationInstant(); + if (creationInstant != null) { + ((SetCookie) cookie).setCreationInstant(creationInstant); + } + } + cookies.remove(oldCookie); + } else { + cookies.remove(cookie); + } if (!cookie.isExpired(Instant.now())) { cookies.add(cookie); } diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/cookie/SetCookie.java b/httpclient5/src/main/java/org/apache/hc/client5/http/cookie/SetCookie.java index 1edfc66e66..b88606cf2d 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/cookie/SetCookie.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/cookie/SetCookie.java @@ -115,5 +115,14 @@ default void setExpiryDate(Instant expiryDate) { default void setHttpOnly(final boolean httpOnly) { } + /** + * Sets creation time of the cookie. + * + * @since 5.7 + */ + default void setCreationInstant(final Instant creationInstant) { + // no-op by default for backward compatibility + } + } diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/cookie/BasicClientCookie.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/cookie/BasicClientCookie.java index 95c65fd9b4..041d875c06 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/cookie/BasicClientCookie.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/cookie/BasicClientCookie.java @@ -330,6 +330,11 @@ public void setCreationDate(final Instant creationDate) { this.creationDate = creationDate; } + @Override + public void setCreationInstant(final Instant creationDate) { + setCreationDate(creationDate); + } + public void setAttribute(final String name, final String value) { this.attribs.put(name, value); } diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/cookie/TestBasicCookieStore.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/cookie/TestBasicCookieStore.java index fc75916655..61ec5f8078 100644 --- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/cookie/TestBasicCookieStore.java +++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/cookie/TestBasicCookieStore.java @@ -74,6 +74,29 @@ void testExpiredCookie() { Assertions.assertEquals(0, list.size()); } + @Test + void testReplacementPreservesCreationTime() { + final BasicCookieStore store = new BasicCookieStore(); + final Instant originalCreation = Instant.now().minus(1, ChronoUnit.DAYS); + + final BasicClientCookie original = new BasicClientCookie("name1", "value1"); + original.setDomain("example.com"); + original.setPath("/"); + original.setCreationDate(originalCreation); + store.addCookie(original); + + final BasicClientCookie replacement = new BasicClientCookie("name1", "value2"); + replacement.setDomain("example.com"); + replacement.setPath("/"); + replacement.setCreationDate(Instant.now()); + store.addCookie(replacement); + + final List list = store.getCookies(); + Assertions.assertEquals(1, list.size()); + Assertions.assertEquals("value2", list.get(0).getValue()); + Assertions.assertEquals(originalCreation, list.get(0).getCreationInstant()); + } + @Test void testSerialization() throws Exception { final BasicCookieStore orig = new BasicCookieStore();