Repository: netty/netty
Issue: Partitioned attribute support in ResponseCookie class

Chrome is going to deprecate third party cookies in near future, and it is mentioned [here](https://developers.google.com/privacy-sandbox/3pcd). 

We have many integration/leading applications depends on cross site cookies; all those will not work if the third-party cookies are not allowed to use.

There are some suggested ways to mitigate cross site issues which depend on cookies.

Cookies having independent partitioned state (CHIPS) is one of the proposals(https://developer.chrome.com/docs/privacy-sandbox/chips/).

For this, in ResponseCookie need a Boolean attribute called **partitioned** similar to secure field

```
private final boolean partitioned;

/**
* Add the "Partitioned" attribute to the cookie.
*/
ResponseCookieBuilder partitioned(boolean partitioned);
```

For testing purposes, we did try extending httpcookie and created custom cookie class but to add that cookie in exchange response, they are expecting only of type ResponseCookie
spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpResponse.java - getCookies() and addCookie() 

We do create the below request https://github.com/spring-projects/spring-framework/issues/31454

Please do provide this support as early as possible, we want to test by disabling third party cookies from leading applications for impact analysis.

Thanks in advance.



Issue comments:
We are also facing the same issue.
We are also facing the same issue

Pull request review comments:

Patch that resolved the issue:
diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/cookie/ClientCookieDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/cookie/ClientCookieDecoder.java
index e143b319051..8b967507c28 100644
--- a/codec-http/src/main/java/io/netty/handler/codec/http/cookie/ClientCookieDecoder.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/cookie/ClientCookieDecoder.java
@@ -156,6 +156,7 @@ private static class CookieBuilder {
         private boolean secure;
         private boolean httpOnly;
         private SameSite sameSite;
+        private boolean partitioned;
 
         CookieBuilder(DefaultCookie cookie, String header) {
             this.cookie = cookie;
@@ -183,6 +184,7 @@ Cookie cookie() {
             cookie.setSecure(secure);
             cookie.setHttpOnly(httpOnly);
             cookie.setSameSite(sameSite);
+            cookie.setPartitioned(partitioned);
             return cookie;
         }
 
@@ -210,6 +212,8 @@ void appendAttribute(int keyStart, int keyEnd, int valueStart, int valueEnd) {
                 parse7(keyStart, valueStart, valueEnd);
             } else if (length == 8) {
                 parse8(keyStart, valueStart, valueEnd);
+            } else if (length == 11) {
+                parse11(keyStart);
             }
         }
 
@@ -252,6 +256,12 @@ private void parse8(int nameStart, int valueStart, int valueEnd) {
             }
         }
 
+        private void parse11(int nameStart) {
+            if (header.regionMatches(true, nameStart, CookieHeaderNames.PARTITIONED, 0, 11)) {
+                partitioned = true;
+            }
+        }
+
         private static boolean isValueDefined(int valueStart, int valueEnd) {
             return valueStart != -1 && valueStart != valueEnd;
         }
diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/cookie/CookieHeaderNames.java b/codec-http/src/main/java/io/netty/handler/codec/http/cookie/CookieHeaderNames.java
index 7e3881ebef0..723f3b980fa 100644
--- a/codec-http/src/main/java/io/netty/handler/codec/http/cookie/CookieHeaderNames.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/cookie/CookieHeaderNames.java
@@ -30,6 +30,8 @@ public final class CookieHeaderNames {
 
     public static final String SAMESITE = "SameSite";
 
+    public static final String PARTITIONED = "Partitioned";
+
     /**
      * Possible values for the SameSite attribute.
      * See <a href="https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-05">changes to RFC6265bis</a>
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 f40a0277d55..41d54ca8e53 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
@@ -36,6 +36,7 @@ public class DefaultCookie implements Cookie {
     private boolean secure;
     private boolean httpOnly;
     private SameSite sameSite;
+    private boolean partitioned;
 
     /**
      * Creates a new cookie with the specified name and value.
@@ -140,6 +141,24 @@ public void setSameSite(SameSite sameSite) {
         this.sameSite = sameSite;
     }
 
+    /**
+     * Checks to see if this {@link Cookie} is partitioned
+     *
+     * @return True if this {@link Cookie} is partitioned, otherwise false
+     */
+    public boolean isPartitioned() {
+        return partitioned;
+    }
+
+    /**
+     * Sets the {@code Partitioned} attribute of this {@link Cookie}
+     *
+     * @param partitioned True if this {@link Cookie} is to be partitioned, otherwise false
+     */
+    public void setPartitioned(boolean partitioned) {
+        this.partitioned = partitioned;
+    }
+
     @Override
     public int hashCode() {
         return name().hashCode();
@@ -256,6 +275,9 @@ public String toString() {
         if (sameSite() != null) {
             buf.append(", SameSite=").append(sameSite());
         }
+        if (isPartitioned()) {
+            buf.append(", Partitioned");
+        }
         return buf.toString();
     }
 }
diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/cookie/ServerCookieEncoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/cookie/ServerCookieEncoder.java
index b33d923b2b5..d5153f9eff0 100644
--- a/codec-http/src/main/java/io/netty/handler/codec/http/cookie/ServerCookieEncoder.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/cookie/ServerCookieEncoder.java
@@ -129,6 +129,9 @@ public String encode(Cookie cookie) {
             if (c.sameSite() != null) {
                 add(buf, CookieHeaderNames.SAMESITE, c.sameSite().name());
             }
+            if (c.isPartitioned()) {
+                add(buf, CookieHeaderNames.PARTITIONED);
+            }
         }
 
         return stripTrailingSeparator(buf);


Test patch:
diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/cookie/ClientCookieDecoderTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/cookie/ClientCookieDecoderTest.java
index deb0edbf339..2cf53b59338 100644
--- a/codec-http/src/test/java/io/netty/handler/codec/http/cookie/ClientCookieDecoderTest.java
+++ b/codec-http/src/test/java/io/netty/handler/codec/http/cookie/ClientCookieDecoderTest.java
@@ -41,7 +41,7 @@ public class ClientCookieDecoderTest {
     public void testDecodingSingleCookieV0() {
         String cookieString = "myCookie=myValue;expires="
                 + DateFormatter.format(new Date(System.currentTimeMillis() + 50000))
-                + ";path=/apathsomewhere;domain=.adomainsomewhere;secure;SameSite=None";
+                + ";path=/apathsomewhere;domain=.adomainsomewhere;secure;SameSite=None;Partitioned";
 
         Cookie cookie = ClientCookieDecoder.STRICT.decode(cookieString);
         assertNotNull(cookie);
@@ -55,7 +55,9 @@ public void testDecodingSingleCookieV0() {
         assertTrue(cookie.isSecure());
 
         assertThat(cookie, is(instanceOf(DefaultCookie.class)));
-        assertEquals(SameSite.None, ((DefaultCookie) cookie).sameSite());
+        DefaultCookie c = (DefaultCookie) cookie;
+        assertEquals(SameSite.None, c.sameSite());
+        assertTrue(c.isPartitioned());
     }
 
     @Test
diff --git a/codec-http/src/test/java/io/netty/handler/codec/http/cookie/ServerCookieEncoderTest.java b/codec-http/src/test/java/io/netty/handler/codec/http/cookie/ServerCookieEncoderTest.java
index 6c86f65ff2d..51863f65870 100644
--- a/codec-http/src/test/java/io/netty/handler/codec/http/cookie/ServerCookieEncoderTest.java
+++ b/codec-http/src/test/java/io/netty/handler/codec/http/cookie/ServerCookieEncoderTest.java
@@ -44,13 +44,14 @@ public void testEncodingSingleCookieV0() throws ParseException {
         int maxAge = 50;
 
         String result = "myCookie=myValue; Max-Age=50; Expires=(.+?); Path=/apathsomewhere;" +
-                " Domain=.adomainsomewhere; Secure; SameSite=Lax";
+                " Domain=.adomainsomewhere; Secure; SameSite=Lax; Partitioned";
         DefaultCookie cookie = new DefaultCookie("myCookie", "myValue");
         cookie.setDomain(".adomainsomewhere");
         cookie.setMaxAge(maxAge);
         cookie.setPath("/apathsomewhere");
         cookie.setSecure(true);
         cookie.setSameSite(SameSite.Lax);
+        cookie.setPartitioned(true);
 
         String encodedCookie = ServerCookieEncoder.STRICT.encode(cookie);