pull/977/head
gedoor 4 years ago
parent 9e029a6823
commit ccb4a0092f
  1. 8
      app/src/main/java/io/legado/app/help/http/HttpHelper.kt
  2. 89
      app/src/main/java/io/legado/app/help/http/OkHttpHelper.kt
  3. 109
      app/src/main/java/io/legado/app/lib/webdav/WebDav.kt
  4. 12
      app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt

@ -1,19 +1,11 @@
package io.legado.app.help.http package io.legado.app.help.http
import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.suspendCancellableCoroutine
import okhttp3.Request
import okhttp3.Response
import kotlin.coroutines.resume import kotlin.coroutines.resume
@Suppress("unused") @Suppress("unused")
object HttpHelper { object HttpHelper {
suspend fun newCall(builder: Request.Builder.() -> Unit, proxy: String? = null): Response {
val client = OkHttpHelper.getProxyClient(proxy)
val requestBuilder = Request.Builder().apply(builder)
return client.newCall(requestBuilder.build()).await()
}
suspend fun ajax(params: AjaxWebView.AjaxParams): StrResponse = suspend fun ajax(params: AjaxWebView.AjaxParams): StrResponse =
suspendCancellableCoroutine { block -> suspendCancellableCoroutine { block ->
val webView = AjaxWebView() val webView = AjaxWebView()

@ -13,6 +13,10 @@ import java.util.concurrent.TimeUnit
import kotlin.coroutines.resume import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException import kotlin.coroutines.resumeWithException
private val proxyClientCache: ConcurrentHashMap<String, OkHttpClient> by lazy {
ConcurrentHashMap()
}
val okHttpClient: OkHttpClient by lazy { val okHttpClient: OkHttpClient by lazy {
val specs = arrayListOf( val specs = arrayListOf(
@ -44,54 +48,53 @@ val okHttpClient: OkHttpClient by lazy {
builder.build() builder.build()
} }
object OkHttpHelper { /**
private val proxyClientCache: ConcurrentHashMap<String, OkHttpClient> by lazy { * 缓存代理okHttp
ConcurrentHashMap() */
fun getProxyClient(proxy: String? = null): OkHttpClient {
if (proxy.isNullOrBlank()) {
return okHttpClient
} }
proxyClientCache[proxy]?.let {
/** return it
* 缓存代理okHttp }
*/ val r = Regex("(http|socks4|socks5)://(.*):(\\d{2,5})(@.*@.*)?")
fun getProxyClient(proxy: String? = null): OkHttpClient { val ms = r.findAll(proxy)
if (proxy.isNullOrBlank()) { val group = ms.first()
return okHttpClient var username = "" //代理服务器验证用户名
} var password = "" //代理服务器验证密码
proxyClientCache[proxy]?.let { val type = if (group.groupValues[1] == "http") "http" else "socks"
return it val host = group.groupValues[2]
} val port = group.groupValues[3].toInt()
val r = Regex("(http|socks4|socks5)://(.*):(\\d{2,5})(@.*@.*)?") if (group.groupValues[4] != "") {
val ms = r.findAll(proxy) username = group.groupValues[4].split("@")[1]
val group = ms.first() password = group.groupValues[4].split("@")[2]
var username = "" //代理服务器验证用户名 }
var password = "" //代理服务器验证密码 if (type != "direct" && host != "") {
val type = if (group.groupValues[1] == "http") "http" else "socks" val builder = okHttpClient.newBuilder()
val host = group.groupValues[2] if (type == "http") {
val port = group.groupValues[3].toInt() builder.proxy(Proxy(Proxy.Type.HTTP, InetSocketAddress(host, port)))
if (group.groupValues[4] != "") { } else {
username = group.groupValues[4].split("@")[1] builder.proxy(Proxy(Proxy.Type.SOCKS, InetSocketAddress(host, port)))
password = group.groupValues[4].split("@")[2]
} }
if (type != "direct" && host != "") { if (username != "" && password != "") {
val builder = okHttpClient.newBuilder() builder.proxyAuthenticator { _, response -> //设置代理服务器账号密码
if (type == "http") { val credential: String = Credentials.basic(username, password)
builder.proxy(Proxy(Proxy.Type.HTTP, InetSocketAddress(host, port))) response.request.newBuilder()
} else { .header("Proxy-Authorization", credential)
builder.proxy(Proxy(Proxy.Type.SOCKS, InetSocketAddress(host, port))) .build()
}
if (username != "" && password != "") {
builder.proxyAuthenticator { _, response -> //设置代理服务器账号密码
val credential: String = Credentials.basic(username, password)
response.request.newBuilder()
.header("Proxy-Authorization", credential)
.build()
}
} }
val proxyClient = builder.build()
proxyClientCache[proxy] = proxyClient
return proxyClient
} }
return okHttpClient val proxyClient = builder.build()
proxyClientCache[proxy] = proxyClient
return proxyClient
} }
return okHttpClient
}
fun OkHttpClient.newCall(builder: Request.Builder.() -> Unit): Call {
val requestBuilder = Request.Builder().apply(builder)
return this.newCall(requestBuilder.build())
} }
suspend fun Call.await(): Response = suspendCancellableCoroutine { block -> suspend fun Call.await(): Response = suspendCancellableCoroutine { block ->

@ -1,7 +1,7 @@
package io.legado.app.lib.webdav package io.legado.app.lib.webdav
import io.legado.app.help.http.HttpHelper
import io.legado.app.help.http.await import io.legado.app.help.http.await
import io.legado.app.help.http.newCall
import io.legado.app.help.http.okHttpClient import io.legado.app.help.http.okHttpClient
import okhttp3.* import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType import okhttp3.MediaType.Companion.toMediaType
@ -21,17 +21,19 @@ class WebDav(urlStr: String) {
companion object { companion object {
// 指定返回哪些属性 // 指定返回哪些属性
private const val DIR = private const val DIR =
"""<?xml version="1.0"?> """
<a:propfind xmlns:a="DAV:"> <?xml version="1.0"?>
<a:prop> <a:propfind xmlns:a="DAV:">
<a:displayname/> <a:prop>
<a:resourcetype/> <a:displayname/>
<a:getcontentlength/> <a:resourcetype/>
<a:creationdate/> <a:getcontentlength/>
<a:getlastmodified/> <a:creationdate/>
%s <a:getlastmodified/>
</a:prop> %s
</a:propfind>""" </a:prop>
</a:propfind>
"""
} }
private val url: URL = URL(urlStr) private val url: URL = URL(urlStr)
@ -92,7 +94,7 @@ class WebDav(urlStr: String) {
} }
@Throws(IOException::class) @Throws(IOException::class)
private suspend fun propFindResponse(propsList: ArrayList<String>, depth: Int = 1): Response? { private suspend fun propFindResponse(propsList: ArrayList<String>): Response? {
val requestProps = StringBuilder() val requestProps = StringBuilder()
for (p in propsList) { for (p in propsList) {
requestProps.append("<a:").append(p).append("/>\n") requestProps.append("<a:").append(p).append("/>\n")
@ -102,19 +104,17 @@ class WebDav(urlStr: String) {
} else { } else {
String.format(DIR, requestProps.toString() + "\n") String.format(DIR, requestProps.toString() + "\n")
} }
httpUrl?.let { url -> val url = httpUrl
// 添加RequestBody对象,可以只返回的属性。如果设为null,则会返回全部属性 val auth = HttpAuth.auth
// 注意:尽量手动指定需要返回的属性。若返回全部属性,可能后由于Prop.java里没有该属性名,而崩溃。 if (url != null && auth != null) {
val requestBody = requestPropsStr.toRequestBody("text/plain".toMediaType()) return okHttpClient.newCall {
val request = Request.Builder() url(url)
.url(url) addHeader("Authorization", Credentials.basic(auth.user, auth.pass))
.method("PROPFIND", requestBody) // 添加RequestBody对象,可以只返回的属性。如果设为null,则会返回全部属性
// 注意:尽量手动指定需要返回的属性。若返回全部属性,可能后由于Prop.java里没有该属性名,而崩溃。
HttpAuth.auth?.let { val requestBody = requestPropsStr.toRequestBody("text/plain".toMediaType())
request.header("Authorization", Credentials.basic(it.user, it.pass)) method("PROPFIND", requestBody)
} }.await()
request.header("Depth", if (depth < 0) "infinity" else depth.toString())
return okHttpClient.newCall(request.build()).await()
} }
return null return null
} }
@ -159,11 +159,14 @@ class WebDav(urlStr: String) {
* @return 是否创建成功 * @return 是否创建成功
*/ */
suspend fun makeAsDir(): Boolean { suspend fun makeAsDir(): Boolean {
httpUrl?.let { url -> val url = httpUrl
val request = Request.Builder() val auth = HttpAuth.auth
.url(url) if (url != null && auth != null) {
.method("MKCOL", null) return okHttpClient.newCall {
return execRequest(request) url(url)
method("MKCOL", null)
addHeader("Authorization", Credentials.basic(auth.user, auth.pass))
}.await().isSuccessful
} }
return false return false
} }
@ -197,11 +200,14 @@ class WebDav(urlStr: String) {
if (!file.exists()) return false if (!file.exists()) return false
// 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息 // 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息
val fileBody = file.asRequestBody(contentType?.toMediaType()) val fileBody = file.asRequestBody(contentType?.toMediaType())
httpUrl?.let { val url = httpUrl
val request = Request.Builder() val auth = HttpAuth.auth
.url(it) if (url != null && auth != null) {
.put(fileBody) return okHttpClient.newCall {
return execRequest(request) url(url)
put(fileBody)
addHeader("Authorization", Credentials.basic(auth.user, auth.pass))
}.await().isSuccessful
} }
return false return false
} }
@ -209,38 +215,27 @@ class WebDav(urlStr: String) {
suspend fun upload(byteArray: ByteArray, contentType: String? = null): Boolean { suspend fun upload(byteArray: ByteArray, contentType: String? = null): Boolean {
// 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息 // 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息
val fileBody = byteArray.toRequestBody(contentType?.toMediaType()) val fileBody = byteArray.toRequestBody(contentType?.toMediaType())
httpUrl?.let { val url = httpUrl
val request = Request.Builder() val auth = HttpAuth.auth
.url(it) if (url != null && auth != null) {
.put(fileBody) return okHttpClient.newCall {
return execRequest(request) url(url)
put(fileBody)
addHeader("Authorization", Credentials.basic(auth.user, auth.pass))
}.await().isSuccessful
} }
return false return false
} }
/**
* 执行请求获取响应结果
* @param requestBuilder 因为还需要追加验证信息所以此处传递Request.Builder的对象而不是Request的对象
* @return 请求执行的结果
*/
@Throws(IOException::class)
private suspend fun execRequest(requestBuilder: Request.Builder): Boolean {
HttpAuth.auth?.let {
requestBuilder.header("Authorization", Credentials.basic(it.user, it.pass))
}
val response = okHttpClient.newCall(requestBuilder.build()).await()
return response.isSuccessful
}
@Throws(IOException::class) @Throws(IOException::class)
private suspend fun getInputStream(): InputStream? { private suspend fun getInputStream(): InputStream? {
val url = httpUrl val url = httpUrl
val auth = HttpAuth.auth val auth = HttpAuth.auth
if (url != null && auth != null) { if (url != null && auth != null) {
return HttpHelper.newCall({ return okHttpClient.newCall {
url(url) url(url)
addHeader("Authorization", Credentials.basic(auth.user, auth.pass)) addHeader("Authorization", Credentials.basic(auth.user, auth.pass))
}).body?.byteStream() }.await().body?.byteStream()
} }
return null return null
} }

@ -312,14 +312,14 @@ class AnalyzeUrl(
if (fieldMap.isNotEmpty() || body.isNullOrBlank()) { if (fieldMap.isNotEmpty() || body.isNullOrBlank()) {
RxHttp.postForm(url) RxHttp.postForm(url)
.setAssemblyEnabled(false) .setAssemblyEnabled(false)
.setOkClient(OkHttpHelper.getProxyClient(proxy)) .setOkClient(getProxyClient(proxy))
.addAllEncoded(fieldMap) .addAllEncoded(fieldMap)
.addAllHeader(headerMap) .addAllHeader(headerMap)
.toStrResponse().await() .toStrResponse().await()
} else { } else {
RxHttp.postJson(url) RxHttp.postJson(url)
.setAssemblyEnabled(false) .setAssemblyEnabled(false)
.setOkClient(OkHttpHelper.getProxyClient(proxy)) .setOkClient(getProxyClient(proxy))
.addAll(body) .addAll(body)
.addAllHeader(headerMap) .addAllHeader(headerMap)
.toStrResponse().await() .toStrResponse().await()
@ -327,7 +327,7 @@ class AnalyzeUrl(
} }
else -> RxHttp.get(url) else -> RxHttp.get(url)
.setAssemblyEnabled(false) .setAssemblyEnabled(false)
.setOkClient(OkHttpHelper.getProxyClient(proxy)) .setOkClient(getProxyClient(proxy))
.addAllEncoded(fieldMap) .addAllEncoded(fieldMap)
.addAllHeader(headerMap) .addAllHeader(headerMap)
.toStrResponse().await() .toStrResponse().await()
@ -341,14 +341,14 @@ class AnalyzeUrl(
if (fieldMap.isNotEmpty() || body.isNullOrBlank()) { if (fieldMap.isNotEmpty() || body.isNullOrBlank()) {
RxHttp.postForm(url) RxHttp.postForm(url)
.setAssemblyEnabled(false) .setAssemblyEnabled(false)
.setOkClient(OkHttpHelper.getProxyClient(proxy)) .setOkClient(getProxyClient(proxy))
.addAllEncoded(fieldMap) .addAllEncoded(fieldMap)
.addAllHeader(headerMap) .addAllHeader(headerMap)
.toByteArray().await() .toByteArray().await()
} else { } else {
RxHttp.postJson(url) RxHttp.postJson(url)
.setAssemblyEnabled(false) .setAssemblyEnabled(false)
.setOkClient(OkHttpHelper.getProxyClient(proxy)) .setOkClient(getProxyClient(proxy))
.addAll(body) .addAll(body)
.addAllHeader(headerMap) .addAllHeader(headerMap)
.toByteArray().await() .toByteArray().await()
@ -356,7 +356,7 @@ class AnalyzeUrl(
} }
else -> RxHttp.get(url) else -> RxHttp.get(url)
.setAssemblyEnabled(false) .setAssemblyEnabled(false)
.setOkClient(OkHttpHelper.getProxyClient(proxy)) .setOkClient(getProxyClient(proxy))
.addAllEncoded(fieldMap) .addAllEncoded(fieldMap)
.addAllHeader(headerMap) .addAllHeader(headerMap)
.toByteArray().await() .toByteArray().await()

Loading…
Cancel
Save