diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/config/TlsConfig.java b/httpclient5/src/main/java/org/apache/hc/client5/http/config/TlsConfig.java index 7a014e263..45acdb96d 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/config/TlsConfig.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/config/TlsConfig.java @@ -32,6 +32,7 @@ import java.util.concurrent.TimeUnit; import org.apache.hc.core5.annotation.Contract; import org.apache.hc.core5.annotation.ThreadingBehavior; +import org.apache.hc.core5.http.ssl.TLS; import org.apache.hc.core5.http2.HttpVersionPolicy; import org.apache.hc.core5.util.Timeout; @@ -166,6 +167,23 @@ public class TlsConfig implements Cloneable { return this; } + /** + * Determines supported TLS protocols. + *

+ * Default: {@code null} (undefined) + *

+ */ + public Builder setSupportedProtocols(final TLS... supportedProtocols) { + this.supportedProtocols = new String[supportedProtocols.length]; + for (int i = 0; i < supportedProtocols.length; i++) { + final TLS protocol = supportedProtocols[i]; + if (protocol != null) { + this.supportedProtocols[i] = protocol.id; + } + } + return this; + } + /** * Determines supported cipher suites. *

diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientConnectionConfig.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientConnectionConfig.java new file mode 100644 index 000000000..7f2dd3a7b --- /dev/null +++ b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientConnectionConfig.java @@ -0,0 +1,133 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.hc.client5.http.examples; + +import java.util.concurrent.Future; + +import org.apache.hc.client5.http.async.methods.SimpleHttpRequest; +import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; +import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder; +import org.apache.hc.client5.http.async.methods.SimpleRequestProducer; +import org.apache.hc.client5.http.async.methods.SimpleResponseConsumer; +import org.apache.hc.client5.http.config.ConnectionConfig; +import org.apache.hc.client5.http.config.TlsConfig; +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.client5.http.impl.async.HttpAsyncClients; +import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager; +import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder; +import org.apache.hc.core5.concurrent.FutureCallback; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.URIScheme; +import org.apache.hc.core5.http.message.StatusLine; +import org.apache.hc.core5.http.ssl.TLS; +import org.apache.hc.core5.io.CloseMode; +import org.apache.hc.core5.util.TimeValue; +import org.apache.hc.core5.util.Timeout; + +/** + * This example demonstrates how to use connection configuration on a per-route or a per-host + * basis. + */ +public class AsyncClientConnectionConfig { + + public static void main(final String[] args) throws Exception { + final PoolingAsyncClientConnectionManager cm = PoolingAsyncClientConnectionManagerBuilder.create() + .setConnectionConfigResolver(route -> { + // Use different settings for all secure (TLS) connections + final HttpHost targetHost = route.getTargetHost(); + if (route.isSecure()) { + return ConnectionConfig.custom() + .setConnectTimeout(Timeout.ofMinutes(2)) + .setSocketTimeout(Timeout.ofMinutes(2)) + .setValidateAfterInactivity(TimeValue.ofMinutes(1)) + .setTimeToLive(TimeValue.ofHours(1)) + .build(); + } else { + return ConnectionConfig.custom() + .setConnectTimeout(Timeout.ofMinutes(1)) + .setSocketTimeout(Timeout.ofMinutes(1)) + .setValidateAfterInactivity(TimeValue.ofSeconds(15)) + .setTimeToLive(TimeValue.ofMinutes(15)) + .build(); + } + }) + .setTlsConfigResolver(host -> { + // Use different settings for specific hosts + if (host.getSchemeName().equalsIgnoreCase("httpbin.org")) { + return TlsConfig.custom() + .setSupportedProtocols(TLS.V_1_3) + .setHandshakeTimeout(Timeout.ofSeconds(10)) + .build(); + } else { + return TlsConfig.DEFAULT; + } + }) + .build(); + try (final CloseableHttpAsyncClient client = HttpAsyncClients.custom() + .setConnectionManager(cm) + .build()) { + + client.start(); + + for (final URIScheme uriScheme : URIScheme.values()) { + final SimpleHttpRequest request = SimpleRequestBuilder.get() + .setHttpHost(new HttpHost(uriScheme.id, "httpbin.org")) + .setPath("/headers") + .build(); + + System.out.println("Executing request " + request); + final Future future = client.execute( + SimpleRequestProducer.create(request), + SimpleResponseConsumer.create(), + new FutureCallback() { + + @Override + public void completed(final SimpleHttpResponse response) { + System.out.println(request + "->" + new StatusLine(response)); + System.out.println(response.getBody()); + } + + @Override + public void failed(final Exception ex) { + System.out.println(request + "->" + ex); + } + + @Override + public void cancelled() { + System.out.println(request + " cancelled"); + } + + }); + future.get(); + } + + System.out.println("Shutting down"); + client.close(CloseMode.GRACEFUL); + } + } + +} diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientConfiguration.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientConfiguration.java index 42d827e3b..5c900af69 100644 --- a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientConfiguration.java +++ b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientConfiguration.java @@ -44,6 +44,7 @@ import org.apache.hc.client5.http.auth.StandardAuthScheme; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.config.ConnectionConfig; import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.config.TlsConfig; import org.apache.hc.client5.http.cookie.BasicCookieStore; import org.apache.hc.client5.http.cookie.CookieStore; import org.apache.hc.client5.http.cookie.StandardCookieSpec; @@ -80,6 +81,7 @@ import org.apache.hc.core5.http.io.entity.EntityUtils; import org.apache.hc.core5.http.message.BasicHeader; import org.apache.hc.core5.http.message.BasicLineParser; import org.apache.hc.core5.http.message.LineParser; +import org.apache.hc.core5.http.ssl.TLS; import org.apache.hc.core5.pool.PoolConcurrencyPolicy; import org.apache.hc.core5.pool.PoolReusePolicy; import org.apache.hc.core5.ssl.SSLContexts; @@ -183,6 +185,13 @@ public class ClientConfiguration { .setConnectTimeout(Timeout.ofSeconds(30)) .setSocketTimeout(Timeout.ofSeconds(30)) .setValidateAfterInactivity(TimeValue.ofSeconds(10)) + .setTimeToLive(TimeValue.ofHours(1)) + .build()); + + // Use TLS v1.3 only + connManager.setDefaultTlsConfig(TlsConfig.custom() + .setHandshakeTimeout(Timeout.ofSeconds(30)) + .setSupportedProtocols(TLS.V_1_3) .build()); // Configure total max or per route limits for persistent connections diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientConnectionConfig.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientConnectionConfig.java new file mode 100644 index 000000000..bcbd2097b --- /dev/null +++ b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientConnectionConfig.java @@ -0,0 +1,103 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.hc.client5.http.examples; + +import org.apache.hc.client5.http.config.ConnectionConfig; +import org.apache.hc.client5.http.config.TlsConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.core5.http.ClassicHttpRequest; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.URIScheme; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.io.support.ClassicRequestBuilder; +import org.apache.hc.core5.http.message.StatusLine; +import org.apache.hc.core5.http.ssl.TLS; +import org.apache.hc.core5.util.TimeValue; +import org.apache.hc.core5.util.Timeout; + +/** + * This example demonstrates how to use connection configuration on a per-route or a per-host + * basis. + */ +public class ClientConnectionConfig { + + public final static void main(final String[] args) throws Exception { + final PoolingHttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create() + .setConnectionConfigResolver(route -> { + // Use different settings for all secure (TLS) connections + final HttpHost targetHost = route.getTargetHost(); + if (route.isSecure()) { + return ConnectionConfig.custom() + .setConnectTimeout(Timeout.ofMinutes(2)) + .setSocketTimeout(Timeout.ofMinutes(2)) + .setValidateAfterInactivity(TimeValue.ofMinutes(1)) + .setTimeToLive(TimeValue.ofHours(1)) + .build(); + } else { + return ConnectionConfig.custom() + .setConnectTimeout(Timeout.ofMinutes(1)) + .setSocketTimeout(Timeout.ofMinutes(1)) + .setValidateAfterInactivity(TimeValue.ofSeconds(15)) + .setTimeToLive(TimeValue.ofMinutes(15)) + .build(); + } + }) + .setTlsConfigResolver(host -> { + // Use different settings for specific hosts + if (host.getSchemeName().equalsIgnoreCase("httpbin.org")) { + return TlsConfig.custom() + .setSupportedProtocols(TLS.V_1_3) + .setHandshakeTimeout(Timeout.ofSeconds(10)) + .build(); + } else { + return TlsConfig.DEFAULT; + } + }) + .build(); + try (CloseableHttpClient httpclient = HttpClients.custom() + .setConnectionManager(cm) + .build()) { + + for (final URIScheme uriScheme : URIScheme.values()) { + final ClassicHttpRequest request = ClassicRequestBuilder.get() + .setHttpHost(new HttpHost(uriScheme.id, "httpbin.org")) + .setPath("/headers") + .build(); + System.out.println("Executing request " + request); + try (CloseableHttpResponse response = httpclient.execute(request)) { + System.out.println(request + "->" + new StatusLine(response)); + EntityUtils.consume(response.getEntity()); + } + } + } + } + +} diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientCustomSSL.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientCustomSSL.java index b9c202554..88382d314 100644 --- a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientCustomSSL.java +++ b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientCustomSSL.java @@ -32,6 +32,7 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.config.TlsConfig; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; import org.apache.hc.client5.http.impl.classic.HttpClients; @@ -43,6 +44,7 @@ import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder; import org.apache.hc.core5.http.io.entity.EntityUtils; import org.apache.hc.core5.http.ssl.TLS; import org.apache.hc.core5.ssl.SSLContexts; +import org.apache.hc.core5.util.Timeout; /** * This example demonstrates how to create secure connections with a custom SSL @@ -58,13 +60,16 @@ public class ClientCustomSSL { return "CN=httpbin.org".equalsIgnoreCase(cert.getSubjectDN().getName()); }) .build(); - // Allow TLSv1.2 protocol only final SSLConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactoryBuilder.create() .setSslContext(sslcontext) - .setTlsVersions(TLS.V_1_2) .build(); + // Allow TLSv1.3 protocol only final HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create() .setSSLSocketFactory(sslSocketFactory) + .setDefaultTlsConfig(TlsConfig.custom() + .setHandshakeTimeout(Timeout.ofSeconds(30)) + .setSupportedProtocols(TLS.V_1_3) + .build()) .build(); try (CloseableHttpClient httpclient = HttpClients.custom() .setConnectionManager(cm)