diff --git a/nima/http2/webclient/src/main/java/io/helidon/nima/http2/webclient/ClientRequestImpl.java b/nima/http2/webclient/src/main/java/io/helidon/nima/http2/webclient/ClientRequestImpl.java index b716ee19896..5013cac89ec 100644 --- a/nima/http2/webclient/src/main/java/io/helidon/nima/http2/webclient/ClientRequestImpl.java +++ b/nima/http2/webclient/src/main/java/io/helidon/nima/http2/webclient/ClientRequestImpl.java @@ -56,6 +56,7 @@ class ClientRequestImpl implements Http2ClientRequest { private final int maxFrameSize; private final long maxHeaderListSize; private final int connectionPrefetch; + private final Map properties; private WritableHeaders explicitHeaders; private Tls tls; @@ -84,6 +85,7 @@ class ClientRequestImpl implements Http2ClientRequest { this.maxFrameSize = client.maxFrameSize(); this.maxHeaderListSize = client.maxHeaderListSize(); this.connectionPrefetch = client.prefetch(); + this.properties = client.properties(); this.tls = tls == null || !tls.enabled() ? null : tls; this.query = query; this.followRedirects = client.followRedirects(); @@ -204,6 +206,12 @@ public Http2ClientRequest skipUriEncoding() { return this; } + @Override + public Http2ClientRequest property(String propertyName, String propertyValue) { + properties.put(propertyName, propertyValue); + return this; + } + @Override public Http2ClientRequest priority(int priority) { if (priority < 1 || priority > 256) { diff --git a/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/ClientRequest.java b/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/ClientRequest.java index 718b44c94cb..0dbd3e4754c 100644 --- a/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/ClientRequest.java +++ b/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/ClientRequest.java @@ -196,6 +196,15 @@ default T request(Class type) { */ B skipUriEncoding(); + /** + * Add a property to be used by this request. + * + * @param propertyName property name + * @param propertyValue property value + * @return updated builder instance + */ + B property(String propertyName, String propertyValue); + /** * Handle output stream. */ diff --git a/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/LoomClient.java b/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/LoomClient.java index 12651692276..fb0f035b8b4 100644 --- a/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/LoomClient.java +++ b/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/LoomClient.java @@ -17,6 +17,7 @@ package io.helidon.nima.webclient; import java.net.URI; +import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -47,6 +48,7 @@ public class LoomClient implements WebClient { private final boolean followRedirects; private final Headers defaultHeaders; private final ParserMode mediaTypeParserMode; + private final Map properties; /** * Construct this instance from a subclass of builder. @@ -63,6 +65,7 @@ protected LoomClient(WebClient.Builder builder) { this.followRedirects = builder.followRedirect(); this.defaultHeaders = builder.defaultHeaders(); this.mediaTypeParserMode = builder.mediaTypeParserMode(); + this.properties = builder.properties(); } /** @@ -146,6 +149,15 @@ public Headers defaultHeaders() { return defaultHeaders; } + /** + * Properties configured for this client. + * + * @return properties + */ + public Map properties() { + return properties; + } + /** * Media type parsing mode for HTTP {@code Content-Type} header. * diff --git a/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/WebClient.java b/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/WebClient.java index f913fbe448a..4dcbf0dfaa0 100644 --- a/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/WebClient.java +++ b/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/WebClient.java @@ -18,7 +18,9 @@ import java.net.URI; import java.time.Duration; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.function.Consumer; import java.util.function.Function; @@ -78,6 +80,7 @@ abstract class Builder, C extends WebClient> implements private int maxRedirect; private WritableHeaders defaultHeaders = WritableHeaders.create(); private ParserMode mediaTypeParserMode = ParserMode.STRICT; + private Map properties = new HashMap<>(); /** * Common builder base for all the client builder. @@ -298,6 +301,18 @@ public B headers(Function> headersConsu return identity(); } + /** + * Properties configured by user when creating this client. + * + * @param properties that were configured (mutable) + * @return updated builder instance + */ + public B properties(Map properties) { + Objects.requireNonNull(properties); + this.properties = properties; + return identity(); + } + /** * Remove header with the selected name from the default headers. * @@ -372,5 +387,8 @@ int maxRedirect() { return maxRedirect; } + Map properties() { + return properties; + } } } diff --git a/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/http1/ClientRequestImpl.java b/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/http1/ClientRequestImpl.java index 1fd43e781c9..89587ec3df3 100644 --- a/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/http1/ClientRequestImpl.java +++ b/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/http1/ClientRequestImpl.java @@ -54,6 +54,7 @@ class ClientRequestImpl implements Http1ClientRequest { private final String requestId; private final Http1ClientConfig clientConfig; private final MediaContext mediaContext; + private final Map properties; private WritableHeaders explicitHeaders = WritableHeaders.create(); private boolean followRedirects; @@ -67,9 +68,11 @@ class ClientRequestImpl implements Http1ClientRequest { ClientRequestImpl(Http1ClientConfig clientConfig, Http.Method method, UriHelper helper, - UriQueryWriteable query) { + UriQueryWriteable query, + Map properties) { this.method = method; this.uri = helper; + this.properties = properties; this.clientConfig = clientConfig; this.mediaContext = clientConfig.mediaContext(); @@ -86,8 +89,9 @@ class ClientRequestImpl implements Http1ClientRequest { private ClientRequestImpl(ClientRequestImpl request, Http.Method method, UriHelper helper, - UriQueryWriteable query) { - this(request.clientConfig, method, helper, query); + UriQueryWriteable query, + Map properties) { + this(request.clientConfig, method, helper, query, properties); this.followRedirects = request.followRedirects; this.maxRedirects = request.maxRedirects; this.tls = request.tls; @@ -224,6 +228,12 @@ public Http1ClientRequest skipUriEncoding() { return this; } + @Override + public Http1ClientRequest property(String propertyName, String propertyValue) { + this.properties.put(propertyName, propertyValue); + return this; + } + Http1ClientConfig clientConfig() { return clientConfig; } @@ -271,11 +281,11 @@ private ClientResponseImpl invokeWithFollowRedirectsEntity(Object entity) { //Method and entity is required to be the same as with original request with 307 and 308 requests if (clientResponse.status() == Http.Status.TEMPORARY_REDIRECT_307 || clientResponse.status() == Http.Status.PERMANENT_REDIRECT_308) { - clientRequest = new ClientRequestImpl(this, method, redirectUri, newQuery); + clientRequest = new ClientRequestImpl(this, method, redirectUri, newQuery, properties); } else { //It is possible to change to GET and send no entity with all other redirect codes entityToBeSent = BufferData.EMPTY_BYTES; //We do not want to send entity after this redirect - clientRequest = new ClientRequestImpl(this, Http.Method.GET, redirectUri, newQuery); + clientRequest = new ClientRequestImpl(this, Http.Method.GET, redirectUri, newQuery, properties); } } throw new IllegalStateException("Maximum number of request redirections (" @@ -324,8 +334,6 @@ private ClientResponseImpl invokeServices(WebClientService.Chain callChain, ClientRequestHeaders headers = ClientRequestHeaders.create(explicitHeaders); - Map properties = new HashMap<>(); - WebClientServiceRequest serviceRequest = new ServiceRequestImpl(uri, method, Http.Version.V1_1, diff --git a/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/http1/Http1ClientImpl.java b/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/http1/Http1ClientImpl.java index 0328769fbee..1eb19a9ef39 100644 --- a/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/http1/Http1ClientImpl.java +++ b/nima/webclient/webclient/src/main/java/io/helidon/nima/webclient/http1/Http1ClientImpl.java @@ -55,7 +55,7 @@ public Http1ClientRequest method(Http.Method method) { UriQueryWriteable query = UriQueryWriteable.create(); UriHelper helper = (uri() == null) ? UriHelper.create() : UriHelper.create(uri(), query); - return new ClientRequestImpl(clientConfig, method, helper, query); + return new ClientRequestImpl(clientConfig, method, helper, query, properties()); } Http1ClientConfig clientConfig() { diff --git a/nima/webclient/webclient/src/test/java/io/helidon/nima/webclient/HttpClientTest.java b/nima/webclient/webclient/src/test/java/io/helidon/nima/webclient/HttpClientTest.java index 43d209abeca..31126ea5e75 100644 --- a/nima/webclient/webclient/src/test/java/io/helidon/nima/webclient/HttpClientTest.java +++ b/nima/webclient/webclient/src/test/java/io/helidon/nima/webclient/HttpClientTest.java @@ -172,5 +172,10 @@ public FakeHttpClientRequest connection(ClientConnection connection) { public FakeHttpClientRequest skipUriEncoding() { return null; } + + @Override + public FakeHttpClientRequest property(String propertyName, String propertyValue) { + return null; + } } }