Skip to content

Commit ca3440c

Browse files
committed
Re-enable support for invalid Expires attributes in MockCookie
Changes introduced in commit 9b20876 caused a regression for Cookie support in MockHttpServletResponse. Specifically, an Expires attribute that cannot be parsed using `ZonedDateTime.parse()` now results in an exception; whereas, previously an entry such as `Expires=0` was allowed. This commit fixes this issue in MockCookie by catching and ignoring any DateTimeException thrown while attempting to parse an Expires attribute. Closes gh-23911
1 parent 48b2229 commit ca3440c

File tree

4 files changed

+66
-8
lines changed

4 files changed

+66
-8
lines changed

spring-test/src/main/java/org/springframework/mock/web/MockCookie.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.mock.web;
1818

19+
import java.time.DateTimeException;
1920
import java.time.ZonedDateTime;
2021
import java.time.format.DateTimeFormatter;
2122

@@ -31,6 +32,7 @@
3132
*
3233
* @author Vedran Pavic
3334
* @author Juergen Hoeller
35+
* @author Sam Brannen
3436
* @since 5.1
3537
*/
3638
public class MockCookie extends Cookie {
@@ -119,8 +121,13 @@ else if (StringUtils.startsWithIgnoreCase(attribute, "Max-Age")) {
119121
cookie.setMaxAge(Integer.parseInt(extractAttributeValue(attribute, setCookieHeader)));
120122
}
121123
else if (StringUtils.startsWithIgnoreCase(attribute, "Expires")) {
122-
cookie.setExpires(ZonedDateTime.parse(extractAttributeValue(attribute, setCookieHeader),
123-
DateTimeFormatter.RFC_1123_DATE_TIME));
124+
try {
125+
cookie.setExpires(ZonedDateTime.parse(extractAttributeValue(attribute, setCookieHeader),
126+
DateTimeFormatter.RFC_1123_DATE_TIME));
127+
}
128+
catch (DateTimeException ex) {
129+
// ignore invalid date formats
130+
}
124131
}
125132
else if (StringUtils.startsWithIgnoreCase(attribute, "Path")) {
126133
cookie.setPath(extractAttributeValue(attribute, setCookieHeader));

spring-test/src/test/java/org/springframework/mock/web/MockCookieTests.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616

1717
package org.springframework.mock.web;
1818

19+
import java.time.ZonedDateTime;
20+
import java.time.format.DateTimeFormatter;
21+
1922
import org.junit.Rule;
2023
import org.junit.Test;
2124
import org.junit.rules.ExpectedException;
2225

23-
import java.time.ZonedDateTime;
24-
import java.time.format.DateTimeFormatter;
25-
2626
import static org.junit.Assert.*;
2727

2828
/**
@@ -84,6 +84,22 @@ public void parseHeaderWithAttributes() {
8484
assertEquals("Lax", cookie.getSameSite());
8585
}
8686

87+
@Test
88+
public void parseHeaderWithZeroExpiresAttribute() {
89+
MockCookie cookie = MockCookie.parse("SESSION=123; Expires=0");
90+
91+
assertCookie(cookie, "SESSION", "123");
92+
assertNull(cookie.getExpires());
93+
}
94+
95+
@Test
96+
public void parseHeaderWithBogusExpiresAttribute() {
97+
MockCookie cookie = MockCookie.parse("SESSION=123; Expires=bogus");
98+
99+
assertCookie(cookie, "SESSION", "123");
100+
assertNull(cookie.getExpires());
101+
}
102+
87103
private void assertCookie(MockCookie cookie, String name, String value) {
88104
assertEquals(name, cookie.getName());
89105
assertEquals(value, cookie.getValue());
@@ -116,7 +132,7 @@ public void parseInvalidAttribute() {
116132
public void parseHeaderWithAttributesCaseSensitivity() {
117133
MockCookie cookie = MockCookie.parse("SESSION=123; domain=example.com; max-age=60; " +
118134
"expires=Tue, 8 Oct 2019 19:50:00 GMT; path=/; secure; httponly; samesite=Lax");
119-
135+
120136
assertCookie(cookie, "SESSION", "123");
121137
assertEquals("example.com", cookie.getDomain());
122138
assertEquals(60, cookie.getMaxAge());

spring-test/src/test/java/org/springframework/mock/web/MockHttpServletResponseTests.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,20 @@ public void setCookieHeaderWithExpiresAttribute() {
351351
assertEquals(cookieValue, response.getHeader(HttpHeaders.SET_COOKIE));
352352
}
353353

354+
/**
355+
* @since 5.1.12
356+
*/
357+
@Test
358+
public void setCookieHeaderWithZeroExpiresAttribute() {
359+
String cookieValue = "SESSION=123; Path=/; Max-Age=100; Expires=0";
360+
response.setHeader(HttpHeaders.SET_COOKIE, cookieValue);
361+
assertNumCookies(1);
362+
String header = response.getHeader(HttpHeaders.SET_COOKIE);
363+
assertNotEquals(cookieValue, header);
364+
// We don't assert the actual Expires value since it is based on the current time.
365+
assertTrue(header.startsWith("SESSION=123; Path=/; Max-Age=100; Expires="));
366+
}
367+
354368
@Test
355369
public void addCookieHeader() {
356370
response.addHeader(HttpHeaders.SET_COOKIE, "SESSION=123; Path=/; Secure; HttpOnly; SameSite=Lax");
@@ -375,6 +389,20 @@ public void addCookieHeaderWithExpiresAttribute() {
375389
assertEquals(cookieValue, response.getHeader(HttpHeaders.SET_COOKIE));
376390
}
377391

392+
/**
393+
* @since 5.1.12
394+
*/
395+
@Test
396+
public void addCookieHeaderWithZeroExpiresAttribute() {
397+
String cookieValue = "SESSION=123; Path=/; Max-Age=100; Expires=0";
398+
response.addHeader(HttpHeaders.SET_COOKIE, cookieValue);
399+
assertNumCookies(1);
400+
String header = response.getHeader(HttpHeaders.SET_COOKIE);
401+
assertNotEquals(cookieValue, header);
402+
// We don't assert the actual Expires value since it is based on the current time.
403+
assertTrue(header.startsWith("SESSION=123; Path=/; Max-Age=100; Expires="));
404+
}
405+
378406
@Test
379407
public void addCookie() {
380408
MockCookie mockCookie = new MockCookie("SESSION", "123");

spring-web/src/test/java/org/springframework/mock/web/test/MockCookie.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.mock.web.test;
1818

19+
import java.time.DateTimeException;
1920
import java.time.ZonedDateTime;
2021
import java.time.format.DateTimeFormatter;
2122

@@ -31,6 +32,7 @@
3132
*
3233
* @author Vedran Pavic
3334
* @author Juergen Hoeller
35+
* @author Sam Brannen
3436
* @since 5.1
3537
*/
3638
public class MockCookie extends Cookie {
@@ -119,8 +121,13 @@ else if (StringUtils.startsWithIgnoreCase(attribute, "Max-Age")) {
119121
cookie.setMaxAge(Integer.parseInt(extractAttributeValue(attribute, setCookieHeader)));
120122
}
121123
else if (StringUtils.startsWithIgnoreCase(attribute, "Expires")) {
122-
cookie.setExpires(ZonedDateTime.parse(extractAttributeValue(attribute, setCookieHeader),
123-
DateTimeFormatter.RFC_1123_DATE_TIME));
124+
try {
125+
cookie.setExpires(ZonedDateTime.parse(extractAttributeValue(attribute, setCookieHeader),
126+
DateTimeFormatter.RFC_1123_DATE_TIME));
127+
}
128+
catch (DateTimeException ex) {
129+
// ignore invalid date formats
130+
}
124131
}
125132
else if (StringUtils.startsWithIgnoreCase(attribute, "Path")) {
126133
cookie.setPath(extractAttributeValue(attribute, setCookieHeader));

0 commit comments

Comments
 (0)