This is an automated email from the ASF dual-hosted git repository.

markt-asf pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/main by this push:
     new 1974ba80aa Fix Map.Entry contract for CaseInsensitiveKeyMap entries 
(#1075)
1974ba80aa is described below

commit 1974ba80aaaa011cc7923a8d986906bb708fcba2
Author: breken <[email protected]>
AuthorDate: Wed Nov 4 16:25:44 2026 +0800

    Fix Map.Entry contract for CaseInsensitiveKeyMap entries (#1075)
    
    The entries returned by entrySet() were a record, so equals() only
    matched other instances of that record and hashCode() did not follow the
    Map.Entry definition. As a result an entry was not equal to an equivalent
    entry from another map, and the map's hashCode() differed from that of an
    equal HashMap. Use AbstractMap.SimpleImmutableEntry, which implements the
    contract and still rejects setValue().
    
    Generated-by: Claude Code (Claude Opus 5.5)
    
    Co-authored-by: breken-ai <[email protected]>
    Co-authored-by: Claude Opus 5.5 <[email protected]>
---
 .../util/collections/CaseInsensitiveKeyMap.java    | 20 +----------------
 .../collections/TestCaseInsensitiveKeyMap.java     | 25 ++++++++++++++++++++++
 webapps/docs/changelog.xml                         |  7 ++++++
 3 files changed, 33 insertions(+), 19 deletions(-)

diff --git a/java/org/apache/tomcat/util/collections/CaseInsensitiveKeyMap.java 
b/java/org/apache/tomcat/util/collections/CaseInsensitiveKeyMap.java
index 45bf9f9886..bfca41d6c4 100644
--- a/java/org/apache/tomcat/util/collections/CaseInsensitiveKeyMap.java
+++ b/java/org/apache/tomcat/util/collections/CaseInsensitiveKeyMap.java
@@ -198,7 +198,7 @@ public class CaseInsensitiveKeyMap<V> extends 
AbstractMap<String,V> {
         @Override
         public Entry<String,V> next() {
             Entry<Key,V> entry = iterator.next();
-            return new EntryImpl<>(entry.getKey().getKey(), entry.getValue());
+            return new SimpleImmutableEntry<>(entry.getKey().getKey(), 
entry.getValue());
         }
 
         @Override
@@ -208,24 +208,6 @@ public class CaseInsensitiveKeyMap<V> extends 
AbstractMap<String,V> {
     }
 
 
-    private record EntryImpl<V>(String key, V value) implements 
Entry<String,V> {
-
-        @Override
-        public String getKey() {
-            return key;
-        }
-
-        @Override
-        public V getValue() {
-            return value;
-        }
-
-        @Override
-        public V setValue(V value) {
-            throw new UnsupportedOperationException();
-        }
-    }
-
     private static class Key {
 
         private final String key;
diff --git 
a/test/org/apache/tomcat/util/collections/TestCaseInsensitiveKeyMap.java 
b/test/org/apache/tomcat/util/collections/TestCaseInsensitiveKeyMap.java
index c61d29ca4d..fb3becc515 100644
--- a/test/org/apache/tomcat/util/collections/TestCaseInsensitiveKeyMap.java
+++ b/test/org/apache/tomcat/util/collections/TestCaseInsensitiveKeyMap.java
@@ -273,4 +273,29 @@ public class TestCaseInsensitiveKeyMap {
         iter.remove();
         Assert.assertTrue(map.isEmpty());
     }
+
+
+    @Test
+    public void testEntryEqualsAndHashCode() {
+        Object o1 = new Object();
+
+        CaseInsensitiveKeyMap<Object> map = new CaseInsensitiveKeyMap<>();
+        map.put("a", o1);
+
+        Map<String,Object> expected = new HashMap<>();
+        expected.put("a", o1);
+
+        Entry<String,Object> entry = map.entrySet().iterator().next();
+        Entry<String,Object> expectedEntry = 
expected.entrySet().iterator().next();
+
+        // Map.Entry contract
+        Assert.assertTrue(entry.equals(expectedEntry));
+        Assert.assertTrue(expectedEntry.equals(entry));
+        Assert.assertEquals(expectedEntry.hashCode(), entry.hashCode());
+
+        // Map contract: equal maps must have equal hash codes
+        Assert.assertEquals(expected, map);
+        Assert.assertEquals(map, expected);
+        Assert.assertEquals(expected.hashCode(), map.hashCode());
+    }
 }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 8a7cc42f52..6be68edd54 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -925,6 +925,13 @@
         challenges that specify a charset other than UTF-8, the only value
         RFC 7617 allows. (remm)
       </fix>
+      <fix>
+        Fix the entries returned by
+        <code>CaseInsensitiveKeyMap.entrySet()</code> so they implement the
+        <code>Map.Entry</code> <code>equals()</code> and 
<code>hashCode()</code>
+        contracts. This map backs the WebSocket handshake request and response
+        header maps. Pull request <pr>1075</pr> provided by breken-ai. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Web applications">


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to