Skip to content

Commit 92e0a21

Browse files
committed
document last changes and add some tests
1 parent d15e143 commit 92e0a21

4 files changed

Lines changed: 81 additions & 6 deletions

File tree

src/changes/changes.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88

99
<body>
1010
<release version="5.0.0" date="April 01, 2026" description="jdk17, Bugfixes">
11+
<action type="fix" dev="Lai Quang Duong">
12+
Align cookie max-age handling for huge values with the spec.
13+
</action>
1114
<action type="fix" dev="rbri">
1215
Intl: fix toStringSymbol for Intl, Collator, DateTimeFormat, Locale, and NumberFormat.
1316
</action>

src/main/java/org/htmlunit/http/CookieParser.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.Date;
2626
import java.util.List;
2727
import java.util.Locale;
28+
import java.util.regex.Pattern;
2829

2930
import org.htmlunit.BrowserVersion;
3031
import org.htmlunit.util.StringUtils;
@@ -55,6 +56,12 @@ public final class CookieParser {
5556
"EEE, dd MMM yy HH:mm:ss z" // Variant
5657
};
5758

59+
// Max-Age should be 400 days at most
60+
// https://httpwg.org/http-extensions/draft-ietf-httpbis-rfc6265bis.html#section-5.5
61+
private static final int MAX_MAX_AGE = 400 * 24 * 60 * 60;
62+
63+
private static final Pattern MAX_AGE_PATTERN = Pattern.compile("-?[0-9]+");
64+
5865
private CookieParser() {
5966
// Utility class
6067
}
@@ -261,11 +268,19 @@ private static Integer parseMaxAge(final String maxAgeString) throws MalformedCo
261268
return null;
262269
}
263270

271+
if (!MAX_AGE_PATTERN.matcher(maxAgeString).matches()) {
272+
throw new MalformedCookieException("Invalid 'max-age' attribute: '" + maxAgeString + "'");
273+
}
274+
275+
if (maxAgeString.startsWith("-")) {
276+
return -1;
277+
}
278+
264279
try {
265-
return Integer.parseInt(maxAgeString);
280+
return Math.min(Integer.parseInt(maxAgeString), MAX_MAX_AGE);
266281
}
267282
catch (final NumberFormatException e) {
268-
throw new MalformedCookieException("Invalid max-age value: " + maxAgeString);
283+
return MAX_MAX_AGE;
269284
}
270285
}
271286

src/test/java/org/htmlunit/CookieManagerTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,38 @@ public void cookieMaxAge_negativeDeletes() throws Exception {
505505
verifyTitle2(getWebDriver(), getExpectedAlerts()[1]);
506506
}
507507

508+
/**
509+
* @throws Exception if the test fails
510+
*/
511+
@Test
512+
@Alerts({"first=1", ""})
513+
public void cookieMaxAge_moreThan400Days() throws Exception {
514+
final String moreThan400Days = "" + ((400 * 24 * 60 * 60) + 60);
515+
516+
List<NameValuePair> responseHeader1 = new ArrayList<>();
517+
responseHeader1.add(new NameValuePair("Set-Cookie", "first=1;max-age=" + moreThan400Days));
518+
getMockWebConnection().setResponse(URL_FIRST, HTML_ALERT_COOKIE, 200, "OK", MimeType.TEXT_HTML,
519+
responseHeader1);
520+
521+
loadPage2(URL_FIRST, StandardCharsets.ISO_8859_1);
522+
verifyTitle2(getWebDriver(), getExpectedAlerts()[0]);
523+
}
524+
525+
/**
526+
* @throws Exception if the test fails
527+
*/
528+
@Test
529+
@Alerts({"first=1", ""})
530+
public void cookieMaxAge_long() throws Exception {
531+
List<NameValuePair> responseHeader1 = new ArrayList<>();
532+
responseHeader1.add(new NameValuePair("Set-Cookie", "first=1;max-age=99999999999"));
533+
getMockWebConnection().setResponse(URL_FIRST, HTML_ALERT_COOKIE, 200, "OK", MimeType.TEXT_HTML,
534+
responseHeader1);
535+
536+
loadPage2(URL_FIRST, StandardCharsets.ISO_8859_1);
537+
verifyTitle2(getWebDriver(), getExpectedAlerts()[0]);
538+
}
539+
508540
/**
509541
* @throws Exception if the test fails
510542
*/

src/test/java/org/htmlunit/http/CookieParserTest.java

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public void testCookieWithBlankName() throws Exception {
112112
}
113113

114114
/**
115-
* Test parsing a cookie with whitespace.
115+
* Test parsing a cookie with whitespace.
116116
*/
117117
@Test
118118
public void testCookieWithWhitespace() throws Exception {
@@ -200,7 +200,7 @@ public void testCookieWithSameSite() throws Exception {
200200
}
201201

202202
/**
203-
* Test parsing a cookie with SameSite=Lax.
203+
* Test parsing a cookie with SameSite=Lax.
204204
*/
205205
@Test
206206
public void testCookieWithSameSiteLax() throws Exception {
@@ -212,7 +212,7 @@ public void testCookieWithSameSiteLax() throws Exception {
212212
}
213213

214214
/**
215-
* Test parsing a cookie with SameSite=None.
215+
* Test parsing a cookie with SameSite=None.
216216
*/
217217
@Test
218218
public void testCookieWithSameSiteNone() throws Exception {
@@ -285,6 +285,31 @@ public void testCookieWithMaxAgeNegative() throws Exception {
285285
assertNull(cookie.getExpires());
286286
}
287287

288+
/**
289+
* Test parsing a cookie with max-age more than 400 days.
290+
*/
291+
@Test
292+
public void testCookieWithMaxAgeTooBig() throws Exception {
293+
final String moreThan400Days = "" + ((400 * 24 * 60 * 60) + 60);
294+
final List<Cookie> cookies = parseCookie("name=value; max-age=" + moreThan400Days);
295+
296+
assertEquals(1, cookies.size());
297+
final Cookie cookie = cookies.get(0);
298+
assertNotNull(cookie.getExpires());
299+
}
300+
301+
/**
302+
* Test parsing a cookie with max-age that does not fit into an integer
303+
*/
304+
@Test
305+
public void testCookieWithMaxAgeLong() throws Exception {
306+
final List<Cookie> cookies = parseCookie("name=value; max-age=99999999999");
307+
308+
assertEquals(1, cookies.size());
309+
final Cookie cookie = cookies.get(0);
310+
assertNotNull(cookie.getExpires());
311+
}
312+
288313
/**
289314
* Test parsing a cookie with all attributes.
290315
*/
@@ -462,7 +487,7 @@ public void testCookieWithVersion() throws Exception {
462487
}
463488

464489
/**
465-
* Test parsing cookie with invalid max-age.
490+
* Test parsing cookie with invalid max-age.
466491
*/
467492
@Test
468493
public void testCookieWithInvalidMaxAge() {

0 commit comments

Comments
 (0)