Skip to content

Commit 0cfac6c

Browse files
author
markjrzhang
committed
merge orign master
2 parents 9c3e426 + ea30e1d commit 0cfac6c

File tree

7 files changed

+482
-23
lines changed

7 files changed

+482
-23
lines changed

src/main/java/com/qcloud/cos/ClientConfig.java

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import com.qcloud.cos.endpoint.EndpointResolver;
2525
import com.qcloud.cos.endpoint.RegionEndpointBuilder;
2626
import com.qcloud.cos.endpoint.SuffixEndpointBuilder;
27+
import com.qcloud.cos.http.DefaultHandlerAfterProcess;
28+
import com.qcloud.cos.http.HandlerAfterProcess;
2729
import com.qcloud.cos.http.HttpProtocol;
2830
import com.qcloud.cos.region.Region;
2931
import com.qcloud.cos.retry.BackoffStrategy;
@@ -95,8 +97,8 @@ public class ClientConfig {
9597
private int readLimit = DEFAULT_READ_LIMIT;
9698
private COSSigner cosSigner = new COSSigner();
9799

98-
private int request_timeout = DEFAULT_REQUEST_TIMEOUT;
99-
private int shutdown_timeout = DEFAULT_SHUTDOWN_TIMEOUT;
100+
private int requestTimeout = DEFAULT_REQUEST_TIMEOUT;
101+
private int shutdownTimeout = DEFAULT_SHUTDOWN_TIMEOUT;
100102
private boolean isRequestTimeOutEnable = false;
101103

102104
// 数据万象特殊请求配置
@@ -113,9 +115,17 @@ public class ClientConfig {
113115

114116
private boolean isCheckRequestPath = true;
115117

116-
private int timeout_client_thread_size = 0;
118+
private int timeoutClientThreadSize = 0;
117119

118-
private int error_log_status_code_thresh = 500;
120+
private int errorLogStatusCodeThresh = 500;
121+
122+
private boolean checkSSLCertificate = true;
123+
124+
private boolean useDefaultDnsResolver = true;
125+
126+
private HandlerAfterProcess handlerAfterProcess = new DefaultHandlerAfterProcess();
127+
128+
private boolean isRefreshEndpointAddr = false;
119129

120130
// 不传入region 用于后续调用List Buckets(获取所有的bucket信息)
121131
public ClientConfig() {
@@ -347,11 +357,11 @@ public boolean isShortConnection() {
347357
}
348358

349359
public int getRequestTimeout () {
350-
return request_timeout;
360+
return requestTimeout;
351361
}
352362

353363
public void setRequestTimeout (int requestTimeout) {
354-
this.request_timeout = requestTimeout;
364+
this.requestTimeout = requestTimeout;
355365
}
356366

357367
public void setRequestTimeOutEnable(boolean requestTimeOutEnable) {
@@ -363,11 +373,11 @@ public boolean getRequestTimeOutEnable() {
363373
}
364374

365375
public void setShutdownTimeout(int shutdownTimeout) {
366-
this.shutdown_timeout = shutdownTimeout;
376+
this.shutdownTimeout = shutdownTimeout;
367377
}
368378

369379
public int getShutdownTimeout() {
370-
return shutdown_timeout;
380+
return shutdownTimeout;
371381
}
372382

373383
public boolean isChangeEndpointRetry() {
@@ -395,18 +405,50 @@ public boolean isCheckRequestPath() {
395405
}
396406

397407
public int getTimeoutClientThreadSize() {
398-
return timeout_client_thread_size;
408+
return timeoutClientThreadSize;
399409
}
400410

401-
public void setTimeoutClientThreadSize(int pool_size) {
402-
timeout_client_thread_size = pool_size;
411+
public void setTimeoutClientThreadSize(int poolSize) {
412+
timeoutClientThreadSize = poolSize;
403413
}
404414

405-
public void setErrorLogStatusCodeThresh(int status_code) {
406-
error_log_status_code_thresh = status_code;
415+
public void setErrorLogStatusCodeThresh(int statusCode) {
416+
errorLogStatusCodeThresh = statusCode;
407417
}
408418

409419
public int getErrorLogStatusCodeThresh() {
410-
return error_log_status_code_thresh;
420+
return errorLogStatusCodeThresh;
421+
}
422+
423+
public void setCheckSSLCertificate(boolean isCheckSSLCertificate) {
424+
checkSSLCertificate = isCheckSSLCertificate;
425+
}
426+
427+
public boolean isCheckSSLCertificate() {
428+
return checkSSLCertificate;
429+
}
430+
431+
public void setUseDefaultDnsResolver(boolean useDefaultDnsResolver) {
432+
this.useDefaultDnsResolver = useDefaultDnsResolver;
433+
}
434+
435+
public boolean isUseDefaultDnsResolver() {
436+
return useDefaultDnsResolver;
437+
}
438+
439+
public void setHandlerAfterProcess(HandlerAfterProcess handler) {
440+
this.handlerAfterProcess = handler;
441+
}
442+
443+
public HandlerAfterProcess getHandlerAfterProcess() {
444+
return handlerAfterProcess;
445+
}
446+
447+
public void turnOnRefreshEndpointAddrSwitch() {
448+
isRefreshEndpointAddr = true;
449+
}
450+
451+
public boolean IsRefreshEndpointAddr() {
452+
return isRefreshEndpointAddr;
411453
}
412454
}

src/main/java/com/qcloud/cos/http/DefaultCosHttpClient.java

Lines changed: 122 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,18 @@
2323
import java.io.FileInputStream;
2424
import java.io.IOException;
2525
import java.io.InputStream;
26+
import java.net.InetAddress;
2627
import java.net.URI;
2728
import java.net.URISyntaxException;
29+
import java.net.UnknownHostException;
30+
import java.security.NoSuchAlgorithmException;
31+
import java.security.KeyManagementException;
32+
import java.security.KeyStoreException;
33+
import java.util.Arrays;
34+
import java.util.ArrayList;
35+
import java.util.Collections;
36+
import java.util.Date;
37+
import java.util.Objects;
2838
import java.util.HashMap;
2939
import java.util.List;
3040
import java.util.Map;
@@ -33,14 +43,16 @@
3343
import java.util.concurrent.TimeoutException;
3444
import java.util.regex.Matcher;
3545
import java.util.regex.Pattern;
36-
import java.util.Date;
37-
import java.util.Objects;
3846

3947
import com.qcloud.cos.ClientConfig;
4048
import com.qcloud.cos.Headers;
4149
import com.qcloud.cos.auth.COSCredentials;
4250
import com.qcloud.cos.auth.COSSigner;
51+
import com.qcloud.cos.endpoint.CIRegionEndpointBuilder;
52+
import com.qcloud.cos.endpoint.CIPicRegionEndpointBuilder;
4353
import com.qcloud.cos.internal.cihandler.HttpEntityEnclosingDelete;
54+
import com.qcloud.cos.internal.CIPicServiceRequest;
55+
import com.qcloud.cos.model.ListBucketsRequest;
4456
import com.qcloud.cos.region.Region;
4557
import com.qcloud.cos.event.ProgressInputStream;
4658
import com.qcloud.cos.event.ProgressListener;
@@ -81,6 +93,14 @@
8193
import org.apache.http.client.methods.HttpPut;
8294
import org.apache.http.client.methods.HttpRequestBase;
8395
import org.apache.http.client.protocol.HttpClientContext;
96+
import org.apache.http.config.Registry;
97+
import org.apache.http.config.RegistryBuilder;
98+
import org.apache.http.conn.DnsResolver;
99+
import org.apache.http.conn.socket.ConnectionSocketFactory;
100+
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
101+
import org.apache.http.conn.ssl.NoopHostnameVerifier;
102+
import org.apache.http.ssl.SSLContextBuilder;
103+
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
84104
import org.apache.http.entity.InputStreamEntity;
85105
import org.apache.http.impl.client.HttpClientBuilder;
86106
import org.apache.http.impl.client.HttpClients;
@@ -89,6 +109,7 @@
89109
import org.slf4j.Logger;
90110
import org.slf4j.LoggerFactory;
91111

112+
import javax.net.ssl.SSLContext;
92113

93114
public class DefaultCosHttpClient implements CosHttpClient {
94115

@@ -102,13 +123,59 @@ public class DefaultCosHttpClient implements CosHttpClient {
102123
private BackoffStrategy backoffStrategy;
103124

104125
private CosErrorResponseHandler errorResponseHandler;
126+
private HandlerAfterProcess handlerAfterProcess;
105127
private static final Logger log = LoggerFactory.getLogger(DefaultCosHttpClient.class);
106128

107129
public DefaultCosHttpClient(ClientConfig clientConfig) {
108130
super();
109131
this.errorResponseHandler = new CosErrorResponseHandler();
110132
this.clientConfig = clientConfig;
111-
this.connectionManager = new PoolingHttpClientConnectionManager();
133+
this.handlerAfterProcess = clientConfig.getHandlerAfterProcess();
134+
DnsResolver dnsResolver = new DnsResolver() {
135+
@Override
136+
public InetAddress[] resolve(String host) throws UnknownHostException {
137+
InetAddress[] addresses = InetAddress.getAllByName(host);
138+
List<InetAddress> addressList = new ArrayList<>(Arrays.asList(addresses));
139+
Collections.shuffle(addressList);
140+
141+
InetAddress[] newAddresses = addressList.toArray(new InetAddress[0]);
142+
return newAddresses;
143+
}
144+
};
145+
146+
if (clientConfig.isCheckSSLCertificate()) {
147+
if (clientConfig.isUseDefaultDnsResolver()) {
148+
this.connectionManager = new PoolingHttpClientConnectionManager();
149+
} else {
150+
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
151+
.register("http", PlainConnectionSocketFactory.getSocketFactory())
152+
.register("https", SSLConnectionSocketFactory.getSocketFactory()).build();
153+
this.connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry, dnsResolver);
154+
}
155+
} else {
156+
try {
157+
SSLContext sslContext = SSLContextBuilder.create().loadTrustMaterial((chain, authType) -> true).build();
158+
159+
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
160+
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
161+
.register("http", PlainConnectionSocketFactory.getSocketFactory())
162+
.register("https", sslSocketFactory).build();
163+
if (clientConfig.isUseDefaultDnsResolver()) {
164+
this.connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
165+
} else {
166+
this.connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry, dnsResolver);
167+
}
168+
} catch (NoSuchAlgorithmException e) {
169+
log.error("fail to init http client: ", e);
170+
throw new RuntimeException(e);
171+
} catch (KeyStoreException e) {
172+
log.error("fail to init http client: ", e);
173+
throw new RuntimeException(e);
174+
} catch (KeyManagementException e) {
175+
log.error("fail to init http client: ", e);
176+
throw new RuntimeException(e);
177+
}
178+
}
112179
this.maxErrorRetry = clientConfig.getMaxErrorRetry();
113180
this.retryPolicy = ValidationUtils.assertNotNull(clientConfig.getRetryPolicy(), "retry policy");
114181
this.backoffStrategy = ValidationUtils.assertNotNull(clientConfig.getBackoffStrategy(), "backoff strategy");
@@ -496,6 +563,10 @@ public <X, Y extends CosServiceRequest> X exeute(CosHttpRequest<Y> request,
496563
originalContent.mark(readLimit);
497564
}
498565

566+
long startTime = 0;
567+
long endTime = 0;
568+
int response_status = 0;
569+
499570
int retryIndex = 0;
500571
while (true) {
501572
try {
@@ -512,17 +583,24 @@ public <X, Y extends CosServiceRequest> X exeute(CosHttpRequest<Y> request,
512583
originalContent.reset();
513584
}
514585
if (retryIndex != 0) {
586+
response_status = 0;
587+
if (clientConfig.IsRefreshEndpointAddr()) {
588+
refreshEndpointAddr(request);
589+
}
590+
515591
long delay = backoffStrategy.computeDelayBeforeNextRetry(retryIndex);
516592
request.addHeader("x-cos-sdk-retry", "true");
517593
Thread.sleep(delay);
518594
}
519595
HttpContext context = HttpClientContext.create();
520596
httpRequest = buildHttpRequest(request);
521597
httpResponse = null;
598+
startTime = System.currentTimeMillis();
522599
httpResponse = executeRequest(context, httpRequest);
523600
checkResponse(request, httpRequest, httpResponse);
524601
break;
525602
} catch (CosServiceException cse) {
603+
response_status = -1;
526604
closeHttpResponseStream(httpResponse);
527605
String errorMsg = String.format("failed to execute http request due to service exception, request timeStamp %d,"
528606
+ " httpRequest: %s, retryIdx:%d, maxErrorRetry:%d", System.currentTimeMillis(), request,
@@ -540,6 +618,7 @@ public <X, Y extends CosServiceRequest> X exeute(CosHttpRequest<Y> request,
540618
}
541619
changeEndpointForRetry(request, httpResponse, retryIndex);
542620
} catch (CosClientException cce) {
621+
response_status = -1;
543622
closeHttpResponseStream(httpResponse);
544623
String errorMsg = String.format("failed to execute http request due to client exception, request timeStamp %d,"
545624
+ " httpRequest: %s, retryIdx:%d, maxErrorRetry:%d", System.currentTimeMillis(), request,
@@ -551,12 +630,15 @@ public <X, Y extends CosServiceRequest> X exeute(CosHttpRequest<Y> request,
551630
}
552631
changeEndpointForRetry(request, httpResponse, retryIndex);
553632
} catch (Exception exp) {
633+
response_status = -1;
554634
String expName = exp.getClass().getName();
555635
String errorMsg = String.format("httpClient execute occur an unknown exception:%s, httpRequest: %s", expName, request);
556636
closeHttpResponseStream(httpResponse);
557637
log.error(errorMsg, exp);
558638
throw new CosClientException(errorMsg, exp);
559639
} finally {
640+
endTime = System.currentTimeMillis();
641+
handlerAfterProcess.handle(response_status, endTime - startTime);
560642
++retryIndex;
561643
}
562644
}
@@ -705,4 +787,41 @@ private <Y extends CosServiceRequest> void changeEndpointForRetry(CosHttpRequest
705787
}
706788
}
707789
}
790+
791+
private <X extends CosServiceRequest> void refreshEndpointAddr(CosHttpRequest<X> request) throws CosClientException {
792+
boolean isCIRequest = request.getOriginalRequest() instanceof CIServiceRequest;
793+
boolean isServiceRequest = request.getOriginalRequest() instanceof ListBucketsRequest;
794+
String endpoint = "";
795+
String endpointAddr = "";
796+
if (isServiceRequest) {
797+
endpoint = clientConfig.getEndpointBuilder().buildGetServiceApiEndpoint();
798+
endpointAddr =
799+
clientConfig.getEndpointResolver().resolveGetServiceApiEndpoint(endpoint);
800+
} else {
801+
802+
if (request.getOriginalRequest() instanceof CIPicServiceRequest) {
803+
endpoint = new CIPicRegionEndpointBuilder(clientConfig.getRegion()).buildGeneralApiEndpoint(request.getBucketName());
804+
} else if (isCIRequest) {
805+
endpoint = new CIRegionEndpointBuilder(clientConfig.getRegion()).buildGeneralApiEndpoint(request.getBucketName());
806+
} else {
807+
endpoint = clientConfig.getEndpointBuilder().buildGeneralApiEndpoint(request.getBucketName());
808+
}
809+
endpointAddr = clientConfig.getEndpointResolver().resolveGeneralApiEndpoint(endpoint);
810+
}
811+
812+
if (endpoint == null) {
813+
throw new CosClientException("endpoint is null, please check your endpoint builder");
814+
}
815+
if (endpointAddr == null) {
816+
throw new CosClientException(
817+
"endpointAddr is null, please check your endpoint resolver");
818+
}
819+
820+
String fixedEndpointAddr = request.getOriginalRequest().getFixedEndpointAddr();
821+
if (fixedEndpointAddr != null) {
822+
request.setEndpoint(fixedEndpointAddr);
823+
} else {
824+
request.setEndpoint(endpointAddr);
825+
}
826+
}
708827
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.qcloud.cos.http;
2+
3+
public class DefaultHandlerAfterProcess implements HandlerAfterProcess{
4+
@Override
5+
public void handle(int status, long time_cost) {}
6+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.qcloud.cos.http;
2+
3+
public interface HandlerAfterProcess {
4+
public void handle(int status, long time_cost);
5+
}

src/main/java/com/qcloud/cos/http/IdleConnectionMonitorThread.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ public void run() {
5454
}
5555
} catch (InterruptedException e) {
5656
log.error("interrupt exception occured:", e);
57+
} catch (Throwable t) {
58+
log.error("error occured when closeExpiredConnections and closeIdleConnections, err:", t);
5759
} finally {
5860
connMgr.shutdown();
5961
}

0 commit comments

Comments
 (0)