Skip to content

Commit e5fc40a

Browse files
committed
MockHttpSevlet[Request|Response] set cookie headers
Issue: SPR-15225
1 parent 4da4f2b commit e5fc40a

File tree

10 files changed

+172
-76
lines changed

10 files changed

+172
-76
lines changed

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

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.security.Principal;
2828
import java.text.ParseException;
2929
import java.text.SimpleDateFormat;
30+
import java.util.Arrays;
3031
import java.util.Collection;
3132
import java.util.Collections;
3233
import java.util.Date;
@@ -55,11 +56,13 @@
5556
import javax.servlet.http.HttpUpgradeHandler;
5657
import javax.servlet.http.Part;
5758

59+
import org.springframework.http.HttpHeaders;
5860
import org.springframework.http.MediaType;
5961
import org.springframework.util.Assert;
6062
import org.springframework.util.LinkedCaseInsensitiveMap;
6163
import org.springframework.util.LinkedMultiValueMap;
6264
import org.springframework.util.MultiValueMap;
65+
import org.springframework.util.ObjectUtils;
6366
import org.springframework.util.StreamUtils;
6467
import org.springframework.util.StringUtils;
6568

@@ -87,10 +90,6 @@ public class MockHttpServletRequest implements HttpServletRequest {
8790

8891
private static final String HTTPS = "https";
8992

90-
private static final String CONTENT_TYPE_HEADER = "Content-Type";
91-
92-
private static final String HOST_HEADER = "Host";
93-
9493
private static final String CHARSET_PREFIX = "charset=";
9594

9695
private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
@@ -219,6 +218,8 @@ public class MockHttpServletRequest implements HttpServletRequest {
219218

220219
private Cookie[] cookies;
221220

221+
private boolean cookieHeaderSet;
222+
222223
private final Map<String, HeaderValueHolder> headers = new LinkedCaseInsensitiveMap<>();
223224

224225
private String method;
@@ -387,7 +388,7 @@ private void updateContentTypeHeader() {
387388
StringUtils.hasLength(this.characterEncoding)) {
388389
sb.append(";").append(CHARSET_PREFIX).append(this.characterEncoding);
389390
}
390-
doAddHeaderValue(CONTENT_TYPE_HEADER, sb.toString(), true);
391+
doAddHeaderValue(HttpHeaders.CONTENT_TYPE, sb.toString(), true);
391392
}
392393
}
393394

@@ -633,7 +634,7 @@ public void setServerName(String serverName) {
633634

634635
@Override
635636
public String getServerName() {
636-
String host = getHeader(HOST_HEADER);
637+
String host = getHeader(HttpHeaders.HOST);
637638
if (host != null) {
638639
host = host.trim();
639640
if (host.startsWith("[")) {
@@ -655,7 +656,7 @@ public void setServerPort(int serverPort) {
655656

656657
@Override
657658
public int getServerPort() {
658-
String host = getHeader(HOST_HEADER);
659+
String host = getHeader(HttpHeaders.HOST);
659660
if (host != null) {
660661
host = host.trim();
661662
int idx;
@@ -922,6 +923,11 @@ public String getAuthType() {
922923

923924
public void setCookies(Cookie... cookies) {
924925
this.cookies = cookies;
926+
if (!this.cookieHeaderSet && !ObjectUtils.isEmpty(cookies)) {
927+
Arrays.stream(cookies)
928+
.map(c -> c.getName() + '=' + (c.getValue() == null ? "" : c.getValue()))
929+
.forEach(value -> doAddHeaderValue(HttpHeaders.COOKIE, value, false));
930+
}
925931
}
926932

927933
@Override
@@ -945,10 +951,11 @@ public Cookie[] getCookies() {
945951
* @see #getDateHeader
946952
*/
947953
public void addHeader(String name, Object value) {
948-
if (CONTENT_TYPE_HEADER.equalsIgnoreCase(name) && !this.headers.containsKey(CONTENT_TYPE_HEADER)) {
954+
if (HttpHeaders.CONTENT_TYPE.equalsIgnoreCase(name) && !this.headers.containsKey(HttpHeaders.CONTENT_TYPE)) {
949955
setContentType(value.toString());
950956
}
951957
else {
958+
this.cookieHeaderSet = HttpHeaders.COOKIE.equalsIgnoreCase(name);
952959
doAddHeaderValue(name, value, false);
953960
}
954961
}

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

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,11 @@
3737
import javax.servlet.http.Cookie;
3838
import javax.servlet.http.HttpServletResponse;
3939

40+
import org.springframework.http.HttpHeaders;
4041
import org.springframework.http.MediaType;
4142
import org.springframework.util.Assert;
4243
import org.springframework.util.LinkedCaseInsensitiveMap;
44+
import org.springframework.util.StringUtils;
4345
import org.springframework.web.util.WebUtils;
4446

4547
/**
@@ -56,12 +58,6 @@ public class MockHttpServletResponse implements HttpServletResponse {
5658

5759
private static final String CHARSET_PREFIX = "charset=";
5860

59-
private static final String CONTENT_TYPE_HEADER = "Content-Type";
60-
61-
private static final String CONTENT_LENGTH_HEADER = "Content-Length";
62-
63-
private static final String LOCATION_HEADER = "Location";
64-
6561
private static final String DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz";
6662

6763
private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
@@ -102,6 +98,8 @@ public class MockHttpServletResponse implements HttpServletResponse {
10298

10399
private final List<Cookie> cookies = new ArrayList<>();
104100

101+
private boolean cookieHeaderSet;
102+
105103
private final Map<String, HeaderValueHolder> headers = new LinkedCaseInsensitiveMap<>();
106104

107105
private int status = HttpServletResponse.SC_OK;
@@ -168,7 +166,7 @@ private void updateContentTypeHeader() {
168166
if (!this.contentType.toLowerCase().contains(CHARSET_PREFIX) && this.charset) {
169167
sb.append(";").append(CHARSET_PREFIX).append(this.characterEncoding);
170168
}
171-
doAddHeaderValue(CONTENT_TYPE_HEADER, sb.toString(), true);
169+
doAddHeaderValue(HttpHeaders.CONTENT_TYPE, sb.toString(), true);
172170
}
173171
}
174172

@@ -208,7 +206,7 @@ public String getContentAsString() throws UnsupportedEncodingException {
208206
@Override
209207
public void setContentLength(int contentLength) {
210208
this.contentLength = contentLength;
211-
doAddHeaderValue(CONTENT_LENGTH_HEADER, contentLength, true);
209+
doAddHeaderValue(HttpHeaders.CONTENT_LENGTH, contentLength, true);
212210
}
213211

214212
public int getContentLength() {
@@ -218,7 +216,7 @@ public int getContentLength() {
218216
@Override
219217
public void setContentLengthLong(long contentLength) {
220218
this.contentLength = contentLength;
221-
doAddHeaderValue(CONTENT_LENGTH_HEADER, contentLength, true);
219+
doAddHeaderValue(HttpHeaders.CONTENT_LENGTH, contentLength, true);
222220
}
223221

224222
public long getContentLengthLong() {
@@ -322,6 +320,36 @@ public Locale getLocale() {
322320
public void addCookie(Cookie cookie) {
323321
Assert.notNull(cookie, "Cookie must not be null");
324322
this.cookies.add(cookie);
323+
if (!this.cookieHeaderSet) {
324+
doAddHeaderValue(HttpHeaders.SET_COOKIE, getCookieHeader(cookie), false);
325+
}
326+
}
327+
328+
private String getCookieHeader(Cookie cookie) {
329+
StringBuilder buf = new StringBuilder();
330+
buf.append(cookie.getName()).append('=').append(cookie.getValue() == null ? "" : cookie.getValue());
331+
if (StringUtils.hasText(cookie.getPath())) {
332+
buf.append(";Path=").append(cookie.getPath());
333+
}
334+
if (StringUtils.hasText(cookie.getDomain())) {
335+
buf.append(";Domain=").append(cookie.getDomain());
336+
}
337+
int maxAge = cookie.getMaxAge();
338+
if (maxAge >= 0) {
339+
buf.append(";Max-Age=").append(maxAge);
340+
buf.append(";Expires=");
341+
HttpHeaders headers = new HttpHeaders();
342+
headers.setExpires(maxAge > 0 ? System.currentTimeMillis() + 1000L * maxAge : 0);
343+
buf.append(headers.getFirst(HttpHeaders.EXPIRES));
344+
}
345+
346+
if (cookie.getSecure()) {
347+
buf.append(";Secure");
348+
}
349+
if (cookie.isHttpOnly()) {
350+
buf.append(";HttpOnly");
351+
}
352+
return buf.toString();
325353
}
326354

327355
public Cookie[] getCookies() {
@@ -466,13 +494,13 @@ public void sendError(int status) throws IOException {
466494
public void sendRedirect(String url) throws IOException {
467495
Assert.state(!isCommitted(), "Cannot send redirect - response is already committed");
468496
Assert.notNull(url, "Redirect URL must not be null");
469-
setHeader(LOCATION_HEADER, url);
497+
setHeader(HttpHeaders.LOCATION, url);
470498
setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
471499
setCommitted(true);
472500
}
473501

474502
public String getRedirectedUrl() {
475-
return getHeader(LOCATION_HEADER);
503+
return getHeader(HttpHeaders.LOCATION);
476504
}
477505

478506
@Override
@@ -505,11 +533,13 @@ private String formatDate(long date) {
505533

506534
@Override
507535
public void setHeader(String name, String value) {
536+
this.cookieHeaderSet = HttpHeaders.SET_COOKIE.equalsIgnoreCase(name);
508537
setHeaderValue(name, value);
509538
}
510539

511540
@Override
512541
public void addHeader(String name, String value) {
542+
this.cookieHeaderSet = HttpHeaders.SET_COOKIE.equalsIgnoreCase(name);
513543
addHeaderValue(name, value);
514544
}
515545

@@ -538,11 +568,11 @@ private void addHeaderValue(String name, Object value) {
538568
}
539569

540570
private boolean setSpecialHeader(String name, Object value) {
541-
if (CONTENT_TYPE_HEADER.equalsIgnoreCase(name)) {
571+
if (HttpHeaders.CONTENT_TYPE.equalsIgnoreCase(name)) {
542572
setContentType(value.toString());
543573
return true;
544574
}
545-
else if (CONTENT_LENGTH_HEADER.equalsIgnoreCase(name)) {
575+
else if (HttpHeaders.CONTENT_LENGTH.equalsIgnoreCase(name)) {
546576
setContentLength(value instanceof Number ? ((Number) value).intValue() :
547577
Integer.parseInt(value.toString()));
548578
return true;

spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/MockMvcWebConnection.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@
2727
import com.gargoylesoftware.htmlunit.WebRequest;
2828
import com.gargoylesoftware.htmlunit.WebResponse;
2929
import com.gargoylesoftware.htmlunit.util.Cookie;
30+
import org.apache.http.impl.cookie.BasicClientCookie;
3031

3132
import org.springframework.mock.web.MockHttpServletResponse;
3233
import org.springframework.mock.web.MockHttpSession;
@@ -161,7 +162,7 @@ private void storeCookies(WebRequest webRequest, javax.servlet.http.Cookie[] coo
161162
if (cookie.getDomain() == null) {
162163
cookie.setDomain(webRequest.getUrl().getHost());
163164
}
164-
Cookie toManage = MockWebResponseBuilder.createCookie(cookie);
165+
Cookie toManage = createCookie(cookie);
165166
Date expires = toManage.getExpires();
166167
if (expires == null || expires.after(now)) {
167168
cookieManager.addCookie(toManage);
@@ -172,6 +173,23 @@ private void storeCookies(WebRequest webRequest, javax.servlet.http.Cookie[] coo
172173
}
173174
}
174175

176+
private static com.gargoylesoftware.htmlunit.util.Cookie createCookie(javax.servlet.http.Cookie cookie) {
177+
Date expires = null;
178+
if (cookie.getMaxAge() > -1) {
179+
expires = new Date(System.currentTimeMillis() + cookie.getMaxAge() * 1000);
180+
}
181+
BasicClientCookie result = new BasicClientCookie(cookie.getName(), cookie.getValue());
182+
result.setDomain(cookie.getDomain());
183+
result.setComment(cookie.getComment());
184+
result.setExpiryDate(expires);
185+
result.setPath(cookie.getPath());
186+
result.setSecure(cookie.getSecure());
187+
if (cookie.isHttpOnly()) {
188+
result.setAttribute("httponly", "true");
189+
}
190+
return new com.gargoylesoftware.htmlunit.util.Cookie(result);
191+
}
192+
175193
@Override
176194
public void close() {
177195
}

spring-test/src/main/java/org/springframework/test/web/servlet/htmlunit/MockWebResponseBuilder.java

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,17 +19,13 @@
1919
import java.io.IOException;
2020
import java.util.ArrayList;
2121
import java.util.Collection;
22-
import java.util.Date;
2322
import java.util.List;
2423

25-
import javax.servlet.http.Cookie;
26-
2724
import com.gargoylesoftware.htmlunit.WebRequest;
2825
import com.gargoylesoftware.htmlunit.WebResponse;
2926
import com.gargoylesoftware.htmlunit.WebResponseData;
3027
import com.gargoylesoftware.htmlunit.util.NameValuePair;
3128

32-
import org.apache.http.impl.cookie.BasicClientCookie;
3329
import org.springframework.http.HttpStatus;
3430
import org.springframework.mock.web.MockHttpServletResponse;
3531
import org.springframework.util.Assert;
@@ -105,30 +101,7 @@ private List<NameValuePair> responseHeaders() {
105101
if (location != null) {
106102
responseHeaders.add(new NameValuePair("Location", location));
107103
}
108-
for (Cookie cookie : this.response.getCookies()) {
109-
responseHeaders.add(new NameValuePair("Set-Cookie", valueOfCookie(cookie)));
110-
}
111104
return responseHeaders;
112105
}
113106

114-
private String valueOfCookie(Cookie cookie) {
115-
return createCookie(cookie).toString();
116-
}
117-
118-
static com.gargoylesoftware.htmlunit.util.Cookie createCookie(Cookie cookie) {
119-
Date expires = null;
120-
if (cookie.getMaxAge() > -1) {
121-
expires = new Date(System.currentTimeMillis() + cookie.getMaxAge() * 1000);
122-
}
123-
BasicClientCookie result = new BasicClientCookie(cookie.getName(), cookie.getValue());
124-
result.setDomain(cookie.getDomain());
125-
result.setComment(cookie.getComment());
126-
result.setExpiryDate(expires);
127-
result.setPath(cookie.getPath());
128-
result.setSecure(cookie.getSecure());
129-
if (cookie.isHttpOnly()) {
130-
result.setAttribute("httponly", "true");
131-
}
132-
return new com.gargoylesoftware.htmlunit.util.Cookie(result);
133-
}
134107
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,12 +251,14 @@ public void cookies() {
251251
request.setCookies(cookie1, cookie2);
252252

253253
Cookie[] cookies = request.getCookies();
254+
List<String> cookieHeaders = Collections.list(request.getHeaders("Cookie"));
254255

255256
assertEquals(2, cookies.length);
256257
assertEquals("foo", cookies[0].getName());
257258
assertEquals("bar", cookies[0].getValue());
258259
assertEquals("baz", cookies[1].getName());
259260
assertEquals("qux", cookies[1].getValue());
261+
assertEquals(Arrays.asList("foo=bar", "baz=qux"), cookieHeaders);
260262
}
261263

262264
@Test

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@
1919
import java.io.IOException;
2020
import java.util.Arrays;
2121
import java.util.Collection;
22+
import java.util.Collections;
23+
import java.util.List;
24+
import javax.servlet.http.Cookie;
2225
import javax.servlet.http.HttpServletResponse;
2326

2427
import org.junit.Test;
2528

29+
import org.springframework.http.HttpHeaders;
2630
import org.springframework.web.util.WebUtils;
2731

2832
import static org.junit.Assert.*;
@@ -155,6 +159,22 @@ public void httpHeaderNameCasingIsPreserved() throws Exception {
155159
assertEquals("HTTP header casing not being preserved", headerName, responseHeaders.iterator().next());
156160
}
157161

162+
@Test
163+
public void cookies() {
164+
Cookie cookie = new Cookie("foo", "bar");
165+
cookie.setPath("/path");
166+
cookie.setDomain("example.com");
167+
cookie.setMaxAge(0);
168+
cookie.setSecure(true);
169+
cookie.setHttpOnly(true);
170+
171+
response.addCookie(cookie);
172+
173+
assertEquals("foo=bar;Path=/path;Domain=example.com;" +
174+
"Max-Age=0;Expires=Thu, 01 Jan 1970 00:00:00 GMT;" +
175+
"Secure;HttpOnly", response.getHeader(HttpHeaders.SET_COOKIE));
176+
}
177+
158178
@Test
159179
public void servletOutputStreamCommittedWhenBufferSizeExceeded() throws IOException {
160180
assertFalse(response.isCommitted());

0 commit comments

Comments
 (0)