Skip to content

Commit dea6a6f

Browse files
authored
Remove special cookie attributes with null value (#13540)
* Remove special cookie attributes with null value Fix #13539 by allowing null to be used to remove cookie special attributes. * Fix handling of bad values * updates from review
1 parent be499ed commit dea6a6f

File tree

2 files changed

+72
-32
lines changed

2 files changed

+72
-32
lines changed

jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCookie.java

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -410,9 +410,12 @@ public String getAttributeValue()
410410
*/
411411
public static SameSite from(String sameSite)
412412
{
413-
if (sameSite == null)
413+
if (StringUtil.isBlank(sameSite))
414414
return null;
415-
return CACHE.get(sameSite);
415+
SameSite ss = CACHE.get(sameSite);
416+
if (ss == null)
417+
throw new IllegalArgumentException("Unknown same site");
418+
return ss;
416419
}
417420
}
418421

@@ -560,41 +563,26 @@ public Builder attribute(String name, String value)
560563
// Sanity checks on the values, expensive but necessary to avoid to store garbage.
561564
switch (name.toLowerCase(Locale.ENGLISH))
562565
{
563-
case "expires" -> expires(parseExpires(value));
564-
case "httponly" ->
565-
{
566-
if (!isTruthy(value))
567-
throw new IllegalArgumentException("Invalid HttpOnly attribute");
568-
httpOnly(true);
569-
}
570-
case "max-age" -> maxAge(Long.parseLong(value));
571-
case "samesite" ->
572-
{
573-
SameSite sameSite = SameSite.from(value);
574-
if (sameSite == null)
575-
throw new IllegalArgumentException("Invalid SameSite attribute");
576-
sameSite(sameSite);
577-
}
578-
case "secure" ->
579-
{
580-
if (!isTruthy(value))
581-
throw new IllegalArgumentException("Invalid Secure attribute");
582-
secure(true);
583-
}
584-
case "partitioned" ->
585-
{
586-
if (!isTruthy(value))
587-
throw new IllegalArgumentException("Invalid Partitioned attribute");
588-
partitioned(true);
589-
}
566+
case "expires" -> expires(StringUtil.isBlank(value) ? null : parseExpires(value));
567+
case "httponly" -> httpOnly(asBoolean("httponly", value));
568+
case "max-age" -> maxAge(StringUtil.isBlank(value) ? -1 : Long.parseLong(value));
569+
case "samesite" -> sameSite(SameSite.from(value));
570+
case "secure" -> secure(asBoolean("secure", value));
571+
case "partitioned" -> partitioned(asBoolean("partitioned", value));
590572
default -> _attributes = lazyAttributePut(_attributes, name, value);
591573
}
592574
return this;
593575
}
594576

595-
private boolean isTruthy(String value)
577+
private boolean asBoolean(String attribute, String value)
596578
{
597-
return value != null && (value.isEmpty() || "true".equalsIgnoreCase(value));
579+
if (value == null)
580+
return false;
581+
if (value.isEmpty() || "true".equalsIgnoreCase(value))
582+
return true;
583+
if ("false".equalsIgnoreCase(value))
584+
return false;
585+
throw new IllegalArgumentException("Invalid value for " + attribute);
598586
}
599587

600588
public Builder comment(String comment)
@@ -653,7 +641,7 @@ public Builder secure(boolean secure)
653641

654642
public Builder sameSite(SameSite sameSite)
655643
{
656-
_attributes = lazyAttributePut(_attributes, SAME_SITE_ATTRIBUTE, sameSite.attributeValue);
644+
_attributes = lazyAttributePut(_attributes, SAME_SITE_ATTRIBUTE, sameSite == null ? null : sameSite.attributeValue);
657645
return this;
658646
}
659647

jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/HttpCookieTest.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,15 @@
1616
import java.time.Instant;
1717
import java.util.List;
1818

19+
import org.junit.jupiter.api.Test;
1920
import org.junit.jupiter.params.ParameterizedTest;
2021
import org.junit.jupiter.params.provider.Arguments;
2122
import org.junit.jupiter.params.provider.MethodSource;
2223

2324
import static org.hamcrest.MatcherAssert.assertThat;
2425
import static org.hamcrest.Matchers.is;
26+
import static org.hamcrest.Matchers.notNullValue;
27+
import static org.hamcrest.Matchers.nullValue;
2528
import static org.junit.jupiter.api.Assertions.assertEquals;
2629
import static org.junit.jupiter.api.Assertions.assertThrows;
2730

@@ -105,4 +108,53 @@ public void testParseInvalidAttributes(String name, String value, Class<? extend
105108
.attribute(name, value));
106109
}
107110

111+
@Test
112+
public void testRemoveSpecialAttributes()
113+
{
114+
HttpCookie cookie = HttpCookie.build("name", "value")
115+
.expires(Instant.now())
116+
.httpOnly(true)
117+
.maxAge(1000)
118+
.sameSite(HttpCookie.SameSite.STRICT)
119+
.secure(true)
120+
.partitioned(true)
121+
.build();
122+
123+
assertThat(cookie.getExpires(), notNullValue());
124+
assertThat(cookie.isHttpOnly(), is(true));
125+
assertThat(cookie.getMaxAge(), is(1000L));
126+
assertThat(cookie.getSameSite(), is(HttpCookie.SameSite.STRICT));
127+
assertThat(cookie.isSecure(), is(true));
128+
assertThat(cookie.isPartitioned(), is(true));
129+
130+
HttpCookie noAttributes = HttpCookie.build(cookie)
131+
.expires(null)
132+
.httpOnly(false)
133+
.maxAge(-1)
134+
.sameSite(null)
135+
.secure(false)
136+
.partitioned(false)
137+
.build();
138+
assertThat(noAttributes.getExpires(), nullValue());
139+
assertThat(noAttributes.isHttpOnly(), is(false));
140+
assertThat(noAttributes.getMaxAge(), is(-1L));
141+
assertThat(noAttributes.getSameSite(), nullValue());
142+
assertThat(noAttributes.isSecure(), is(false));
143+
assertThat(noAttributes.isPartitioned(), is(false));
144+
145+
noAttributes = HttpCookie.build(cookie)
146+
.attribute(HttpCookie.EXPIRES_ATTRIBUTE, null)
147+
.attribute(HttpCookie.HTTP_ONLY_ATTRIBUTE, null)
148+
.attribute(HttpCookie.MAX_AGE_ATTRIBUTE, null)
149+
.attribute(HttpCookie.SAME_SITE_ATTRIBUTE, null)
150+
.attribute(HttpCookie.SECURE_ATTRIBUTE, null)
151+
.attribute(HttpCookie.PARTITIONED_ATTRIBUTE, null)
152+
.build();
153+
assertThat(noAttributes.getExpires(), nullValue());
154+
assertThat(noAttributes.isHttpOnly(), is(false));
155+
assertThat(noAttributes.getMaxAge(), is(-1L));
156+
assertThat(noAttributes.getSameSite(), nullValue());
157+
assertThat(noAttributes.isSecure(), is(false));
158+
assertThat(noAttributes.isPartitioned(), is(false));
159+
}
108160
}

0 commit comments

Comments
 (0)