Repository: jhy/jsoup
Pull request #2218 (2024-10-21 23:26:55)

Bump org.junit.jupiter:junit-jupiter from 5.11.0 to 5.11.3
Bumps [org.junit.jupiter:junit-jupiter](https://github.com/junit-team/junit5) from 5.11.0 to 5.11.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/junit-team/junit5/releases">org.junit.jupiter:junit-jupiter's releases</a>.</em></p>
<blockquote>
<p>JUnit 5.11.3 = Platform 1.11.3 + Jupiter 5.11.3 + Vintage 5.11.3</p>
<p>See <a href="http://junit.org/junit5/docs/5.11.3/release-notes/">Release Notes</a>.</p>
<p><strong>Full Changelog</strong>: <a href="https://github.com/junit-team/junit5/compare/r5.11.2...r5.11.3">https://github.com/junit-team/junit5/compare/r5.11.2...r5.11.3</a></p>
<p>JUnit 5.11.2 = Platform 1.11.2 + Jupiter 5.11.2 + Vintage 5.11.2</p>
<p>See <a href="http://junit.org/junit5/docs/5.11.2/release-notes/">Release Notes</a>.</p>
<p><strong>Full Changelog</strong>: <a href="https://github.com/junit-team/junit5/compare/r5.11.1...r5.11.2">https://github.com/junit-team/junit5/compare/r5.11.1...r5.11.2</a></p>
<p>JUnit 5.11.1 = Platform 1.11.1 + Jupiter 5.11.1 + Vintage 5.11.1</p>
<p>See <a href="http://junit.org/junit5/docs/5.11.1/release-notes/">Release Notes</a>.</p>
<p><strong>Full Changelog</strong>: <a href="https://github.com/junit-team/junit5/compare/r5.11.0...r5.11.1">https://github.com/junit-team/junit5/compare/r5.11.0...r5.11.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/junit-team/junit5/commit/b20991e3760b3053d5b71846ce5950de90650ab9"><code>b20991e</code></a> Release 5.11.3</li>
<li><a href="https://github.com/junit-team/junit5/commit/e57b508692765e0e4c869d96d889f3d82216dd5e"><code>e57b508</code></a> Finalize 5.11.3 release notes</li>
<li><a href="https://github.com/junit-team/junit5/commit/fb1254cb132135221852e7d048c906a6ce13ea4e"><code>fb1254c</code></a> Allow repeating <code>ExtendWith</code> annotation on fields and parameters</li>
<li><a href="https://github.com/junit-team/junit5/commit/a3192bd97fa13adb6c2aa1fe9207a4de18dcc002"><code>a3192bd</code></a> Fix package name comparison on Java 8 (<a href="https://redirect.github.com/junit-team/junit5/issues/4077">#4077</a>)</li>
<li><a href="https://github.com/junit-team/junit5/commit/fcb7b0197ec1569396253e257dce0b5fd2a02211"><code>fcb7b01</code></a> Remove useless <code>Order</code> annotation</li>
<li><a href="https://github.com/junit-team/junit5/commit/57dfcb515f98289aefe9d318ba970a3149b235dc"><code>57dfcb5</code></a> Allow repeating <code>@…Source</code> annotations when used as meta annotations</li>
<li><a href="https://github.com/junit-team/junit5/commit/09cd8b35982a1890285d09cae18828f4c967fcf2"><code>09cd8b3</code></a> Add ArchUnit test for consistency of repeatable annotations</li>
<li><a href="https://github.com/junit-team/junit5/commit/fa46a92fc5b31139ae84660c74160eea95de4c85"><code>fa46a92</code></a> Hard-wrap at 90 characters</li>
<li><a href="https://github.com/junit-team/junit5/commit/8f45eeab5662706facaa327902dd02639ffe02e7"><code>8f45eea</code></a> Find repeatable @⁠ExtendWith meta-annotations on fields again</li>
<li><a href="https://github.com/junit-team/junit5/commit/b451122115c398b29e8d97363bf47725484a7bac"><code>b451122</code></a> Introduce release notes for 5.11.3</li>
<li>Additional commits viewable in <a href="https://github.com/junit-team/junit5/compare/r5.11.0...r5.11.3">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.junit.jupiter:junit-jupiter&package-manager=maven&previous-version=5.11.0&new-version=5.11.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

You can trigger a rebase of this PR by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>

> **Note**
> Automatic rebases have been disabled on this pull request as it has been open for over 30 days.



Patch:
diff --git a/.gitignore b/.gitignore
index b22249a2..a7ff73a6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@ target/
 *Thrash*
 bin/
 .vscode/
+.java-version
diff --git a/CHANGES.md b/CHANGES.md
index 39b789d9..73d01e17 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -29,8 +29,10 @@
   children. [2187](https://github.com/jhy/jsoup/issues/2187)
 * A selector query that included multiple `:has()` components in a nested `:has()` might incorrectly
   execute. [2131](https://github.com/jhy/jsoup/issues/2131)
-* Updated the simple view of cookies available via `Connection.Response#cookies()` to reflect the contents of the 
-  current cookie jar for the current URL. [1831](https://github.com/jhy/jsoup/issues/1831)
+* When cookie names in a response are duplicated, the simple view of cookies available via
+  `Connection.Response#cookies()` will provide the last one set. Generally it is better to use
+  the [Jsoup.newSession](https://jsoup.org/cookbook/web/request-session) method to maintain a cookie jar, as that
+  applies appropriate path selection on cookies when making requests. [1831](https://github.com/jhy/jsoup/issues/1831)
 
 ## 1.18.1 (2024-Jul-10)
 
diff --git a/pom.xml b/pom.xml
index 201f441b..aa01a6f3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -118,7 +118,7 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-javadoc-plugin</artifactId>
-        <version>3.10.0</version>
+        <version>3.11.1</version>
         <configuration>
           <doclint>none</doclint>
           <source>8</source>
@@ -203,7 +203,7 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-surefire-plugin</artifactId>
-        <version>3.5.0</version>
+        <version>3.5.2</version>
         <configuration>
           <!-- smaller stack to find stack overflows. Was 256, but Zulu on MacOS ARM needs >= 640 -->
           <argLine>-Xss640k</argLine>
@@ -211,7 +211,7 @@
       </plugin>
       <plugin>
         <artifactId>maven-failsafe-plugin</artifactId>
-        <version>3.5.0</version>
+        <version>3.5.2</version>
         <executions>
           <execution>
             <goals>
@@ -372,7 +372,7 @@
         <plugins>
           <plugin>
             <artifactId>maven-failsafe-plugin</artifactId>
-            <version>3.5.0</version>
+            <version>3.5.2</version>
             <executions>
               <execution>
                 <goals>
@@ -393,7 +393,7 @@
     <dependency>
       <groupId>org.junit.jupiter</groupId>
       <artifactId>junit-jupiter</artifactId>
-      <version>5.11.0</version>
+      <version>5.11.3</version>
       <scope>test</scope>
     </dependency>
 
diff --git a/src/main/java/org/jsoup/Connection.java b/src/main/java/org/jsoup/Connection.java
index 55a5dbac..8ced43f0 100644
--- a/src/main/java/org/jsoup/Connection.java
+++ b/src/main/java/org/jsoup/Connection.java
@@ -632,9 +632,12 @@ public interface Connection {
         T removeCookie(String name);
 
         /**
-         * Retrieve all of the request/response cookies as a map
-         * @return cookies
-         * @see #cookieStore()
+         Retrieve the request/response cookies as a map. For response cookies, if duplicate cookie names were sent, the
+         last one set will be the one included. For session management, rather than using these response cookies, prefer
+         to use {@link Jsoup#newSession()} and related methods.
+
+         @return simple cookie map
+         @see #cookieStore()
          */
         Map<String, String> cookies();
     }
diff --git a/src/main/java/org/jsoup/helper/CookieUtil.java b/src/main/java/org/jsoup/helper/CookieUtil.java
index 218e935e..5ef9c468 100644
--- a/src/main/java/org/jsoup/helper/CookieUtil.java
+++ b/src/main/java/org/jsoup/helper/CookieUtil.java
@@ -2,6 +2,7 @@ package org.jsoup.helper;
 
 import org.jsoup.Connection;
 import org.jsoup.internal.StringUtil;
+import org.jsoup.parser.TokenQueue;
 
 import java.io.IOException;
 import java.net.CookieManager;
@@ -91,13 +92,21 @@ class CookieUtil {
         URI uri = CookieUtil.asUri(url);
         manager.put(uri, resHeaders); // stores cookies for session
 
-        // set up the simple cookie(name, value) map:
-        Map<String, List<String>> cookieMap = manager.get(uri, resHeaders); // get cookies for url; may have been set on this or earlier requests. the headers here are ignored other than a null check
-        for (List<String> values : cookieMap.values()) {
-            for (String headerVal : values) {
-                List<HttpCookie> cookies = HttpCookie.parse(headerVal);
-                for (HttpCookie cookie : cookies) {
-                    res.cookie(cookie.getName(), cookie.getValue());
+        // set up the simple cookies() map
+        // the response may include cookies that are not relevant to this request, but users may require them if they are not using the cookie manager (setting request cookies only from the simple cookies() response):
+        for (Map.Entry<String, List<String>> entry : resHeaders.entrySet()) {
+            String name = entry.getKey();
+            List<String> values = entry.getValue();
+            if (name.equalsIgnoreCase("Set-Cookie")) {
+                for (String value : values) {
+                    if (value == null)
+                        continue;
+                    TokenQueue cd = new TokenQueue(value);
+                    String cookieName = cd.chompTo("=").trim();
+                    String cookieVal = cd.consumeTo(";").trim();
+                    // ignores path, date, domain, validateTLSCertificates et al. full details will be available in cookiestore if required
+                    // name not blank, value not null
+                    res.cookie(cookieName, cookieVal); // if duplicate names, last set will win
                 }
             }
         }
diff --git a/src/main/java/org/jsoup/helper/HttpConnection.java b/src/main/java/org/jsoup/helper/HttpConnection.java
index 71201910..a33bcd91 100644
--- a/src/main/java/org/jsoup/helper/HttpConnection.java
+++ b/src/main/java/org/jsoup/helper/HttpConnection.java
@@ -1136,6 +1136,11 @@ public class HttpConnection implements Connection {
             CookieUtil.storeCookies(req, this, url, resHeaders); // add set cookies to cookie store
 
             if (previousResponse != null) { // was redirected
+                // map previous response cookies into this response cookies() object
+                for (Map.Entry<String, String> prevCookie : previousResponse.cookies().entrySet()) {
+                    if (!hasCookie(prevCookie.getKey()))
+                        cookie(prevCookie.getKey(), prevCookie.getValue());
+                }
                 previousResponse.safeClose();
 
                 // enforce too many redirects:


Test patch:
diff --git a/src/test/java/org/jsoup/integration/ConnectTest.java b/src/test/java/org/jsoup/integration/ConnectTest.java
index 6042f81c..8929dcac 100644
--- a/src/test/java/org/jsoup/integration/ConnectTest.java
+++ b/src/test/java/org/jsoup/integration/ConnectTest.java
@@ -1026,4 +1026,3 @@ public class ConnectTest {
         assertEquals(LargeDocTextLen, document.text().length());
     }
 }
-
diff --git a/src/test/java/org/jsoup/integration/SessionTest.java b/src/test/java/org/jsoup/integration/SessionTest.java
index 89264050..4ae5c5e6 100644
--- a/src/test/java/org/jsoup/integration/SessionTest.java
+++ b/src/test/java/org/jsoup/integration/SessionTest.java
@@ -48,9 +48,12 @@ public class SessionTest {
         Connection con2 = session.newRequest().data(CookieServlet.SetCookiesParam, "1");
         Document doc2 = con2.get();
         assertEquals(0, doc2.select("table tr").size());  // none sent to servlet - we just got them!
-        Map<String, String> cookies = con2.response().cookies(); // simple cookie response, all named "One", so should be first sent
-        assertEquals(1, cookies.size());
-        assertEquals("Root", cookies.get("One"));
+        Map<String, String> cookies = con2.response().cookies(); // simple cookie response, all named "One", so should be last sent
+        assertEquals(2, cookies.size());
+        assertEquals("EchoServlet", cookies.get("One"));
+
+        // test that all response cookies are present, even if would not be sent for this request path (i.e. cookies() res can be set on a req, without using sessions)
+        assertEquals("Override", cookies.get("Two"));
 
         // todo - interrogate cookie-store
 
diff --git a/src/test/java/org/jsoup/integration/servlets/CookieServlet.java b/src/test/java/org/jsoup/integration/servlets/CookieServlet.java
index ef5955f5..ccddee72 100644
--- a/src/test/java/org/jsoup/integration/servlets/CookieServlet.java
+++ b/src/test/java/org/jsoup/integration/servlets/CookieServlet.java
@@ -61,6 +61,14 @@ public class CookieServlet extends BaseServlet {
         Cookie three = new Cookie("One", "EchoServlet");
         three.setPath("/EchoServlet");
         res.addCookie(three);
+
+        Cookie four = new Cookie("Two", "NoSuchPath");
+        four.setPath("/bogus");
+        res.addCookie(four);
+
+        Cookie five = new Cookie("Two", "Override");
+        five.setPath("/bogus");
+        res.addCookie(five);
     }
 
 }