Commit fbe8af61 authored by Mygod's avatar Mygod

Refine cancelling of HttpUrlConnection

parent cd199278
...@@ -32,10 +32,7 @@ import com.github.shadowsocks.database.ProfileManager ...@@ -32,10 +32,7 @@ import com.github.shadowsocks.database.ProfileManager
import com.github.shadowsocks.plugin.PluginConfiguration import com.github.shadowsocks.plugin.PluginConfiguration
import com.github.shadowsocks.plugin.PluginManager import com.github.shadowsocks.plugin.PluginManager
import com.github.shadowsocks.preference.DataStore import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.DirectBoot import com.github.shadowsocks.utils.*
import com.github.shadowsocks.utils.disconnectFromMain
import com.github.shadowsocks.utils.parseNumericAddress
import com.github.shadowsocks.utils.signaturesCompat
import kotlinx.coroutines.* import kotlinx.coroutines.*
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
...@@ -65,15 +62,11 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro ...@@ -65,15 +62,11 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
conn.requestMethod = "POST" conn.requestMethod = "POST"
conn.doOutput = true conn.doOutput = true
val proxies = try { val proxies = conn.useCancellable {
withContext(Dispatchers.IO) { outputStream.bufferedWriter().use {
conn.outputStream.bufferedWriter().use { it.write("sig=" + Base64.encodeToString(mdg.digest(), Base64.DEFAULT))
it.write("sig=" + Base64.encodeToString(mdg.digest(), Base64.DEFAULT))
}
conn.inputStream.bufferedReader().readText()
} }
} finally { inputStream.bufferedReader().readText()
conn.disconnectFromMain()
}.split('|').toMutableList() }.split('|').toMutableList()
proxies.shuffle() proxies.shuffle()
val proxy = proxies.first().split(':') val proxy = proxies.first().split(':')
......
...@@ -30,8 +30,11 @@ import com.github.shadowsocks.acl.Acl ...@@ -30,8 +30,11 @@ import com.github.shadowsocks.acl.Acl
import com.github.shadowsocks.core.R import com.github.shadowsocks.core.R
import com.github.shadowsocks.preference.DataStore import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.Key import com.github.shadowsocks.utils.Key
import com.github.shadowsocks.utils.disconnectFromMain import com.github.shadowsocks.utils.useCancellable
import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import java.io.IOException import java.io.IOException
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.Proxy import java.net.Proxy
...@@ -75,7 +78,7 @@ class HttpsTest : ViewModel() { ...@@ -75,7 +78,7 @@ class HttpsTest : ViewModel() {
} }
} }
private var running: Pair<HttpURLConnection, Job>? = null private var running: Job? = null
val status = MutableLiveData<Status>().apply { value = Status.Idle } val status = MutableLiveData<Status>().apply { value = Status.Idle }
fun testConnection() { fun testConnection() {
...@@ -91,26 +94,25 @@ class HttpsTest : ViewModel() { ...@@ -91,26 +94,25 @@ class HttpsTest : ViewModel() {
conn.setRequestProperty("Connection", "close") conn.setRequestProperty("Connection", "close")
conn.instanceFollowRedirects = false conn.instanceFollowRedirects = false
conn.useCaches = false conn.useCaches = false
running = conn to GlobalScope.launch(Dispatchers.Main.immediate) { running = GlobalScope.launch(Dispatchers.Main.immediate) {
status.value = withContext(Dispatchers.IO) { status.value = conn.useCancellable {
try { try {
val start = SystemClock.elapsedRealtime() val start = SystemClock.elapsedRealtime()
val code = conn.responseCode val code = responseCode
val elapsed = SystemClock.elapsedRealtime() - start val elapsed = SystemClock.elapsedRealtime() - start
if (code == 204 || code == 200 && conn.responseLength == 0L) Status.Success(elapsed) if (code == 204 || code == 200 && responseLength == 0L) Status.Success(elapsed)
else Status.Error.UnexpectedResponseCode(code) else Status.Error.UnexpectedResponseCode(code)
} catch (e: IOException) { } catch (e: IOException) {
Status.Error.IOFailure(e) Status.Error.IOFailure(e)
} finally { } finally {
conn.disconnect() disconnect()
} }
} }
} }
} }
private fun cancelTest() = running?.let { (conn, job) -> private fun cancelTest() {
job.cancel() // ensure job is cancelled before interrupting running?.cancel()
conn.disconnectFromMain()
running = null running = null
} }
......
...@@ -36,11 +36,10 @@ import android.util.TypedValue ...@@ -36,11 +36,10 @@ import android.util.TypedValue
import androidx.annotation.AttrRes import androidx.annotation.AttrRes
import androidx.preference.Preference import androidx.preference.Preference
import com.crashlytics.android.Crashlytics import com.crashlytics.android.Crashlytics
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.*
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.InetAddress import java.net.InetAddress
import kotlin.coroutines.resume
val Throwable.readableMessage get() = localizedMessage ?: javaClass.name val Throwable.readableMessage get() = localizedMessage ?: javaClass.name
...@@ -60,8 +59,13 @@ fun String.parseNumericAddress(): InetAddress? = Os.inet_pton(OsConstants.AF_INE ...@@ -60,8 +59,13 @@ fun String.parseNumericAddress(): InetAddress? = Os.inet_pton(OsConstants.AF_INE
fun <K, V> MutableMap<K, V>.computeIfAbsentCompat(key: K, value: () -> V) = if (Build.VERSION.SDK_INT >= 24) fun <K, V> MutableMap<K, V>.computeIfAbsentCompat(key: K, value: () -> V) = if (Build.VERSION.SDK_INT >= 24)
computeIfAbsent(key) { value() } else this[key] ?: value().also { put(key, it) } computeIfAbsent(key) { value() } else this[key] ?: value().also { put(key, it) }
fun HttpURLConnection.disconnectFromMain() { suspend fun <T> HttpURLConnection.useCancellable(block: HttpURLConnection.() -> T) = withContext(Dispatchers.IO) {
if (Build.VERSION.SDK_INT >= 26) disconnect() else GlobalScope.launch(Dispatchers.IO) { disconnect() } suspendCancellableCoroutine<T> { cont ->
cont.invokeOnCancellation {
if (Build.VERSION.SDK_INT >= 26) disconnect() else launch(Dispatchers.IO) { disconnect() }
}
cont.resume(block())
}
} }
fun parsePort(str: String?, default: Int, min: Int = 1025): Int { fun parsePort(str: String?, default: Int, min: Int = 1025): Int {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment