Просмотр исходного кода

Merge remote-tracking branch 'origin/master'

kunfei 4 лет назад
Родитель
Сommit
80a0b06a57

+ 6 - 0
app/src/main/java/io/legado/app/data/entities/BaseSource.kt

@@ -95,11 +95,17 @@ interface BaseSource : JsExtensions {
      * 保存登录头部信息,map格式,访问时自动添加
      */
     fun putLoginHeader(header: String) {
+        val headerMap = GSON.fromJsonObject<Map<String, String>>(header).getOrNull()
+        val cookie = headerMap?.get("Cookie") ?: headerMap?.get("cookie")
+        cookie?.let {
+            CookieStore.replaceCookie(getKey(), it)
+        }
         CacheManager.put("loginHeader_${getKey()}", header)
     }
 
     fun removeLoginHeader() {
         CacheManager.delete("loginHeader_${getKey()}")
+        CookieStore.removeCookie(getKey())
     }
 
     /**

+ 15 - 19
app/src/main/java/io/legado/app/help/CacheManager.kt

@@ -11,7 +11,7 @@ import splitties.init.appCtx
 object CacheManager {
 
     private val queryTTFMap = hashMapOf<String, Pair<Long, QueryTTF>>()
-    private val memoryLruCache = object : LruCache<String, Cache>(100) {}
+    private val memoryLruCache = object : LruCache<String, String>(100) {}
 
     /**
      * saveTime 单位为秒
@@ -25,15 +25,23 @@ object CacheManager {
             is ByteArray -> ACache.get(appCtx).put(key, value, saveTime)
             else -> {
                 val cache = Cache(key, value.toString(), deadline)
-                memoryLruCache.put(key, cache)
+                putMemory(key, value.toString())
                 appDb.cacheDao.insert(cache)
             }
         }
     }
 
-    fun putMemory(key: String, value: Any) {
-        val cache = Cache(key, value.toString(), 0)
-        memoryLruCache.put(key, cache)
+    fun putMemory(key: String, value: String) {
+        memoryLruCache.put(key, value)
+    }
+
+    //从内存中获取数据 使用lruCache
+    fun getFromMemory(key: String): String? {
+        return memoryLruCache.get(key)
+    }
+
+    fun deleteMemory(key: String) {
+        memoryLruCache.remove(key)
     }
 
     fun get(key: String): String? {
@@ -42,24 +50,12 @@ object CacheManager {
         }
         val cache = appDb.cacheDao.get(key)
         if (cache != null && (cache.deadline == 0L || cache.deadline > System.currentTimeMillis())) {
-            memoryLruCache.put(key, cache)
+            putMemory(key, cache.value ?: "")
             return cache.value
         }
         return null
     }
 
-    //从内存中获取数据 使用lruCache 支持过期功能
-    private fun getFromMemory(key: String): String? {
-        val cache = memoryLruCache.get(key) ?: return null
-        val deadline = cache.deadline
-        return if (deadline == 0L || deadline > System.currentTimeMillis()) {
-            cache.value
-        } else {
-            memoryLruCache.remove(key)
-            null
-        }
-    }
-
     fun getInt(key: String): Int? {
         return get(key)?.toIntOrNull()
     }
@@ -100,7 +96,7 @@ object CacheManager {
 
     fun delete(key: String) {
         appDb.cacheDao.delete(key)
-        memoryLruCache.remove(key)
+        deleteMemory(key)
         ACache.get(appCtx).remove(key)
     }
 }

+ 8 - 3
app/src/main/java/io/legado/app/help/glide/OkHttpStreamFetcher.kt

@@ -8,9 +8,11 @@ import com.bumptech.glide.load.data.DataFetcher
 import com.bumptech.glide.load.model.GlideUrl
 import com.bumptech.glide.util.ContentLengthInputStream
 import com.bumptech.glide.util.Preconditions
+import io.legado.app.constant.AppConst
 import io.legado.app.data.appDb
 import io.legado.app.exception.NoStackTraceException
 import io.legado.app.help.http.okHttpClient
+import io.legado.app.help.http.addHeaders
 import io.legado.app.utils.isWifiConnect
 import okhttp3.Call
 import okhttp3.Request
@@ -37,16 +39,19 @@ class OkHttpStreamFetcher(private val url: GlideUrl, private val options: Option
             return
         }
         val requestBuilder: Request.Builder = Request.Builder().url(url.toStringUrl())
+        val headerMap = HashMap<String, String>()
+        
         options.get(OkHttpModelLoader.sourceOriginOption)?.let { sourceUrl ->
             val source = appDb.bookSourceDao.getBookSource(sourceUrl)
                 ?: appDb.rssSourceDao.getByKey(sourceUrl)
-            source?.getHeaderMap(true)?.forEach {
-                requestBuilder.addHeader(it.key, it.value)
+            source?.getHeaderMap(true)?.let {
+                headerMap.putAll(it)
             }
         }
         for ((key, value) in url.headers.entries) {
-            requestBuilder.addHeader(key, value)
+            headerMap.put(key, value)
         }
+        requestBuilder.addHeaders(headerMap)
         val request: Request = requestBuilder.build()
         this.callback = callback
         call = okHttpClient.newCall(request)

+ 13 - 4
app/src/main/java/io/legado/app/help/http/CookieStore.kt

@@ -6,6 +6,7 @@ import android.text.TextUtils
 import io.legado.app.data.appDb
 import io.legado.app.data.entities.Cookie
 import io.legado.app.help.http.api.CookieManager
+import io.legado.app.help.CacheManager
 import io.legado.app.utils.NetworkUtils
 
 object CookieStore : CookieManager {
@@ -14,7 +15,9 @@ object CookieStore : CookieManager {
      *保存cookie到数据库,会自动识别url的二级域名
      */
     override fun setCookie(url: String, cookie: String?) {
-        val cookieBean = Cookie(NetworkUtils.getSubDomain(url), cookie ?: "")
+        val domain = NetworkUtils.getSubDomain(url)
+        CacheManager.putMemory("${domain}_cookie", cookie ?: "")
+        val cookieBean = Cookie(domain, cookie ?: "")
         appDb.cookieDao.insert(cookieBean)
     }
 
@@ -37,8 +40,12 @@ object CookieStore : CookieManager {
      *获取url所属的二级域名的cookie
      */
     override fun getCookie(url: String): String {
-        val cookieBean = appDb.cookieDao.get(NetworkUtils.getSubDomain(url))
-        return cookieBean?.cookie ?: ""
+        val domain = NetworkUtils.getSubDomain(url)
+        CacheManager.getFromMemory("${domain}_cookie")?.let { return it }
+        val cookieBean = appDb.cookieDao.get(domain)
+        val cookie = cookieBean?.cookie ?: ""
+        CacheManager.putMemory(url, cookie ?: "")
+        return cookie
     }
 
     fun getKey(url: String, key: String): String {
@@ -48,7 +55,9 @@ object CookieStore : CookieManager {
     }
 
     override fun removeCookie(url: String) {
-        appDb.cookieDao.delete(NetworkUtils.getSubDomain(url))
+        val domain = NetworkUtils.getSubDomain(url)
+        CacheManager.deleteMemory("${domain}_cookie")
+        appDb.cookieDao.delete(domain)
     }
 
     override fun cookieToMap(cookie: String): MutableMap<String, String> {

+ 19 - 5
app/src/main/java/io/legado/app/help/http/HttpHelper.kt

@@ -4,10 +4,7 @@ import io.legado.app.constant.AppConst
 import io.legado.app.help.config.AppConfig
 import io.legado.app.help.http.cronet.CronetInterceptor
 import io.legado.app.help.http.cronet.CronetLoader
-import okhttp3.ConnectionSpec
-import okhttp3.Credentials
-import okhttp3.Interceptor
-import okhttp3.OkHttpClient
+import okhttp3.*
 import java.net.InetSocketAddress
 import java.net.Proxy
 import java.util.concurrent.ConcurrentHashMap
@@ -17,6 +14,22 @@ private val proxyClientCache: ConcurrentHashMap<String, OkHttpClient> by lazy {
     ConcurrentHashMap()
 }
 
+val cookieJar by lazy {
+    object : CookieJar {
+
+        override fun loadForRequest(url: HttpUrl): List<Cookie> {
+            return emptyList()
+        }
+
+        override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
+            cookies.forEach {
+                CookieStore.replaceCookie(url.toString(), "${it.name}=${it.value}")
+            }
+        }
+
+    }
+}
+
 val okHttpClient: OkHttpClient by lazy {
     val specs = arrayListOf(
         ConnectionSpec.MODERN_TLS,
@@ -29,6 +42,7 @@ val okHttpClient: OkHttpClient by lazy {
         .writeTimeout(15, TimeUnit.SECONDS)
         .readTimeout(15, TimeUnit.SECONDS)
         .callTimeout(60, TimeUnit.SECONDS)
+        .cookieJar(cookieJar = cookieJar)
         .sslSocketFactory(SSLHelper.unsafeSSLSocketFactory, SSLHelper.unsafeTrustManager)
         .retryOnConnectionFailure(true)
         .hostnameVerifier(SSLHelper.unsafeHostnameVerifier)
@@ -47,7 +61,7 @@ val okHttpClient: OkHttpClient by lazy {
             chain.proceed(builder.build())
         })
     if (!AppConfig.isGooglePlay && AppConfig.isCronet && CronetLoader.install()) {
-        builder.addInterceptor(CronetInterceptor(null))
+        builder.addInterceptor(CronetInterceptor(cookieJar = cookieJar))
     }
     builder.build()
 }

+ 19 - 23
app/src/main/java/io/legado/app/help/http/cronet/CronetInterceptor.kt

@@ -1,12 +1,12 @@
 package io.legado.app.help.http.cronet
 
 import android.os.Build
-import io.legado.app.help.http.CookieStore
 import io.legado.app.utils.printOnDebug
 import okhttp3.*
+import okhttp3.internal.http.receiveHeaders
 
 
-class CronetInterceptor(private val cookieJar: CookieJar?) : Interceptor {
+class CronetInterceptor(private val cookieJar: CookieJar = CookieJar.NO_COOKIES) : Interceptor {
 
     override fun intercept(chain: Interceptor.Chain): Response {
         val original: Request = chain.request()
@@ -18,15 +18,18 @@ class CronetInterceptor(private val cookieJar: CookieJar?) : Interceptor {
             //移除Keep-Alive,手动设置会导致400 BadRequest
             builder.removeHeader("Keep-Alive")
             builder.removeHeader("Accept-Encoding")
-            val cookieStr = getCookie(original.url)
-            //设置Cookie
-            if (cookieStr.length > 3) {
-                builder.header("Cookie", cookieStr)
+            if (cookieJar != CookieJar.NO_COOKIES) {
+                val cookieStr = getCookie(original.url)
+                //设置Cookie
+                if (cookieStr.length > 3) {
+                    builder.addHeader("Cookie", cookieStr)
+                }
             }
-            val new = builder.build()
-            proceedWithCronet(new, chain.call())?.let { response ->
+
+            val newReq = builder.build()
+            proceedWithCronet(newReq, chain.call())?.let { response ->
                 //从Response 中保存Cookie到CookieJar
-                cookieJar?.saveFromResponse(new.url, Cookie.parseAll(new.url, response.headers))
+                cookieJar.receiveHeaders(newReq.url, response.headers)
                 response
             } ?: chain.proceed(original)
         } catch (e: Exception) {
@@ -54,21 +57,14 @@ class CronetInterceptor(private val cookieJar: CookieJar?) : Interceptor {
         return null
     }
 
-    private fun getCookie(url: HttpUrl): String {
-        val sb = StringBuilder()
-        //处理从 Cookiejar 获取到的Cookies
-        if (cookieJar != null) {
-            val cookies = cookieJar.loadForRequest(url)
-            for (cookie in cookies) {
-                sb.append(cookie.name).append("=").append(cookie.value).append("; ")
-            }
-        }
-        //处理自定义的Cookie
-        val cookie = CookieStore.getCookie(url.toString())
-        if (cookie.length > 3) {
-            sb.append(cookie)
+
+    /** Returns a 'Cookie' HTTP request header with all cookies, like `a=b; c=d`. */
+    private fun getCookie(url: HttpUrl): String = buildString {
+        val cookies = cookieJar.loadForRequest(url)
+        cookies.forEachIndexed { index, cookie ->
+            if (index > 0) append("; ")
+            append(cookie.name).append('=').append(cookie.value)
         }
-        return sb.toString()
     }
 
 }

+ 0 - 3
app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt

@@ -192,9 +192,6 @@ class AnalyzeUrl(
                     }
                 }
         }
-        headerMap[UA_NAME] ?: let {
-            headerMap[UA_NAME] = AppConfig.userAgent
-        }
         urlNoQuery = url
         when (method) {
             RequestMethod.GET -> {

+ 5 - 3
app/src/main/java/io/legado/app/ui/association/VerificationCodeDialog.kt

@@ -7,6 +7,7 @@ import android.view.ViewGroup
 import android.view.MenuItem
 import androidx.appcompat.widget.Toolbar
 import com.bumptech.glide.request.RequestOptions
+import com.bumptech.glide.load.engine.DiskCacheStrategy
 import io.legado.app.R
 import io.legado.app.base.BaseDialogFragment
 import io.legado.app.databinding.DialogVerificationCodeViewBinding
@@ -46,7 +47,6 @@ class VerificationCodeDialog() : BaseDialogFragment(R.layout.dialog_verification
         binding.run {
             toolBar.setBackgroundColor(primaryColor)
             val sourceOrigin = arguments?.getString("sourceOrigin")
-            val key = "${sourceOrigin}_verificationResult"
             arguments?.getString("imageUrl")?.let { imageUrl ->
                 ImageLoader.load(requireContext(), imageUrl).apply {
                     sourceOrigin?.let {
@@ -58,8 +58,10 @@ class VerificationCodeDialog() : BaseDialogFragment(R.layout.dialog_verification
                         )
                     }
                 }.error(R.drawable.image_loading_error)
-                    .into(ivImage)
-                ivImage.setOnClickListener {
+                    .diskCacheStrategy(DiskCacheStrategy.NONE)
+                    .skipMemoryCache(true)
+                    .into(verificationCodeImageView)
+                verificationCodeImageView.setOnClickListener {
                     showDialogFragment(PhotoDialog(imageUrl, sourceOrigin))
                 }
             }

+ 3 - 4
app/src/main/res/layout/dialog_verification_code_view.xml

@@ -18,11 +18,10 @@
         app:titleTextAppearance="@style/ToolbarTitle" />
 
     <androidx.appcompat.widget.AppCompatImageView
-        android:id="@+id/iv_image"
-        android:scaleType="fitXY"
+        android:id="@+id/verification_code_image_view"
         android:layout_width="match_parent"
-        android:layout_height="50dp"
-        android:padding="3dp"
+        android:layout_height="100dp"
+        android:scaleType="centerCrop"
         android:background="?android:attr/selectableItemBackgroundBorderless"
         tools:ignore="UnusedAttribute" />