Skip to content

Commit a599859

Browse files
committed
ServerCookie ignores empty domain with double quotes
Closes gh-24663
1 parent 4aedf2e commit a599859

File tree

4 files changed

+63
-23
lines changed

4 files changed

+63
-23
lines changed

spring-web/src/main/java/org/springframework/http/ResponseCookie.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 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.
@@ -185,9 +185,28 @@ public String toString() {
185185
* with a name-value pair and may also include attributes.
186186
* @param name the cookie name
187187
* @param value the cookie value
188-
* @return the created cookie instance
188+
* @return a builder to create the cookie with
189189
*/
190190
public static ResponseCookieBuilder from(final String name, final String value) {
191+
return from(name, value, false);
192+
}
193+
194+
/**
195+
* Factory method to obtain a builder for a server-defined cookie. Unlike
196+
* {@link #from(String, String)} this option assumes input from a remote
197+
* server, which can be handled more leniently, e.g. ignoring a empty domain
198+
* name with double quotes.
199+
* @param name the cookie name
200+
* @param value the cookie value
201+
* @return a builder to create the cookie with
202+
* @since 5.2.5
203+
*/
204+
public static ResponseCookieBuilder fromClientResponse(final String name, final String value) {
205+
return from(name, value, true);
206+
}
207+
208+
209+
private static ResponseCookieBuilder from(final String name, final String value, boolean lenient) {
191210

192211
return new ResponseCookieBuilder() {
193212

@@ -220,10 +239,23 @@ public ResponseCookieBuilder maxAge(long maxAgeSeconds) {
220239

221240
@Override
222241
public ResponseCookieBuilder domain(String domain) {
223-
this.domain = domain;
242+
this.domain = initDomain(domain);
224243
return this;
225244
}
226245

246+
@Nullable
247+
private String initDomain(String domain) {
248+
if (lenient) {
249+
String s = domain.trim();
250+
if (s.startsWith("\"") && s.endsWith("\"")) {
251+
if (s.substring(1, domain.length() - 1).trim().isEmpty()) {
252+
return null;
253+
}
254+
}
255+
}
256+
return domain;
257+
}
258+
227259
@Override
228260
public ResponseCookieBuilder path(String path) {
229261
this.path = path;

spring-web/src/main/java/org/springframework/http/client/reactive/JettyClientHttpResponse.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 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.
@@ -66,16 +66,14 @@ public MultiValueMap<String, ResponseCookie> getCookies() {
6666
MultiValueMap<String, ResponseCookie> result = new LinkedMultiValueMap<>();
6767
List<String> cookieHeader = getHeaders().get(HttpHeaders.SET_COOKIE);
6868
if (cookieHeader != null) {
69-
cookieHeader.forEach(header ->
70-
HttpCookie.parse(header)
71-
.forEach(cookie -> result.add(cookie.getName(),
72-
ResponseCookie.from(cookie.getName(), cookie.getValue())
73-
.domain(cookie.getDomain())
74-
.path(cookie.getPath())
75-
.maxAge(cookie.getMaxAge())
76-
.secure(cookie.getSecure())
77-
.httpOnly(cookie.isHttpOnly())
78-
.build()))
69+
cookieHeader.forEach(header -> HttpCookie.parse(header)
70+
.forEach(c -> result.add(c.getName(), ResponseCookie.fromClientResponse(c.getName(), c.getValue())
71+
.domain(c.getDomain())
72+
.path(c.getPath())
73+
.maxAge(c.getMaxAge())
74+
.secure(c.getSecure())
75+
.httpOnly(c.isHttpOnly())
76+
.build()))
7977
);
8078
}
8179
return CollectionUtils.unmodifiableMultiValueMap(result);

spring-web/src/main/java/org/springframework/http/client/reactive/ReactorClientHttpResponse.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 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.
@@ -100,13 +100,13 @@ public int getRawStatusCode() {
100100
public MultiValueMap<String, ResponseCookie> getCookies() {
101101
MultiValueMap<String, ResponseCookie> result = new LinkedMultiValueMap<>();
102102
this.response.cookies().values().stream().flatMap(Collection::stream)
103-
.forEach(cookie ->
104-
result.add(cookie.name(), ResponseCookie.from(cookie.name(), cookie.value())
105-
.domain(cookie.domain())
106-
.path(cookie.path())
107-
.maxAge(cookie.maxAge())
108-
.secure(cookie.isSecure())
109-
.httpOnly(cookie.isHttpOnly())
103+
.forEach(c ->
104+
result.add(c.name(), ResponseCookie.fromClientResponse(c.name(), c.value())
105+
.domain(c.domain())
106+
.path(c.path())
107+
.maxAge(c.maxAge())
108+
.secure(c.isSecure())
109+
.httpOnly(c.isHttpOnly())
110110
.build()));
111111
return CollectionUtils.unmodifiableMultiValueMap(result);
112112
}

spring-web/src/test/java/org/springframework/http/ResponseCookieTests.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 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.
@@ -81,4 +81,14 @@ public void domainChecks() {
8181
.hasMessageContaining("invalid cookie domain char"));
8282
}
8383

84+
@Test // gh-24663
85+
public void domainWithEmptyDoubleQuotes() {
86+
87+
Arrays.asList("\"\"", "\t\"\" ", " \" \t \"\t")
88+
.forEach(domain -> {
89+
ResponseCookie cookie = ResponseCookie.fromClientResponse("id", "1fWa").domain("\"\"").build();
90+
assertThat(cookie.getDomain()).isNull();
91+
});
92+
93+
}
8494
}

0 commit comments

Comments
 (0)