Apply attributes to the underlying HTTP request
See gh-29958
This commit is contained in:
@@ -265,6 +265,12 @@ final class DefaultClientRequestBuilder implements ClientRequest.Builder {
|
||||
requestCookies.add(name, cookie);
|
||||
}));
|
||||
}
|
||||
|
||||
Map<String, Object> requestAttributes = request.getAttributes();
|
||||
if (!this.attributes.isEmpty()) {
|
||||
this.attributes.forEach((key, value) -> requestAttributes.put(key, value));
|
||||
}
|
||||
|
||||
if (this.httpRequestConsumer != null) {
|
||||
this.httpRequestConsumer.accept(request);
|
||||
}
|
||||
|
||||
@@ -89,6 +89,8 @@ final class DefaultWebClientBuilder implements WebClient.Builder {
|
||||
@Nullable
|
||||
private MultiValueMap<String, String> defaultCookies;
|
||||
|
||||
private boolean applyAttributes;
|
||||
|
||||
@Nullable
|
||||
private Consumer<WebClient.RequestHeadersSpec<?>> defaultRequest;
|
||||
|
||||
@@ -137,6 +139,7 @@ final class DefaultWebClientBuilder implements WebClient.Builder {
|
||||
|
||||
this.defaultCookies = (other.defaultCookies != null ?
|
||||
new LinkedMultiValueMap<>(other.defaultCookies) : null);
|
||||
this.applyAttributes = other.applyAttributes;
|
||||
this.defaultRequest = other.defaultRequest;
|
||||
this.statusHandlers = (other.statusHandlers != null ? new LinkedHashMap<>(other.statusHandlers) : null);
|
||||
this.filters = (other.filters != null ? new ArrayList<>(other.filters) : null);
|
||||
@@ -200,6 +203,12 @@ final class DefaultWebClientBuilder implements WebClient.Builder {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebClient.Builder applyAttributes(boolean applyAttributes) {
|
||||
this.applyAttributes = applyAttributes;
|
||||
return this;
|
||||
}
|
||||
|
||||
private MultiValueMap<String, String> initCookies() {
|
||||
if (this.defaultCookies == null) {
|
||||
this.defaultCookies = new LinkedMultiValueMap<>(3);
|
||||
@@ -335,21 +344,24 @@ final class DefaultWebClientBuilder implements WebClient.Builder {
|
||||
}
|
||||
|
||||
private ClientHttpConnector initConnector() {
|
||||
final ClientHttpConnector connector;
|
||||
if (reactorNettyClientPresent) {
|
||||
return new ReactorClientHttpConnector();
|
||||
connector = new ReactorClientHttpConnector();
|
||||
}
|
||||
else if (reactorNetty2ClientPresent) {
|
||||
return new ReactorNetty2ClientHttpConnector();
|
||||
}
|
||||
else if (jettyClientPresent) {
|
||||
return new JettyClientHttpConnector();
|
||||
connector = new JettyClientHttpConnector();
|
||||
}
|
||||
else if (httpComponentsClientPresent) {
|
||||
return new HttpComponentsClientHttpConnector();
|
||||
connector = new HttpComponentsClientHttpConnector();
|
||||
}
|
||||
else {
|
||||
return new JdkClientHttpConnector();
|
||||
connector = new JdkClientHttpConnector();
|
||||
}
|
||||
connector.setApplyAttributes(this.applyAttributes);
|
||||
return connector;
|
||||
}
|
||||
|
||||
private ExchangeStrategies initExchangeStrategies() {
|
||||
|
||||
@@ -250,6 +250,13 @@ public interface WebClient {
|
||||
*/
|
||||
Builder defaultCookies(Consumer<MultiValueMap<String, String>> cookiesConsumer);
|
||||
|
||||
/**
|
||||
* Global option to specify whether or not the request attributes should be applied
|
||||
* to the underlying http-client request, if the used {@link ClientHttpConnector} allows it.
|
||||
* @param applyAttributes whether or not to apply the attributes
|
||||
*/
|
||||
Builder applyAttributes(boolean applyAttributes);
|
||||
|
||||
/**
|
||||
* Provide a consumer to customize every request being built.
|
||||
* @param defaultRequest the consumer to use for modifying requests
|
||||
|
||||
@@ -34,14 +34,18 @@ import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import io.netty.util.Attribute;
|
||||
import io.netty.util.AttributeKey;
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
import okhttp3.mockwebserver.RecordedRequest;
|
||||
import org.eclipse.jetty.client.Request;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Named;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -50,6 +54,7 @@ import org.junit.jupiter.params.provider.MethodSource;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.publisher.Sinks;
|
||||
import reactor.netty.channel.ChannelOperations;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
import reactor.netty.resources.ConnectionProvider;
|
||||
import reactor.test.StepVerifier;
|
||||
@@ -186,6 +191,67 @@ class WebClientIntegrationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@ParameterizedWebClientTest
|
||||
void applyAttributesInNativeRequest(ClientHttpConnector connector) {
|
||||
startServer(connector);
|
||||
connector.setApplyAttributes(true);
|
||||
checkAttributesInNativeRequest(true);
|
||||
}
|
||||
|
||||
@ParameterizedWebClientTest
|
||||
void dontApplyAttributesInNativeRequest(ClientHttpConnector connector) {
|
||||
startServer(connector);
|
||||
connector.setApplyAttributes(false);
|
||||
checkAttributesInNativeRequest(false);
|
||||
}
|
||||
|
||||
private void checkAttributesInNativeRequest(boolean expectAttributesApplied){
|
||||
prepareResponse(response -> {});
|
||||
|
||||
final AtomicReference<Object> nativeRequest = new AtomicReference<>();
|
||||
Mono<Void> result = this.webClient.get()
|
||||
.uri("/pojo")
|
||||
.attribute("foo","bar")
|
||||
.httpRequest(clientHttpRequest -> nativeRequest.set(clientHttpRequest.getNativeRequest()))
|
||||
.retrieve()
|
||||
.bodyToMono(Void.class);
|
||||
StepVerifier.create(result)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
if (nativeRequest.get() instanceof ChannelOperations<?,?> nativeReq) {
|
||||
Attribute<Map<String, Object>> attributes = nativeReq.channel().attr(AttributeKey.valueOf("attributes"));
|
||||
if (expectAttributesApplied) {
|
||||
assertThat(attributes.get()).isNotNull();
|
||||
assertThat(attributes.get()).containsEntry("foo", "bar");
|
||||
}
|
||||
else {
|
||||
assertThat(attributes.get()).isNull();
|
||||
}
|
||||
}
|
||||
else if (nativeRequest.get() instanceof reactor.netty5.channel.ChannelOperations<?,?> nativeReq) {
|
||||
io.netty5.util.Attribute<Map<String, Object>> attributes = nativeReq.channel().attr(io.netty5.util.AttributeKey.valueOf("attributes"));
|
||||
if (expectAttributesApplied) {
|
||||
assertThat(attributes.get()).isNotNull();
|
||||
assertThat(attributes.get()).containsEntry("foo", "bar");
|
||||
}
|
||||
else {
|
||||
assertThat(attributes.get()).isNull();
|
||||
}
|
||||
}
|
||||
else if (nativeRequest.get() instanceof Request nativeReq) {
|
||||
if (expectAttributesApplied) {
|
||||
assertThat(nativeReq.getAttributes()).containsEntry("foo", "bar");
|
||||
}
|
||||
else {
|
||||
assertThat(nativeReq.getAttributes()).doesNotContainEntry("foo", "bar");
|
||||
}
|
||||
}
|
||||
else if (nativeRequest.get() instanceof org.apache.hc.core5.http.HttpRequest nativeReq) {
|
||||
// TODO get attributes from HttpClientContext
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ParameterizedWebClientTest
|
||||
void retrieveJsonWithParameterizedTypeReference(ClientHttpConnector connector) {
|
||||
startServer(connector);
|
||||
|
||||
Reference in New Issue
Block a user