保存時にURLからファイル名を決める際のサニタイズの改善
This commit is contained in:
parent
448472cbbd
commit
0955dff8db
|
@ -55,8 +55,8 @@ suspend fun <T : Throwable?> assertThrowsSuspend(
|
|||
expected += "@" + Integer.toHexString(System.identityHashCode(expectedThrowable))
|
||||
actual += "@" + Integer.toHexString(System.identityHashCode(actualThrowable))
|
||||
}
|
||||
val mismatchMessage = (buildPrefix(message)
|
||||
+ format("unexpected exception type thrown;", expected, actual))
|
||||
val mismatchMessage = (buildPrefix(message) +
|
||||
format("unexpected exception type thrown;", expected, actual))
|
||||
|
||||
// The AssertionError(String, Throwable) ctor is only available on JDK7.
|
||||
val assertionError = AssertionError(mismatchMessage)
|
||||
|
|
|
@ -49,6 +49,7 @@ import kotlinx.coroutines.yield
|
|||
import okhttp3.Request
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.IOException
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.*
|
||||
import javax.net.ssl.HttpsURLConnection
|
||||
import kotlin.math.max
|
||||
|
@ -675,13 +676,49 @@ class ActMediaViewer : AppCompatActivity(), View.OnClickListener {
|
|||
download_history_list.addLast(DownloadHistory(now, url))
|
||||
}
|
||||
|
||||
val fileName = (
|
||||
url.mayUri()?.pathSegments?.findLast { !it.isNullOrBlank() }
|
||||
?: url
|
||||
.replaceFirst("https?://".asciiRegex(), "")
|
||||
.replaceAll("[^.\\w\\d]+".asciiPattern(), "-")
|
||||
)
|
||||
.take(20)
|
||||
/**
|
||||
* Linuxはフォルダ中のファイルの名前の上限が255バイトと決まっている。
|
||||
* その上限に収まるように文字を切りたいが、それはUTF-8の区切りを考慮する必要がある。
|
||||
*/
|
||||
fun shortenName(src: String, limitBytes: Int): String {
|
||||
val bytes = src.encodeUTF8()
|
||||
if (bytes.size <= limitBytes) return src
|
||||
// 制限バイト数の終端の一つ先
|
||||
var pos = limitBytes
|
||||
while (pos >= 0) {
|
||||
if (bytes[pos].toInt().and(0x80) == 0) {
|
||||
// 現在位置がUTF-8の後続ではないなら、その手前までを返す
|
||||
return String(bytes, 0, pos, StandardCharsets.UTF_8)
|
||||
}
|
||||
// 現在位置はUTF-8の文字の2バイト目以降なので、この手前で切ると文字が壊れる
|
||||
--pos
|
||||
}
|
||||
// UTF-8表現がおかしい
|
||||
return "media"
|
||||
}
|
||||
|
||||
var fileName = url.mayUri()?.pathSegments?.findLast { !it.isNullOrBlank() }
|
||||
?: url.replaceFirst("https?://".asciiRegex(), "")
|
||||
|
||||
// Windowsでファイル名に使えない文字を避ける
|
||||
fileName = """[\\/|"<>?*:-]+""".toRegex().replace(fileName, "-")
|
||||
|
||||
// 末尾から20文字以内にある最初のドット
|
||||
val extDotPos = fileName.indexOf('.', startIndex = max(0, fileName.length - 20))
|
||||
val fileNameMaxBytes = 255
|
||||
fileName = if (extDotPos == -1) {
|
||||
// 拡張子なし
|
||||
shortenName(fileName, fileNameMaxBytes)
|
||||
} else {
|
||||
// 拡張子の手前だけを短縮する
|
||||
val extPart = fileName.substring(extDotPos)
|
||||
val extPartBytes = extPart.encodeUTF8().size
|
||||
val namePart = shortenName(
|
||||
fileName.substring(0, extDotPos),
|
||||
fileNameMaxBytes - extPartBytes
|
||||
)
|
||||
"$namePart$extPart"
|
||||
}
|
||||
|
||||
val request = DownloadManager.Request(url.toUri())
|
||||
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName)
|
||||
|
|
|
@ -163,7 +163,8 @@ class ResponseBeforeRead(
|
|||
throw SendException(
|
||||
response = response,
|
||||
request = request,
|
||||
message = parseErrorResponse(ex.withCaption("readString failed."))
|
||||
message = parseErrorResponse(ex.withCaption("readString failed.")),
|
||||
cause = ex,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -219,7 +220,8 @@ class ResponseBeforeRead(
|
|||
throw SendException(
|
||||
response = response,
|
||||
request = request,
|
||||
message = parseErrorResponse(ex.withCaption("readString failed."))
|
||||
message = parseErrorResponse(ex.withCaption("readString failed.")),
|
||||
cause = ex,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -304,7 +306,7 @@ suspend fun ResponseWith<String?>.stringToJsonObject(): JsonObject =
|
|||
else -> throw SendException(
|
||||
response = response,
|
||||
request = response.request,
|
||||
message = parseErrorResponse("not a JSON object.")
|
||||
message = parseErrorResponse("not a JSON object."),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -317,6 +319,7 @@ suspend fun ResponseWith<String?>.stringToJsonObject(): JsonObject =
|
|||
response = response,
|
||||
request = response.request,
|
||||
message = ex.withCaption("readJsonObject failed. ($errorSuffix)"),
|
||||
cause = ex,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue