This commit is contained in:
Looly 2020-01-29 10:58:45 +08:00
parent 1c13d73010
commit 63a8c5766d
10 changed files with 129 additions and 49 deletions

View File

@ -9,6 +9,8 @@
* 【core 】 XmlUtil支持可选是否输出omit xml declarationpr#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的bugissue#733@Gtihub

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}
}

View File

@ -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) {
}
}

View File

@ -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);
}
}