Browse Source

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
pull/27217/head
Vedran Pavic 6 years ago committed by Sam Brannen
parent
commit
3814f12b67
  1. 24
      spring-test/src/main/java/org/springframework/mock/web/MockCookie.java
  2. 12
      spring-test/src/main/java/org/springframework/mock/web/MockHttpServletResponse.java
  3. 17
      spring-test/src/test/java/org/springframework/mock/web/MockCookieTests.java
  4. 9
      spring-test/src/test/java/org/springframework/mock/web/MockHttpServletResponseTests.java
  5. 24
      spring-web/src/test/java/org/springframework/mock/web/test/MockCookie.java
  6. 12
      spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletResponse.java

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

@ -16,6 +16,9 @@ @@ -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 { @@ -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 { @@ -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 { @@ -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));
}

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

@ -26,6 +26,7 @@ import java.io.Writer; @@ -26,6 +26,7 @@ import java.io.Writer;
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;
@ -345,9 +346,14 @@ public class MockHttpServletResponse implements HttpServletResponse { @@ -345,9 +346,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()) {

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

@ -20,6 +20,9 @@ import org.junit.Rule; @@ -20,6 +20,9 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import static org.junit.Assert.*;
/**
@ -67,8 +70,8 @@ public class MockCookieTests { @@ -67,8 +70,8 @@ public class MockCookieTests {
@Test
public 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");
assertEquals("example.com", cookie.getDomain());
@ -76,6 +79,8 @@ public class MockCookieTests { @@ -76,6 +79,8 @@ public class MockCookieTests {
assertEquals("/", cookie.getPath());
assertTrue(cookie.getSecure());
assertTrue(cookie.isHttpOnly());
assertEquals(ZonedDateTime.parse("Tue, 8 Oct 2019 19:50:00 GMT",
DateTimeFormatter.RFC_1123_DATE_TIME), cookie.getExpires());
assertEquals("Lax", cookie.getSameSite());
}
@ -109,15 +114,17 @@ public class MockCookieTests { @@ -109,15 +114,17 @@ public class MockCookieTests {
@Test
public 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");
assertEquals("example.com", cookie.getDomain());
assertEquals(60, cookie.getMaxAge());
assertEquals("/", cookie.getPath());
assertTrue(cookie.getSecure());
assertTrue(cookie.isHttpOnly());
assertEquals(ZonedDateTime.parse("Tue, 8 Oct 2019 19:50:00 GMT",
DateTimeFormatter.RFC_1123_DATE_TIME), cookie.getExpires());
assertEquals("Lax", cookie.getSameSite());
}

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

@ -39,6 +39,7 @@ import static org.junit.Assert.*; @@ -39,6 +39,7 @@ import static org.junit.Assert.*;
* @author Rob Winch
* @author Sam Brannen
* @author Brian Clozel
* @author Vedran Pavic
* @since 19.02.2006
*/
public class MockHttpServletResponseTests {
@ -351,6 +352,14 @@ public class MockHttpServletResponseTests { @@ -351,6 +352,14 @@ public class MockHttpServletResponseTests {
assertCookieValues("123", "999");
}
@Test
public 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);
assertEquals(cookieValue, response.getHeader(HttpHeaders.SET_COOKIE));
}
@Test
public void addCookie() {
MockCookie mockCookie = new MockCookie("SESSION", "123");

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

@ -16,6 +16,9 @@ @@ -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 { @@ -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 { @@ -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 { @@ -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));
}

12
spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletResponse.java

@ -26,6 +26,7 @@ import java.io.Writer; @@ -26,6 +26,7 @@ import java.io.Writer;
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;
@ -345,9 +346,14 @@ public class MockHttpServletResponse implements HttpServletResponse { @@ -345,9 +346,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()) {

Loading…
Cancel
Save