Preserve expires attribute in MockCookie
At present, MockCookie doesn't preserve expires attribute. This has a consequence that a cookie value set using MockHttpServletResponse#addHeader containing an expires attribute will not match the cookie value obtained from MockHttpServletResponse#getHeader, since the expires attribute will get calculated based on current time. This commit enhances MockCookie to preserve the expires attribute. Closes gh-23769
This commit is contained in:
committed by
Sam Brannen
parent
2482209437
commit
9b2087618b
@@ -16,6 +16,9 @@
|
||||
|
||||
package org.springframework.mock.web;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -35,6 +38,9 @@ public class MockCookie extends Cookie {
|
||||
private static final long serialVersionUID = 4312531139502726325L;
|
||||
|
||||
|
||||
@Nullable
|
||||
private ZonedDateTime expires;
|
||||
|
||||
@Nullable
|
||||
private String sameSite;
|
||||
|
||||
@@ -49,6 +55,20 @@ public class MockCookie extends Cookie {
|
||||
super(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the "Expires" attribute to the cookie.
|
||||
*/
|
||||
public void setExpires(@Nullable ZonedDateTime expires) {
|
||||
this.expires = expires;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the "Expires" attribute, or {@code null} if not set.
|
||||
*/
|
||||
@Nullable
|
||||
public ZonedDateTime getExpires() {
|
||||
return this.expires;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the "SameSite" attribute to the cookie.
|
||||
@@ -94,6 +114,10 @@ public class MockCookie extends Cookie {
|
||||
else if (StringUtils.startsWithIgnoreCase(attribute, "Max-Age")) {
|
||||
cookie.setMaxAge(Integer.parseInt(extractAttributeValue(attribute, setCookieHeader)));
|
||||
}
|
||||
else if (StringUtils.startsWithIgnoreCase(attribute, "Expires")) {
|
||||
cookie.setExpires(ZonedDateTime.parse(extractAttributeValue(attribute, setCookieHeader),
|
||||
DateTimeFormatter.RFC_1123_DATE_TIME));
|
||||
}
|
||||
else if (StringUtils.startsWithIgnoreCase(attribute, "Path")) {
|
||||
cookie.setPath(extractAttributeValue(attribute, setCookieHeader));
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.nio.charset.Charset;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -374,9 +375,14 @@ public class MockHttpServletResponse implements HttpServletResponse {
|
||||
if (maxAge >= 0) {
|
||||
buf.append("; Max-Age=").append(maxAge);
|
||||
buf.append("; Expires=");
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setExpires(maxAge > 0 ? System.currentTimeMillis() + 1000L * maxAge : 0);
|
||||
buf.append(headers.getFirst(HttpHeaders.EXPIRES));
|
||||
if (cookie instanceof MockCookie && ((MockCookie) cookie).getExpires() != null) {
|
||||
buf.append(((MockCookie) cookie).getExpires().format(DateTimeFormatter.RFC_1123_DATE_TIME));
|
||||
}
|
||||
else {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setExpires(maxAge > 0 ? System.currentTimeMillis() + 1000L * maxAge : 0);
|
||||
buf.append(headers.getFirst(HttpHeaders.EXPIRES));
|
||||
}
|
||||
}
|
||||
|
||||
if (cookie.getSecure()) {
|
||||
|
||||
@@ -18,6 +18,9 @@ package org.springframework.mock.web;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
@@ -62,8 +65,8 @@ class MockCookieTests {
|
||||
|
||||
@Test
|
||||
void parseHeaderWithAttributes() {
|
||||
MockCookie cookie = MockCookie.parse(
|
||||
"SESSION=123; Domain=example.com; Max-Age=60; Path=/; Secure; HttpOnly; SameSite=Lax");
|
||||
MockCookie cookie = MockCookie.parse("SESSION=123; Domain=example.com; Max-Age=60; " +
|
||||
"Expires=Tue, 8 Oct 2019 19:50:00 GMT; Path=/; Secure; HttpOnly; SameSite=Lax");
|
||||
|
||||
assertCookie(cookie, "SESSION", "123");
|
||||
assertThat(cookie.getDomain()).isEqualTo("example.com");
|
||||
@@ -71,6 +74,8 @@ class MockCookieTests {
|
||||
assertThat(cookie.getPath()).isEqualTo("/");
|
||||
assertThat(cookie.getSecure()).isTrue();
|
||||
assertThat(cookie.isHttpOnly()).isTrue();
|
||||
assertThat(cookie.getExpires()).isEqualTo(ZonedDateTime.parse("Tue, 8 Oct 2019 19:50:00 GMT",
|
||||
DateTimeFormatter.RFC_1123_DATE_TIME));
|
||||
assertThat(cookie.getSameSite()).isEqualTo("Lax");
|
||||
}
|
||||
|
||||
@@ -104,8 +109,8 @@ class MockCookieTests {
|
||||
|
||||
@Test
|
||||
void parseHeaderWithAttributesCaseSensitivity() {
|
||||
MockCookie cookie = MockCookie.parse(
|
||||
"SESSION=123; domain=example.com; max-age=60; path=/; secure; httponly; samesite=Lax");
|
||||
MockCookie cookie = MockCookie.parse("SESSION=123; domain=example.com; max-age=60; " +
|
||||
"expires=Tue, 8 Oct 2019 19:50:00 GMT; path=/; secure; httponly; samesite=Lax");
|
||||
|
||||
assertCookie(cookie, "SESSION", "123");
|
||||
assertThat(cookie.getDomain()).isEqualTo("example.com");
|
||||
@@ -113,6 +118,8 @@ class MockCookieTests {
|
||||
assertThat(cookie.getPath()).isEqualTo("/");
|
||||
assertThat(cookie.getSecure()).isTrue();
|
||||
assertThat(cookie.isHttpOnly()).isTrue();
|
||||
assertThat(cookie.getExpires()).isEqualTo(ZonedDateTime.parse("Tue, 8 Oct 2019 19:50:00 GMT",
|
||||
DateTimeFormatter.RFC_1123_DATE_TIME));
|
||||
assertThat(cookie.getSameSite()).isEqualTo("Lax");
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
* @author Sam Brannen
|
||||
* @author Brian Clozel
|
||||
* @author Sebastien Deleuze
|
||||
* @author Vedran Pavic
|
||||
* @since 19.02.2006
|
||||
*/
|
||||
class MockHttpServletResponseTests {
|
||||
@@ -362,6 +363,14 @@ class MockHttpServletResponseTests {
|
||||
assertCookieValues("123", "999");
|
||||
}
|
||||
|
||||
@Test
|
||||
void addCookieHeaderWithExpires() {
|
||||
String cookieValue = "SESSION=123; Path=/; Max-Age=100; Expires=Tue, 8 Oct 2019 19:50:00 GMT; Secure; " +
|
||||
"HttpOnly; SameSite=Lax";
|
||||
response.addHeader(HttpHeaders.SET_COOKIE, cookieValue);
|
||||
assertThat(response.getHeader(HttpHeaders.SET_COOKIE)).isEqualTo(cookieValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
void addCookie() {
|
||||
MockCookie mockCookie = new MockCookie("SESSION", "123");
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package org.springframework.mock.web.test;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -35,6 +38,9 @@ public class MockCookie extends Cookie {
|
||||
private static final long serialVersionUID = 4312531139502726325L;
|
||||
|
||||
|
||||
@Nullable
|
||||
private ZonedDateTime expires;
|
||||
|
||||
@Nullable
|
||||
private String sameSite;
|
||||
|
||||
@@ -49,6 +55,20 @@ public class MockCookie extends Cookie {
|
||||
super(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the "Expires" attribute to the cookie.
|
||||
*/
|
||||
public void setExpires(@Nullable ZonedDateTime expires) {
|
||||
this.expires = expires;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the "Expires" attribute, or {@code null} if not set.
|
||||
*/
|
||||
@Nullable
|
||||
public ZonedDateTime getExpires() {
|
||||
return this.expires;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the "SameSite" attribute to the cookie.
|
||||
@@ -94,6 +114,10 @@ public class MockCookie extends Cookie {
|
||||
else if (StringUtils.startsWithIgnoreCase(attribute, "Max-Age")) {
|
||||
cookie.setMaxAge(Integer.parseInt(extractAttributeValue(attribute, setCookieHeader)));
|
||||
}
|
||||
else if (StringUtils.startsWithIgnoreCase(attribute, "Expires")) {
|
||||
cookie.setExpires(ZonedDateTime.parse(extractAttributeValue(attribute, setCookieHeader),
|
||||
DateTimeFormatter.RFC_1123_DATE_TIME));
|
||||
}
|
||||
else if (StringUtils.startsWithIgnoreCase(attribute, "Path")) {
|
||||
cookie.setPath(extractAttributeValue(attribute, setCookieHeader));
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.nio.charset.Charset;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -374,9 +375,14 @@ public class MockHttpServletResponse implements HttpServletResponse {
|
||||
if (maxAge >= 0) {
|
||||
buf.append("; Max-Age=").append(maxAge);
|
||||
buf.append("; Expires=");
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setExpires(maxAge > 0 ? System.currentTimeMillis() + 1000L * maxAge : 0);
|
||||
buf.append(headers.getFirst(HttpHeaders.EXPIRES));
|
||||
if (cookie instanceof MockCookie && ((MockCookie) cookie).getExpires() != null) {
|
||||
buf.append(((MockCookie) cookie).getExpires().format(DateTimeFormatter.RFC_1123_DATE_TIME));
|
||||
}
|
||||
else {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setExpires(maxAge > 0 ? System.currentTimeMillis() + 1000L * maxAge : 0);
|
||||
buf.append(headers.getFirst(HttpHeaders.EXPIRES));
|
||||
}
|
||||
}
|
||||
|
||||
if (cookie.getSecure()) {
|
||||
|
||||
Reference in New Issue
Block a user