Refactor cookie support for Apache HttpClient

Closes gh-33822
This commit is contained in:
rstoyanchev 2024-11-05 15:55:37 +00:00
parent e67f892e44
commit 37243f44e8
2 changed files with 64 additions and 26 deletions

View File

@ -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();
}
/**

View File

@ -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;
}