Skip to content

Commit 37243f4

Browse files
committed
Refactor cookie support for Apache HttpClient
Closes gh-33822
1 parent e67f892 commit 37243f4

File tree

2 files changed

+64
-26
lines changed

2 files changed

+64
-26
lines changed

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

+22-14
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@
1919
import java.net.URI;
2020
import java.net.URISyntaxException;
2121
import java.nio.ByteBuffer;
22-
import java.util.Collection;
22+
import java.util.List;
2323
import java.util.function.Function;
2424

25-
import org.apache.hc.client5.http.cookie.CookieStore;
26-
import org.apache.hc.client5.http.impl.cookie.BasicClientCookie;
2725
import org.apache.hc.client5.http.protocol.HttpClientContext;
2826
import org.apache.hc.core5.http.ContentType;
2927
import org.apache.hc.core5.http.HttpRequest;
@@ -37,11 +35,13 @@
3735

3836
import org.springframework.core.io.buffer.DataBuffer;
3937
import org.springframework.core.io.buffer.DataBufferFactory;
38+
import org.springframework.http.HttpCookie;
4039
import org.springframework.http.HttpHeaders;
4140
import org.springframework.http.HttpMethod;
4241
import org.springframework.http.MediaType;
4342
import org.springframework.http.support.HttpComponentsHeadersAdapter;
4443
import org.springframework.lang.Nullable;
44+
import org.springframework.util.CollectionUtils;
4545

4646
/**
4747
* {@link ClientHttpRequest} implementation for the Apache HttpComponents HttpClient 5.x.
@@ -143,18 +143,26 @@ protected void applyCookies() {
143143
if (getCookies().isEmpty()) {
144144
return;
145145
}
146+
if (!CollectionUtils.isEmpty(getCookies())) {
147+
this.httpRequest.setHeader(HttpHeaders.COOKIE, serializeCookies());
148+
}
149+
}
146150

147-
CookieStore cookieStore = this.context.getCookieStore();
148-
149-
getCookies().values()
150-
.stream()
151-
.flatMap(Collection::stream)
152-
.forEach(cookie -> {
153-
BasicClientCookie clientCookie = new BasicClientCookie(cookie.getName(), cookie.getValue());
154-
clientCookie.setDomain(getURI().getHost());
155-
clientCookie.setPath(getURI().getPath());
156-
cookieStore.addCookie(clientCookie);
157-
});
151+
private String serializeCookies() {
152+
boolean first = true;
153+
StringBuilder sb = new StringBuilder();
154+
for (List<HttpCookie> cookies : getCookies().values()) {
155+
for (HttpCookie cookie : cookies) {
156+
if (!first) {
157+
sb.append("; ");
158+
}
159+
else {
160+
first = false;
161+
}
162+
sb.append(cookie.getName()).append("=").append(cookie.getValue());
163+
}
164+
}
165+
return sb.toString();
158166
}
159167

160168
/**

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

+42-12
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,15 @@
2121
import java.time.ZonedDateTime;
2222
import java.time.format.DateTimeFormatter;
2323
import java.time.format.DateTimeParseException;
24+
import java.util.Iterator;
25+
import java.util.List;
2426

2527
import org.apache.hc.client5.http.cookie.Cookie;
28+
import org.apache.hc.client5.http.cookie.CookieOrigin;
29+
import org.apache.hc.client5.http.cookie.CookieSpec;
30+
import org.apache.hc.client5.http.cookie.MalformedCookieException;
2631
import org.apache.hc.client5.http.protocol.HttpClientContext;
32+
import org.apache.hc.core5.http.Header;
2733
import org.apache.hc.core5.http.HttpResponse;
2834
import org.apache.hc.core5.http.Message;
2935
import org.reactivestreams.Publisher;
@@ -53,23 +59,47 @@ public HttpComponentsClientHttpResponse(DataBufferFactory dataBufferFactory,
5359

5460
super(HttpStatusCode.valueOf(message.getHead().getCode()),
5561
HttpHeaders.readOnlyHttpHeaders(new HttpComponentsHeadersAdapter(message.getHead())),
56-
adaptCookies(context),
62+
adaptCookies(message.getHead(), context),
5763
Flux.from(message.getBody()).map(dataBufferFactory::wrap)
5864
);
5965
}
6066

61-
private static MultiValueMap<String, ResponseCookie> adaptCookies(HttpClientContext context) {
67+
private static MultiValueMap<String, ResponseCookie> adaptCookies(
68+
HttpResponse response, HttpClientContext context) {
69+
6270
LinkedMultiValueMap<String, ResponseCookie> result = new LinkedMultiValueMap<>();
63-
context.getCookieStore().getCookies().forEach(cookie ->
64-
result.add(cookie.getName(),
65-
ResponseCookie.fromClientResponse(cookie.getName(), cookie.getValue())
66-
.domain(cookie.getDomain())
67-
.path(cookie.getPath())
68-
.maxAge(getMaxAgeSeconds(cookie))
69-
.secure(cookie.isSecure())
70-
.httpOnly(cookie.containsAttribute("httponly"))
71-
.sameSite(cookie.getAttribute("samesite"))
72-
.build()));
71+
72+
CookieSpec cookieSpec = context.getCookieSpec();
73+
CookieOrigin cookieOrigin = context.getCookieOrigin();
74+
75+
Iterator<Header> itr = response.headerIterator(HttpHeaders.SET_COOKIE);
76+
while (itr.hasNext()) {
77+
Header header = itr.next();
78+
try {
79+
List<Cookie> cookies = cookieSpec.parse(header, cookieOrigin);
80+
for (Cookie cookie : cookies) {
81+
try {
82+
cookieSpec.validate(cookie, cookieOrigin);
83+
result.add(cookie.getName(),
84+
ResponseCookie.fromClientResponse(cookie.getName(), cookie.getValue())
85+
.domain(cookie.getDomain())
86+
.path(cookie.getPath())
87+
.maxAge(getMaxAgeSeconds(cookie))
88+
.secure(cookie.isSecure())
89+
.httpOnly(cookie.containsAttribute("httponly"))
90+
.sameSite(cookie.getAttribute("samesite"))
91+
.build());
92+
}
93+
catch (final MalformedCookieException ex) {
94+
// ignore invalid cookie
95+
}
96+
}
97+
}
98+
catch (final MalformedCookieException ex) {
99+
// ignore invalid cookie
100+
}
101+
}
102+
73103
return result;
74104
}
75105

0 commit comments

Comments
 (0)