one
Version:
One is a React framework for web, iOS, and Android apps.
126 lines (125 loc) • 4.11 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all) __defProp(target, name, {
get: all[name],
enumerable: true
});
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: () => from[key],
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var assetRange_exports = {};
__export(assetRange_exports, { withRange: () => withRange });
module.exports = __toCommonJS(assetRange_exports);
async function withRange(request, response) {
const 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;
}
const match = /^bytes=(\d*)-(\d*)$/.exec(range.trim());
if (!match || !match[1] && !match[2]) return response;
const length = response.headers.get("content-length");
const known = length && /^\d+$/.test(length) ? Number(length) : void 0;
const headers = new Headers(response.headers);
headers.set("accept-ranges", "bytes");
headers.delete("content-length");
const { size, kept, keptStart } = await readRange(response.body, match, known);
const 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;
const value = ifRange.trim();
if (value.startsWith("\"")) {
const 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) {
let start;
let 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) {
const span = known === void 0 ? void 0 : resolve(match, known) ?? {
start: known,
end: -1
};
const suffix = !span && !match[1] ? Number(match[2]) : 0;
const from = span ? span.start : match[1] ? Number(match[1]) : 0;
const to = span ? span.end : match[2] && match[1] ? Number(match[2]) : Number.POSITIVE_INFINITY;
const chunks = [];
let keptBytes = 0;
let size = 0;
const reader = body.getReader();
while (known === void 0 || size <= to) {
const { done, value } = await reader.read();
if (done) break;
const 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;
}
const lo = Math.max(from, chunkStart);
const 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;
}
const kept = new Uint8Array(keptBytes);
let at = 0;
for (const chunk of chunks) {
kept.set(chunk, at);
at += chunk.byteLength;
}
return {
size,
kept,
keptStart: suffix ? size - keptBytes : from
};
}