Skip to content

Commit

Permalink
feat(content_range): add checking format of content-range header
Browse files Browse the repository at this point in the history
  • Loading branch information
TomokiMiyauci committed Mar 25, 2023
1 parent 068dd87 commit 169b15d
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 6 deletions.
55 changes: 50 additions & 5 deletions content_range.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

// TODO:(miyauci) Packaging and externalization this module.

import { isNumber } from "./deps.ts";
import { isNonNegativeInteger, isNumber } from "./deps.ts";

export interface ContentRange {
readonly rangeUnit: string;
Expand All @@ -25,7 +25,10 @@ export interface UnsatisfiedRange {
readonly completeLength: number;
}

/** Deserialize {@link ContentRange} into string. */
/** Deserialize {@link ContentRange} into string.
*
* @throws {TypeError} If the {@link ContentRange} is invalid.
*/
export function stringify(contentRange: ContentRange): string {
const fmt = isRangeResp(contentRange.range)
? stringifyRangeResp(contentRange.range)
Expand All @@ -45,19 +48,61 @@ function stringifyRangeResp(rangeResp: RangeResp): string {
function stringifyInclRange(inclRange: InclRange): string {
const { firstPos, lastPos } = inclRange;

assertNonNegativeInteger(
firstPos,
Msg.InvalidNonNegativeInt(ABNF.FirstPos, firstPos),
);

assertNonNegativeInteger(
lastPos,
Msg.InvalidNonNegativeInt(ABNF.LastPos, lastPos),
);

return `${firstPos}-${lastPos}`;
}

function stringifyContentLength(completeLength: number | undefined): string {
const length = isNumber(completeLength) ? completeLength : "*";
if (!isNumber(completeLength)) return "*";

assertNonNegativeInteger(
completeLength,
Msg.InvalidNonNegativeInt(ABNF.CompleteLength, completeLength),
);

return length.toString();
return completeLength.toString();
}

function stringifyUnsatisfiedRange(unsatisfiedRange: UnsatisfiedRange): string {
return `*/${unsatisfiedRange.completeLength}`;
const { completeLength } = unsatisfiedRange;

assertNonNegativeInteger(
completeLength,
Msg.InvalidNonNegativeInt(ABNF.CompleteLength, completeLength),
);

return `*/${completeLength}`;
}

function isRangeResp(rangeLike: RangeLike): rangeLike is RangeResp {
return "firstPos" in rangeLike;
}

const enum ABNF {
CompleteLength = "<complete-length>",
FirstPos = "<first-pos>",
LastPos = "<last-pos>",
}

const Msg = {
InvalidNonNegativeInt: (subject: string, actual: unknown) =>
`${subject} is not non-negative integer. ${actual}`,
};

function assertNonNegativeInteger(
input: number,
msg?: string,
): asserts input {
if (!isNonNegativeInteger(input)) {
throw TypeError(msg);
}
}
19 changes: 18 additions & 1 deletion content_range_test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type ContentRange, stringify } from "./content_range.ts";
import { assertEquals, describe, it } from "./_dev_deps.ts";
import { assertEquals, assertThrows, describe, it } from "./_dev_deps.ts";

describe("stringify", () => {
it("should return deserialized string if the content rage is valid", () => {
Expand All @@ -22,4 +22,21 @@ describe("stringify", () => {
assertEquals(stringify(contentRange), expected);
});
});

it("should throw error", () => {
const table: ContentRange[] = [
{
rangeUnit: "a",
range: { firstPos: NaN, lastPos: NaN, completeLength: NaN },
},
{
rangeUnit: "a",
range: { firstPos: 0, lastPos: 1, completeLength: -1 },
},
];

table.forEach((contentRange) => {
assertThrows(() => stringify(contentRange));
});
});
});
1 change: 1 addition & 0 deletions deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

export { Status } from "https://deno.land/std@0.180.0/http/http_status.ts";
export {
isNonNegativeInteger,
isNull,
isNumber,
isString,
Expand Down

0 comments on commit 169b15d

Please sign in to comment.