Looly 6 years ago
parent
commit
63a8c5766d

+ 2 - 0
CHANGELOG.md

@@ -9,6 +9,8 @@
 * 【core 】     XmlUtil支持可选是否输出omit xml declaration(pr#732@Github)
 * 【core 】     车牌号校验兼容新能源车牌(pr#92@Gitee)
 * 【core 】     在NetUtil中新增ping功能(pr#91@Gitee)
+* 【core 】     DateUtil.offset不支持ERA,增加异常提示(issue#I18KD5@Gitee)
+* 【http 】     改进HttpUtil访问HTTPS接口性能问题,SSL证书使用单例(issue#I18AL1@Gitee)
 
 ### Bug修复
 * 【core 】     修复isExpired的bug(issue#733@Gtihub)

+ 4 - 0
hutool-core/src/main/java/cn/hutool/core/date/DateTime.java

@@ -268,6 +268,10 @@ public class DateTime extends Date {
 	 * @return 如果此对象为可变对象,返回自身,否则返回新对象
 	 */
 	public DateTime offset(DateField datePart, int offset) {
+		if(DateField.ERA == datePart){
+			throw new IllegalArgumentException("ERA is not support offset!");
+		}
+
 		final Calendar cal = toCalendar();
 		//noinspection MagicConstant
 		cal.add(datePart.getValue(), offset);

+ 1 - 0
hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java

@@ -645,6 +645,7 @@ public class DateUtilTest {
 		DateTime startDate = DateUtil.parse("2019-12-01 17:02:30");
 		DateTime endDate = DateUtil.parse("2019-12-02 17:02:30");
 		int length = 3;
+		//noinspection deprecation
 		boolean expired = DateUtil.isExpired(startDate, DateField.DAY_OF_YEAR, length, endDate);
 		Assert.assertTrue(expired);
 	}

+ 13 - 25
hutool-http/src/main/java/cn/hutool/http/HttpConnection.java

@@ -1,5 +1,16 @@
 package cn.hutool.http;
 
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.util.URLUtil;
+import cn.hutool.http.ssl.AndroidSupportSSLFactory;
+import cn.hutool.http.ssl.DefaultSSLInfo;
+import cn.hutool.http.ssl.SSLSocketFactoryBuilder;
+
+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;
@@ -16,17 +27,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLSocketFactory;
-
-import cn.hutool.core.map.MapUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.core.util.URLUtil;
-import cn.hutool.http.ssl.AndroidSupportSSLFactory;
-import cn.hutool.http.ssl.SSLSocketFactoryBuilder;
-import cn.hutool.http.ssl.TrustAnyHostnameVerifier;
-
 /**
  * http连接对象,对HttpURLConnection的包装
  * 
@@ -262,20 +262,8 @@ public class HttpConnection {
 			// Https请求
 			final HttpsURLConnection httpsConn = (HttpsURLConnection) conn;
 			// 验证域
-			httpsConn.setHostnameVerifier(null != hostnameVerifier ? hostnameVerifier : new TrustAnyHostnameVerifier());
-			if (null == ssf) {
-				try {
-					if (StrUtil.equalsIgnoreCase("dalvik", System.getProperty("java.vm.name"))) {
-						// 兼容android低版本SSL连接
-						ssf = new AndroidSupportSSLFactory();
-					} else {
-						ssf = SSLSocketFactoryBuilder.create().build();
-					}
-				} catch (KeyManagementException | NoSuchAlgorithmException e) {
-					throw new HttpException(e);
-				}
-			}
-			httpsConn.setSSLSocketFactory(ssf);
+			httpsConn.setHostnameVerifier(ObjectUtil.defaultIfNull(hostnameVerifier, DefaultSSLInfo.TRUST_ANY_HOSTNAME_VERIFIER));
+			httpsConn.setSSLSocketFactory(ObjectUtil.defaultIfNull(ssf, DefaultSSLInfo.DEFAULT_SSF));
 		}
 
 		return this;

+ 9 - 10
hutool-http/src/main/java/cn/hutool/http/HttpRequest.java

@@ -857,12 +857,11 @@ public class HttpRequest extends HttpBase<HttpRequest> {
 	 * @see #setSSLSocketFactory(SSLSocketFactory)
 	 */
 	public HttpRequest setSSLProtocol(String protocol) {
-		if (null == this.ssf) {
-			try {
-				this.ssf = SSLSocketFactoryBuilder.create().setProtocol(protocol).build();
-			} catch (Exception e) {
-				throw new HttpException(e);
-			}
+		Assert.notBlank(protocol, "protocol must be not blank!");
+		try {
+			this.ssf = SSLSocketFactoryBuilder.create().setProtocol(protocol).build();
+		} catch (Exception e) {
+			throw new HttpException(e);
 		}
 		return this;
 	}
@@ -930,13 +929,13 @@ public class HttpRequest extends HttpBase<HttpRequest> {
 			this.url = HttpUtil.encodeParams(this.url, this.charset);
 		}
 		// 初始化 connection
-		initConnecton();
+		initConnection();
 
 		// 发送请求
 		send();
 
 		// 手动实现重定向
-		HttpResponse httpResponse = sendRedirectIfPosible();
+		HttpResponse httpResponse = sendRedirectIfPossible();
 
 		// 获取响应
 		if (null == httpResponse) {
@@ -966,7 +965,7 @@ public class HttpRequest extends HttpBase<HttpRequest> {
 	/**
 	 * 初始化网络连接
 	 */
-	private void initConnecton() {
+	private void initConnection() {
 		if (null != this.httpConnection) {
 			// 执行下次请求时自动关闭上次请求(常用于转发)
 			this.httpConnection.disconnectQuietly();
@@ -1018,7 +1017,7 @@ public class HttpRequest extends HttpBase<HttpRequest> {
 	 *
 	 * @return {@link HttpResponse},无转发返回 <code>null</code>
 	 */
-	private HttpResponse sendRedirectIfPosible() {
+	private HttpResponse sendRedirectIfPossible() {
 		if (this.maxRedirectCount < 1) {
 			// 不重定向
 			return null;

+ 11 - 11
hutool-http/src/main/java/cn/hutool/http/ssl/CustomProtocolsSSLFactory.java

@@ -1,5 +1,7 @@
 package cn.hutool.http.ssl;
 
+import cn.hutool.core.util.ArrayUtil;
+
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.Socket;
@@ -13,7 +15,6 @@ import javax.net.ssl.SSLSocketFactory;
  * 自定义支持协议类型的SSLSocketFactory
  * 
  * @author looly
- *
  */
 public class CustomProtocolsSSLFactory extends SSLSocketFactory {
 
@@ -45,45 +46,42 @@ public class CustomProtocolsSSLFactory extends SSLSocketFactory {
 
 	@Override
 	public Socket createSocket() throws IOException {
-		SSLSocket sslSocket = (SSLSocket) base.createSocket();
+		final SSLSocket sslSocket = (SSLSocket) base.createSocket();
 		resetProtocols(sslSocket);
 		return sslSocket;
 	}
 
 	@Override
 	public SSLSocket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
-		SSLSocket socket = (SSLSocket) base.createSocket(s, host, port, autoClose);
+		final SSLSocket socket = (SSLSocket) base.createSocket(s, host, port, autoClose);
 		resetProtocols(socket);
 		return socket;
 	}
 
 	@Override
 	public Socket createSocket(String host, int port) throws IOException {
-		SSLSocket socket = (SSLSocket) base.createSocket(host, port);
+		final SSLSocket socket = (SSLSocket) base.createSocket(host, port);
 		resetProtocols(socket);
 		return socket;
 	}
 
 	@Override
 	public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
-
-		SSLSocket socket = (SSLSocket) base.createSocket(host, port, localHost, localPort);
+		final SSLSocket socket = (SSLSocket) base.createSocket(host, port, localHost, localPort);
 		resetProtocols(socket);
 		return socket;
 	}
 
 	@Override
 	public Socket createSocket(InetAddress host, int port) throws IOException {
-
-		SSLSocket socket = (SSLSocket) base.createSocket(host, port);
+		final SSLSocket socket = (SSLSocket) base.createSocket(host, port);
 		resetProtocols(socket);
 		return socket;
 	}
 
 	@Override
 	public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
-
-		SSLSocket socket = (SSLSocket) base.createSocket(address, port, localAddress, localPort);
+		final SSLSocket socket = (SSLSocket) base.createSocket(address, port, localAddress, localPort);
 		resetProtocols(socket);
 		return socket;
 	}
@@ -94,7 +92,9 @@ public class CustomProtocolsSSLFactory extends SSLSocketFactory {
 	 * @param socket SSLSocket
 	 */
 	private void resetProtocols(SSLSocket socket) {
-		socket.setEnabledProtocols(protocols);
+		if(ArrayUtil.isNotEmpty(this.protocols)){
+			socket.setEnabledProtocols(this.protocols);
+		}
 	}
 
 }

+ 18 - 0
hutool-http/src/main/java/cn/hutool/http/ssl/DefaultSSLFactory.java

@@ -0,0 +1,18 @@
+package cn.hutool.http.ssl;
+
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * 默认的SSLSocketFactory
+ *
+ * @author Looly
+ * @since 5.1.2
+ */
+public class DefaultSSLFactory extends CustomProtocolsSSLFactory {
+
+	public DefaultSSLFactory() throws KeyManagementException, NoSuchAlgorithmException {
+		super();
+	}
+
+}

+ 40 - 0
hutool-http/src/main/java/cn/hutool/http/ssl/DefaultSSLInfo.java

@@ -0,0 +1,40 @@
+package cn.hutool.http.ssl;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpException;
+
+import javax.net.ssl.SSLSocketFactory;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * 默认的SSL配置,当用户未设置相关信息时,使用默认设置,默认设置为单例模式。
+ *
+ * @author looly
+ * @since 5.1.2
+ */
+public class DefaultSSLInfo {
+	/**
+	 * 默认信任全部的域名校验器
+	 */
+	public static final TrustAnyHostnameVerifier TRUST_ANY_HOSTNAME_VERIFIER;
+	/**
+	 * 默认的SSLSocketFactory,区分安卓
+	 */
+	public static final SSLSocketFactory DEFAULT_SSF;
+
+	static {
+		TRUST_ANY_HOSTNAME_VERIFIER = new TrustAnyHostnameVerifier();
+
+		try {
+			if (StrUtil.equalsIgnoreCase("dalvik", System.getProperty("java.vm.name"))) {
+				// 兼容android低版本SSL连接
+				DEFAULT_SSF = new AndroidSupportSSLFactory();
+			} else {
+				DEFAULT_SSF = new DefaultSSLFactory();
+			}
+		} catch (KeyManagementException | NoSuchAlgorithmException e) {
+			throw new HttpException(e);
+		}
+	}
+}

+ 3 - 3
hutool-http/src/main/java/cn/hutool/http/ssl/DefaultTrustManager.java

@@ -7,8 +7,8 @@ import javax.net.ssl.X509TrustManager;
 
 /**
  * 证书管理
- * @author Looly
  *
+ * @author Looly
  */
 public class DefaultTrustManager implements X509TrustManager {
 
@@ -18,10 +18,10 @@ public class DefaultTrustManager implements X509TrustManager {
 	}
 
 	@Override
-	public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+	public void checkClientTrusted(X509Certificate[] chain, String authType) {
 	}
 
 	@Override
-	public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+	public void checkServerTrusted(X509Certificate[] chain, String authType) {
 	}
 }

+ 28 - 0
hutool-http/src/test/java/cn/hutool/http/test/HttpsTest.java

@@ -0,0 +1,28 @@
+package cn.hutool.http.test;
+
+import cn.hutool.core.lang.Console;
+import cn.hutool.core.thread.ThreadUtil;
+import cn.hutool.http.HttpUtil;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class HttpsTest {
+
+	/**
+	 * 测试单例的SSLSocketFactory是否有线程安全问题
+	 */
+	@Test
+	@Ignore
+	public void getTest() {
+		final AtomicInteger count = new AtomicInteger();
+		for(int i =0; i < 100; i++){
+			ThreadUtil.execute(()->{
+				final String s = HttpUtil.get("https://www.baidu.com/");
+				Console.log(count.incrementAndGet());
+			});
+		}
+		ThreadUtil.sync(this);
+	}
+}