提交 9b208761 编写于 作者: V Vedran Pavic 提交者: Sam Brannen

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
上级 24822094
...@@ -16,6 +16,9 @@ ...@@ -16,6 +16,9 @@
package org.springframework.mock.web; package org.springframework.mock.web;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import javax.servlet.http.Cookie; import javax.servlet.http.Cookie;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
...@@ -35,6 +38,9 @@ public class MockCookie extends Cookie { ...@@ -35,6 +38,9 @@ public class MockCookie extends Cookie {
private static final long serialVersionUID = 4312531139502726325L; private static final long serialVersionUID = 4312531139502726325L;
@Nullable
private ZonedDateTime expires;
@Nullable @Nullable
private String sameSite; private String sameSite;
...@@ -49,6 +55,20 @@ public class MockCookie extends Cookie { ...@@ -49,6 +55,20 @@ public class MockCookie extends Cookie {
super(name, value); 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. * Add the "SameSite" attribute to the cookie.
...@@ -94,6 +114,10 @@ public class MockCookie extends Cookie { ...@@ -94,6 +114,10 @@ public class MockCookie extends Cookie {
else if (StringUtils.startsWithIgnoreCase(attribute, "Max-Age")) { else if (StringUtils.startsWithIgnoreCase(attribute, "Max-Age")) {
cookie.setMaxAge(Integer.parseInt(extractAttributeValue(attribute, setCookieHeader))); 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")) { else if (StringUtils.startsWithIgnoreCase(attribute, "Path")) {
cookie.setPath(extractAttributeValue(attribute, setCookieHeader)); cookie.setPath(extractAttributeValue(attribute, setCookieHeader));
} }
......
...@@ -27,6 +27,7 @@ import java.nio.charset.Charset; ...@@ -27,6 +27,7 @@ import java.nio.charset.Charset;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
...@@ -374,9 +375,14 @@ public class MockHttpServletResponse implements HttpServletResponse { ...@@ -374,9 +375,14 @@ public class MockHttpServletResponse implements HttpServletResponse {
if (maxAge >= 0) { if (maxAge >= 0) {
buf.append("; Max-Age=").append(maxAge); buf.append("; Max-Age=").append(maxAge);
buf.append("; Expires="); buf.append("; Expires=");
HttpHeaders headers = new HttpHeaders(); if (cookie instanceof MockCookie && ((MockCookie) cookie).getExpires() != null) {
headers.setExpires(maxAge > 0 ? System.currentTimeMillis() + 1000L * maxAge : 0); buf.append(((MockCookie) cookie).getExpires().format(DateTimeFormatter.RFC_1123_DATE_TIME));
buf.append(headers.getFirst(HttpHeaders.EXPIRES)); }
else {
HttpHeaders headers = new HttpHeaders();
headers.setExpires(maxAge > 0 ? System.currentTimeMillis() + 1000L * maxAge : 0);
buf.append(headers.getFirst(HttpHeaders.EXPIRES));
}
} }
if (cookie.getSecure()) { if (cookie.getSecure()) {
......
...@@ -18,6 +18,9 @@ package org.springframework.mock.web; ...@@ -18,6 +18,9 @@ package org.springframework.mock.web;
import org.junit.jupiter.api.Test; 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.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
...@@ -62,8 +65,8 @@ class MockCookieTests { ...@@ -62,8 +65,8 @@ class MockCookieTests {
@Test @Test
void parseHeaderWithAttributes() { void parseHeaderWithAttributes() {
MockCookie cookie = MockCookie.parse( MockCookie cookie = MockCookie.parse("SESSION=123; Domain=example.com; Max-Age=60; " +
"SESSION=123; Domain=example.com; Max-Age=60; Path=/; Secure; HttpOnly; SameSite=Lax"); "Expires=Tue, 8 Oct 2019 19:50:00 GMT; Path=/; Secure; HttpOnly; SameSite=Lax");
assertCookie(cookie, "SESSION", "123"); assertCookie(cookie, "SESSION", "123");
assertThat(cookie.getDomain()).isEqualTo("example.com"); assertThat(cookie.getDomain()).isEqualTo("example.com");
...@@ -71,6 +74,8 @@ class MockCookieTests { ...@@ -71,6 +74,8 @@ class MockCookieTests {
assertThat(cookie.getPath()).isEqualTo("/"); assertThat(cookie.getPath()).isEqualTo("/");
assertThat(cookie.getSecure()).isTrue(); assertThat(cookie.getSecure()).isTrue();
assertThat(cookie.isHttpOnly()).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"); assertThat(cookie.getSameSite()).isEqualTo("Lax");
} }
...@@ -104,8 +109,8 @@ class MockCookieTests { ...@@ -104,8 +109,8 @@ class MockCookieTests {
@Test @Test
void parseHeaderWithAttributesCaseSensitivity() { void parseHeaderWithAttributesCaseSensitivity() {
MockCookie cookie = MockCookie.parse( MockCookie cookie = MockCookie.parse("SESSION=123; domain=example.com; max-age=60; " +
"SESSION=123; domain=example.com; max-age=60; path=/; secure; httponly; samesite=Lax"); "expires=Tue, 8 Oct 2019 19:50:00 GMT; path=/; secure; httponly; samesite=Lax");
assertCookie(cookie, "SESSION", "123"); assertCookie(cookie, "SESSION", "123");
assertThat(cookie.getDomain()).isEqualTo("example.com"); assertThat(cookie.getDomain()).isEqualTo("example.com");
...@@ -113,6 +118,8 @@ class MockCookieTests { ...@@ -113,6 +118,8 @@ class MockCookieTests {
assertThat(cookie.getPath()).isEqualTo("/"); assertThat(cookie.getPath()).isEqualTo("/");
assertThat(cookie.getSecure()).isTrue(); assertThat(cookie.getSecure()).isTrue();
assertThat(cookie.isHttpOnly()).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"); assertThat(cookie.getSameSite()).isEqualTo("Lax");
} }
......
...@@ -42,6 +42,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException ...@@ -42,6 +42,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
* @author Sam Brannen * @author Sam Brannen
* @author Brian Clozel * @author Brian Clozel
* @author Sebastien Deleuze * @author Sebastien Deleuze
* @author Vedran Pavic
* @since 19.02.2006 * @since 19.02.2006
*/ */
class MockHttpServletResponseTests { class MockHttpServletResponseTests {
...@@ -362,6 +363,14 @@ class MockHttpServletResponseTests { ...@@ -362,6 +363,14 @@ class MockHttpServletResponseTests {
assertCookieValues("123", "999"); 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 @Test
void addCookie() { void addCookie() {
MockCookie mockCookie = new MockCookie("SESSION", "123"); MockCookie mockCookie = new MockCookie("SESSION", "123");
......
...@@ -16,6 +16,9 @@ ...@@ -16,6 +16,9 @@
package org.springframework.mock.web.test; package org.springframework.mock.web.test;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import javax.servlet.http.Cookie; import javax.servlet.http.Cookie;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
...@@ -35,6 +38,9 @@ public class MockCookie extends Cookie { ...@@ -35,6 +38,9 @@ public class MockCookie extends Cookie {
private static final long serialVersionUID = 4312531139502726325L; private static final long serialVersionUID = 4312531139502726325L;
@Nullable
private ZonedDateTime expires;
@Nullable @Nullable
private String sameSite; private String sameSite;
...@@ -49,6 +55,20 @@ public class MockCookie extends Cookie { ...@@ -49,6 +55,20 @@ public class MockCookie extends Cookie {
super(name, value); 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. * Add the "SameSite" attribute to the cookie.
...@@ -94,6 +114,10 @@ public class MockCookie extends Cookie { ...@@ -94,6 +114,10 @@ public class MockCookie extends Cookie {
else if (StringUtils.startsWithIgnoreCase(attribute, "Max-Age")) { else if (StringUtils.startsWithIgnoreCase(attribute, "Max-Age")) {
cookie.setMaxAge(Integer.parseInt(extractAttributeValue(attribute, setCookieHeader))); 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")) { else if (StringUtils.startsWithIgnoreCase(attribute, "Path")) {
cookie.setPath(extractAttributeValue(attribute, setCookieHeader)); cookie.setPath(extractAttributeValue(attribute, setCookieHeader));
} }
......
...@@ -27,6 +27,7 @@ import java.nio.charset.Charset; ...@@ -27,6 +27,7 @@ import java.nio.charset.Charset;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
...@@ -374,9 +375,14 @@ public class MockHttpServletResponse implements HttpServletResponse { ...@@ -374,9 +375,14 @@ public class MockHttpServletResponse implements HttpServletResponse {
if (maxAge >= 0) { if (maxAge >= 0) {
buf.append("; Max-Age=").append(maxAge); buf.append("; Max-Age=").append(maxAge);
buf.append("; Expires="); buf.append("; Expires=");
HttpHeaders headers = new HttpHeaders(); if (cookie instanceof MockCookie && ((MockCookie) cookie).getExpires() != null) {
headers.setExpires(maxAge > 0 ? System.currentTimeMillis() + 1000L * maxAge : 0); buf.append(((MockCookie) cookie).getExpires().format(DateTimeFormatter.RFC_1123_DATE_TIME));
buf.append(headers.getFirst(HttpHeaders.EXPIRES)); }
else {
HttpHeaders headers = new HttpHeaders();
headers.setExpires(maxAge > 0 ? System.currentTimeMillis() + 1000L * maxAge : 0);
buf.append(headers.getFirst(HttpHeaders.EXPIRES));
}
} }
if (cookie.getSecure()) { if (cookie.getSecure()) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册