diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/httpclient4/ConnectionSocketFactoryRegistryBuilder.java b/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/httpclient4/ConnectionSocketFactoryRegistryBuilder.java new file mode 100644 index 000000000..56ddc3632 --- /dev/null +++ b/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/httpclient4/ConnectionSocketFactoryRegistryBuilder.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2024 Hutool Team and hutool.cn + * + * Licensed 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. + */ + +package org.dromara.hutool.http.client.engine.httpclient4; + +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.dromara.hutool.core.lang.builder.Builder; +import org.dromara.hutool.http.ssl.SSLInfo; + +/** + * HttpClient4连接工厂注册器构建器 + * + * @author Looly + * @since 6.0.0 + */ +public class ConnectionSocketFactoryRegistryBuilder implements Builder> { + private static final long serialVersionUID = 1L; + + /** + * 创建 + * + * @return {@code ConnectionSocketFactoryRegistryBuilder} + */ + public static ConnectionSocketFactoryRegistryBuilder of() { + return new ConnectionSocketFactoryRegistryBuilder(); + } + + /** + * 构建默认的连接工厂注册器,默认支持SSL + * + * @param sslInfo SSL配置,{@code null}表示使用默认配置,即{@link SSLConnectionSocketFactory#getSocketFactory()} + * @return {@code Registry} + */ + public static Registry build(final SSLInfo sslInfo) { + return of().registerPlainHttp().registerHttps(sslInfo).build(); + } + + private final RegistryBuilder builder; + + /** + * 构造 + */ + public ConnectionSocketFactoryRegistryBuilder() { + builder = RegistryBuilder.create(); + } + + /** + * 注册HTTP协议,使用默认的普通(非加密)连接工厂 + * + * @return this + */ + public ConnectionSocketFactoryRegistryBuilder registerPlainHttp() { + return registerHttp(PlainConnectionSocketFactory.getSocketFactory()); + } + + /** + * 注册HTTP协议,使用默认的普通连接工厂 + * + * @param socketFactory {@link ConnectionSocketFactory} + * @return this + */ + public ConnectionSocketFactoryRegistryBuilder registerHttp(final ConnectionSocketFactory socketFactory) { + return register("http", socketFactory); + } + + /** + * 注册HTTPS协议 + * + * @param sslInfo SSL配置,{@code null}表示使用默认配置,即{@link SSLConnectionSocketFactory#getSocketFactory()} + * @return this + */ + public ConnectionSocketFactoryRegistryBuilder registerHttps(final SSLInfo sslInfo) { + return register("https", buildSocketFactory(sslInfo)); + } + + /** + * 注册连接工厂 + * + * @param protocol 协议 + * @param socketFactory 连接工厂 + * @return this + */ + public ConnectionSocketFactoryRegistryBuilder register(final String protocol, final ConnectionSocketFactory socketFactory) { + builder.register(protocol, socketFactory); + return this; + } + + @Override + public Registry build() { + return builder.build(); + } + + /** + * 支持SSL + * + * @param sslInfo SSL配置,{@code null}表示使用默认配置,即{@link SSLConnectionSocketFactory#getSocketFactory()} + * @return SSLConnectionSocketFactory + */ + private static SSLConnectionSocketFactory buildSocketFactory(final SSLInfo sslInfo) { + if (null == sslInfo) { + return SSLConnectionSocketFactory.getSocketFactory(); + } + return new SSLConnectionSocketFactory( + sslInfo.getSslContext(), + sslInfo.getProtocols(), + null, + sslInfo.getHostnameVerifier()); + } +} diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/httpclient4/HttpClient4Engine.java b/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/httpclient4/HttpClient4Engine.java index 5ead5af0e..7375f7387 100644 --- a/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/httpclient4/HttpClient4Engine.java +++ b/hutool-http/src/main/java/org/dromara/hutool/http/client/engine/httpclient4/HttpClient4Engine.java @@ -23,7 +23,6 @@ import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; @@ -43,7 +42,6 @@ import org.dromara.hutool.http.client.Response; import org.dromara.hutool.http.client.cookie.InMemoryCookieStore; import org.dromara.hutool.http.client.engine.AbstractClientEngine; import org.dromara.hutool.http.proxy.ProxyInfo; -import org.dromara.hutool.http.ssl.SSLInfo; import java.io.IOException; import java.net.PasswordAuthentication; @@ -112,13 +110,7 @@ public class HttpClient4Engine extends AbstractClientEngine { final HttpClientBuilder clientBuilder = HttpClients.custom(); final ClientConfig config = ObjUtil.defaultIfNull(this.config, ApacheHttpClientConfig::of); - // SSL配置 - final SSLInfo sslInfo = config.getSslInfo(); - if (null != sslInfo) { - clientBuilder.setSSLSocketFactory(buildSocketFactory(sslInfo)); - } - - // 连接配置,包括连接池 + // 连接配置,包括SSL配置和连接池 clientBuilder.setConnectionManager(buildConnectionManager(config)); // 实例级别默认请求配置 @@ -136,7 +128,7 @@ public class HttpClient4Engine extends AbstractClientEngine { setProxy(clientBuilder, config); // Cookie管理 - if(config.isUseCookieManager()){ + if (config.isUseCookieManager()) { this.cookieStore = new InMemoryCookieStore(); clientBuilder.setDefaultCookieStore(new HttpClient4CookieStore(this.cookieStore)); } @@ -155,19 +147,6 @@ public class HttpClient4Engine extends AbstractClientEngine { return result; } - /** - * 支持SSL - * - * @return SSLConnectionSocketFactory - */ - private static SSLConnectionSocketFactory buildSocketFactory(final SSLInfo sslInfo) { - return new SSLConnectionSocketFactory( - sslInfo.getSslContext(), - sslInfo.getProtocols(), - null, - sslInfo.getHostnameVerifier()); - } - /** * 构建连接池管理器 * @@ -175,17 +154,20 @@ public class HttpClient4Engine extends AbstractClientEngine { * @return PoolingHttpClientConnectionManager */ private PoolingHttpClientConnectionManager buildConnectionManager(final ClientConfig config) { - final PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager(); + final PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager( + // SSL配置,当config.getSslInfo()为null时,使用默认配置 + ConnectionSocketFactoryRegistryBuilder.build(config.getSslInfo()) + ); // 连接池配置 if (config instanceof ApacheHttpClientConfig) { final ApacheHttpClientConfig apacheHttpClientConfig = (ApacheHttpClientConfig) config; final int maxTotal = apacheHttpClientConfig.getMaxTotal(); - if(maxTotal > 0){ + if (maxTotal > 0) { manager.setMaxTotal(maxTotal); } final int maxPerRoute = apacheHttpClientConfig.getMaxPerRoute(); - if(maxPerRoute > 0){ + if (maxPerRoute > 0) { manager.setDefaultMaxPerRoute(maxPerRoute); } } @@ -234,7 +216,7 @@ public class HttpClient4Engine extends AbstractClientEngine { final ProxyInfo proxy = config.getProxy(); if (null != proxy) { final ProxySelector proxySelector = proxy.getProxySelector(); - if(null != proxySelector){ + if (null != proxySelector) { clientBuilder.setRoutePlanner(new SystemDefaultRoutePlanner(proxySelector)); } final PasswordAuthentication auth = proxy.getAuth(); diff --git a/hutool-http/src/test/java/org/dromara/hutool/http/client/IssueIBC5N8Test.java b/hutool-http/src/test/java/org/dromara/hutool/http/client/IssueIBC5N8Test.java new file mode 100644 index 000000000..73aa0ef3f --- /dev/null +++ b/hutool-http/src/test/java/org/dromara/hutool/http/client/IssueIBC5N8Test.java @@ -0,0 +1,28 @@ +package org.dromara.hutool.http.client; + +import org.dromara.hutool.core.lang.Console; +import org.dromara.hutool.http.HttpGlobalConfig; +import org.dromara.hutool.http.HttpUtil; +import org.dromara.hutool.http.client.engine.ClientEngine; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +public class IssueIBC5N8Test { + @Test + @Disabled + public void getBadSSLTest(){ + HttpGlobalConfig.setTrustAnyHost(true); + requestBadSSL("httpclient4"); + requestBadSSL("httpclient5"); + requestBadSSL("okhttp"); + requestBadSSL("jdkClient"); + } + + private void requestBadSSL(final String engineName) { + final ClientEngine engine = HttpUtil.createClient(engineName); + + final Request req = Request.of("https://expired.badssl.com/"); + final Response res = engine.send(req); + Console.log(res.getStatus()); + } +}