Add Partitioned cookie attribute support for servers
This commit adds support for the "Partitioned" cookie attribute in WebFlux servers and the related testing infrastructure. Note, Undertow does not support this feature at the moment. Closes gh-31454
This commit is contained in:
@@ -98,6 +98,24 @@ public class MockCookie extends Cookie {
|
||||
return getAttribute(SAME_SITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the "Partitioned" attribute for this cookie.
|
||||
* @since 6.2
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/draft-cutler-httpbis-partitioned-cookies#section-2.1">The Partitioned attribute spec</a>
|
||||
*/
|
||||
public void setPartitioned(boolean partitioned) {
|
||||
setAttribute("Partitioned", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the "Partitioned" attribute is set for this cookie.
|
||||
* @since 6.2
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/draft-cutler-httpbis-partitioned-cookies#section-2.1">The Partitioned attribute spec</a>
|
||||
*/
|
||||
public boolean isPartitioned() {
|
||||
return getAttribute("Partitioned") != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method that parses the value of the supplied "Set-Cookie" header.
|
||||
* @param setCookieHeader the "Set-Cookie" value; never {@code null} or empty
|
||||
@@ -146,6 +164,9 @@ public class MockCookie extends Cookie {
|
||||
else if (StringUtils.startsWithIgnoreCase(attribute, "Comment")) {
|
||||
cookie.setComment(extractAttributeValue(attribute, setCookieHeader));
|
||||
}
|
||||
else if (!attribute.isEmpty()) {
|
||||
cookie.setAttribute(attribute, extractOptionalAttributeValue(attribute, setCookieHeader));
|
||||
}
|
||||
}
|
||||
return cookie;
|
||||
}
|
||||
@@ -157,6 +178,11 @@ public class MockCookie extends Cookie {
|
||||
return nameAndValue[1];
|
||||
}
|
||||
|
||||
private static String extractOptionalAttributeValue(String attribute, String header) {
|
||||
String[] nameAndValue = attribute.split("=");
|
||||
return nameAndValue.length == 2 ? nameAndValue[1] : "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, @Nullable String value) {
|
||||
if (EXPIRES.equalsIgnoreCase(name)) {
|
||||
@@ -176,6 +202,7 @@ public class MockCookie extends Cookie {
|
||||
.append("Comment", getComment())
|
||||
.append("Secure", getSecure())
|
||||
.append("HttpOnly", isHttpOnly())
|
||||
.append("Partitioned", isPartitioned())
|
||||
.append(SAME_SITE, getSameSite())
|
||||
.append("Max-Age", getMaxAge())
|
||||
.append(EXPIRES, getAttribute(EXPIRES))
|
||||
|
||||
@@ -481,6 +481,9 @@ public class MockHttpServletResponse implements HttpServletResponse {
|
||||
if (cookie.isHttpOnly()) {
|
||||
buf.append("; HttpOnly");
|
||||
}
|
||||
if (cookie.getAttribute("Partitioned") != null) {
|
||||
buf.append("; Partitioned");
|
||||
}
|
||||
if (cookie instanceof MockCookie mockCookie) {
|
||||
if (StringUtils.hasText(mockCookie.getSameSite())) {
|
||||
buf.append("; SameSite=").append(mockCookie.getSameSite());
|
||||
|
||||
@@ -197,6 +197,19 @@ public class CookieAssertions {
|
||||
return this.responseSpec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert a cookie's "Partitioned" attribute.
|
||||
* @since 6.2
|
||||
*/
|
||||
public WebTestClient.ResponseSpec partitioned(String name, boolean expected) {
|
||||
boolean isPartitioned = getCookie(name).isPartitioned();
|
||||
this.exchangeResult.assertWithDiagnostics(() -> {
|
||||
String message = getMessage(name) + " isPartitioned";
|
||||
assertEquals(message, expected, isPartitioned);
|
||||
});
|
||||
return this.responseSpec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert a cookie's "SameSite" attribute.
|
||||
*/
|
||||
|
||||
@@ -209,6 +209,7 @@ public class MockMvcHttpConnector implements ClientHttpConnector {
|
||||
.path(cookie.getPath())
|
||||
.secure(cookie.getSecure())
|
||||
.httpOnly(cookie.isHttpOnly())
|
||||
.partitioned(cookie.getAttribute("Partitioned") != null)
|
||||
.sameSite(cookie.getAttribute("samesite"))
|
||||
.build();
|
||||
clientResponse.getCookies().add(httpCookie.getName(), httpCookie);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -229,6 +229,17 @@ public class CookieResultMatchers {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert whether the cookie is partitioned.
|
||||
* @since 6.2
|
||||
*/
|
||||
public ResultMatcher partitioned(String name, boolean partitioned) {
|
||||
return result -> {
|
||||
Cookie cookie = getCookie(result, name);
|
||||
assertEquals("Response cookie '" + name + "' partitioned", partitioned, cookie.getAttribute("Partitioned") != null);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert a cookie's specified attribute with a Hamcrest {@link Matcher}.
|
||||
* @param cookieAttribute the name of the Cookie attribute (case-insensitive)
|
||||
|
||||
Reference in New Issue
Block a user