Refactor cookie support for Apache HttpClient
Closes gh-33822
This commit is contained in:
parent
e67f892e44
commit
37243f44e8
|
|
@ -19,11 +19,9 @@ package org.springframework.http.client.reactive;
|
|||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.apache.hc.client5.http.cookie.CookieStore;
|
||||
import org.apache.hc.client5.http.impl.cookie.BasicClientCookie;
|
||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||
import org.apache.hc.core5.http.ContentType;
|
||||
import org.apache.hc.core5.http.HttpRequest;
|
||||
|
|
@ -37,11 +35,13 @@ import reactor.core.publisher.Mono;
|
|||
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.support.HttpComponentsHeadersAdapter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* {@link ClientHttpRequest} implementation for the Apache HttpComponents HttpClient 5.x.
|
||||
|
|
@ -143,18 +143,26 @@ class HttpComponentsClientHttpRequest extends AbstractClientHttpRequest {
|
|||
if (getCookies().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(getCookies())) {
|
||||
this.httpRequest.setHeader(HttpHeaders.COOKIE, serializeCookies());
|
||||
}
|
||||
}
|
||||
|
||||
CookieStore cookieStore = this.context.getCookieStore();
|
||||
|
||||
getCookies().values()
|
||||
.stream()
|
||||
.flatMap(Collection::stream)
|
||||
.forEach(cookie -> {
|
||||
BasicClientCookie clientCookie = new BasicClientCookie(cookie.getName(), cookie.getValue());
|
||||
clientCookie.setDomain(getURI().getHost());
|
||||
clientCookie.setPath(getURI().getPath());
|
||||
cookieStore.addCookie(clientCookie);
|
||||
});
|
||||
private String serializeCookies() {
|
||||
boolean first = true;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (List<HttpCookie> cookies : getCookies().values()) {
|
||||
for (HttpCookie cookie : cookies) {
|
||||
if (!first) {
|
||||
sb.append("; ");
|
||||
}
|
||||
else {
|
||||
first = false;
|
||||
}
|
||||
sb.append(cookie.getName()).append("=").append(cookie.getValue());
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -21,9 +21,15 @@ import java.time.Duration;
|
|||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.hc.client5.http.cookie.Cookie;
|
||||
import org.apache.hc.client5.http.cookie.CookieOrigin;
|
||||
import org.apache.hc.client5.http.cookie.CookieSpec;
|
||||
import org.apache.hc.client5.http.cookie.MalformedCookieException;
|
||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||
import org.apache.hc.core5.http.Header;
|
||||
import org.apache.hc.core5.http.HttpResponse;
|
||||
import org.apache.hc.core5.http.Message;
|
||||
import org.reactivestreams.Publisher;
|
||||
|
|
@ -53,23 +59,47 @@ class HttpComponentsClientHttpResponse extends AbstractClientHttpResponse {
|
|||
|
||||
super(HttpStatusCode.valueOf(message.getHead().getCode()),
|
||||
HttpHeaders.readOnlyHttpHeaders(new HttpComponentsHeadersAdapter(message.getHead())),
|
||||
adaptCookies(context),
|
||||
adaptCookies(message.getHead(), context),
|
||||
Flux.from(message.getBody()).map(dataBufferFactory::wrap)
|
||||
);
|
||||
}
|
||||
|
||||
private static MultiValueMap<String, ResponseCookie> adaptCookies(HttpClientContext context) {
|
||||
private static MultiValueMap<String, ResponseCookie> adaptCookies(
|
||||
HttpResponse response, HttpClientContext context) {
|
||||
|
||||
LinkedMultiValueMap<String, ResponseCookie> result = new LinkedMultiValueMap<>();
|
||||
context.getCookieStore().getCookies().forEach(cookie ->
|
||||
result.add(cookie.getName(),
|
||||
ResponseCookie.fromClientResponse(cookie.getName(), cookie.getValue())
|
||||
.domain(cookie.getDomain())
|
||||
.path(cookie.getPath())
|
||||
.maxAge(getMaxAgeSeconds(cookie))
|
||||
.secure(cookie.isSecure())
|
||||
.httpOnly(cookie.containsAttribute("httponly"))
|
||||
.sameSite(cookie.getAttribute("samesite"))
|
||||
.build()));
|
||||
|
||||
CookieSpec cookieSpec = context.getCookieSpec();
|
||||
CookieOrigin cookieOrigin = context.getCookieOrigin();
|
||||
|
||||
Iterator<Header> itr = response.headerIterator(HttpHeaders.SET_COOKIE);
|
||||
while (itr.hasNext()) {
|
||||
Header header = itr.next();
|
||||
try {
|
||||
List<Cookie> cookies = cookieSpec.parse(header, cookieOrigin);
|
||||
for (Cookie cookie : cookies) {
|
||||
try {
|
||||
cookieSpec.validate(cookie, cookieOrigin);
|
||||
result.add(cookie.getName(),
|
||||
ResponseCookie.fromClientResponse(cookie.getName(), cookie.getValue())
|
||||
.domain(cookie.getDomain())
|
||||
.path(cookie.getPath())
|
||||
.maxAge(getMaxAgeSeconds(cookie))
|
||||
.secure(cookie.isSecure())
|
||||
.httpOnly(cookie.containsAttribute("httponly"))
|
||||
.sameSite(cookie.getAttribute("samesite"))
|
||||
.build());
|
||||
}
|
||||
catch (final MalformedCookieException ex) {
|
||||
// ignore invalid cookie
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (final MalformedCookieException ex) {
|
||||
// ignore invalid cookie
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue