diff --git a/hutool-core/src/main/java/cn/hutool/core/net/ssl/SSLContextBuilder.java b/hutool-core/src/main/java/cn/hutool/core/net/ssl/SSLContextBuilder.java
index 62975599f..4f8b72d9d 100644
--- a/hutool-core/src/main/java/cn/hutool/core/net/ssl/SSLContextBuilder.java
+++ b/hutool-core/src/main/java/cn/hutool/core/net/ssl/SSLContextBuilder.java
@@ -13,6 +13,7 @@ import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
+
/**
* {@link SSLContext}构建器,可以自定义:
*
- * 1. TLSv1.2 - * 2. TLSv1.1 - * 3. SSLv3 - * ... - *- * - * @param protocol 协议 - * @return this - * @see SSLUtil#createTrustAnySSLContext(String) - * @see #setSocketFactory(SSLSocketFactory) - */ - public ClientConfig setSSLProtocol(final String protocol) { - Assert.notBlank(protocol, "protocol must be not blank!"); - setSocketFactory(SSLUtil.createTrustAnySSLContext(protocol).getSocketFactory()); + public ClientConfig setSSLInfo(final SSLInfo sslInfo) { + this.sslInfo = sslInfo; return this; } diff --git a/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient4/HttpClient4Engine.java b/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient4/HttpClient4Engine.java index 571e02aca..2fe5f828e 100755 --- a/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient4/HttpClient4Engine.java +++ b/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient4/HttpClient4Engine.java @@ -10,19 +10,26 @@ import cn.hutool.http.client.ClientEngine; import cn.hutool.http.client.Request; import cn.hutool.http.client.Response; import cn.hutool.http.client.body.HttpBody; +import cn.hutool.http.ssl.SSLInfo; import org.apache.http.Header; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicHeader; import java.io.IOException; import java.net.URI; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.concurrent.TimeUnit; /** * Apache HttpClient5的HTTP请求引擎 @@ -38,7 +45,8 @@ public class HttpClient4Engine implements ClientEngine { /** * 构造 */ - public HttpClient4Engine() {} + public HttpClient4Engine() { + } @Override public HttpClient4Engine setConfig(final ClientConfig config) { @@ -77,33 +85,27 @@ public class HttpClient4Engine implements ClientEngine { /** * 初始化引擎 */ - private void initEngine(){ - if(null != this.engine){ + private void initEngine() { + if (null != this.engine) { return; } - RequestConfig requestConfig = null; - if(null != this.config){ - final RequestConfig.Builder builder = RequestConfig.custom(); - - final int connectionTimeout = this.config.getConnectionTimeout(); - if(connectionTimeout > 0){ - builder.setConnectTimeout(connectionTimeout); - builder.setConnectionRequestTimeout(connectionTimeout); - } - final int readTimeout = this.config.getReadTimeout(); - if(readTimeout > 0){ - builder.setSocketTimeout(readTimeout); + final HttpClientBuilder clientBuilder = HttpClients.custom(); + final ClientConfig config = this.config; + if (null != config) { + // SSL配置 + final SSLInfo sslInfo = config.getSslInfo(); + if (null != sslInfo) { + clientBuilder.setSSLSocketFactory(buildSocketFactory(sslInfo)); } - requestConfig = builder.build(); + clientBuilder.setDefaultRequestConfig(buildRequestConfig(config)); } - this.engine = HttpClients.custom() - // 设置默认头信息 - .setDefaultRequestConfig(requestConfig) - .setDefaultHeaders(toHeaderList(GlobalHeaders.INSTANCE.headers())) - .build(); + // 设置默认头信息 + clientBuilder.setDefaultHeaders(toHeaderList(GlobalHeaders.INSTANCE.headers())); + + this.engine = clientBuilder.build(); } /** @@ -151,4 +153,41 @@ public class HttpClient4Engine implements ClientEngine { headersMap.forEach((k, v1) -> v1.forEach((v2) -> result.add(new BasicHeader(k, v2)))); return result; } + + /** + * 支持SSL + * + * @return SSLConnectionSocketFactory + */ + private static SSLConnectionSocketFactory buildSocketFactory(final SSLInfo sslInfo) { + return new SSLConnectionSocketFactory( + sslInfo.getSslContext(), + sslInfo.getProtocols(), + null, + sslInfo.getHostnameVerifier()); + } + + /** + * 构建请求配置,包括连接请求超时和响应(读取)超时 + * + * @param config {@link ClientConfig} + * @return {@link RequestConfig} + */ + private static RequestConfig buildRequestConfig(final ClientConfig config) { + // 请求配置 + final RequestConfig.Builder requestConfigBuilder = RequestConfig.custom(); + + // 连接超时 + final int connectionTimeout = config.getConnectionTimeout(); + if (connectionTimeout > 0) { + requestConfigBuilder.setConnectTimeout(connectionTimeout); + requestConfigBuilder.setConnectionRequestTimeout(connectionTimeout); + } + final int readTimeout = config.getReadTimeout(); + if (readTimeout > 0) { + requestConfigBuilder.setSocketTimeout(readTimeout); + } + + return requestConfigBuilder.build(); + } } diff --git a/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient5/HttpClient5Engine.java b/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient5/HttpClient5Engine.java index 33690ec10..52502214c 100755 --- a/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient5/HttpClient5Engine.java +++ b/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient5/HttpClient5Engine.java @@ -11,12 +11,14 @@ import cn.hutool.http.client.ClientEngine; import cn.hutool.http.client.Request; import cn.hutool.http.client.Response; import cn.hutool.http.client.body.HttpBody; +import cn.hutool.http.ssl.SSLInfo; import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase; import org.apache.hc.client5.http.config.ConnectionConfig; import org.apache.hc.client5.http.config.RequestConfig; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; 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.client5.http.ssl.SSLConnectionSocketFactoryBuilder; import org.apache.hc.core5.http.ClassicHttpRequest; @@ -45,7 +47,8 @@ public class HttpClient5Engine implements ClientEngine { /** * 构造 */ - public HttpClient5Engine() {} + public HttpClient5Engine() { + } @Override public HttpClient5Engine setConfig(final ClientConfig config) { @@ -84,47 +87,25 @@ public class HttpClient5Engine implements ClientEngine { /** * 初始化引擎 */ - private void initEngine(){ - if(null != this.engine){ + private void initEngine() { + if (null != this.engine) { return; } - // 连接配置 - final PoolingHttpClientConnectionManagerBuilder connectionManagerBuilder = PoolingHttpClientConnectionManagerBuilder.create() - .setSSLSocketFactory(SSLConnectionSocketFactoryBuilder.create() - .setSslContext(SSLUtil.createTrustAnySSLContext()).build()); + final HttpClientBuilder clientBuilder = HttpClients.custom(); - // 请求配置 - RequestConfig requestConfig = null; - - if(null != this.config){ - final int connectionTimeout = this.config.getConnectionTimeout(); - if(connectionTimeout > 0){ - connectionManagerBuilder.setDefaultConnectionConfig(ConnectionConfig.custom() - .setConnectTimeout(connectionTimeout, TimeUnit.MILLISECONDS).build()); - } - final RequestConfig.Builder builder = RequestConfig.custom(); - - if(connectionTimeout > 0){ - builder.setConnectionRequestTimeout(connectionTimeout, TimeUnit.MILLISECONDS); - } - final int readTimeout = this.config.getReadTimeout(); - if(readTimeout > 0){ - builder.setResponseTimeout(readTimeout, TimeUnit.MILLISECONDS); - } - - requestConfig = builder.build(); + final ClientConfig config = this.config; + if (null != config) { + clientBuilder.setConnectionManager(buildConnectionManager(config)); + clientBuilder.setDefaultRequestConfig(buildRequestConfig(config)); } - final HttpClientBuilder builder = HttpClients.custom() - .setConnectionManager(connectionManagerBuilder.build()) - .setDefaultRequestConfig(requestConfig) - // 设置默认头信息 - .setDefaultHeaders(toHeaderList(GlobalHeaders.INSTANCE.headers())); + // 设置默认头信息 + clientBuilder.setDefaultHeaders(toHeaderList(GlobalHeaders.INSTANCE.headers())); // TODO 设置代理 - this.engine = builder.build(); + this.engine = clientBuilder.build(); } /** @@ -167,4 +148,54 @@ public class HttpClient5Engine implements ClientEngine { headersMap.forEach((k, v1) -> v1.forEach((v2) -> result.add(new BasicHeader(k, v2)))); return result; } + + /** + * 构建连接管理器,包括SSL配置和连接超时配置 + * + * @param config {@link ClientConfig} + * @return {@link PoolingHttpClientConnectionManager} + */ + private static PoolingHttpClientConnectionManager buildConnectionManager(final ClientConfig config) { + final PoolingHttpClientConnectionManagerBuilder connectionManagerBuilder = PoolingHttpClientConnectionManagerBuilder.create(); + // SSL配置 + final SSLInfo sslInfo = config.getSslInfo(); + if (null != sslInfo) { + connectionManagerBuilder.setSSLSocketFactory(SSLConnectionSocketFactoryBuilder.create() + .setTlsVersions(sslInfo.getProtocols()) + .setSslContext(sslInfo.getSslContext()) + .setHostnameVerifier(sslInfo.getHostnameVerifier()) + .build()); + } + // 连接超时配置 + final int connectionTimeout = config.getConnectionTimeout(); + if (connectionTimeout > 0) { + connectionManagerBuilder.setDefaultConnectionConfig(ConnectionConfig.custom() + .setSocketTimeout(connectionTimeout, TimeUnit.MILLISECONDS) + .setConnectTimeout(connectionTimeout, TimeUnit.MILLISECONDS).build()); + } + + return connectionManagerBuilder.build(); + } + + /** + * 构建请求配置,包括连接请求超时和响应(读取)超时 + * + * @param config {@link ClientConfig} + * @return {@link RequestConfig} + */ + private static RequestConfig buildRequestConfig(final ClientConfig config) { + final int connectionTimeout = config.getConnectionTimeout(); + + // 请求配置 + final RequestConfig.Builder requestConfigBuilder = RequestConfig.custom(); + if (connectionTimeout > 0) { + requestConfigBuilder.setConnectionRequestTimeout(connectionTimeout, TimeUnit.MILLISECONDS); + } + final int readTimeout = config.getReadTimeout(); + if (readTimeout > 0) { + requestConfigBuilder.setResponseTimeout(readTimeout, TimeUnit.MILLISECONDS); + } + + return requestConfigBuilder.build(); + } } diff --git a/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpConnection.java b/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpConnection.java index 302046572..c03afbeb1 100644 --- a/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpConnection.java +++ b/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpConnection.java @@ -7,11 +7,9 @@ import cn.hutool.core.util.ObjUtil; import cn.hutool.http.HttpException; import cn.hutool.http.client.HeaderOperation; import cn.hutool.http.meta.Method; -import cn.hutool.http.ssl.TrustAnySSLInfo; +import cn.hutool.http.ssl.SSLInfo; -import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLSocketFactory; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -196,23 +194,23 @@ public class HttpConnection implements HeaderOperation
- * 最后发现原来是某些SSL协议没有开启 - * - * @author MikaGuraNTK - */ -public class AndroidSupportSSLFactory extends CustomProtocolsSSLFactory { - - // Android低版本不重置的话某些SSL访问就会失败 - private static final String[] protocols = { - SSLProtocols.SSLv3, SSLProtocols.TLSv1, SSLProtocols.TLSv11, SSLProtocols.TLSv12}; - - /** - * 构造 - * - * @throws IORuntimeException IO异常 - */ - public AndroidSupportSSLFactory() throws IORuntimeException { - super(protocols); - } - -} diff --git a/hutool-http/src/main/java/cn/hutool/http/ssl/CustomProtocolsSSLFactory.java b/hutool-http/src/main/java/cn/hutool/http/ssl/CustomProtocolsSSLFactory.java index 4433c766a..d45bbeae1 100644 --- a/hutool-http/src/main/java/cn/hutool/http/ssl/CustomProtocolsSSLFactory.java +++ b/hutool-http/src/main/java/cn/hutool/http/ssl/CustomProtocolsSSLFactory.java @@ -17,68 +17,68 @@ import java.net.Socket; */ public class CustomProtocolsSSLFactory extends SSLSocketFactory { + private final SSLSocketFactory raw; private final String[] protocols; - private final SSLSocketFactory base; /** * 构造 * + * @param factory {@link SSLSocketFactory} * @param protocols 支持协议列表 - * @throws IORuntimeException IO异常 */ - public CustomProtocolsSSLFactory(final String... protocols) throws IORuntimeException { + public CustomProtocolsSSLFactory(final SSLSocketFactory factory, final String... protocols) { + this.raw = factory; this.protocols = protocols; - this.base = SSLUtil.createTrustAnySSLContext(null).getSocketFactory(); } @Override public String[] getDefaultCipherSuites() { - return base.getDefaultCipherSuites(); + return raw.getDefaultCipherSuites(); } @Override public String[] getSupportedCipherSuites() { - return base.getSupportedCipherSuites(); + return raw.getSupportedCipherSuites(); } @Override public Socket createSocket() throws IOException { - final SSLSocket sslSocket = (SSLSocket) base.createSocket(); + final SSLSocket sslSocket = (SSLSocket) raw.createSocket(); resetProtocols(sslSocket); return sslSocket; } @Override public SSLSocket createSocket(final Socket s, final String host, final int port, final boolean autoClose) throws IOException { - final SSLSocket socket = (SSLSocket) base.createSocket(s, host, port, autoClose); + final SSLSocket socket = (SSLSocket) raw.createSocket(s, host, port, autoClose); resetProtocols(socket); return socket; } @Override public Socket createSocket(final String host, final int port) throws IOException { - final SSLSocket socket = (SSLSocket) base.createSocket(host, port); + final SSLSocket socket = (SSLSocket) raw.createSocket(host, port); resetProtocols(socket); return socket; } @Override public Socket createSocket(final String host, final int port, final InetAddress localHost, final int localPort) throws IOException { - final SSLSocket socket = (SSLSocket) base.createSocket(host, port, localHost, localPort); + final SSLSocket socket = (SSLSocket) raw.createSocket(host, port, localHost, localPort); resetProtocols(socket); return socket; } @Override public Socket createSocket(final InetAddress host, final int port) throws IOException { - final SSLSocket socket = (SSLSocket) base.createSocket(host, port); + final SSLSocket socket = (SSLSocket) raw.createSocket(host, port); resetProtocols(socket); return socket; } @Override public Socket createSocket(final InetAddress address, final int port, final InetAddress localAddress, final int localPort) throws IOException { - final SSLSocket socket = (SSLSocket) base.createSocket(address, port, localAddress, localPort); + final SSLSocket socket = (SSLSocket) raw.createSocket(address, port, localAddress, localPort); resetProtocols(socket); return socket; } diff --git a/hutool-http/src/main/java/cn/hutool/http/ssl/DefaultSSLFactory.java b/hutool-http/src/main/java/cn/hutool/http/ssl/DefaultSSLFactory.java deleted file mode 100644 index c784b0140..000000000 --- a/hutool-http/src/main/java/cn/hutool/http/ssl/DefaultSSLFactory.java +++ /dev/null @@ -1,15 +0,0 @@ -package cn.hutool.http.ssl; - -/** - * 默认的SSLSocketFactory - * - * @author Looly - * @since 5.1.2 - */ -public class DefaultSSLFactory extends CustomProtocolsSSLFactory { - - /** - * 构造 - */ - public DefaultSSLFactory() {} -} diff --git a/hutool-http/src/main/java/cn/hutool/http/ssl/SSLInfo.java b/hutool-http/src/main/java/cn/hutool/http/ssl/SSLInfo.java new file mode 100755 index 000000000..b105e5fee --- /dev/null +++ b/hutool-http/src/main/java/cn/hutool/http/ssl/SSLInfo.java @@ -0,0 +1,169 @@ +package cn.hutool.http.ssl; + +import cn.hutool.core.net.ssl.SSLProtocols; +import cn.hutool.core.net.ssl.SSLUtil; +import cn.hutool.core.net.ssl.TrustAnyHostnameVerifier; +import cn.hutool.core.net.ssl.TrustAnyTrustManager; +import cn.hutool.core.text.StrUtil; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.X509TrustManager; + +/** + * HTTP请求中SSL相关信息,包括: + *