@onekeyfe/react-native-range-downloader 6.7.0-alpha.310 → 6.7.0-alpha.311
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -148,12 +148,15 @@ class ConcurrentRangeDownloader(
|
|
|
148
148
|
* Fills [partialFilePath] completely with the resource at [url] using
|
|
149
149
|
* concurrent ranges. See [Outcome]. Throws on a transient/IO error after
|
|
150
150
|
* per-segment retries, leaving the segment files in place so a later attempt
|
|
151
|
-
* resumes.
|
|
151
|
+
* resumes. [maxTotalBytes] rejects a known oversized probe before workers
|
|
152
|
+
* or artifact writes; callers with unknown single-stream sizes enforce their
|
|
153
|
+
* own streaming limit.
|
|
152
154
|
*/
|
|
153
155
|
fun download(
|
|
154
156
|
url: String,
|
|
155
157
|
partialFilePath: String,
|
|
156
158
|
cancelHandle: CancelHandle? = null,
|
|
159
|
+
maxTotalBytes: Long = Long.MAX_VALUE,
|
|
157
160
|
onProgress: (transferred: Long, total: Long) -> Unit,
|
|
158
161
|
): Outcome {
|
|
159
162
|
val partialFile = File(partialFilePath)
|
|
@@ -168,6 +171,9 @@ class ConcurrentRangeDownloader(
|
|
|
168
171
|
}
|
|
169
172
|
|
|
170
173
|
val probe = probe(url) ?: return Outcome.FALLBACK
|
|
174
|
+
if (probe.totalSize > maxTotalBytes) {
|
|
175
|
+
throw SecurityException("Range download exceeds caller size limit")
|
|
176
|
+
}
|
|
171
177
|
if (!probe.supportsRange || probe.totalSize < minConcurrentBytes) {
|
|
172
178
|
log("concurrent: not eligible (supportsRange=${probe.supportsRange}, size=${probe.totalSize})")
|
|
173
179
|
return Outcome.FALLBACK
|
|
@@ -2,6 +2,9 @@ package com.margelo.nitro.reactnativerangedownloader
|
|
|
2
2
|
|
|
3
3
|
import okhttp3.OkHttpClient
|
|
4
4
|
import okhttp3.mockwebserver.MockWebServer
|
|
5
|
+
import okhttp3.mockwebserver.Dispatcher
|
|
6
|
+
import okhttp3.mockwebserver.MockResponse
|
|
7
|
+
import okhttp3.mockwebserver.RecordedRequest
|
|
5
8
|
import org.junit.After
|
|
6
9
|
import org.junit.Assert.assertEquals
|
|
7
10
|
import org.junit.Assert.assertFalse
|
|
@@ -82,6 +85,52 @@ class ConcurrentRangeDownloaderOcdsTest {
|
|
|
82
85
|
}
|
|
83
86
|
}
|
|
84
87
|
|
|
88
|
+
@Test
|
|
89
|
+
fun oversizedProbedTotalRejectsBeforeRangeWorkers() {
|
|
90
|
+
val cap = content.size.toLong()
|
|
91
|
+
server = MockWebServer()
|
|
92
|
+
server.dispatcher = object : Dispatcher() {
|
|
93
|
+
override fun dispatch(request: RecordedRequest) = MockResponse()
|
|
94
|
+
.setResponseCode(206)
|
|
95
|
+
.addHeader("Content-Range", "bytes 0-0/${cap + 1}")
|
|
96
|
+
.setBody("x")
|
|
97
|
+
}
|
|
98
|
+
server.start()
|
|
99
|
+
|
|
100
|
+
val partial = partialPath()
|
|
101
|
+
val failure = runCatching {
|
|
102
|
+
newDownloader().download(
|
|
103
|
+
url = url(),
|
|
104
|
+
partialFilePath = partial,
|
|
105
|
+
maxTotalBytes = cap,
|
|
106
|
+
onProgress = { _, _ -> },
|
|
107
|
+
)
|
|
108
|
+
}.exceptionOrNull()
|
|
109
|
+
|
|
110
|
+
assertTrue("oversized total must reject", failure is SecurityException)
|
|
111
|
+
assertEquals("only the probe may reach the server", 1, server.requestCount)
|
|
112
|
+
assertEquals("bytes=0-0", server.takeRequest().getHeader("Range"))
|
|
113
|
+
assertNoArtifactsLeft(partial)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@Test
|
|
117
|
+
fun probedTotalAtLimitCanComplete() {
|
|
118
|
+
val fs = RangeFaultServer(content)
|
|
119
|
+
startServer(fs)
|
|
120
|
+
|
|
121
|
+
val partial = partialPath()
|
|
122
|
+
val outcome = newDownloader().download(
|
|
123
|
+
url = url(),
|
|
124
|
+
partialFilePath = partial,
|
|
125
|
+
maxTotalBytes = content.size.toLong(),
|
|
126
|
+
onProgress = { _, _ -> },
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
assertEquals(ConcurrentRangeDownloader.Outcome.COMPLETED, outcome)
|
|
130
|
+
assertEquals(content.size.toLong(), File(partial).length())
|
|
131
|
+
assertEquals(sha256(content), sha256(File(partial)))
|
|
132
|
+
}
|
|
133
|
+
|
|
85
134
|
// ------------------------------------------------------------------------
|
|
86
135
|
// OCDS-T1: drop one segment's connection mid-body a couple of times.
|
|
87
136
|
// Only that segment is re-fetched (retries stay in its own window); the
|
package/package.json
CHANGED