one
Version:
One is a React framework for web, iOS, and Android apps.
124 lines (122 loc) • 3.81 kB
JavaScript
async function withRange(request, response) {
var range = request.headers.get("range");
if (!range || request.method !== "GET" || response.status !== 200 || !response.body || response.headers.has("content-range") || response.headers.has("content-encoding") || !ifRangeMatches(request.headers.get("if-range"), response.headers)) {
return response;
}
var match = /^bytes=(\d*)-(\d*)$/.exec(range.trim());
if (!match || !match[1] && !match[2]) return response;
var length = response.headers.get("content-length");
var known = length && /^\d+$/.test(length) ? Number(length) : void 0;
var headers = new Headers(response.headers);
headers.set("accept-ranges", "bytes");
headers.delete("content-length");
var { size, kept, keptStart } = await readRange(response.body, match, known);
var span = resolve(match, size);
if (!span) {
headers.set("content-range", `bytes */${size}`);
return new Response(null, {
status: 416,
headers
});
}
headers.set("content-range", `bytes ${span.start}-${span.end}/${size}`);
headers.set("content-length", String(span.end - span.start + 1));
return new Response(kept.subarray(span.start - keptStart, span.end - keptStart + 1), {
status: 206,
headers
});
}
function ifRangeMatches(ifRange, headers) {
if (!ifRange) return true;
var value = ifRange.trim();
if (value.startsWith("\"")) {
var etag = headers.get("etag");
return !!etag && !etag.startsWith("W/") && etag === value;
}
if (value.startsWith("W/")) return false;
return headers.get("last-modified") === value;
}
function resolve(match, size) {
var start;
var end;
if (!match[1]) {
start = Math.max(0, size - Number(match[2]));
end = size - 1;
} else {
start = Number(match[1]);
end = match[2] ? Math.min(Number(match[2]), size - 1) : size - 1;
}
if (start >= size || start > end) return;
return {
start,
end
};
}
async function readRange(body, match, known) {
var _resolve;
var span = known === void 0 ? void 0 : (_resolve = resolve(match, known)) !== null && _resolve !== void 0 ? _resolve : {
start: known,
end: -1
};
var suffix = !span && !match[1] ? Number(match[2]) : 0;
var from = span ? span.start : match[1] ? Number(match[1]) : 0;
var to = span ? span.end : match[2] && match[1] ? Number(match[2]) : Number.POSITIVE_INFINITY;
var chunks = [];
var keptBytes = 0;
var size = 0;
var reader = body.getReader();
while (known === void 0 || size <= to) {
var { done, value } = await reader.read();
if (done) break;
var chunkStart = size;
size += value.byteLength;
if (suffix) {
chunks.push(value);
keptBytes += value.byteLength;
while (chunks.length > 1 && keptBytes - chunks[0].byteLength >= suffix) {
keptBytes -= chunks.shift().byteLength;
}
continue;
}
var lo = Math.max(from, chunkStart);
var hi = Math.min(to + 1, size);
if (hi > lo) {
chunks.push(value.subarray(lo - chunkStart, hi - chunkStart));
keptBytes += hi - lo;
}
}
if (known !== void 0) {
await reader.cancel();
size = known;
}
var kept = new Uint8Array(keptBytes);
var at = 0;
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
try {
for (var _iterator = chunks[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var chunk = _step.value;
kept.set(chunk, at);
at += chunk.byteLength;
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return {
size,
kept,
keptStart: suffix ? size - keptBytes : from
};
}
export { withRange };
//# sourceMappingURL=assetRange.native.js.map