diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6cfea34c2..df6ad1390 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,9 @@
#Changelog
+## 8.2.0(2021-02-20)
+## 增加
+* 增加网络监控功能,选择最优 Host 进行上传
+* 优化日志统计
+
## 8.1.2(2021-01-18)
* 区域查询采用SingleFlight模式
* 增加网络链接状态检测
diff --git a/README.md b/README.md
index 66725c7fb..753d6b876 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ https://github.com/qiniudemo/qiniu-lab-android
| Qiniu SDK 版本 | 最低 Android版本 | 依赖库版本 |
|------------ |-----------------|------------------------|
+| 8.2.x | Android 5.0+ | okhttp 4+ |
| 8.1.x | Android 5.0+ | okhttp 4+ |
| 8.0.x | Android 5.0+ | okhttp 4+ |
| 7.7.x | Android 5.0+ | okhttp 4+ |
@@ -28,7 +29,7 @@ https://github.com/qiniudemo/qiniu-lab-android
| 7.0.7 | Android 2.2+ | android-async-http 1.4.8 |
### 注意
-* 推荐使用最新版:8.1.2
+* 推荐使用最新版:8.2.0
* AndroidNetwork.getMobileDbm()可以获取手机信号强度,需要如下权限(API>=18时生效)
```
diff --git a/library/src/androidTest/java/com/qiniu/android/ConnectCheckTest.java b/library/src/androidTest/java/com/qiniu/android/ConnectCheckTest.java
index bc77e6698..8232647fa 100644
--- a/library/src/androidTest/java/com/qiniu/android/ConnectCheckTest.java
+++ b/library/src/androidTest/java/com/qiniu/android/ConnectCheckTest.java
@@ -10,7 +10,7 @@ public void testCheck() {
int maxCount = 100;
int successCount = 0;
for (int i = 0; i < maxCount; i++) {
- if (ConnectChecker.check()) {
+ if (ConnectChecker.isConnected(ConnectChecker.check())) {
successCount += 1;
}
}
@@ -23,7 +23,7 @@ public void testCustomCheckHosts() {
int maxCount = 100;
int successCount = 0;
for (int i = 0; i < maxCount; i++) {
- if (ConnectChecker.check()) {
+ if (ConnectChecker.isConnected(ConnectChecker.check())) {
successCount += 1;
}
}
@@ -36,7 +36,7 @@ public void testNotConnected() {
int maxCount = 100;
int successCount = 0;
for (int i = 0; i < maxCount; i++) {
- if (ConnectChecker.check()) {
+ if (ConnectChecker.isConnected(ConnectChecker.check())) {
successCount += 1;
}
}
diff --git a/library/src/androidTest/java/com/qiniu/android/DnsTransactionTest.java b/library/src/androidTest/java/com/qiniu/android/DnsTransactionTest.java
index af15fd4a0..2afe03f34 100644
--- a/library/src/androidTest/java/com/qiniu/android/DnsTransactionTest.java
+++ b/library/src/androidTest/java/com/qiniu/android/DnsTransactionTest.java
@@ -61,10 +61,12 @@ public void test_CheckAndPrefetch(){
public void run() {
boolean isSuccess = DnsPrefetchTransaction.addDnsCheckAndPrefetchTransaction(zone, UpToken.parse(TestConfig.token_z0));
- if (isSuccess){
- successCount += 1;
+ synchronized (this) {
+ if (isSuccess) {
+ successCount += 1;
+ }
+ completeCount += 1;
}
- completeCount += 1;
}
}).start();
}
@@ -80,7 +82,7 @@ public boolean shouldWait() {
}
}, 60);
- assertTrue("successCount:" + successCount, successCount < 2);
+ assertTrue("successCount:" + successCount, successCount < 3);
}
diff --git a/library/src/androidTest/java/com/qiniu/android/TestConfig.java b/library/src/androidTest/java/com/qiniu/android/TestConfig.java
index 4d909b9f0..1072f6756 100644
--- a/library/src/androidTest/java/com/qiniu/android/TestConfig.java
+++ b/library/src/androidTest/java/com/qiniu/android/TestConfig.java
@@ -10,20 +10,20 @@ public final class TestConfig {
// TODO: 2020-05-09 bad token for testPutBytesWithFixedZoneUseBackupDomains
// 华东上传凭证
public static final String bucket_z0 = "kodo-phone-zone0-space";
- public static final String token_z0 = "dxVQk8gyk3WswArbNhdKIwmwibJ9nFsQhMNUmtIM:Tq8MZRIC2hc1hxWxH3RqLcdFuQw=:eyJzY29wZSI6ImtvZG8tcGhvbmUtem9uZTAtc3BhY2UiLCJkZWFkbGluZSI6MTYxMzE4NDg0OCwgInJldHVybkJvZHkiOiJ7XCJjYWxsYmFja1VybFwiOlwiaHR0cDpcL1wvY2FsbGJhY2suZGV2LnFpbml1LmlvXCIsIFwiZm9vXCI6JCh4OmZvbyksIFwiYmFyXCI6JCh4OmJhciksIFwibWltZVR5cGVcIjokKG1pbWVUeXBlKSwgXCJoYXNoXCI6JChldGFnKSwgXCJrZXlcIjokKGtleSksIFwiZm5hbWVcIjokKGZuYW1lKX0ifQ==";
+ public static final String token_z0 = "dxVQk8gyk3WswArbNhdKIwmwibJ9nFsQhMNUmtIM:m1kHxpdaFH3NK120iAkHlSwBpio=:eyJzY29wZSI6ImtvZG8tcGhvbmUtem9uZTAtc3BhY2UiLCJkZWFkbGluZSI6MTYxODgxNDM5MCwgInJldHVybkJvZHkiOiJ7XCJjYWxsYmFja1VybFwiOlwiaHR0cDpcL1wvY2FsbGJhY2suZGV2LnFpbml1LmlvXCIsIFwiZm9vXCI6JCh4OmZvbyksIFwiYmFyXCI6JCh4OmJhciksIFwibWltZVR5cGVcIjokKG1pbWVUeXBlKSwgXCJoYXNoXCI6JChldGFnKSwgXCJrZXlcIjokKGtleSksIFwiZm5hbWVcIjokKGZuYW1lKX0ifQ==";
// 华北上传凭证
public static final String bucket_z1 = "kodo-phone-zone1-space";
- public static final String token_z1 = "dxVQk8gyk3WswArbNhdKIwmwibJ9nFsQhMNUmtIM:FZiNMb3SKDFpdat2q9wpG6zbn_w=:eyJzY29wZSI6ImtvZG8tcGhvbmUtem9uZTEtc3BhY2UiLCJkZWFkbGluZSI6MTYxMzE4NDg0OCwgInJldHVybkJvZHkiOiJ7XCJjYWxsYmFja1VybFwiOlwiaHR0cDpcL1wvY2FsbGJhY2suZGV2LnFpbml1LmlvXCIsIFwiZm9vXCI6JCh4OmZvbyksIFwiYmFyXCI6JCh4OmJhciksIFwibWltZVR5cGVcIjokKG1pbWVUeXBlKSwgXCJoYXNoXCI6JChldGFnKSwgXCJrZXlcIjokKGtleSksIFwiZm5hbWVcIjokKGZuYW1lKX0ifQ==";
+ public static final String token_z1 = "dxVQk8gyk3WswArbNhdKIwmwibJ9nFsQhMNUmtIM:1vkQkb72ANFiAftABJAF2dhbXd0=:eyJzY29wZSI6ImtvZG8tcGhvbmUtem9uZTEtc3BhY2UiLCJkZWFkbGluZSI6MTYxODgxNDM5MCwgInJldHVybkJvZHkiOiJ7XCJjYWxsYmFja1VybFwiOlwiaHR0cDpcL1wvY2FsbGJhY2suZGV2LnFpbml1LmlvXCIsIFwiZm9vXCI6JCh4OmZvbyksIFwiYmFyXCI6JCh4OmJhciksIFwibWltZVR5cGVcIjokKG1pbWVUeXBlKSwgXCJoYXNoXCI6JChldGFnKSwgXCJrZXlcIjokKGtleSksIFwiZm5hbWVcIjokKGZuYW1lKX0ifQ==";
// 华南上传凭证
public static final String bucket_z2 = "kodo-phone-zone2-space";
- public static final String token_z2 = "dxVQk8gyk3WswArbNhdKIwmwibJ9nFsQhMNUmtIM:cP9NhEWUWhPrxlfAxaemVj6uIKI=:eyJzY29wZSI6ImtvZG8tcGhvbmUtem9uZTItc3BhY2UiLCJkZWFkbGluZSI6MTYxMzE4NDg0OCwgInJldHVybkJvZHkiOiJ7XCJjYWxsYmFja1VybFwiOlwiaHR0cDpcL1wvY2FsbGJhY2suZGV2LnFpbml1LmlvXCIsIFwiZm9vXCI6JCh4OmZvbyksIFwiYmFyXCI6JCh4OmJhciksIFwibWltZVR5cGVcIjokKG1pbWVUeXBlKSwgXCJoYXNoXCI6JChldGFnKSwgXCJrZXlcIjokKGtleSksIFwiZm5hbWVcIjokKGZuYW1lKX0ifQ==";
+ public static final String token_z2 = "dxVQk8gyk3WswArbNhdKIwmwibJ9nFsQhMNUmtIM:ZTqDdbvHJuP3hJFckpadCyW08Cs=:eyJzY29wZSI6ImtvZG8tcGhvbmUtem9uZTItc3BhY2UiLCJkZWFkbGluZSI6MTYxODgxNDM5MCwgInJldHVybkJvZHkiOiJ7XCJjYWxsYmFja1VybFwiOlwiaHR0cDpcL1wvY2FsbGJhY2suZGV2LnFpbml1LmlvXCIsIFwiZm9vXCI6JCh4OmZvbyksIFwiYmFyXCI6JCh4OmJhciksIFwibWltZVR5cGVcIjokKG1pbWVUeXBlKSwgXCJoYXNoXCI6JChldGFnKSwgXCJrZXlcIjokKGtleSksIFwiZm5hbWVcIjokKGZuYW1lKX0ifQ==";
// 北美上传凭证
public static final String bucket_na0 = "kodo-phone-zone-na0-space";
- public static final String token_na0 = "dxVQk8gyk3WswArbNhdKIwmwibJ9nFsQhMNUmtIM:V9zBCBaNWrKZvqLu4b5Dem0hOrQ=:eyJzY29wZSI6ImtvZG8tcGhvbmUtem9uZS1uYTAtc3BhY2UiLCJkZWFkbGluZSI6MTYxMzE4NDg0OCwgInJldHVybkJvZHkiOiJ7XCJjYWxsYmFja1VybFwiOlwiaHR0cDpcL1wvY2FsbGJhY2suZGV2LnFpbml1LmlvXCIsIFwiZm9vXCI6JCh4OmZvbyksIFwiYmFyXCI6JCh4OmJhciksIFwibWltZVR5cGVcIjokKG1pbWVUeXBlKSwgXCJoYXNoXCI6JChldGFnKSwgXCJrZXlcIjokKGtleSksIFwiZm5hbWVcIjokKGZuYW1lKX0ifQ==";
+ public static final String token_na0 = "dxVQk8gyk3WswArbNhdKIwmwibJ9nFsQhMNUmtIM:I8Q0E32hEelHH4xWBH2p17SxhdA=:eyJzY29wZSI6ImtvZG8tcGhvbmUtem9uZS1uYTAtc3BhY2UiLCJkZWFkbGluZSI6MTYxODgxNDM5MCwgInJldHVybkJvZHkiOiJ7XCJjYWxsYmFja1VybFwiOlwiaHR0cDpcL1wvY2FsbGJhY2suZGV2LnFpbml1LmlvXCIsIFwiZm9vXCI6JCh4OmZvbyksIFwiYmFyXCI6JCh4OmJhciksIFwibWltZVR5cGVcIjokKG1pbWVUeXBlKSwgXCJoYXNoXCI6JChldGFnKSwgXCJrZXlcIjokKGtleSksIFwiZm5hbWVcIjokKGZuYW1lKX0ifQ==";
// 东南亚上传凭证
public static final String bucket_as0 = "kodo-phone-zone-as0-space";
- public static final String token_as0 = "dxVQk8gyk3WswArbNhdKIwmwibJ9nFsQhMNUmtIM:PaaKXdrwQgI4J7Fw5nhtbwQ_bu8=:eyJzY29wZSI6ImtvZG8tcGhvbmUtem9uZS1hczAtc3BhY2UiLCJkZWFkbGluZSI6MTYxMzE4NDg0OCwgInJldHVybkJvZHkiOiJ7XCJjYWxsYmFja1VybFwiOlwiaHR0cDpcL1wvY2FsbGJhY2suZGV2LnFpbml1LmlvXCIsIFwiZm9vXCI6JCh4OmZvbyksIFwiYmFyXCI6JCh4OmJhciksIFwibWltZVR5cGVcIjokKG1pbWVUeXBlKSwgXCJoYXNoXCI6JChldGFnKSwgXCJrZXlcIjokKGtleSksIFwiZm5hbWVcIjokKGZuYW1lKX0ifQ==";
- public static final String invalidBucketToken = "dxVQk8gyk3WswArbNhdKIwmwibJ9nFsQhMNUmtIM:k9olgJ5rgs-SvzirMtdU_ASmArY=:eyJzY29wZSI6InpvbmVfaW52YWxpZCIsImRlYWRsaW5lIjoxNjEzMTg0ODQ4LCAicmV0dXJuQm9keSI6IntcImNhbGxiYWNrVXJsXCI6XCJodHRwOlwvXC9jYWxsYmFjay5kZXYucWluaXUuaW9cIiwgXCJmb29cIjokKHg6Zm9vKSwgXCJiYXJcIjokKHg6YmFyKSwgXCJtaW1lVHlwZVwiOiQobWltZVR5cGUpLCBcImhhc2hcIjokKGV0YWcpLCBcImtleVwiOiQoa2V5KSwgXCJmbmFtZVwiOiQoZm5hbWUpfSJ9";
+ public static final String token_as0 = "dxVQk8gyk3WswArbNhdKIwmwibJ9nFsQhMNUmtIM:DDXIo7KzUj3ceh5LveRXyNfsiZU=:eyJzY29wZSI6ImtvZG8tcGhvbmUtem9uZS1hczAtc3BhY2UiLCJkZWFkbGluZSI6MTYxODgxNDM5MCwgInJldHVybkJvZHkiOiJ7XCJjYWxsYmFja1VybFwiOlwiaHR0cDpcL1wvY2FsbGJhY2suZGV2LnFpbml1LmlvXCIsIFwiZm9vXCI6JCh4OmZvbyksIFwiYmFyXCI6JCh4OmJhciksIFwibWltZVR5cGVcIjokKG1pbWVUeXBlKSwgXCJoYXNoXCI6JChldGFnKSwgXCJrZXlcIjokKGtleSksIFwiZm5hbWVcIjokKGZuYW1lKX0ifQ==";
+ public static final String invalidBucketToken = "dxVQk8gyk3WswArbNhdKIwmwibJ9nFsQhMNUmtIM:Kpi_0B6gZSf7nF5UgdZtvHx0h8M=:eyJzY29wZSI6InpvbmVfaW52YWxpZCIsImRlYWRsaW5lIjoxNjE4ODE0MzkwLCAicmV0dXJuQm9keSI6IntcImNhbGxiYWNrVXJsXCI6XCJodHRwOlwvXC9jYWxsYmFjay5kZXYucWluaXUuaW9cIiwgXCJmb29cIjokKHg6Zm9vKSwgXCJiYXJcIjokKHg6YmFyKSwgXCJtaW1lVHlwZVwiOiQobWltZVR5cGUpLCBcImhhc2hcIjokKGV0YWcpLCBcImtleVwiOiQoa2V5KSwgXCJmbmFtZVwiOiQoZm5hbWUpfSJ9";
// -----------
public static final String ak = "bjtWBQXrcxgo7HWwlC_bgHg81j352_GhgBGZPeOW";
diff --git a/library/src/androidTest/java/com/qiniu/android/UploadDomainRegionTest.java b/library/src/androidTest/java/com/qiniu/android/UploadDomainRegionTest.java
index 2cb18cb03..148ffa610 100644
--- a/library/src/androidTest/java/com/qiniu/android/UploadDomainRegionTest.java
+++ b/library/src/androidTest/java/com/qiniu/android/UploadDomainRegionTest.java
@@ -2,6 +2,7 @@
import com.qiniu.android.common.FixedZone;
import com.qiniu.android.http.request.IUploadServer;
+import com.qiniu.android.http.request.UploadRequestState;
import com.qiniu.android.http.serverRegion.UploadDomainRegion;
import com.qiniu.android.http.serverRegion.UploadServerFreezeManager;
import com.qiniu.android.utils.Utils;
@@ -18,9 +19,11 @@ public void testGetOneServer(){
UploadDomainRegion region = new UploadDomainRegion();
region.setupRegionData(zone.getZonesInfo(null).zonesInfo.get(0));
- UploadServerFreezeManager.getInstance().freezeHost(host, type, 100);
+ UploadServerFreezeManager.getInstance().freezeType(type, 100);
- IUploadServer server = region.getNextServer(false, null, null);
+ UploadRequestState state = new UploadRequestState();
+ state.setUseOldServer(false);
+ IUploadServer server = region.getNextServer(state, null, null);
assertNotNull(server);
}
diff --git a/library/src/androidTest/java/com/qiniu/android/UploadServerFreezeManagerTest.java b/library/src/androidTest/java/com/qiniu/android/UploadServerFreezeManagerTest.java
index 1500fa8dc..007907f91 100644
--- a/library/src/androidTest/java/com/qiniu/android/UploadServerFreezeManagerTest.java
+++ b/library/src/androidTest/java/com/qiniu/android/UploadServerFreezeManagerTest.java
@@ -8,9 +8,9 @@ public void testFreeze() {
String host = "baidu.com";
String type = host;
- UploadServerFreezeManager.getInstance().freezeHost(host, type, 10);
+ UploadServerFreezeManager.getInstance().freezeType(type, 10);
- boolean isFrozen = UploadServerFreezeManager.getInstance().isFreezeHost(host, type);
+ boolean isFrozen = UploadServerFreezeManager.getInstance().isTypeFrozen(type);
assertTrue(isFrozen);
}
@@ -18,13 +18,13 @@ public void testUnfreeze() {
String host = "baidu.com";
String type = host;
- UploadServerFreezeManager.getInstance().freezeHost(host, type, 10);
+ UploadServerFreezeManager.getInstance().freezeType(type, 10);
- boolean isFrozen = UploadServerFreezeManager.getInstance().isFreezeHost(host, type);
+ boolean isFrozen = UploadServerFreezeManager.getInstance().isTypeFrozen(type);
assertTrue(isFrozen);
- UploadServerFreezeManager.getInstance().unfreezeHost(host, type);
- isFrozen = UploadServerFreezeManager.getInstance().isFreezeHost(host, type);
+ UploadServerFreezeManager.getInstance().unfreezeType(type);
+ isFrozen = UploadServerFreezeManager.getInstance().isTypeFrozen(type);
assertTrue(isFrozen == false);
}
diff --git a/library/src/main/java/com/qiniu/android/collect/ReportItem.java b/library/src/main/java/com/qiniu/android/collect/ReportItem.java
index 0d3171185..285ec7183 100644
--- a/library/src/main/java/com/qiniu/android/collect/ReportItem.java
+++ b/library/src/main/java/com/qiniu/android/collect/ReportItem.java
@@ -47,6 +47,7 @@ public String toJson(){
public static final String RequestKeyStatusCode = "status_code";
public static final String RequestKeyRequestId = "req_id";
public static final String RequestKeyHost = "host";
+ public static final String RequestKeyHttpVersion = "http_version";
public static final String RequestKeyRemoteIp = "remote_ip";
public static final String RequestKeyPort = "port";
public static final String RequestKeyTargetBucket = "target_bucket";
@@ -80,6 +81,7 @@ public String toJson(){
public static final String RequestKeyPrefetchedDnsSource = "prefetched_dns_source";
public static final String RequestKeyPrefetchedBefore = "prefetched_before";
public static final String RequestKeyPrefetchedErrorMessage = "prefetched_error_message";
+ public static final String RequestKeyNetworkMeasuring = "network_measuring";
// 分块上传统计⽇志
public static final String BlockKeyLogType = "log_type";
diff --git a/library/src/main/java/com/qiniu/android/common/AutoZone.java b/library/src/main/java/com/qiniu/android/common/AutoZone.java
index 020e40a11..d056fd89a 100644
--- a/library/src/main/java/com/qiniu/android/common/AutoZone.java
+++ b/library/src/main/java/com/qiniu/android/common/AutoZone.java
@@ -123,7 +123,7 @@ public void complete(Object value) {
} catch (Exception e) {
/// 此处永远不会执行,回调只为占位
- completeHandler.complete(ResponseInfo.NetworkError, ResponseInfo.localIOError("uc query"), null);
+ completeHandler.complete(ResponseInfo.NetworkError, ResponseInfo.localIOError(e.toString()), null);
}
}
diff --git a/library/src/main/java/com/qiniu/android/common/Constants.java b/library/src/main/java/com/qiniu/android/common/Constants.java
index a76e38c45..1e2652ce0 100644
--- a/library/src/main/java/com/qiniu/android/common/Constants.java
+++ b/library/src/main/java/com/qiniu/android/common/Constants.java
@@ -2,7 +2,7 @@
public final class Constants {
- public static final String VERSION = "8.1.2";
+ public static final String VERSION = "8.2.0";
public static final String UTF_8 = "utf-8";
}
diff --git a/library/src/main/java/com/qiniu/android/common/ZoneInfo.java b/library/src/main/java/com/qiniu/android/common/ZoneInfo.java
index 6d647d269..b6a880368 100644
--- a/library/src/main/java/com/qiniu/android/common/ZoneInfo.java
+++ b/library/src/main/java/com/qiniu/android/common/ZoneInfo.java
@@ -24,6 +24,7 @@ public class ZoneInfo {
private static int DOMAIN_FROZEN_SECONDS = 10 * 60;
public final int ttl;
+ public final boolean http3Enabled;
public final List domains;
public final List old_domains;
@@ -70,10 +71,12 @@ public static ZoneInfo buildInfo(List mainHosts,
}
private ZoneInfo(int ttl,
+ boolean http3Enabled,
String regionId,
List domains,
List old_domains) {
this.ttl = ttl;
+ this.http3Enabled = http3Enabled;
this.regionId = regionId;
this.domains = domains;
this.old_domains = old_domains;
@@ -91,6 +94,14 @@ public static ZoneInfo buildFromJson(JSONObject obj) throws JSONException {
}
int ttl = obj.optInt("ttl");
+ boolean http3Enabled = false;
+ try {
+ JSONObject features = obj.getJSONObject("features");
+ JSONObject http3 = features.getJSONObject("http3");
+ http3Enabled = http3.getBoolean("enabled");
+ } catch (Exception ignored) {
+ }
+
String regionId = obj.optString("region");
if (regionId == null) {
regionId = EmptyRegionId;
@@ -130,7 +141,7 @@ public static ZoneInfo buildFromJson(JSONObject obj) throws JSONException {
return null;
}
- ZoneInfo zoneInfo = new ZoneInfo(ttl, regionId, domains, old_domains);
+ ZoneInfo zoneInfo = new ZoneInfo(ttl, http3Enabled, regionId, domains, old_domains);
zoneInfo.detailInfo = obj;
zoneInfo.allHosts = allHosts;
diff --git a/library/src/main/java/com/qiniu/android/http/connectCheck/ConnectChecker.java b/library/src/main/java/com/qiniu/android/http/connectCheck/ConnectChecker.java
index 9c8acd995..8bd9e94a0 100644
--- a/library/src/main/java/com/qiniu/android/http/connectCheck/ConnectChecker.java
+++ b/library/src/main/java/com/qiniu/android/http/connectCheck/ConnectChecker.java
@@ -14,53 +14,57 @@
public class ConnectChecker {
- private static SingleFlight singleFlight = new SingleFlight<>();
+ private static SingleFlight singleFlight = new SingleFlight<>();
- public static boolean check() {
+ public static boolean isConnected(UploadSingleRequestMetrics metrics) {
+ return metrics != null && metrics.response != null && metrics.response.statusCode > 99;
+ }
+
+ public static UploadSingleRequestMetrics check() {
final CheckResult result = new CheckResult();
final Wait wait = new Wait();
check(new CheckCompleteHandler() {
@Override
- public void complete(boolean isConnected) {
- result.isConnected = isConnected;
+ public void complete(UploadSingleRequestMetrics metrics) {
+ result.metrics = metrics;
wait.stopWait();
}
});
wait.startWait();
- return result.isConnected;
+ return result.metrics;
}
private static void check(final CheckCompleteHandler completeHandler) {
try {
- singleFlight.perform("connect_check", new SingleFlight.ActionHandler() {
+ singleFlight.perform("connect_check", new SingleFlight.ActionHandler() {
@Override
- public void action(final SingleFlight.CompleteHandler singleFlightComplete) throws Exception {
+ public void action(final SingleFlight.CompleteHandler singleFlightComplete) throws Exception {
checkAllHosts(new CheckCompleteHandler() {
@Override
- public void complete(boolean isConnected) {
- singleFlightComplete.complete(isConnected);
+ public void complete(UploadSingleRequestMetrics metrics) {
+ singleFlightComplete.complete(metrics);
}
});
}
- }, new SingleFlight.CompleteHandler() {
+ }, new SingleFlight.CompleteHandler() {
@Override
- public void complete(Boolean value) {
- completeHandler.complete(value);
+ public void complete(UploadSingleRequestMetrics metrics) {
+ completeHandler.complete(metrics);
}
});
} catch (Exception e) {
- completeHandler.complete(true);
+ completeHandler.complete(null);
}
}
private static void checkAllHosts(final CheckCompleteHandler completeHandler) {
String[] allHosts = GlobalConfiguration.getInstance().connectCheckURLStrings;
if (allHosts == null) {
- completeHandler.complete(true);
+ completeHandler.complete(null);
return;
}
@@ -72,8 +76,8 @@ private static void checkAllHosts(final CheckCompleteHandler completeHandler) {
for (String host : allHosts) {
checkHost(host, new CheckCompleteHandler() {
@Override
- public void complete(boolean isHostConnected) {
-
+ public void complete(UploadSingleRequestMetrics metrics) {
+ boolean isHostConnected = isConnected(metrics);
synchronized (checkStatus) {
checkStatus.completeCount += 1;
}
@@ -90,7 +94,7 @@ public void complete(boolean isHostConnected) {
checkStatus.isCompleted = true;
}
}
- completeHandler.complete(checkStatus.isConnected);
+ completeHandler.complete(metrics);
} else {
LogUtil.i("== check all hosts not completed totalCount:" + checkStatus.totalCount + " completeCount:" + checkStatus.completeCount);
}
@@ -109,20 +113,15 @@ private static void checkHost(final String host, final CheckCompleteHandler comp
client.request(request, true, null, null, new IRequestClient.RequestClientCompleteHandler() {
@Override
public void complete(ResponseInfo responseInfo, UploadSingleRequestMetrics metrics, JSONObject response) {
- if (responseInfo.statusCode > 99) {
- LogUtil.i("== checkHost:" + host + " result: true");
- completeHandler.complete(true);
- } else {
- LogUtil.i("== checkHost:" + host + " result: false");
- completeHandler.complete(false);
- }
+ LogUtil.i("== checkHost:" + host + " responseInfo:" + responseInfo);
+ completeHandler.complete(metrics);
}
});
}
private interface CheckCompleteHandler {
- void complete(boolean isConnected);
+ void complete(UploadSingleRequestMetrics metrics);
}
private static class CheckStatus {
@@ -133,6 +132,6 @@ private static class CheckStatus {
}
private static class CheckResult {
- private boolean isConnected = false;
+ private UploadSingleRequestMetrics metrics;
}
}
diff --git a/library/src/main/java/com/qiniu/android/http/metrics/UploadSingleRequestMetrics.java b/library/src/main/java/com/qiniu/android/http/metrics/UploadSingleRequestMetrics.java
index 31c562f8f..788647162 100644
--- a/library/src/main/java/com/qiniu/android/http/metrics/UploadSingleRequestMetrics.java
+++ b/library/src/main/java/com/qiniu/android/http/metrics/UploadSingleRequestMetrics.java
@@ -9,6 +9,12 @@
public class UploadSingleRequestMetrics {
+ // 请求的 httpVersion
+ public String httpVersion;
+
+ // 只有进行网络检测才会有 connectCheckMetrics
+ public UploadSingleRequestMetrics connectCheckMetrics;
+
public Request request;
public ResponseInfo response;
diff --git a/library/src/main/java/com/qiniu/android/http/networkStatus/NetworkStatusManager.java b/library/src/main/java/com/qiniu/android/http/networkStatus/NetworkStatusManager.java
new file mode 100644
index 000000000..d4ee9c535
--- /dev/null
+++ b/library/src/main/java/com/qiniu/android/http/networkStatus/NetworkStatusManager.java
@@ -0,0 +1,194 @@
+package com.qiniu.android.http.networkStatus;
+
+import com.qiniu.android.storage.FileRecorder;
+import com.qiniu.android.storage.Recorder;
+import com.qiniu.android.utils.AsyncRun;
+import com.qiniu.android.utils.Utils;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Date;
+import java.util.Iterator;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class NetworkStatusManager {
+
+ private static String kNetworkStatusDiskKey = "NetworkStatus:v1.0.0";
+
+ private boolean hasInit = false;
+ private boolean isHandlingNetworkInfoOfDisk = false;
+ private Recorder recorder;
+ private ConcurrentHashMap networkStatusInfo;
+ private static NetworkStatusManager networkStatusManager = new NetworkStatusManager();
+
+ public static NetworkStatusManager getInstance() {
+ networkStatusManager.initData();
+ return networkStatusManager;
+ }
+
+ public synchronized void initData() {
+ if (hasInit){
+ return;
+ }
+ networkStatusManager.networkStatusInfo = new ConcurrentHashMap<>();
+ networkStatusManager.asyncRecoverNetworkStatusFromDisk();
+ }
+
+ public static String getNetworkStatusType(String host, String ip) {
+ return Utils.getIpType(ip, host);
+ }
+
+ public NetworkStatus getNetworkStatus(String type) {
+ if (type == null || type.length() == 0) {
+ return null;
+ }
+ NetworkStatus status = networkStatusInfo.get(type);
+ if (status == null) {
+ status = new NetworkStatus();
+ }
+ return status;
+ }
+
+ public void updateNetworkStatus(String type, int speed) {
+ if (type == null || type.length() == 0) {
+ return;
+ }
+ NetworkStatus status = networkStatusInfo.get(type);
+ if (status == null) {
+ status = new NetworkStatus();
+ networkStatusInfo.put(type, status);
+ }
+ status.setSpeed(speed);
+
+ asyncRecordNetworkStatusInfo();
+ }
+
+ // ---------- 持久化 -----------
+ private void asyncRecordNetworkStatusInfo() {
+ synchronized (this) {
+ if (isHandlingNetworkInfoOfDisk) {
+ return;
+ }
+ isHandlingNetworkInfoOfDisk = true;
+ }
+ AsyncRun.runInBack(new Runnable() {
+ @Override
+ public void run() {
+ recordNetworkStatusInfo();
+ isHandlingNetworkInfoOfDisk = false;
+ }
+ });
+ }
+
+ private void asyncRecoverNetworkStatusFromDisk() {
+ synchronized (this) {
+ if (isHandlingNetworkInfoOfDisk) {
+ return;
+ }
+ isHandlingNetworkInfoOfDisk = true;
+ }
+ AsyncRun.runInBack(new Runnable() {
+ @Override
+ public void run() {
+ recoverNetworkStatusFromDisk();
+ isHandlingNetworkInfoOfDisk = true;
+ }
+ });
+ }
+
+ private void recordNetworkStatusInfo() {
+
+ setupRecorder();
+
+ if (recorder == null || networkStatusInfo == null) {
+ return;
+ }
+
+ JSONObject networkStatusInfoJson = new JSONObject();
+ for (String key : networkStatusInfo.keySet()) {
+ NetworkStatus status = networkStatusInfo.get(key);
+ if (status != null) {
+ try {
+ networkStatusInfoJson.put(key, status.toJson());
+ } catch (Exception ignored) {
+ }
+ }
+ }
+ recorder.set(kNetworkStatusDiskKey, networkStatusInfoJson.toString().getBytes());
+ }
+
+ private void recoverNetworkStatusFromDisk() {
+
+ setupRecorder();
+
+ if (recorder == null || networkStatusInfo == null) {
+ return;
+ }
+
+ byte[] networkStatusInfoData = recorder.get(kNetworkStatusDiskKey);
+ JSONObject networkStatusInfoJSON = null;
+ try {
+ networkStatusInfoJSON = new JSONObject(new String(networkStatusInfoData));
+ } catch (Exception ignored) {
+ return;
+ }
+
+ for (Iterator it = networkStatusInfoJSON.keys(); it.hasNext(); ) {
+ String key = it.next();
+ try {
+ JSONObject statusJson = networkStatusInfoJSON.getJSONObject(key);
+ NetworkStatus status = NetworkStatus.statusFromJson(statusJson);
+ if (status != null) {
+ networkStatusInfo.put(key, status);
+ }
+ } catch (JSONException ignored) {
+ }
+ }
+ }
+
+
+ private synchronized void setupRecorder() {
+ if (recorder == null) {
+ try {
+ recorder = new FileRecorder(Utils.sdkDirectory() + "/NetworkInfo");
+ } catch (Exception ignored) {
+ }
+ }
+ }
+
+ public static class NetworkStatus {
+
+ private int speed;
+
+ public int getSpeed() {
+ return speed;
+ }
+
+ public void setSpeed(int speed) {
+ this.speed = speed;
+ }
+
+ private JSONObject toJson() {
+ JSONObject jsonObject = new JSONObject();
+ try {
+ jsonObject.put("speed", speed);
+ } catch (Exception ignored) {
+ }
+ return jsonObject;
+ }
+
+ private static NetworkStatus statusFromJson(JSONObject jsonObject) {
+ if (jsonObject == null) {
+ return null;
+ }
+
+ NetworkStatus status = new NetworkStatus();
+ try {
+ status.speed = jsonObject.getInt("speed");
+ } catch (Exception ignored) {
+ }
+ return status;
+ }
+ }
+}
diff --git a/library/src/main/java/com/qiniu/android/http/networkStatus/UploadServerNetworkStatus.java b/library/src/main/java/com/qiniu/android/http/networkStatus/UploadServerNetworkStatus.java
new file mode 100644
index 000000000..9429d327f
--- /dev/null
+++ b/library/src/main/java/com/qiniu/android/http/networkStatus/UploadServerNetworkStatus.java
@@ -0,0 +1,32 @@
+package com.qiniu.android.http.networkStatus;
+
+import com.qiniu.android.http.request.IUploadServer;
+import com.qiniu.android.utils.Utils;
+
+public class UploadServerNetworkStatus {
+
+ public static IUploadServer getBetterNetworkServer(IUploadServer serverA, IUploadServer serverB) {
+ return isServerNetworkBetter(serverA, serverB) ? serverA : serverB;
+ }
+
+ public static boolean isServerNetworkBetter(IUploadServer serverA, IUploadServer serverB) {
+ if (serverA == null) {
+ return false;
+ } else if (serverB == null) {
+ return true;
+ }
+
+ String serverTypeA = NetworkStatusManager.getNetworkStatusType(serverA.getHost(), serverA.getIp());
+ String serverTypeB = NetworkStatusManager.getNetworkStatusType(serverB.getHost(), serverB.getIp());
+ if (serverTypeA == null) {
+ return false;
+ } else if (serverTypeB == null) {
+ return true;
+ }
+
+ NetworkStatusManager.NetworkStatus serverStatusA = NetworkStatusManager.getInstance().getNetworkStatus(serverTypeA);
+ NetworkStatusManager.NetworkStatus serverStatusB = NetworkStatusManager.getInstance().getNetworkStatus(serverTypeB);
+
+ return serverStatusB.getSpeed() < serverStatusA.getSpeed();
+ }
+}
diff --git a/library/src/main/java/com/qiniu/android/http/request/HttpRegionRequest.java b/library/src/main/java/com/qiniu/android/http/request/HttpRegionRequest.java
index 94d62d451..a7dc33d9f 100644
--- a/library/src/main/java/com/qiniu/android/http/request/HttpRegionRequest.java
+++ b/library/src/main/java/com/qiniu/android/http/request/HttpRegionRequest.java
@@ -24,7 +24,7 @@ class HttpRegionRequest {
private final IUploadRegion region;
private final UploadRequestInfo requestInfo;
- private boolean isUseOldServer;
+ private UploadRequestState requestState;
private HttpSingleRequest singleRequest;
private IUploadServer currentServer;
private UploadRegionRequestMetrics requestMetrics;
@@ -40,6 +40,7 @@ class HttpRegionRequest {
this.token = token;
this.region = region;
this.requestInfo = requestInfo;
+ this.requestState = requestState;
singleRequest = new HttpSingleRequest(config, uploadOption, token, requestInfo, requestState);
}
@@ -97,30 +98,22 @@ private void performRequest(IUploadServer server,
String serverIP = server.getIp();
if (config.urlConverter != null){
- serverHost = config.urlConverter.convert(serverHost);
serverIP = null;
- server = null;
+ serverHost = config.urlConverter.convert(serverHost);
}
- boolean toSkipDns;
String scheme = config.useHttps ? "https://" : "http://";
String urlString = scheme + serverHost + (action != null ? action : "");
- if (serverIP != null && serverIP.length() > 0) {
- toSkipDns = false;
- } else {
- toSkipDns = true;
- }
final Request request = new Request(urlString, method, header, data, config.connectTimeout);
request.host = serverHost;
request.ip = serverIP;
- request.uploadServer = server;
LogUtil.i("key:" + StringUtils.toNonnullString(requestInfo.key) +
" url:" + StringUtils.toNonnullString(request.urlString));
LogUtil.i("key:" + StringUtils.toNonnullString(requestInfo.key) +
" headers:" + StringUtils.toNonnullString(request.allHeaders));
- singleRequest.request(request, isAsync, toSkipDns, shouldRetryHandler, progressHandler, new HttpSingleRequest.RequestCompleteHandler() {
+ singleRequest.request(request, server, isAsync, shouldRetryHandler, progressHandler, new HttpSingleRequest.RequestCompleteHandler() {
@Override
public void complete(ResponseInfo responseInfo, ArrayList requestMetricsList, JSONObject response) {
@@ -160,11 +153,11 @@ private void completeAction(ResponseInfo responseInfo,
private IUploadServer getNextServer(ResponseInfo responseInfo){
- if (responseInfo != null && responseInfo.isTlsError()) {
- isUseOldServer = true;
+ if (requestState != null && responseInfo != null && responseInfo.isTlsError()) {
+ requestState.setUseOldServer(true);
}
- return region.getNextServer(isUseOldServer, responseInfo, currentServer);
+ return region.getNextServer(requestState, responseInfo, currentServer);
}
diff --git a/library/src/main/java/com/qiniu/android/http/request/HttpSingleRequest.java b/library/src/main/java/com/qiniu/android/http/request/HttpSingleRequest.java
index d970d6a67..e286e4d70 100644
--- a/library/src/main/java/com/qiniu/android/http/request/HttpSingleRequest.java
+++ b/library/src/main/java/com/qiniu/android/http/request/HttpSingleRequest.java
@@ -6,6 +6,7 @@
import com.qiniu.android.http.ResponseInfo;
import com.qiniu.android.http.connectCheck.ConnectChecker;
import com.qiniu.android.http.dns.DnsPrefetcher;
+import com.qiniu.android.http.networkStatus.NetworkStatusManager;
import com.qiniu.android.http.request.httpclient.SystemHttpClient;
import com.qiniu.android.http.request.handler.CheckCancelHandler;
import com.qiniu.android.http.request.handler.RequestProgressHandler;
@@ -21,6 +22,7 @@
import org.json.JSONObject;
import java.util.ArrayList;
+import java.util.Locale;
class HttpSingleRequest {
@@ -32,7 +34,7 @@ class HttpSingleRequest {
private final UploadRequestInfo requestInfo;
private final UploadRequestState requestState;
- private ArrayList requestMetricsList;
+ private ArrayList requestMetricsList;
private IRequestClient client;
@@ -50,24 +52,24 @@ class HttpSingleRequest {
}
void request(Request request,
+ IUploadServer server,
boolean isAsync,
- boolean toSkipDns,
RequestShouldRetryHandler shouldRetryHandler,
RequestProgressHandler progressHandler,
- RequestCompleteHandler completeHandler){
+ RequestCompleteHandler completeHandler) {
currentRetryTime = 0;
requestMetricsList = new ArrayList<>();
- retryRequest(request, isAsync, toSkipDns, shouldRetryHandler, progressHandler, completeHandler);
+ retryRequest(request, server, isAsync, shouldRetryHandler, progressHandler, completeHandler);
}
private void retryRequest(final Request request,
+ final IUploadServer server,
final boolean isAsync,
- final boolean toSkipDns,
final RequestShouldRetryHandler shouldRetryHandler,
final RequestProgressHandler progressHandler,
- final RequestCompleteHandler completeHandler){
+ final RequestCompleteHandler completeHandler) {
- if (toSkipDns){
+ if (server.isHttp3()) {
client = new SystemHttpClient();
} else {
client = new SystemHttpClient();
@@ -77,7 +79,7 @@ private void retryRequest(final Request request,
@Override
public boolean checkCancel() {
boolean isCancelled = requestState.isUserCancel();
- if (! isCancelled && uploadOption.cancellationSignal != null) {
+ if (!isCancelled && uploadOption.cancellationSignal != null) {
isCancelled = uploadOption.cancellationSignal.isCancelled();
}
return isCancelled;
@@ -94,39 +96,45 @@ public boolean checkCancel() {
public void progress(long totalBytesWritten, long totalBytesExpectedToWrite) {
if (checkCancelHandler.checkCancel()) {
requestState.setUserCancel(true);
- if (client != null){
+ if (client != null) {
client.cancel();
}
- } else if (progressHandler != null){
+ } else if (progressHandler != null) {
progressHandler.progress(totalBytesWritten, totalBytesExpectedToWrite);
}
}
}, new IRequestClient.RequestClientCompleteHandler() {
@Override
public void complete(ResponseInfo responseInfo, UploadSingleRequestMetrics metrics, JSONObject response) {
- if (metrics != null){
+ if (metrics != null) {
requestMetricsList.add(metrics);
}
- if (shouldCheckConnect(responseInfo) && !ConnectChecker.check()) {
- String message = "check origin statusCode:" + responseInfo.statusCode + " error:" + responseInfo.error;
- responseInfo = ResponseInfo.errorInfo(ResponseInfo.NetworkSlow, message);
+ if (shouldCheckConnect(responseInfo)) {
+ UploadSingleRequestMetrics checkMetrics = ConnectChecker.check();
+ if (metrics != null) {
+ metrics.connectCheckMetrics = checkMetrics;
+ }
+ if (!ConnectChecker.isConnected(checkMetrics)) {
+ String message = "check origin statusCode:" + responseInfo.statusCode + " error:" + responseInfo.error;
+ responseInfo = ResponseInfo.errorInfo(ResponseInfo.NetworkSlow, message);
+ }
}
LogUtil.i("key:" + StringUtils.toNonnullString(requestInfo.key) +
" response:" + StringUtils.toNonnullString(responseInfo));
if (shouldRetryHandler != null && shouldRetryHandler.shouldRetry(responseInfo, response)
- && currentRetryTime < config.retryMax
- && responseInfo.couldHostRetry()){
+ && currentRetryTime < config.retryMax
+ && responseInfo.couldHostRetry()) {
currentRetryTime += 1;
try {
Thread.sleep(config.retryInterval);
} catch (InterruptedException ignored) {
}
- retryRequest(request, isAsync, toSkipDns, shouldRetryHandler, progressHandler, completeHandler);
+ retryRequest(request, server, isAsync, shouldRetryHandler, progressHandler, completeHandler);
} else {
- completeAction(request, responseInfo, response, metrics, completeHandler);
+ completeAction(server, responseInfo, response, metrics, completeHandler);
}
}
});
@@ -134,47 +142,63 @@ public void complete(ResponseInfo responseInfo, UploadSingleRequestMetrics metri
}
private boolean shouldCheckConnect(ResponseInfo responseInfo) {
- return responseInfo != null && (
- responseInfo.statusCode == -1001 || /* timeout */
- responseInfo.statusCode == -1003 || /* unknown host */
- responseInfo.statusCode == -1004 || /* cannot connect to host */
- responseInfo.statusCode == -1005 || /* connection lost */
- responseInfo.statusCode == -1009 || /* not connected to host */
- responseInfo.isTlsError());
+ return responseInfo != null &&
+ (responseInfo.statusCode == ResponseInfo.NetworkError || /* network error */
+ responseInfo.statusCode == -1001 || /* timeout */
+ responseInfo.statusCode == -1003 || /* unknown host */
+ responseInfo.statusCode == -1004 || /* cannot connect to host */
+ responseInfo.statusCode == -1005 || /* connection lost */
+ responseInfo.statusCode == -1009 || /* not connected to host */
+ responseInfo.isTlsError());
}
- private synchronized void completeAction(Request request,
+ private synchronized void completeAction(IUploadServer server,
ResponseInfo responseInfo,
JSONObject response,
UploadSingleRequestMetrics requestMetrics,
RequestCompleteHandler completeHandler) {
- if (client == null){
+ if (client == null) {
return;
}
client = null;
- if (completeHandler != null){
+ updateHostNetworkStatus(responseInfo, server, requestMetrics);
+ reportRequest(responseInfo, server, requestMetrics);
+
+ if (completeHandler != null) {
completeHandler.complete(responseInfo, requestMetricsList, response);
}
- reportRequest(responseInfo, request, requestMetrics);
+ }
+
+ private void updateHostNetworkStatus(ResponseInfo responseInfo, IUploadServer server, UploadSingleRequestMetrics requestMetrics) {
+ if (requestMetrics == null) {
+ return;
+ }
+ long byteCount = requestMetrics.bytesSend();
+ long second = requestMetrics.totalElapsedTime();
+ if (second > 0 && byteCount >= 1024 * 1024) {
+ int speed = (int) (byteCount * 1000 / second);
+ String type = NetworkStatusManager.getNetworkStatusType(server.getHost(), server.getIp());
+ NetworkStatusManager.getInstance().updateNetworkStatus(type, speed);
+ }
}
private void reportRequest(ResponseInfo responseInfo,
- Request request,
- UploadSingleRequestMetrics requestMetrics){
+ IUploadServer server,
+ UploadSingleRequestMetrics requestMetrics) {
- if (token == null || !token.isValid() || requestInfo == null || !requestInfo.shouldReportRequestLog() || requestMetrics == null){
+ if (token == null || !token.isValid() || requestInfo == null || !requestInfo.shouldReportRequestLog() || requestMetrics == null) {
return;
}
long currentTimestamp = Utils.currentTimestamp();
ReportItem item = new ReportItem();
item.setReport(ReportItem.LogTypeRequest, ReportItem.RequestKeyLogType);
- item.setReport((currentTimestamp/1000), ReportItem.RequestKeyUpTime);
+ item.setReport((currentTimestamp / 1000), ReportItem.RequestKeyUpTime);
item.setReport(ReportItem.requestReportStatusCode(responseInfo), ReportItem.RequestKeyStatusCode);
item.setReport(responseInfo != null ? responseInfo.reqId : null, ReportItem.RequestKeyRequestId);
- item.setReport(request != null ? request.host : null, ReportItem.RequestKeyHost);
+ item.setReport(requestMetrics.request != null ? requestMetrics.request.host : null, ReportItem.RequestKeyHost);
item.setReport(requestMetrics.remoteAddress, ReportItem.RequestKeyRemoteIp);
item.setReport(requestMetrics.remotePort, ReportItem.RequestKeyPort);
item.setReport(requestInfo.bucket, ReportItem.RequestKeyTargetBucket);
@@ -197,7 +221,7 @@ private void reportRequest(ResponseInfo responseInfo,
String errorType = ReportItem.requestReportErrorType(responseInfo);
item.setReport(errorType, ReportItem.RequestKeyErrorType);
String errorDesc = null;
- if (responseInfo != null && errorType != null){
+ if (responseInfo != null && errorType != null) {
errorDesc = responseInfo.error != null ? responseInfo.error : responseInfo.message;
}
item.setReport(errorDesc, ReportItem.RequestKeyErrorDescription);
@@ -210,9 +234,9 @@ private void reportRequest(ResponseInfo responseInfo,
item.setReport(Utils.getCurrentNetworkType(), ReportItem.RequestKeyNetworkType);
item.setReport(Utils.getCurrentSignalStrength(), ReportItem.RequestKeySignalStrength);
- item.setReport(request.uploadServer.getSource(), ReportItem.RequestKeyPrefetchedDnsSource);
- if (request.uploadServer.getIpPrefetchedTime() != null){
- Long prefetchTime = request.uploadServer.getIpPrefetchedTime() - currentTimestamp;
+ item.setReport(server.getSource(), ReportItem.RequestKeyPrefetchedDnsSource);
+ if (server.getIpPrefetchedTime() != null) {
+ Long prefetchTime = server.getIpPrefetchedTime() - currentTimestamp;
item.setReport(prefetchTime, ReportItem.RequestKeyPrefetchedBefore);
}
item.setReport(DnsPrefetcher.getInstance().lastPrefetchErrorMessage, ReportItem.RequestKeyPrefetchedErrorMessage);
@@ -220,6 +244,18 @@ private void reportRequest(ResponseInfo responseInfo,
item.setReport(requestMetrics.clientName, ReportItem.RequestKeyHttpClient);
item.setReport(requestMetrics.clientVersion, ReportItem.RequestKeyHttpClientVersion);
+ if (requestMetrics.connectCheckMetrics != null) {
+ String connectCheckDuration = String.format(Locale.ENGLISH,"%d", requestMetrics.connectCheckMetrics.totalElapsedTime());
+ String connectCheckStatusCode = "";
+ if (requestMetrics.connectCheckMetrics.response != null) {
+ connectCheckStatusCode = String.format(Locale.ENGLISH,"%d", requestMetrics.connectCheckMetrics.response.statusCode);
+ }
+ String networkMeasuring = String.format("duration:%s status_code:%s", connectCheckDuration, connectCheckStatusCode);
+ item.setReport(networkMeasuring, ReportItem.RequestKeyNetworkMeasuring);
+ }
+
+ item.setReport(requestMetrics.httpVersion, ReportItem.RequestKeyHttpVersion);
+
UploadInfoReporter.getInstance().report(item, token.token);
}
diff --git a/library/src/main/java/com/qiniu/android/http/request/IUploadRegion.java b/library/src/main/java/com/qiniu/android/http/request/IUploadRegion.java
index 6afd16339..300c65bf2 100644
--- a/library/src/main/java/com/qiniu/android/http/request/IUploadRegion.java
+++ b/library/src/main/java/com/qiniu/android/http/request/IUploadRegion.java
@@ -13,5 +13,5 @@ public interface IUploadRegion {
void setupRegionData(ZoneInfo zoneInfo);
- IUploadServer getNextServer(boolean isOldServer, ResponseInfo responseInfo, IUploadServer freezeServer);
+ IUploadServer getNextServer(UploadRequestState requestState, ResponseInfo responseInfo, IUploadServer freezeServer);
}
diff --git a/library/src/main/java/com/qiniu/android/http/request/IUploadServer.java b/library/src/main/java/com/qiniu/android/http/request/IUploadServer.java
index d8328743f..9c93c1a41 100644
--- a/library/src/main/java/com/qiniu/android/http/request/IUploadServer.java
+++ b/library/src/main/java/com/qiniu/android/http/request/IUploadServer.java
@@ -1,15 +1,36 @@
package com.qiniu.android.http.request;
-public interface IUploadServer {
+public abstract class IUploadServer {
+ public static String HttpVersion1 = "http_version_1";
+ public static String HttpVersion2 = "http_version_2";
+ public static String HttpVersion3 = "http_version_3";
- String getServerId();
+ public boolean isHttp3() {
+ String httpVersion = getHttpVersion();
+ if (httpVersion == null) {
+ return false;
+ }
+ return httpVersion.equals(IUploadServer.HttpVersion3);
+ }
- String getHost();
+ public boolean isHttp2() {
+ String httpVersion = getHttpVersion();
+ if (httpVersion == null) {
+ return false;
+ }
+ return httpVersion.equals(IUploadServer.HttpVersion2);
+ }
- String getIp();
+ public abstract String getServerId();
- String getSource();
+ public abstract String getHttpVersion();
- Long getIpPrefetchedTime();
+ public abstract String getHost();
+
+ public abstract String getIp();
+
+ public abstract String getSource();
+
+ public abstract Long getIpPrefetchedTime();
}
diff --git a/library/src/main/java/com/qiniu/android/http/request/Request.java b/library/src/main/java/com/qiniu/android/http/request/Request.java
index 943d31470..ec6345478 100644
--- a/library/src/main/java/com/qiniu/android/http/request/Request.java
+++ b/library/src/main/java/com/qiniu/android/http/request/Request.java
@@ -20,8 +20,6 @@ public class Request {
public String host;
public String ip;
- protected IUploadServer uploadServer;
-
public Request(String urlString,
String httpMethod,
Map allHeaders,
@@ -36,12 +34,12 @@ public Request(String urlString,
}
public InetAddress getInetAddress(){
- if (host == null || uploadServer == null || uploadServer.getIp() == null) {
+ if (host == null || ip == null || ip.length() == 0) {
return null;
}
try {
- InetAddress ipAddress = InetAddress.getByName(uploadServer.getIp());
+ InetAddress ipAddress = InetAddress.getByName(ip);
return InetAddress.getByAddress(host, ipAddress.getAddress());
} catch (Exception e) {
return null;
diff --git a/library/src/main/java/com/qiniu/android/http/request/RequestTransaction.java b/library/src/main/java/com/qiniu/android/http/request/RequestTransaction.java
index 8848fac13..363c4eda6 100644
--- a/library/src/main/java/com/qiniu/android/http/request/RequestTransaction.java
+++ b/library/src/main/java/com/qiniu/android/http/request/RequestTransaction.java
@@ -109,7 +109,7 @@ public boolean shouldRetry(ResponseInfo responseInfo, JSONObject response) {
HashMap header = new HashMap<>();
header.put("User-Agent", userAgent);
- String action = "/v4/query?ak=" + (token.accessKey != null ? token.accessKey : "") + "&bucket=" + (token.bucket != null ? token.bucket : "");
+ String action = String.format("/v4/query?ak=%s&bucket=%s&sdk_version=%s&sdk_name=%s", token.accessKey, token.bucket, Utils.sdkVerion(), Utils.sdkLanguage());
regionRequest.get(action, isAsync, header, shouldRetryHandler, new HttpRegionRequest.RequestCompleteHandler() {
@Override
public void complete(ResponseInfo responseInfo, UploadRegionRequestMetrics requestMetrics, JSONObject response) {
diff --git a/library/src/main/java/com/qiniu/android/http/request/UploadRequestState.java b/library/src/main/java/com/qiniu/android/http/request/UploadRequestState.java
index c7f5b063c..a25b01b7b 100644
--- a/library/src/main/java/com/qiniu/android/http/request/UploadRequestState.java
+++ b/library/src/main/java/com/qiniu/android/http/request/UploadRequestState.java
@@ -1,7 +1,8 @@
package com.qiniu.android.http.request;
-class UploadRequestState {
+public class UploadRequestState {
+ private boolean isUseOldServer;
private boolean isUserCancel;
boolean isUserCancel(){
@@ -11,4 +12,19 @@ boolean isUserCancel(){
void setUserCancel(boolean isUserCancel) {
this.isUserCancel = isUserCancel;
}
+
+ public boolean isUseOldServer() {
+ return isUseOldServer;
+ }
+
+ public void setUseOldServer(boolean useOldServer) {
+ isUseOldServer = useOldServer;
+ }
+
+ protected UploadRequestState clone() {
+ UploadRequestState state = new UploadRequestState();
+ state.isUseOldServer = isUseOldServer;
+ state.isUserCancel = isUserCancel;
+ return state;
+ }
}
diff --git a/library/src/main/java/com/qiniu/android/http/request/httpclient/SystemHttpClient.java b/library/src/main/java/com/qiniu/android/http/request/httpclient/SystemHttpClient.java
index d8a8b78fa..9161a8908 100644
--- a/library/src/main/java/com/qiniu/android/http/request/httpclient/SystemHttpClient.java
+++ b/library/src/main/java/com/qiniu/android/http/request/httpclient/SystemHttpClient.java
@@ -81,7 +81,7 @@ public void request(Request request,
completeHandler = complete;
okhttp3.Request.Builder requestBuilder = createRequestBuilder(requestProgress);
- if (requestBuilder == null){
+ if (requestBuilder == null) {
ResponseInfo responseInfo = ResponseInfo.invalidArgument("invalid http request");
handleError(request, responseInfo.statusCode, responseInfo.message, complete);
return;
@@ -90,14 +90,14 @@ public void request(Request request,
ResponseTag tag = new ResponseTag();
call = httpClient.newCall(requestBuilder.tag(tag).build());
- if (isAsync){
+ if (isAsync) {
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
String msg = e.getMessage();
int status = getStatusCodeByException(e);
- if (call.isCanceled()){
+ if (call.isCanceled()) {
status = ResponseInfo.Cancelled;
msg = "user cancelled";
}
@@ -123,7 +123,7 @@ public void run() {
e.printStackTrace();
String msg = e.getMessage();
int status = getStatusCodeByException(e);
- if (call.isCanceled()){
+ if (call.isCanceled()) {
status = ResponseInfo.Cancelled;
msg = "user cancelled";
}
@@ -140,8 +140,8 @@ public synchronized void cancel() {
}
}
- private OkHttpClient createHttpClient(ProxyConfiguration connectionProxy){
- if (currentRequest == null){
+ private OkHttpClient createHttpClient(ProxyConfiguration connectionProxy) {
+ if (currentRequest == null) {
return null;
}
@@ -159,7 +159,7 @@ private OkHttpClient createHttpClient(ProxyConfiguration connectionProxy){
clientBuilder.dns(new Dns() {
@Override
public List lookup(String s) throws UnknownHostException {
- if (currentRequest.getInetAddress() != null && s.equals(currentRequest.host)){
+ if (currentRequest.getInetAddress() != null && s.equals(currentRequest.host)) {
List inetAddressList = new ArrayList<>();
inetAddressList.add(currentRequest.getInetAddress());
return inetAddressList;
@@ -199,14 +199,14 @@ public okhttp3.Response intercept(Chain chain) throws IOException {
return clientBuilder.build();
}
- private synchronized static ConnectionPool getConnectPool(){
- if (pool == null){
+ private synchronized static ConnectionPool getConnectPool() {
+ if (pool == null) {
pool = new ConnectionPool(5, 10, TimeUnit.MINUTES);
}
return pool;
}
- private okhttp3.Request.Builder createRequestBuilder(final RequestClientProgress progress){
+ private okhttp3.Request.Builder createRequestBuilder(final RequestClientProgress progress) {
if (currentRequest == null) {
return null;
}
@@ -215,14 +215,14 @@ private okhttp3.Request.Builder createRequestBuilder(final RequestClientProgress
okhttp3.Request.Builder requestBuilder = null;
if (currentRequest.httpMethod.equals(Request.HttpMethodHEAD) ||
- currentRequest.httpMethod.equals(Request.HttpMethodGet)){
+ currentRequest.httpMethod.equals(Request.HttpMethodGet)) {
requestBuilder = new okhttp3.Request.Builder().get().url(currentRequest.urlString);
- for (String key : currentRequest.allHeaders.keySet()){
+ for (String key : currentRequest.allHeaders.keySet()) {
String value = currentRequest.allHeaders.get(key);
requestBuilder.header(key, value);
}
} else if (currentRequest.httpMethod.equals(Request.HttpMethodPOST) ||
- currentRequest.httpMethod.equals(Request.HttpMethodPUT)){
+ currentRequest.httpMethod.equals(Request.HttpMethodPUT)) {
requestBuilder = new okhttp3.Request.Builder().url(currentRequest.urlString);
requestBuilder = requestBuilder.headers(allHeaders);
@@ -240,15 +240,15 @@ private okhttp3.Request.Builder createRequestBuilder(final RequestClientProgress
rbody = new CountingRequestBody(rbody, new ProgressHandler() {
@Override
public void onProgress(long bytesWritten, long totalSize) {
- if (progress != null){
- progress.progress(bytesWritten, totalSize);
- }
+ if (progress != null) {
+ progress.progress(bytesWritten, totalSize);
+ }
}
}, currentRequest.httpBody.length, null);
- if (currentRequest.httpMethod.equals(Request.HttpMethodPOST)){
+ if (currentRequest.httpMethod.equals(Request.HttpMethodPOST)) {
requestBuilder = requestBuilder.post(rbody);
- } else if (currentRequest.httpMethod.equals(Request.HttpMethodPUT)){
+ } else if (currentRequest.httpMethod.equals(Request.HttpMethodPUT)) {
requestBuilder = requestBuilder.put(rbody);
}
@@ -256,86 +256,127 @@ public void onProgress(long bytesWritten, long totalSize) {
return requestBuilder;
}
- private EventListener createEventLister(){
+ private EventListener createEventLister() {
return new EventListener() {
- @Override public void callStart(Call call) {
+ @Override
+ public void callStart(Call call) {
metrics.startDate = new Date();
}
- @Override public void dnsStart(Call call,
- String domainName) {
+
+ @Override
+ public void dnsStart(Call call,
+ String domainName) {
metrics.domainLookupStartDate = new Date();
}
- @Override public void dnsEnd(Call call,
- String domainName,
- List inetAddressList) {
+
+ @Override
+ public void dnsEnd(Call call,
+ String domainName,
+ List inetAddressList) {
metrics.domainLookupEndDate = new Date();
}
- @Override public void connectStart(Call call,
- InetSocketAddress inetSocketAddress,
- Proxy proxy) {
+
+ @Override
+ public void connectStart(Call call,
+ InetSocketAddress inetSocketAddress,
+ Proxy proxy) {
metrics.connectStartDate = new Date();
metrics.remoteAddress = inetSocketAddress.getAddress().getHostAddress();
metrics.remotePort = inetSocketAddress.getPort();
metrics.localAddress = AndroidNetwork.getHostIP();
}
- @Override public void secureConnectStart(Call call) {
+
+ @Override
+ public void secureConnectStart(Call call) {
metrics.connectEndDate = new Date();
}
- @Override public void secureConnectEnd(Call call,
- Handshake handshake) {
+
+ @Override
+ public void secureConnectEnd(Call call,
+ Handshake handshake) {
metrics.secureConnectionStartDate = new Date();
}
- @Override public void connectEnd(Call call,
- InetSocketAddress inetSocketAddress,
- Proxy proxy,
- Protocol protocol) {
+
+ @Override
+ public void connectEnd(Call call,
+ InetSocketAddress inetSocketAddress,
+ Proxy proxy,
+ Protocol protocol) {
metrics.secureConnectionEndDate = new Date();
}
- @Override public void connectFailed(Call call,
- InetSocketAddress inetSocketAddress,
- Proxy proxy,
- Protocol protocol,
- IOException ioe) {
+
+ @Override
+ public void connectFailed(Call call,
+ InetSocketAddress inetSocketAddress,
+ Proxy proxy,
+ Protocol protocol,
+ IOException ioe) {
metrics.connectEndDate = new Date();
}
- @Override public void connectionAcquired(Call call, Connection connection) {
+
+ @Override
+ public void connectionAcquired(Call call, Connection connection) {
}
- @Override public void connectionReleased(Call call, Connection connection) {
+
+ @Override
+ public void connectionReleased(Call call, Connection connection) {
}
- @Override public void requestHeadersStart(Call call) {
+
+ @Override
+ public void requestHeadersStart(Call call) {
metrics.requestStartDate = new Date();
}
- @Override public void requestHeadersEnd(Call call, okhttp3.Request request) {
+
+ @Override
+ public void requestHeadersEnd(Call call, okhttp3.Request request) {
metrics.countOfRequestHeaderBytesSent = request.headers().toString().length();
}
- @Override public void requestBodyStart(Call call) {
+
+ @Override
+ public void requestBodyStart(Call call) {
}
- @Override public void requestBodyEnd(Call call, long byteCount) {
+
+ @Override
+ public void requestBodyEnd(Call call, long byteCount) {
metrics.requestEndDate = new Date();
metrics.countOfRequestBodyBytesSent = byteCount;
}
+
public void requestFailed(Call call, IOException ioe) {
metrics.requestEndDate = new Date();
metrics.countOfRequestBodyBytesSent = 0;
}
- @Override public void responseHeadersStart(Call call) {
+
+ @Override
+ public void responseHeadersStart(Call call) {
metrics.responseStartDate = new Date();
}
- @Override public void responseHeadersEnd(Call call, Response response) {
+
+ @Override
+ public void responseHeadersEnd(Call call, Response response) {
}
- @Override public void responseBodyStart(Call call) {
+
+ @Override
+ public void responseBodyStart(Call call) {
}
- @Override public void responseBodyEnd(Call call, long byteCount) {
+
+ @Override
+ public void responseBodyEnd(Call call, long byteCount) {
metrics.responseEndDate = new Date();
}
+
public void responseFailed(Call call, IOException ioe) {
metrics.responseEndDate = new Date();
}
- @Override public void callEnd(Call call) {
+
+ @Override
+ public void callEnd(Call call) {
metrics.endDate = new Date();
}
- @Override public void callFailed(Call call, IOException ioe) {
+
+ @Override
+ public void callFailed(Call call, IOException ioe) {
metrics.endDate = new Date();
}
};
@@ -344,15 +385,14 @@ public void responseFailed(Call call, IOException ioe) {
private synchronized void handleError(Request request,
int responseCode,
String errorMsg,
- RequestClientCompleteHandler complete){
+ RequestClientCompleteHandler complete) {
if (metrics == null || metrics.response != null) {
return;
}
- ResponseInfo info = ResponseInfo.create(request, responseCode, null,null, errorMsg);
+ ResponseInfo info = ResponseInfo.create(request, responseCode, null, null, errorMsg);
metrics.response = info;
- metrics.response = null;
- metrics.request = null;
+ metrics.request = request;
complete.complete(info, metrics, info.response);
releaseResource();
@@ -360,7 +400,7 @@ private synchronized void handleError(Request request,
private synchronized void handleResponse(Request request,
okhttp3.Response response,
- RequestClientCompleteHandler complete){
+ RequestClientCompleteHandler complete) {
if (metrics == null || metrics.response != null) {
return;
}
@@ -384,14 +424,15 @@ private synchronized void handleResponse(Request request,
errorMessage = e.getMessage();
}
- if (responseBody == null){
+ if (responseBody == null) {
errorMessage = response.message();
- } else if (responseContentType(response) != "application/json"){
+ } else if (responseContentType(response) != "application/json") {
String responseString = new String(responseBody);
- if (responseString.length() > 0){
+ if (responseString.length() > 0) {
try {
responseJson = new JSONObject(responseString);
- } catch (Exception ignored) {}
+ } catch (Exception ignored) {
+ }
}
} else {
try {
@@ -405,12 +446,20 @@ private synchronized void handleResponse(Request request,
final ResponseInfo info = ResponseInfo.create(request, statusCode, responseHeader, responseJson, errorMessage);
metrics.response = info;
+ metrics.request = request;
+ if (response.protocol() == Protocol.HTTP_1_0) {
+ metrics.httpVersion = "1.0";
+ } else if (response.protocol() == Protocol.HTTP_1_1) {
+ metrics.httpVersion = "1.1";
+ } else if (response.protocol() == Protocol.HTTP_2) {
+ metrics.httpVersion = "2";
+ }
complete.complete(info, metrics, info.response);
releaseResource();
}
- private void releaseResource(){
+ private void releaseResource() {
this.currentRequest = null;
this.requestProgress = null;
this.completeHandler = null;
@@ -427,10 +476,10 @@ private static String responseContentType(okhttp3.Response response) {
return mediaType.type() + "/" + mediaType.subtype();
}
- private int getStatusCodeByException(Exception e){
+ private int getStatusCodeByException(Exception e) {
int statusCode = NetworkError;
String msg = e.getMessage();
- if (msg != null && msg.contains("Canceled")){
+ if (msg != null && msg.contains("Canceled")) {
statusCode = ResponseInfo.Cancelled;
} else if (e instanceof CancellationHandler.CancellationException) {
statusCode = ResponseInfo.Cancelled;
diff --git a/library/src/main/java/com/qiniu/android/http/serverRegion/UploadDomainRegion.java b/library/src/main/java/com/qiniu/android/http/serverRegion/UploadDomainRegion.java
index fe659801a..bc5c51bb4 100644
--- a/library/src/main/java/com/qiniu/android/http/serverRegion/UploadDomainRegion.java
+++ b/library/src/main/java/com/qiniu/android/http/serverRegion/UploadDomainRegion.java
@@ -4,8 +4,10 @@
import com.qiniu.android.http.ResponseInfo;
import com.qiniu.android.http.dns.DnsPrefetcher;
import com.qiniu.android.http.dns.IDnsNetworkAddress;
+import com.qiniu.android.http.networkStatus.UploadServerNetworkStatus;
import com.qiniu.android.http.request.IUploadRegion;
import com.qiniu.android.http.request.IUploadServer;
+import com.qiniu.android.http.request.UploadRequestState;
import com.qiniu.android.storage.GlobalConfiguration;
import com.qiniu.android.utils.LogUtil;
import com.qiniu.android.utils.StringUtils;
@@ -17,12 +19,16 @@
public class UploadDomainRegion implements IUploadRegion {
+ private static int Http3FrozenTime = 3600 * 24;
- // 是否获取过,PS:当第一次获取Domain,而区域所有Domain又全部冻结时,返回一个domain尝试一次
- private boolean hasGot;
+ // 是否支持http3
+ private boolean http3Enabled;
+
+ // 是否冻结过Host,PS:如果没有冻结过 Host,则当前 Region 上传也就不会有错误信息,可能会返回-9,所以必须要再进行一次尝试
+ private boolean hasFreezeHost;
private boolean isAllFrozen;
// 局部冻结管理对象
- private UploadServerFreezeManager partialFreezeManager = new UploadServerFreezeManager();
+ private UploadServerFreezeManager partialHttp2Freezer = new UploadServerFreezeManager();
private ArrayList domainHostList;
private HashMap domainHashMap;
@@ -78,6 +84,9 @@ public void setupRegionData(ZoneInfo zoneInfo) {
this.zoneInfo = zoneInfo;
isAllFrozen = false;
+ http3Enabled = zoneInfo.http3Enabled;
+ // 暂不开启
+ http3Enabled = false;
ArrayList domainHostList = new ArrayList<>();
if (zoneInfo.domains != null) {
@@ -97,28 +106,98 @@ public void setupRegionData(ZoneInfo zoneInfo) {
LogUtil.i("region old:" + StringUtils.toNonnullString(oldDomainHostList));
}
+ private HashMap createDomainDictionary(List hosts) {
+ HashMap domainHashMap = new HashMap<>();
+ for (int i = 0; i < hosts.size(); i++) {
+ String host = hosts.get(i);
+ UploadServerDomain domain = new UploadServerDomain(host);
+ domainHashMap.put(host, domain);
+ }
+ return domainHashMap;
+ }
+
@Override
- public IUploadServer getNextServer(boolean isOldServer, ResponseInfo responseInfo, IUploadServer freezeServer) {
- if (isAllFrozen) {
+ public IUploadServer getNextServer(UploadRequestState requestState, ResponseInfo responseInfo, IUploadServer freezeServer) {
+ if (isAllFrozen || requestState == null) {
return null;
}
freezeServerIfNeed(responseInfo, freezeServer);
- ArrayList hostList = isOldServer ? oldDomainHostList : domainHostList;
- HashMap domainInfo = isOldServer ? oldDomainHashMap : domainHashMap;
- IUploadServer server = null;
+ UploadServer server = null;
+ boolean isUseOldServer = requestState.isUseOldServer();
+ ArrayList hostList = isUseOldServer ? oldDomainHostList : domainHostList;
+ HashMap domainInfo = isUseOldServer ? oldDomainHashMap : domainHashMap;
+
+ // 1. 优先选择http3
+ if (http3Enabled && freezeServer != null && freezeServer.isHttp3()) {
+ for (String host : hostList) {
+ UploadServerDomain domain = domainInfo.get(host);
+ if (domain == null) {
+ continue;
+ }
+ IUploadServer domainServer = domain.getServer(new UploadServerDomain.GetServerCondition() {
+ @Override
+ public boolean condition(String host, UploadServer serverP, UploadServer filterServer) {
+
+ // 1.1 剔除冻结对象
+ String filterServerIP = filterServer == null ? null : filterServer.getIp();
+ String frozenType = UploadServerFreezeUtil.getFrozenType(host, filterServerIP);
+ boolean isFrozen = UploadServerFreezeUtil.isTypeFrozenByFreezeManagers(frozenType, new UploadServerFreezeManager[]{UploadServerFreezeUtil.globalHttp3Freezer()});
+
+ if (isFrozen) {
+ return false;
+ }
+
+ // 1.2 挑选网络状态最优
+ return UploadServerNetworkStatus.isServerNetworkBetter(filterServer, serverP);
+ }
+ });
+
+ server = (UploadServer) UploadServerNetworkStatus.getBetterNetworkServer(domainServer, server);
+
+ if (server != null) {
+ break;
+ }
+ }
+
+ if (server != null) {
+ server.setHttpVersion(IUploadServer.HttpVersion3);
+ return server;
+ }
+ }
+
+ // 2. 挑选http2
for (String host : hostList) {
UploadServerDomain domain = domainInfo.get(host);
- if (domain != null) {
- server = domain.getServer(new UploadServerFreezeManager[]{partialFreezeManager, UploadServerFreezeManager.getInstance()});
+ if (domain == null) {
+ continue;
}
+ IUploadServer domainServer = domain.getServer(new UploadServerDomain.GetServerCondition() {
+ @Override
+ public boolean condition(String host, UploadServer serverP, UploadServer filterServer) {
+ // 1.1 剔除冻结对象
+ String filterServerIP = filterServer == null ? null : filterServer.getIp();
+ String frozenType = UploadServerFreezeUtil.getFrozenType(host, filterServerIP);
+ boolean isFrozen = UploadServerFreezeUtil.isTypeFrozenByFreezeManagers(frozenType, new UploadServerFreezeManager[]{partialHttp2Freezer, UploadServerFreezeUtil.globalHttp2Freezer()});
+
+ if (isFrozen) {
+ return false;
+ }
+
+ // 1.2 挑选网络状态最优
+ return UploadServerNetworkStatus.isServerNetworkBetter(filterServer, serverP);
+ }
+ });
+
+ server = (UploadServer) UploadServerNetworkStatus.getBetterNetworkServer(domainServer, server);
+
if (server != null) {
break;
}
}
- if (server == null && !hasGot && hostList.size() > 0) {
+ if (server == null && !hasFreezeHost && hostList.size() > 0) {
int index = (int) (Math.random() * hostList.size());
String host = hostList.get(index);
UploadServerDomain domain = domainInfo.get(host);
@@ -127,16 +206,13 @@ public IUploadServer getNextServer(boolean isOldServer, ResponseInfo responseInf
}
unfreezeServer(server);
}
- hasGot = true;
- if (server == null) {
+ if (server != null) {
+ server.setHttpVersion(IUploadServer.HttpVersion2);
+ LogUtil.i("get server host:" + StringUtils.toNonnullString(server.getHost()) + " ip:" + StringUtils.toNonnullString(server.getIp()));
+ } else {
isAllFrozen = true;
- }
-
- if (server == null) {
LogUtil.i("get server host:null ip:null");
- } else {
- LogUtil.i("get server host:" + StringUtils.toNonnullString(server.getHost()) + " ip:" + StringUtils.toNonnullString(server.getIp()));
}
return server;
@@ -148,34 +224,29 @@ private void freezeServerIfNeed(ResponseInfo responseInfo, IUploadServer freezeS
return;
}
- // 无法连接到Host || Host不可用, 局部冻结
+ String frozenType = UploadServerFreezeUtil.getFrozenType(freezeServer.getHost(), freezeServer.getIp());
+ // 1. http3 冻结
+ if (freezeServer.isHttp3()) {
+ if (!responseInfo.canConnectToHost() || responseInfo.isHostUnavailable()) {
+ hasFreezeHost = true;
+ UploadServerFreezeUtil.globalHttp3Freezer().freezeType(frozenType, Http3FrozenTime);
+ }
+ return;
+ }
+
+ // 2. http2 冻结
+ // 2.1 无法连接到Host || Host不可用, 局部冻结
if (!responseInfo.canConnectToHost() || responseInfo.isHostUnavailable()) {
+ hasFreezeHost = true;
LogUtil.i("partial freeze server host:" + StringUtils.toNonnullString(freezeServer.getHost()) + " ip:" + StringUtils.toNonnullString(freezeServer.getIp()));
-
- UploadServerDomain domain = null;
- domain = domainHashMap.get(freezeServer.getServerId());
- if (domain != null) {
- domain.freeze(freezeServer.getIp(), partialFreezeManager, GlobalConfiguration.getInstance().partialHostFrozenTime);
- }
- domain = oldDomainHashMap.get(freezeServer.getServerId());
- if (domain != null) {
- domain.freeze(freezeServer.getIp(), partialFreezeManager, GlobalConfiguration.getInstance().partialHostFrozenTime);
- }
+ partialHttp2Freezer.freezeType(frozenType, GlobalConfiguration.getInstance().partialHostFrozenTime);
}
- // Host不可用,全局冻结
+ // 2.2 Host不可用,全局冻结
if (responseInfo.isHostUnavailable()) {
+ hasFreezeHost = true;
LogUtil.i("global freeze server host:" + StringUtils.toNonnullString(freezeServer.getHost()) + " ip:" + StringUtils.toNonnullString(freezeServer.getIp()));
-
- UploadServerDomain domain = null;
- domain = domainHashMap.get(freezeServer.getServerId());
- if (domain != null) {
- domain.freeze(freezeServer.getIp(), UploadServerFreezeManager.getInstance(), GlobalConfiguration.getInstance().globalHostFrozenTime);
- }
- domain = oldDomainHashMap.get(freezeServer.getServerId());
- if (domain != null) {
- domain.freeze(freezeServer.getIp(), UploadServerFreezeManager.getInstance(), GlobalConfiguration.getInstance().globalHostFrozenTime);
- }
+ UploadServerFreezeUtil.globalHttp2Freezer().freezeType(frozenType, GlobalConfiguration.getInstance().globalHostFrozenTime);
}
}
@@ -184,31 +255,13 @@ private void unfreezeServer(IUploadServer freezeServer) {
return;
}
- UploadServerDomain domain = null;
- domain = domainHashMap.get(freezeServer.getServerId());
- if (domain != null) {
- domain.unfreeze(freezeServer.getIp(), new UploadServerFreezeManager[]{partialFreezeManager, UploadServerFreezeManager.getInstance()});
- }
- domain = oldDomainHashMap.get(freezeServer.getServerId());
- if (domain != null) {
- domain.unfreeze(freezeServer.getIp(), new UploadServerFreezeManager[]{partialFreezeManager, UploadServerFreezeManager.getInstance()});
- }
- }
-
- private HashMap createDomainDictionary(List hosts) {
- HashMap domainHashMap = new HashMap<>();
- for (int i = 0; i < hosts.size(); i++) {
- String host = hosts.get(i);
- UploadServerDomain domain = new UploadServerDomain(host);
- domainHashMap.put(host, domain);
- }
- return domainHashMap;
+ String frozenType = UploadServerFreezeUtil.getFrozenType(freezeServer.getHost(), freezeServer.getIp());
+ partialHttp2Freezer.unfreezeType(frozenType);
}
private static class UploadServerDomain {
- private boolean isAllFrozen = false;
protected final String host;
protected ArrayList ipGroupList = new ArrayList<>();
@@ -216,59 +269,44 @@ protected UploadServerDomain(String host) {
this.host = host;
}
- protected IUploadServer getServer(UploadServerFreezeManager[] freezeManagerList) {
- if (isAllFrozen || host == null || host.length() == 0) {
+ protected UploadServer getServer(GetServerCondition condition) {
+ if (host == null || host.length() == 0) {
return null;
}
- if (ipGroupList == null || ipGroupList.size() == 0) {
- createIpGroupList();
+ synchronized (this) {
+ if (ipGroupList == null || ipGroupList.size() == 0) {
+ createIpGroupList();
+ }
}
+ UploadServer server = null;
+
// 解析到IP:
if (ipGroupList != null && ipGroupList.size() > 0) {
- UploadServer server = null;
for (UploadIpGroup ipGroup : ipGroupList) {
- // 黑名单中不存在 & 未被冻结
- if (ipGroup.groupType != null && !isGroupFrozenByFreezeManagers(ipGroup.groupType, freezeManagerList)) {
- IDnsNetworkAddress networkAddress = ipGroup.getNetworkAddress();
- server = new UploadServer(host, host, networkAddress.getIpValue(), networkAddress.getSourceValue(), networkAddress.getTimestampValue());
+ IDnsNetworkAddress networkAddress = ipGroup.getNetworkAddress();
+ UploadServer filterServer = new UploadServer(host, host, networkAddress.getIpValue(), networkAddress.getSourceValue(), networkAddress.getTimestampValue());
+
+ if (condition == null || condition.condition(host, server, filterServer)) {
+ server = filterServer;
+ }
+
+ if (condition == null) {
break;
}
}
- if (server == null) {
- isAllFrozen = true;
- }
+
return server;
}
// 未解析到IP:
- // 黑名单中不存在 & 未被冻结
- String groupType = Utils.getIpType(null, host);
- if (groupType != null && !isGroupFrozenByFreezeManagers(groupType, freezeManagerList)) {
- return new UploadServer(host, host, null, null, null);
- } else {
- isAllFrozen = true;
- return null;
+ if (condition == null || condition.condition(host, null, null)) {
+ // 未解析时,没有可比性,直接返回自身,自身即为最优
+ server = new UploadServer(host, host, null, null, null);
}
- }
- protected boolean isGroupFrozenByFreezeManagers(String groupType, UploadServerFreezeManager[] freezeManagerList) {
- if (groupType == null) {
- return true;
- }
- if (freezeManagerList == null || freezeManagerList.length == 0) {
- return false;
- }
-
- boolean isFrozen = false;
- for (UploadServerFreezeManager freezeManager : freezeManagerList) {
- isFrozen = freezeManager.isFreezeHost(host, groupType);
- if (isFrozen) {
- break;
- }
- }
- return isFrozen;
+ return server;
}
protected UploadServer getOneServer() {
@@ -286,7 +324,7 @@ protected UploadServer getOneServer() {
}
}
- private synchronized void createIpGroupList() {
+ private void createIpGroupList() {
if (ipGroupList != null && ipGroupList.size() > 0) {
return;
}
@@ -322,20 +360,8 @@ private synchronized void createIpGroupList() {
this.ipGroupList = ipGroupList;
}
- protected void freeze(String ip, UploadServerFreezeManager freezeManager, int frozenTime) {
- if (freezeManager == null) {
- return;
- }
- freezeManager.freezeHost(host, Utils.getIpType(ip, this.host), frozenTime);
- }
-
- protected void unfreeze(String ip, UploadServerFreezeManager[] freezeManagerList) {
- if (freezeManagerList == null || freezeManagerList.length == 0) {
- return;
- }
- for (UploadServerFreezeManager freezeManager : freezeManagerList) {
- freezeManager.unfreezeHost(host, Utils.getIpType(ip, this.host));
- }
+ protected interface GetServerCondition {
+ boolean condition(String host, UploadServer server, UploadServer filterServer);
}
}
diff --git a/library/src/main/java/com/qiniu/android/http/serverRegion/UploadServer.java b/library/src/main/java/com/qiniu/android/http/serverRegion/UploadServer.java
index 1f79ae2d3..dabb9cd89 100644
--- a/library/src/main/java/com/qiniu/android/http/serverRegion/UploadServer.java
+++ b/library/src/main/java/com/qiniu/android/http/serverRegion/UploadServer.java
@@ -2,13 +2,14 @@
import com.qiniu.android.http.request.IUploadServer;
-public class UploadServer implements IUploadServer {
+public class UploadServer extends IUploadServer {
private final String serverId;
private final String host;
private final String ip;
private final String source;
private final Long ipPrefetchedTime;
+ private String httpVersion;
public UploadServer(String serverId,
String host,
@@ -27,6 +28,15 @@ public String getServerId() {
return this.serverId;
}
+ @Override
+ public String getHttpVersion() {
+ return httpVersion;
+ }
+
+ public void setHttpVersion(String httpVersion) {
+ this.httpVersion = httpVersion;
+ }
+
@Override
public String getIp() {
return ip;
diff --git a/library/src/main/java/com/qiniu/android/http/serverRegion/UploadServerFreezeManager.java b/library/src/main/java/com/qiniu/android/http/serverRegion/UploadServerFreezeManager.java
index 620842473..c21bdb1f2 100644
--- a/library/src/main/java/com/qiniu/android/http/serverRegion/UploadServerFreezeManager.java
+++ b/library/src/main/java/com/qiniu/android/http/serverRegion/UploadServerFreezeManager.java
@@ -20,58 +20,46 @@ public static UploadServerFreezeManager getInstance() {
return manager;
}
- public boolean isFreezeHost(String host, String type) {
- if (host == null || host.length() == 0) {
+ public boolean isTypeFrozen(String type) {
+ if (type == null || type.length() == 0) {
return true;
}
boolean isFrozen = true;
- String infoKey = getItemInfoKey(host, type);
- UploadServerFreezeItem item = frozenInfo.get(infoKey);
+ UploadServerFreezeItem item = frozenInfo.get(type);
if (item == null || !item.isFrozenByDate(new Date())) {
isFrozen = false;
}
return isFrozen;
}
- public void freezeHost(String host, String type, int frozenTime) {
- if (host == null || host.length() == 0) {
+ public void freezeType(String type, int frozenTime) {
+ if (type == null || type.length() == 0) {
return;
}
- String infoKey = getItemInfoKey(host, type);
- UploadServerFreezeItem item = frozenInfo.get(infoKey);
+ UploadServerFreezeItem item = frozenInfo.get(type);
if (item == null) {
- item = new UploadServerFreezeItem(host, type);
- frozenInfo.put(infoKey, item);
+ item = new UploadServerFreezeItem(type);
+ frozenInfo.put(type, item);
}
item.freeze(frozenTime);
}
- public void unfreezeHost(String host, String type) {
- if (host == null || host.length() == 0) {
+ public void unfreezeType(String type) {
+ if (type == null || type.length() == 0) {
return;
}
- String infoKey = getItemInfoKey(host, type);
- if (infoKey != null) {
- frozenInfo.remove(infoKey);
- }
- }
-
- private String getItemInfoKey(String host, String type) {
- return String.format("%s:%s", (host != null ? host : "none"), (type != null ? type : "none"));
+ frozenInfo.remove(type);
}
private static class UploadServerFreezeItem {
- protected final String host;
protected final String type;
- protected Date freezeDate;
+ private Date freezeDate;
- protected UploadServerFreezeItem(String host,
- String type) {
- this.host = host;
+ private UploadServerFreezeItem(String type) {
this.type = type;
}
- protected synchronized boolean isFrozenByDate(Date date) {
+ private synchronized boolean isFrozenByDate(Date date) {
boolean isFrozen = true;
if (freezeDate == null || freezeDate.getTime() < date.getTime()) {
isFrozen = false;
@@ -79,7 +67,7 @@ protected synchronized boolean isFrozenByDate(Date date) {
return isFrozen;
}
- protected synchronized void freeze(int frozenTime) {
+ private synchronized void freeze(int frozenTime) {
freezeDate = new Date(Utils.currentTimestamp() + frozenTime * 1000);
}
diff --git a/library/src/main/java/com/qiniu/android/http/serverRegion/UploadServerFreezeUtil.java b/library/src/main/java/com/qiniu/android/http/serverRegion/UploadServerFreezeUtil.java
new file mode 100644
index 000000000..fa8c09aee
--- /dev/null
+++ b/library/src/main/java/com/qiniu/android/http/serverRegion/UploadServerFreezeUtil.java
@@ -0,0 +1,40 @@
+package com.qiniu.android.http.serverRegion;
+
+import com.qiniu.android.utils.Utils;
+
+import java.util.List;
+
+public class UploadServerFreezeUtil {
+ private final static UploadServerFreezeManager globalHttp3Freezer = new UploadServerFreezeManager();
+ public static UploadServerFreezeManager globalHttp3Freezer() {
+ return globalHttp3Freezer;
+ }
+
+ private final static UploadServerFreezeManager globalHttp2Freezer = new UploadServerFreezeManager();
+ public static UploadServerFreezeManager globalHttp2Freezer() {
+ return globalHttp2Freezer;
+ }
+
+ public static boolean isTypeFrozenByFreezeManagers(String type, UploadServerFreezeManager[] freezeManagerList) {
+ if (type == null || type.length() == 0) {
+ return true;
+ }
+ if (freezeManagerList == null || freezeManagerList.length == 0) {
+ return false;
+ }
+
+ boolean isFrozen = false;
+ for (UploadServerFreezeManager freezeManager : freezeManagerList) {
+ isFrozen = freezeManager.isTypeFrozen(type);
+ if (isFrozen) {
+ break;
+ }
+ }
+ return isFrozen;
+ }
+
+ public static String getFrozenType(String host, String ip) {
+ String ipType = Utils.getIpType(ip, host);
+ return String.format("%s-%s", host, ipType);
+ }
+}
diff --git a/library/src/main/java/com/qiniu/android/storage/GlobalConfiguration.java b/library/src/main/java/com/qiniu/android/storage/GlobalConfiguration.java
index 2e73b8d89..f17d2b6bc 100644
--- a/library/src/main/java/com/qiniu/android/storage/GlobalConfiguration.java
+++ b/library/src/main/java/com/qiniu/android/storage/GlobalConfiguration.java
@@ -52,7 +52,7 @@ public class GlobalConfiguration {
* 当请求的 Response 为网络异常时,并发对 connectCheckURLStrings 中 URLString 进行 HEAD 请求,以此检测当前网络状态的链接状态,其中任意一个 URLString 链接成功则认为当前网络状态链接良好;
* 当 connectCheckURLStrings 为 nil 或者 空数组时则弃用检测功能。
*/
- public String[] connectCheckURLStrings = new String[]{"http://www.qiniu.com", "http://www.baidu.com", "http://www.google.com"};
+ public String[] connectCheckURLStrings = new String[]{"https://www.qiniu.com", "https://www.baidu.com", "https://www.google.com"};
/**
* 网络连接状态检测HEAD请求超时,默认:3s