diff --git a/mobile/src/main/java/com/github/shadowsocks/MainActivity.kt b/mobile/src/main/java/com/github/shadowsocks/MainActivity.kt index f3738a73..f534c8cb 100644 --- a/mobile/src/main/java/com/github/shadowsocks/MainActivity.kt +++ b/mobile/src/main/java/com/github/shadowsocks/MainActivity.kt @@ -41,7 +41,9 @@ import android.support.v7.content.res.AppCompatResources import android.support.v7.preference.PreferenceDataStore import android.text.format.Formatter import android.util.Log +import android.util.Patterns import android.view.View +import android.webkit.URLUtil import android.widget.TextView import com.github.shadowsocks.App.Companion.app import com.github.shadowsocks.acl.Acl @@ -65,6 +67,7 @@ import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem import java.io.IOException import java.net.HttpURLConnection import java.net.InetSocketAddress +import java.net.MalformedURLException import java.net.Proxy import java.net.URL import java.util.* @@ -162,28 +165,36 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, Drawe * Based on: https://android.googlesource.com/platform/frameworks/base/+/97bfd27/services/core/java/com/android/server/connectivity/NetworkMonitor.java#879 */ private fun testConnection(id: Int) { - val url = URL("https", when (app.currentProfile!!.route) { - Acl.CHINALIST -> "www.qualcomm.cn" - else -> "www.google.com" - }, "/generate_204") - val conn = (if (BaseService.usingVpnMode) url.openConnection() else - url.openConnection(Proxy(Proxy.Type.SOCKS, - InetSocketAddress("127.0.0.1", DataStore.portProxy)))) - as HttpURLConnection - conn.setRequestProperty("Connection", "close") - conn.instanceFollowRedirects = false - conn.useCaches = false val (success, result) = try { - val start = SystemClock.elapsedRealtime() - val code = conn.responseCode - val elapsed = SystemClock.elapsedRealtime() - start - if (code == 204 || code == 200 && conn.responseLength == 0L) - Pair(true, getString(R.string.connection_test_available, elapsed)) - else throw IOException(getString(R.string.connection_test_error_status_code, code)) - } catch (e: IOException) { - Pair(false, getString(R.string.connection_test_error, e.message)) - } finally { - conn.disconnect() + val urlString = when (app.currentProfile!!.route) { + Acl.CHINALIST -> DataStore.testUrlChinaList + else -> DataStore.testUrl} + val url = URL(urlString) + if (url.protocol != "https") + throw MalformedURLException(getString(R.string.connection_test_url_non_https, urlString)) + if (!URLUtil.isValidUrl(urlString) || !Patterns.WEB_URL.matcher(urlString).matches()) + throw MalformedURLException(getString(R.string.connection_test_url_invalid, urlString)) + val conn = (if (BaseService.usingVpnMode) url.openConnection() else + url.openConnection(Proxy(Proxy.Type.SOCKS, + InetSocketAddress("127.0.0.1", DataStore.portProxy)))) + as HttpURLConnection + conn.setRequestProperty("Connection", "close") + conn.instanceFollowRedirects = false + conn.useCaches = false + try { + val start = SystemClock.elapsedRealtime() + val code = conn.responseCode + val elapsed = SystemClock.elapsedRealtime() - start + if (code == 204 || code == 200 && conn.responseLength == 0L) + Pair(true, getString(R.string.connection_test_available, elapsed)) + else throw IOException(getString(R.string.connection_test_error_status_code, code)) + } catch (e: IOException) { + Pair(false, getString(R.string.connection_test_error, e.message)) + } finally { + conn.disconnect() + } + } catch (e: MalformedURLException) { + Pair(false, getString(R.string.connection_test_url_error, e.message)) } if (testCount == id) app.handler.post { if (success) statusText.text = result else { diff --git a/mobile/src/main/java/com/github/shadowsocks/preference/DataStore.kt b/mobile/src/main/java/com/github/shadowsocks/preference/DataStore.kt index 144f2eab..61b61ad6 100644 --- a/mobile/src/main/java/com/github/shadowsocks/preference/DataStore.kt +++ b/mobile/src/main/java/com/github/shadowsocks/preference/DataStore.kt @@ -51,6 +51,12 @@ object DataStore { } val canToggleLocked: Boolean get() = publicStore.getBoolean(Key.directBootAware) == true val directBootAware: Boolean get() = app.directBootSupported && canToggleLocked + var testUrl: String + get() = publicStore.getString(Key.testUrl) ?: "https://www.google.com/generate_204" + set(value) = publicStore.putString(Key.testUrl, value) + var testUrlChinaList: String + get() = publicStore.getString(Key.testUrlChinaList) ?: "https://www.qualcomm.cn/generate_204" + set(value) = publicStore.putString(Key.testUrlChinaList, value) var serviceMode: String get() = publicStore.getString(Key.serviceMode) ?: Key.modeVpn set(value) = publicStore.putString(Key.serviceMode, value) @@ -66,6 +72,8 @@ object DataStore { fun initGlobal() { // temporary workaround for support lib bug + if (publicStore.getString(Key.testUrl) == null) testUrl = testUrl + if (publicStore.getString(Key.testUrlChinaList) == null) testUrlChinaList = testUrlChinaList if (publicStore.getString(Key.serviceMode) == null) serviceMode = serviceMode if (publicStore.getString(Key.portProxy) == null) portProxy = portProxy if (publicStore.getString(Key.portLocalDns) == null) portLocalDns = portLocalDns diff --git a/mobile/src/main/java/com/github/shadowsocks/utils/Constants.kt b/mobile/src/main/java/com/github/shadowsocks/utils/Constants.kt index 05f8e480..1c841cdc 100644 --- a/mobile/src/main/java/com/github/shadowsocks/utils/Constants.kt +++ b/mobile/src/main/java/com/github/shadowsocks/utils/Constants.kt @@ -49,6 +49,8 @@ object Key { const val bypass = "isBypassApps" const val udpdns = "isUdpDns" const val ipv6 = "isIpv6" + const val testUrl = "testUrl" + const val testUrlChinaList = "testUrlChinaList" const val host = "proxy" const val password = "sitekey" diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml index 4479c013..ee7fbac2 100644 --- a/mobile/src/main/res/values/strings.xml +++ b/mobile/src/main/res/values/strings.xml @@ -20,9 +20,14 @@ %s↑\t%s↓ Sent: \t\t\t\t\t%3$s\t↑\t%1$s\nReceived: \t%4$s\t↓\t%2$s %s/s + Connection Test URL + Connection Test URL (China List mode only) Check Connectivity Testing… Success: %dms latency + Check connection test URL. %s + Non-HTTPS URL: %s + Invalid URL: %s Fail to detect internet connection: %s Internet Unavailable Error code: #%d diff --git a/mobile/src/main/res/xml/pref_global.xml b/mobile/src/main/res/xml/pref_global.xml index d8bcbce8..bfd81e2d 100644 --- a/mobile/src/main/res/xml/pref_global.xml +++ b/mobile/src/main/res/xml/pref_global.xml @@ -12,6 +12,14 @@ + +