UNPKG

one

Version:

One is a React framework for web, iOS, and Android apps.

106 lines (104 loc) • 3.26 kB
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 }; } export { withRange }; //# sourceMappingURL=assetRange.mjs.map