[SCB-2361] Solve URL conversion problem (#2715)

diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/AbstractAddressManager.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/AbstractAddressManager.java
index 971fc42..f8fb59a 100644
--- a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/AbstractAddressManager.java
+++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/AbstractAddressManager.java
@@ -54,6 +54,8 @@
 
   private static final int DEFAULT_METRICS_WINDOW_TIME = 1;
 
+  private static final int ISOLATION_THRESHOLD = 3;
+
   private List<String> addresses = new ArrayList<>();
 
   private int index = 0;
@@ -196,10 +198,7 @@
   }
 
   protected String normalizeUri(String endpoint) {
-    if (endpoint.contains("sslEnabled=true")) {
-      return StringUtils.replace(endpoint, "rest", "https");
-    }
-    return StringUtils.replace(endpoint, "rest", "http");
+    return new URLEndPoint(endpoint).toString();
   }
 
   public void refreshEndpoint(RefreshEndpointEvent event, String key) {
@@ -221,7 +220,7 @@
     }
     synchronized (lock) {
       int number = recodeStatus.get(address) + 1;
-      if (number < 3) {
+      if (number < ISOLATION_THRESHOLD) {
         recodeStatus.put(address, number);
       } else {
         removeAddress(address);
diff --git a/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/URLEndPoint.java b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/URLEndPoint.java
new file mode 100644
index 0000000..3163f75
--- /dev/null
+++ b/clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/URLEndPoint.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.http.client.common;
+
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
+
+public class URLEndPoint {
+  private static final String SSL_ENABLED_KEY = "sslEnabled";
+
+  private static final String HTTP_KEY = "http://";
+
+  private static final String HTTPS_KEY = "https://";
+
+  private boolean sslEnabled;
+
+  private Map<String, List<String>> querys;
+
+  private String hostOrIp;
+
+  private int port;
+
+  public URLEndPoint(String endpoint) {
+    URI uri = URI.create(endpoint);
+    hostOrIp = uri.getHost();
+    if (uri.getPort() < 0) {
+      throw new IllegalArgumentException("port not specified.");
+    }
+    port = uri.getPort();
+    querys = splitQuery(uri);
+    if (endpoint.contains(HTTPS_KEY)) {
+      sslEnabled = true;
+    } else {
+      sslEnabled = Boolean.parseBoolean(getFirst(SSL_ENABLED_KEY));
+    }
+  }
+
+  public static Map<String, List<String>> splitQuery(URI uri) {
+    final Map<String, List<String>> queryPairs = new LinkedHashMap<>();
+    List<NameValuePair> pairs = URLEncodedUtils.parse(uri, StandardCharsets.UTF_8);
+    for (NameValuePair pair : pairs) {
+      List<String> list = queryPairs.computeIfAbsent(pair.getName(), name -> new ArrayList<>());
+      list.add(pair.getValue());
+    }
+    return queryPairs;
+  }
+
+  public String getFirst(String key) {
+    List<String> values = querys.get(key);
+    if (values == null) {
+      return null;
+    }
+    return values.get(0);
+  }
+
+  @Override
+  public String toString() {
+    if (sslEnabled) {
+      return HTTPS_KEY + hostOrIp + ":" + port;
+    }
+    return HTTP_KEY + hostOrIp + ":" + port;
+  }
+}
diff --git a/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/AbstractAddressManagerTest.java b/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/AbstractAddressManagerTest.java
index ee38ced..3bfa3bc 100644
--- a/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/AbstractAddressManagerTest.java
+++ b/clients/http-client-common/src/test/java/org/apache/servicecomb/http/client/common/AbstractAddressManagerTest.java
@@ -173,7 +173,7 @@
     addressAZ.add("http://127.0.0.1:30100");
     addressAZ.add("https://127.0.0.2:30100");
     addressAZ.add("rest://127.0.0.1:30100?sslEnabled=true");
-    addressAZ.add("rest://127.0.0.2:30100");
+    addressAZ.add("rest://127.0.0.2:30100?sslEnabled=false");
 
     Map<String, List<String>> zoneAndRegion = new HashMap<>();
     zoneAndRegion.put("sameZone", addressAZ);
@@ -182,7 +182,7 @@
     addressManager1.refreshEndpoint(event1, "TEST");
 
     Assert.assertEquals("https://127.0.0.2:30100", addressManager1.address());
-    Assert.assertEquals("https://127.0.0.1:30100?sslEnabled=true", addressManager1.address());
+    Assert.assertEquals("https://127.0.0.1:30100", addressManager1.address());
     Assert.assertEquals("http://127.0.0.2:30100", addressManager1.address());
     Assert.assertEquals("http://127.0.0.1:30100", addressManager1.address());
     Assert.assertEquals("https://127.0.0.2:30100", addressManager1.address());
@@ -204,7 +204,7 @@
     Assert.assertEquals("http://127.0.0.6:30100", addressManager1.address());
     Assert.assertEquals("http://127.0.0.7:30100", addressManager1.address());
     Assert.assertEquals("https://127.0.0.8:30100", addressManager1.address());
-    Assert.assertEquals("https://127.0.0.5:30100?sslEnabled=true", addressManager1.address());
+    Assert.assertEquals("https://127.0.0.5:30100", addressManager1.address());
     Assert.assertEquals("http://127.0.0.6:30100", addressManager1.address());
   }
 
@@ -223,17 +223,17 @@
     addressManager1.refreshEndpoint(event, "TEST");
 
     Assert.assertEquals("https://127.0.0.2:30100", addressManager1.address());
-    Assert.assertEquals("https://127.0.0.1:30100?sslEnabled=true", addressManager1.address());
+    Assert.assertEquals("https://127.0.0.1:30100", addressManager1.address());
     Assert.assertEquals("https://127.0.0.2:30100", addressManager1.address());
 
     addressManager1.removeAddress("https://127.0.0.2:30100");
-    addressManager1.removeAddress("https://127.0.0.1:30100?sslEnabled=true");
-    Assert.assertEquals("https://127.0.0.3:30100?sslEnabled=true", addressManager1.address());
+    addressManager1.removeAddress("https://127.0.0.1:30100");
+    Assert.assertEquals("https://127.0.0.3:30100", addressManager1.address());
     Assert.assertEquals("https://127.0.0.4:30100", addressManager1.address());
-    Assert.assertEquals("https://127.0.0.3:30100?sslEnabled=true", addressManager1.address());
+    Assert.assertEquals("https://127.0.0.3:30100", addressManager1.address());
 
     addressManager1.removeAddress("https://127.0.0.4:30100");
-    addressManager1.removeAddress("https://127.0.0.3:30100?sslEnabled=true");
+    addressManager1.removeAddress("https://127.0.0.3:30100");
     Assert.assertEquals("https://127.0.0.2:30103", addressManager1.address());
     Assert.assertEquals("http://127.0.0.1:30103", addressManager1.address());
     Assert.assertEquals("https://127.0.0.2:30103", addressManager1.address());
@@ -296,4 +296,16 @@
     Assert.assertEquals("http://127.0.0.1:30100", addressManager2.address());
     Assert.assertEquals("http://127.0.0.1:30100", addressManager2.address());
   }
+
+  @Test
+  void normalizeUri() {
+    String uri = addressManager1.normalizeUri("rest://127.0.0.1:30100?sslEnabled=true");
+    Assert.assertEquals("https://127.0.0.1:30100", uri);
+
+    uri = addressManager1.normalizeUri("rest://127.0.0.1:30100?sslEnabled=false");
+    Assert.assertEquals("http://127.0.0.1:30100", uri);
+
+    uri = addressManager1.normalizeUri("rest://127.0.0.1:30100");
+    Assert.assertEquals("http://127.0.0.1:30100", uri);
+  }
 }
\ No newline at end of file
diff --git a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/refresh/ClassificationAddress.java b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/refresh/ClassificationAddress.java
index 2c2ccda..80af0f7 100644
--- a/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/refresh/ClassificationAddress.java
+++ b/service-registry/registry-service-center/src/main/java/org/apache/servicecomb/serviceregistry/refresh/ClassificationAddress.java
@@ -25,8 +25,10 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.servicecomb.foundation.common.event.EventManager;
 import org.apache.servicecomb.foundation.common.net.IpPort;
@@ -110,8 +112,8 @@
   }
 
   private Map<String, List<String>> refreshEndPoint(MicroserviceCache microserviceCache) {
-    List<String> sameZone = new ArrayList<>();
-    List<String> sameRegion = new ArrayList<>();
+    Set<String> sameZone = new HashSet<>();
+    Set<String> sameRegion = new HashSet<>();
     Map<String, List<String>> zoneAndRegion = new HashMap<>();
 
     List<MicroserviceInstance> microserviceCacheInstances = microserviceCache.getInstances();
@@ -124,8 +126,8 @@
         sameRegion.add(endPoint);
       }
     });
-    zoneAndRegion.put("sameZone", sameZone);
-    zoneAndRegion.put("sameRegion", sameRegion);
+    zoneAndRegion.put("sameZone", new ArrayList<>(sameZone));
+    zoneAndRegion.put("sameRegion", new ArrayList<>(sameRegion));
     return zoneAndRegion;
   }
 
@@ -145,8 +147,8 @@
     Map<String, List<String>> zoneAndRegion = new HashMap<>();
     dataCenterInfo = findRegion(CacheEndpoints);
 
-    List<String> sameZone = new ArrayList<>();
-    List<String> sameRegion = new ArrayList<>();
+    Set<String> sameZone = new HashSet<>();
+    Set<String> sameRegion = new HashSet<>();
     for (CacheEndpoint cacheEndpoint : CacheEndpoints) {
       if (regionAndAZMatch(dataCenterInfo, cacheEndpoint.getInstance())) {
         sameZone.add(cacheEndpoint.getEndpoint());
@@ -154,8 +156,8 @@
         sameRegion.add(cacheEndpoint.getEndpoint());
       }
     }
-    zoneAndRegion.put("sameZone", sameZone);
-    zoneAndRegion.put("sameRegion", sameRegion);
+    zoneAndRegion.put("sameZone", new ArrayList<>(sameZone));
+    zoneAndRegion.put("sameRegion", new ArrayList<>(sameRegion));
     return zoneAndRegion;
   }