Content-Range Header Builder and Parser

Format and parse Content-Range response headers for byte ranges, validating start, end and total values in both directions.

TypescriptData Integrity

Code

snippet
export interface ContentRange {
  unit: "bytes";
  start: number;
  end: number;
  total: number | "*";
}

export function formatContentRange(range: ContentRange): string {
  if (range.unit !== "bytes") {
    throw new RangeError("only the bytes unit is supported");
  }
  if (!Number.isInteger(range.start) || range.start < 0) {
    throw new RangeError("start must be a non-negative integer");
  }
  if (!Number.isInteger(range.end) || range.end < range.start) {
    throw new RangeError("end must be an integer not less than start");
  }
  if (
    range.total !== "*" &&
    (!Number.isInteger(range.total) || range.total <= range.end)
  ) {
    throw new RangeError("total must be * or an integer greater than end");
  }
  return "bytes " + range.start + "-" + range.end + "/" + range.total;
}

export function parseContentRange(value: string): ContentRange {
  if (typeof value !== "string") throw new TypeError("value must be a string");
  const match = /^bytes (\d+)-(\d+)\/(\d+|\*)$/.exec(value.trim());
  if (!match) throw new RangeError("invalid Content-Range header");
  const start = Number(match[1]);
  const end = Number(match[2]);
  const total = match[3] === "*" ? "*" : Number(match[3]);
  const range: ContentRange = { unit: "bytes", start, end, total };
  formatContentRange(range);
  return range;
}