@httpland/range-request-middleware
Version:
HTTP range request middleware
70 lines (69 loc) • 2.97 kB
JavaScript
// Copyright 2023-latest the httpland authors. All rights reserved. MIT license.
// This module is browser compatible.
Object.defineProperty(exports, "__esModule", { value: true });
exports.acceptRanges = exports.contentRange = exports.rangeRequest = void 0;
const deps_js_1 = require("./deps.js");
const transform_js_1 = require("./transform.js");
const bytes_js_1 = require("./ranges/bytes.js");
const utils_js_1 = require("./utils.js");
/** Create range request middleware.
*
* @example
* ```ts
* import { rangeRequest } from "https://deno.land/x/range_request_middleware@$VERSION/middleware.ts";
* import {
* assert,
* assertEquals,
* assertThrows,
* } from "https://deno.land/std/testing/asserts.ts";
*
* const middleware = rangeRequest();
* const request = new Request("test:", {
* headers: { range: "bytes=5-9" },
* });
* const response = await middleware(
* request,
* () => new Response("abcdefghijklmnopqrstuvwxyz"),
* );
*
* assertEquals(response.status, 206);
* assertEquals(response.headers.get("content-range"), "bytes 5-9/26");
* assertEquals(response.headers.get("accept-ranges"), "bytes");
* assertEquals(await response.text(), "fghij");
* ```
*/
function rangeRequest(ranges) {
const $ranges = ranges ?? [new bytes_js_1.BytesRange()];
const units = Array.from($ranges).map((range) => range.rangeUnit);
const unitLike = (0, deps_js_1.isNotEmpty)(units) ? units : utils_js_1.RangeUnit.None;
const contentRangeMiddleware = contentRange($ranges);
const acceptRangesMiddleware = acceptRanges(unitLike);
return (request, next) => {
return contentRangeMiddleware(request, (request) => acceptRangesMiddleware(request, next));
};
}
exports.rangeRequest = rangeRequest;
function contentRange(ranges) {
const $ranges = ranges ?? [new bytes_js_1.BytesRange()];
return async (request, next) => {
const rangeValue = request.headers.get(deps_js_1.RangeHeader.Range);
// A server MUST ignore a Range header field received with a request method that is unrecognized or for which range handling is not defined. For this specification, GET is the only method for which range handling is defined.
// @see https://www.rfc-editor.org/rfc/rfc9110#section-14.2-4
if (request.method !== deps_js_1.Method.Get ||
(0, deps_js_1.isNull)(rangeValue) ||
request.headers.has(deps_js_1.ConditionalHeader.IfRange))
return next(request);
const response = await next(request);
return (0, transform_js_1.withContentRange)(response, { ranges: $ranges, rangeValue });
};
}
exports.contentRange = contentRange;
function acceptRanges(unitLike) {
const rangeUnit = unitLike ?? utils_js_1.RangeUnit.Bytes;
return async (request, next) => {
const response = await next(request);
return (0, transform_js_1.withAcceptRanges)(response, rangeUnit);
};
}
exports.acceptRanges = acceptRanges;
;