Repository: netty/netty
Issue: Why cookie name is case-insensitive
Labels: defect

I fall in such situation when HTTP-server (implemented with Netty) receives two cookies: `session_id` and `Session_id`. But after parsing such header only one cookie is returned from method `decode`. 

Example:

``` java
Set<Cookie> cookies = ServerCookieDecoder.STRICT.decode("session_id=a; Session_id=b");
for (Cookie cookie: cookies) {
    System.out.println(cookie.name());
}
```

will print only `session_id`.

Is this a bug? [RFC 6265](https://tools.ietf.org/search/rfc6265) does not state that cookie names must be case insensitive.


Issue comments:
Yep, looks like a bug to me. The issue lays in `io.netty.handler.codec.http.cookie.DefaultCookie#equals` implementation that compares names with `equalsIgnoreCase`.

Would you like to contribute a fix?

yes, I'd like

https://github.com/netty/netty/pull/5737

Can be closed, as of #5737


Pull request review comments:
I know the spec doesn't say anything here, but it feels very weird to me that domain would be case sensitive. After all, it's more or less the host name of the server that originally set the cookie. And host names are definitively case insensitive. I would vote to keep case insensitivity here.

same as above

ping @normanmaurer @Scottmitch 

revert it back


Patch that resolved the issue:
diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/cookie/DefaultCookie.java b/codec-http/src/main/java/io/netty/handler/codec/http/cookie/DefaultCookie.java
index fb98555bb85..17fe5c43688 100644
--- a/codec-http/src/main/java/io/netty/handler/codec/http/cookie/DefaultCookie.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/cookie/DefaultCookie.java
@@ -135,7 +135,7 @@ public boolean equals(Object o) {
         }
 
         Cookie that = (Cookie) o;
-        if (!name().equalsIgnoreCase(that.name())) {
+        if (!name().equals(that.name())) {
             return false;
         }
 
@@ -164,7 +164,7 @@ public boolean equals(Object o) {
 
     @Override
     public int compareTo(Cookie c) {
-        int v = name().compareToIgnoreCase(c.name());
+        int v = name().compareTo(c.name());
         if (v != 0) {
             return v;
         }


Test patch:
diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/cookie/ServerCookieDecoderTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/cookie/ServerCookieDecoderTest.java
index d0c07646a55..fe9df5ec300 100644
--- a/codec-http/src/test/java/io/netty/handler/codec/http/cookie/ServerCookieDecoderTest.java
+++ b/codec-http/src/test/java/io/netty/handler/codec/http/cookie/ServerCookieDecoderTest.java
@@ -72,6 +72,10 @@ public void testDecodingGoogleAnalyticsCookie() {
         Iterator<Cookie> it = cookies.iterator();
         Cookie c;
 
+        c = it.next();
+        assertEquals("ARPT", c.name());
+        assertEquals("LWUKQPSWRTUN04CKKJI", c.value());
+
         c = it.next();
         assertEquals("__utma", c.name());
         assertEquals("48461872.1094088325.1258140131.1258140131.1258140131.1", c.value());
@@ -90,10 +94,6 @@ public void testDecodingGoogleAnalyticsCookie() {
                 "utmccn=(referral)|utmcmd=referral|utmcct=/Home-Garden/Furniture/Clearance/clearance/32/dept.html",
                 c.value());
 
-        c = it.next();
-        assertEquals("ARPT", c.name());
-        assertEquals("LWUKQPSWRTUN04CKKJI", c.value());
-
         c = it.next();
         assertEquals("kw-2E343B92-B097-442c-BFA5-BE371E0325A2", c.name());
         assertEquals("unfinished_furniture", c.value());
@@ -182,4 +182,21 @@ public void testRejectCookieValueWithSemicolon() {
         Set<Cookie> cookies = ServerCookieDecoder.STRICT.decode("name=\"foo;bar\";");
         assertTrue(cookies.isEmpty());
     }
+
+    @Test
+    public void testCaseSensitiveNames() {
+        Set<Cookie> cookies = ServerCookieDecoder.STRICT.decode("session_id=a; Session_id=b;");
+        Iterator<Cookie> it = cookies.iterator();
+        Cookie c;
+
+        c = it.next();
+        assertEquals("Session_id", c.name());
+        assertEquals("b", c.value());
+
+        c = it.next();
+        assertEquals("session_id", c.name());
+        assertEquals("a", c.value());
+
+        assertFalse(it.hasNext());
+    }
 }