Browse Source

Refactor cookie support for Apache HttpClient

Closes gh-33822
pull/33865/head
rstoyanchev 1 year ago
parent
commit
37243f44e8
  1. 36
      spring-web/src/main/java/org/springframework/http/client/reactive/HttpComponentsClientHttpRequest.java
  2. 54
      spring-web/src/main/java/org/springframework/http/client/reactive/HttpComponentsClientHttpResponse.java

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

@ -19,11 +19,9 @@ package org.springframework.http.client.reactive;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Collection; import java.util.List;
import java.util.function.Function; 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.client5.http.protocol.HttpClientContext;
import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpRequest; 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.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.support.HttpComponentsHeadersAdapter; import org.springframework.http.support.HttpComponentsHeadersAdapter;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
/** /**
* {@link ClientHttpRequest} implementation for the Apache HttpComponents HttpClient 5.x. * {@link ClientHttpRequest} implementation for the Apache HttpComponents HttpClient 5.x.
@ -143,18 +143,26 @@ class HttpComponentsClientHttpRequest extends AbstractClientHttpRequest {
if (getCookies().isEmpty()) { if (getCookies().isEmpty()) {
return; return;
} }
if (!CollectionUtils.isEmpty(getCookies())) {
this.httpRequest.setHeader(HttpHeaders.COOKIE, serializeCookies());
}
}
CookieStore cookieStore = this.context.getCookieStore(); private String serializeCookies() {
boolean first = true;
getCookies().values() StringBuilder sb = new StringBuilder();
.stream() for (List<HttpCookie> cookies : getCookies().values()) {
.flatMap(Collection::stream) for (HttpCookie cookie : cookies) {
.forEach(cookie -> { if (!first) {
BasicClientCookie clientCookie = new BasicClientCookie(cookie.getName(), cookie.getValue()); sb.append("; ");
clientCookie.setDomain(getURI().getHost()); }
clientCookie.setPath(getURI().getPath()); else {
cookieStore.addCookie(clientCookie); first = false;
}); }
sb.append(cookie.getName()).append("=").append(cookie.getValue());
}
}
return sb.toString();
} }
/** /**

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

@ -21,9 +21,15 @@ import java.time.Duration;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException; 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.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.client5.http.protocol.HttpClientContext;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpResponse; import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.Message; import org.apache.hc.core5.http.Message;
import org.reactivestreams.Publisher; import org.reactivestreams.Publisher;
@ -53,23 +59,47 @@ class HttpComponentsClientHttpResponse extends AbstractClientHttpResponse {
super(HttpStatusCode.valueOf(message.getHead().getCode()), super(HttpStatusCode.valueOf(message.getHead().getCode()),
HttpHeaders.readOnlyHttpHeaders(new HttpComponentsHeadersAdapter(message.getHead())), HttpHeaders.readOnlyHttpHeaders(new HttpComponentsHeadersAdapter(message.getHead())),
adaptCookies(context), adaptCookies(message.getHead(), context),
Flux.from(message.getBody()).map(dataBufferFactory::wrap) 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<>(); LinkedMultiValueMap<String, ResponseCookie> result = new LinkedMultiValueMap<>();
context.getCookieStore().getCookies().forEach(cookie ->
result.add(cookie.getName(), CookieSpec cookieSpec = context.getCookieSpec();
ResponseCookie.fromClientResponse(cookie.getName(), cookie.getValue()) CookieOrigin cookieOrigin = context.getCookieOrigin();
.domain(cookie.getDomain())
.path(cookie.getPath()) Iterator<Header> itr = response.headerIterator(HttpHeaders.SET_COOKIE);
.maxAge(getMaxAgeSeconds(cookie)) while (itr.hasNext()) {
.secure(cookie.isSecure()) Header header = itr.next();
.httpOnly(cookie.containsAttribute("httponly")) try {
.sameSite(cookie.getAttribute("samesite")) List<Cookie> cookies = cookieSpec.parse(header, cookieOrigin);
.build())); 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; return result;
} }

Loading…
Cancel
Save