From 411479633e72d0c77fea1fec932615da4cb5541a Mon Sep 17 00:00:00 2001 From: Xwite <1797350009@qq.com> Date: Thu, 16 Mar 2023 08:53:28 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=90=8D=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/io/legado/app/utils/UrlUtil.kt | 98 ++++++++++++++----- 1 file changed, 72 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/UrlUtil.kt b/app/src/main/java/io/legado/app/utils/UrlUtil.kt index 8b6adc46b..df2ee99ff 100644 --- a/app/src/main/java/io/legado/app/utils/UrlUtil.kt +++ b/app/src/main/java/io/legado/app/utils/UrlUtil.kt @@ -9,6 +9,13 @@ import java.nio.charset.StandardCharsets object UrlUtil { + // 有时候文件名在query里,截取path会截到其他内容 + // https://www.example.com/download.php?filename=文件.txt + // https://www.example.com/txt/文件.txt?token=123456 + private val unExpectFileSuffixs = arrayOf( + "php", "html" + ) + fun replaceReservedChar(text: String): String { return text.replace("%", "%25") .replace(" ", "%20") @@ -41,40 +48,66 @@ object UrlUtil { * 根据网络url获取文件信息 文件名 */ fun getFileName(fileUrl: String, headerMap: Map? = null): String? { - // 如果获取到后缀可直接截取链接 - if (getSuffix(fileUrl, "") != "") return fileUrl.substringAfterLast("/") return kotlin.runCatching { - var fileName: String = "" val url = URL(fileUrl) + var fileName: String? = getFileNameFromPath(url, headerMap) + if (fileName == null) { + fileName = getFileNameFromResponseHeader(url) + } + fileName + }.getOrNull() + } + + private getFileNameFromResponseHeader( + url: URL, + headerMap: Map? = null + ): String? { + // HEAD方式获取链接响应头信息 val conn: HttpURLConnection = url.openConnection() as HttpURLConnection - // HEAD方式获取返回头信息 conn.requestMethod = "HEAD" - // 下载链接可能还需要书源header才能成功访问 + // 下载链接可能还需要header才能成功访问 headerMap?.forEach { key, value -> conn.setRequestProperty(key, value) } + // 禁止重定向 否则获取不到响应头返回的Location + conn.setInstanceFollowRedirects(false) conn.connect() - // val contentLength = conn.getContentLengthLong() - // Content-Disposition - // 解析文件名 filename= filename*= + // val fileSize = conn.getContentLengthLong() / 1024 + /** Content-Disposition 存在三种情况 + * filename="filename" + * filename=filename + * filename*=charset''filename + */ val raw: String? = conn.getHeaderField("Content-Disposition") - if (raw != null && raw.indexOf("=") > 0) { - fileName = raw.split("=".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1] - fileName = - String( - fileName.toByteArray(StandardCharsets.ISO_8859_1), - StandardCharsets.UTF_8 //? - ) + // Location跳转到实际链接 + val redirectUrl: String? = conn.getHeaderField("Location") + + return if (raw != null) { + val fileNames = raw.split(";".toRegex()).filter { it.contains("filename") } + val names = hashSetOf() + fileNames.forEach { + var filename = it.substringAfter("=") + if (it.contains("filename*")) { + val data = filename.split("''") + names.add(URLDecoder.decode(data[1], data[0])) + } else { + fileName = fileName + .replace("^\"".toRegex(), "") + .replace("\"$".toRegex(), "") + names.add( + String( + fileName.toByteArray(StandardCharsets.ISO_8859_1), + StandardCharsets.UTF_8 + ) + ) + } + } + names.firstOrNull() + } else if (redirectUrl != null) { + val newUrl= URL(URLDecoder.decode(redirectUrl, "UTF-8")) + getFileNameFromPath(newUrl) } else { - // Location跳转到实际的下载链接 - var newUrl: String = conn.url.path ?: return null - newUrl = URLDecoder.decode(newUrl, "UTF-8") - if (getSuffix(newUrl, "") != "") { - fileName = newUrl.substringAfterLast("/") - } - } - if (fileName == "") { // 其余情况 返回响应头 val headers = conn.getHeaderFields() val headersString = buildString { @@ -88,9 +121,21 @@ object UrlUtil { } } AppLog.put("Cannot obtain URL file name:\n$headersString") + null } - fileName - }.getOrNull() + } + } + + private fun getFileNameFromPath(fileUrl: URL): String? { + val path = fileUrl.path ?: return null + val suffix = getSuffix(path, "") + return if ( + suffix != "" && !unExpectFileSuffixs.contains(suffix) + ) { + path.substringAfterLast("/") + } else { + null + } } /* 获取合法的文件后缀 */ @@ -99,7 +144,8 @@ object UrlUtil { //检查截取的后缀字符是否合法 [a-zA-Z0-9] val fileSuffixRegex = Regex("^[a-z\\d]+$", RegexOption.IGNORE_CASE) return if (suffix.length > 5 || !suffix.matches(fileSuffixRegex)) { - default ?: throw IllegalArgumentException("Cannot find illegal suffix:\n target: $str\nsuffix: $suffix") + AppLog.put("Cannot find illegal suffix:\n target: $str\nsuffix: $suffix") + default ?: "ext" } else { suffix } From 111e6c777e5e4d422614b4ad8bf61995ed73f848 Mon Sep 17 00:00:00 2001 From: Xwite <1797350009@qq.com> Date: Thu, 16 Mar 2023 09:01:15 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=90=8D=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/io/legado/app/utils/UrlUtil.kt | 109 +++++++++--------- 1 file changed, 54 insertions(+), 55 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/UrlUtil.kt b/app/src/main/java/io/legado/app/utils/UrlUtil.kt index df2ee99ff..068e0a505 100644 --- a/app/src/main/java/io/legado/app/utils/UrlUtil.kt +++ b/app/src/main/java/io/legado/app/utils/UrlUtil.kt @@ -62,67 +62,66 @@ object UrlUtil { url: URL, headerMap: Map? = null ): String? { - // HEAD方式获取链接响应头信息 - val conn: HttpURLConnection = url.openConnection() as HttpURLConnection - conn.requestMethod = "HEAD" - // 下载链接可能还需要header才能成功访问 - headerMap?.forEach { key, value -> - conn.setRequestProperty(key, value) - } - // 禁止重定向 否则获取不到响应头返回的Location - conn.setInstanceFollowRedirects(false) - conn.connect() + // HEAD方式获取链接响应头信息 + val conn: HttpURLConnection = url.openConnection() as HttpURLConnection + conn.requestMethod = "HEAD" + // 下载链接可能还需要header才能成功访问 + headerMap?.forEach { key, value -> + conn.setRequestProperty(key, value) + } + // 禁止重定向 否则获取不到响应头返回的Location + conn.setInstanceFollowRedirects(false) + conn.connect() - // val fileSize = conn.getContentLengthLong() / 1024 - /** Content-Disposition 存在三种情况 - * filename="filename" - * filename=filename - * filename*=charset''filename - */ - val raw: String? = conn.getHeaderField("Content-Disposition") - // Location跳转到实际链接 - val redirectUrl: String? = conn.getHeaderField("Location") + // val fileSize = conn.getContentLengthLong() / 1024 + /** Content-Disposition 存在三种情况 + * filename="filename" + * filename=filename + * filename*=charset''filename + */ + val raw: String? = conn.getHeaderField("Content-Disposition") + // Location跳转到实际链接 + val redirectUrl: String? = conn.getHeaderField("Location") - return if (raw != null) { - val fileNames = raw.split(";".toRegex()).filter { it.contains("filename") } - val names = hashSetOf() - fileNames.forEach { - var filename = it.substringAfter("=") - if (it.contains("filename*")) { - val data = filename.split("''") - names.add(URLDecoder.decode(data[1], data[0])) - } else { - fileName = fileName - .replace("^\"".toRegex(), "") - .replace("\"$".toRegex(), "") - names.add( - String( - fileName.toByteArray(StandardCharsets.ISO_8859_1), - StandardCharsets.UTF_8 - ) + return if (raw != null) { + val fileNames = raw.split(";".toRegex()).filter { it.contains("filename") } + val names = hashSetOf() + fileNames.forEach { + var filename = it.substringAfter("=") + if (it.contains("filename*")) { + val data = filename.split("''") + names.add(URLDecoder.decode(data[1], data[0])) + } else { + fileName = fileName + .replace("^\"".toRegex(), "") + .replace("\"$".toRegex(), "") + names.add( + String( + fileName.toByteArray(StandardCharsets.ISO_8859_1), + StandardCharsets.UTF_8 ) - } - } - names.firstOrNull() - } else if (redirectUrl != null) { - val newUrl= URL(URLDecoder.decode(redirectUrl, "UTF-8")) - getFileNameFromPath(newUrl) - } else { - // 其余情况 返回响应头 - val headers = conn.getHeaderFields() - val headersString = buildString { - headers.forEach { key, value -> - value.forEach { - append(key) - append(": ") - append(it) - append("\n") - } + ) + } + } + names.firstOrNull() + } else if (redirectUrl != null) { + val newUrl= URL(URLDecoder.decode(redirectUrl, "UTF-8")) + getFileNameFromPath(newUrl) + } else { + // 其余情况 返回响应头 + val headers = conn.getHeaderFields() + val headersString = buildString { + headers.forEach { key, value -> + value.forEach { + append(key) + append(": ") + append(it) + append("\n") } } - AppLog.put("Cannot obtain URL file name:\n$headersString") - null } + AppLog.put("Cannot obtain URL file name:\n$headersString") + null } } From 86f302a2765f9feda3c100ded0019e47042c8926 Mon Sep 17 00:00:00 2001 From: Xwite <1797350009@qq.com> Date: Thu, 16 Mar 2023 09:02:22 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=90=8D=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/io/legado/app/utils/UrlUtil.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/UrlUtil.kt b/app/src/main/java/io/legado/app/utils/UrlUtil.kt index 068e0a505..e10bc19e0 100644 --- a/app/src/main/java/io/legado/app/utils/UrlUtil.kt +++ b/app/src/main/java/io/legado/app/utils/UrlUtil.kt @@ -50,9 +50,9 @@ object UrlUtil { fun getFileName(fileUrl: String, headerMap: Map? = null): String? { return kotlin.runCatching { val url = URL(fileUrl) - var fileName: String? = getFileNameFromPath(url, headerMap) + var fileName: String? = getFileNameFromPath(url) if (fileName == null) { - fileName = getFileNameFromResponseHeader(url) + fileName = getFileNameFromResponseHeader(url, headerMap) } fileName }.getOrNull() From 6f74177feb5fdb30a6efdd1214b05748c73a4416 Mon Sep 17 00:00:00 2001 From: Xwite <1797350009@qq.com> Date: Thu, 16 Mar 2023 09:06:52 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=90=8D=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/io/legado/app/utils/UrlUtil.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/utils/UrlUtil.kt b/app/src/main/java/io/legado/app/utils/UrlUtil.kt index e10bc19e0..1bd86ea1c 100644 --- a/app/src/main/java/io/legado/app/utils/UrlUtil.kt +++ b/app/src/main/java/io/legado/app/utils/UrlUtil.kt @@ -58,7 +58,7 @@ object UrlUtil { }.getOrNull() } - private getFileNameFromResponseHeader( + private fun getFileNameFromResponseHeader( url: URL, headerMap: Map? = null ): String? { From 8c0708d63f8257e70db57538fb7488ddd716b6c5 Mon Sep 17 00:00:00 2001 From: Xwite <1797350009@qq.com> Date: Thu, 16 Mar 2023 09:19:09 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=90=8D=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/io/legado/app/utils/UrlUtil.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/UrlUtil.kt b/app/src/main/java/io/legado/app/utils/UrlUtil.kt index 1bd86ea1c..1984396ac 100644 --- a/app/src/main/java/io/legado/app/utils/UrlUtil.kt +++ b/app/src/main/java/io/legado/app/utils/UrlUtil.kt @@ -87,9 +87,9 @@ object UrlUtil { val fileNames = raw.split(";".toRegex()).filter { it.contains("filename") } val names = hashSetOf() fileNames.forEach { - var filename = it.substringAfter("=") + var fileName = it.substringAfter("=") if (it.contains("filename*")) { - val data = filename.split("''") + val data = fileName.split("''") names.add(URLDecoder.decode(data[1], data[0])) } else { fileName = fileName