From 7c43e8f349dc628ffc404be5148db99c4d222045 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Mon, 30 Oct 2023 00:04:38 +0800 Subject: [PATCH] Avoid uncaught exceptions crashing entire app --- .../com/hippo/ehviewer/EhApplication.kt | 2 ++ .../interceptor/CloudflareInterceptor.kt | 14 ++++------ .../UncaughtExceptionInterceptor.kt | 28 +++++++++++++++++++ 3 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 app/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/UncaughtExceptionInterceptor.kt diff --git a/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt b/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt index 19f143982..2627bcd65 100644 --- a/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt +++ b/app/src/main/kotlin/com/hippo/ehviewer/EhApplication.kt @@ -51,6 +51,7 @@ import com.hippo.ehviewer.util.isAtLeastP import com.hippo.ehviewer.util.isAtLeastQ import com.hippo.ehviewer.util.isCronetSupported import eu.kanade.tachiyomi.network.interceptor.CloudflareInterceptor +import eu.kanade.tachiyomi.network.interceptor.UncaughtExceptionInterceptor import eu.kanade.tachiyomi.util.lang.launchIO import kotlinx.coroutines.launch import moe.tarsin.kt.unreachable @@ -170,6 +171,7 @@ class EhApplication : Application(), ImageLoaderFactory { dns(AsyncDns.toDns(AndroidAsyncDns.IPv4, AndroidAsyncDns.IPv6)) } chunker { alwaysReadResponseBody(false) } + addInterceptor(UncaughtExceptionInterceptor()) addInterceptor(CloudflareInterceptor(appCtx)) } } diff --git a/app/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt b/app/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt index 006ddef9b..6d0b2cf1e 100644 --- a/app/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt +++ b/app/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt @@ -8,7 +8,6 @@ import android.webkit.WebViewClient import androidx.core.content.ContextCompat import com.hippo.ehviewer.client.EhCookieStore import com.hippo.ehviewer.client.exception.CloudflareBypassException -import java.io.IOException import java.util.concurrent.CountDownLatch import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.Interceptor @@ -27,14 +26,11 @@ class CloudflareInterceptor(context: Context) : WebViewInterceptor(context) { request: Request, response: Response, ): Response { - // Because OkHttp's enqueue only handles IOExceptions, wrap the exception so that - // we don't crash the entire app - return runCatching { - response.close() - EhCookieStore.deleteCookie(request.url, COOKIE_NAME) - resolveWithWebView(request) - chain.proceed(request) - }.getOrElse { throw IOException(it) } + response.close() + EhCookieStore.deleteCookie(request.url, COOKIE_NAME) + resolveWithWebView(request) + + return chain.proceed(request) } private fun resolveWithWebView(originalRequest: Request) { diff --git a/app/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/UncaughtExceptionInterceptor.kt b/app/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/UncaughtExceptionInterceptor.kt new file mode 100644 index 000000000..a746ae773 --- /dev/null +++ b/app/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/UncaughtExceptionInterceptor.kt @@ -0,0 +1,28 @@ +package eu.kanade.tachiyomi.network.interceptor + +import java.io.IOException +import okhttp3.Interceptor +import okhttp3.Response + +/** + * Catches any uncaught exceptions from later in the chain and rethrows as a non-fatal + * IOException to avoid catastrophic failure. + * + * This should be the first interceptor in the client. + * + * See [Interceptor](https://square.github.io/okhttp/5.x/okhttp/okhttp3/-interceptor/index.html) + */ +class UncaughtExceptionInterceptor : Interceptor { + + override fun intercept(chain: Interceptor.Chain): Response { + return try { + chain.proceed(chain.request()) + } catch (e: Exception) { + if (e is IOException) { + throw e + } else { + throw IOException(e) + } + } + } +}