-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(middleware): add rangeRequest, contentRange and acceptRanges mid…
…dleware
- Loading branch information
1 parent
ff78387
commit 03e8d6b
Showing
3 changed files
with
95 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,63 @@ | ||
// deno-lint-ignore-file no-explicit-any | ||
// Copyright 2023-latest the httpland authors. All rights reserved. MIT license. | ||
// This module is browser compatible. | ||
|
||
import { type Middleware } from "./deps.ts"; | ||
import { withContentRange } from "./transform.ts"; | ||
import { | ||
ConditionalHeader, | ||
isNotEmpty, | ||
isNull, | ||
Method, | ||
type Middleware, | ||
RangeHeader, | ||
} from "./deps.ts"; | ||
import { UnitLike, withAcceptRanges, withContentRange } from "./transform.ts"; | ||
import { BytesRange } from "./ranges/bytes.ts"; | ||
import { RangeUnit } from "./utils.ts"; | ||
import type { Range } from "./types.ts"; | ||
|
||
interface Options { | ||
readonly ranges?: readonly Range<any>[]; | ||
const DefaultRanges = [new BytesRange()]; | ||
|
||
export function rangeRequest(ranges?: Iterable<Range>): Middleware { | ||
const $ranges = ranges ?? DefaultRanges; | ||
const units = Array.from($ranges).map((range) => range.unit); | ||
const unitLike = isNotEmpty(units) ? units : RangeUnit.None; | ||
|
||
const contentRangeMiddleware = contentRange($ranges); | ||
const acceptRangesMiddleware = acceptRanges(unitLike); | ||
|
||
return (request, next) => { | ||
return contentRangeMiddleware( | ||
request, | ||
(request) => acceptRangesMiddleware(request, next), | ||
); | ||
}; | ||
} | ||
|
||
export function contentRange(ranges?: Iterable<Range>): Middleware { | ||
const $ranges = ranges ?? DefaultRanges; | ||
|
||
return async (request, next) => { | ||
const rangeValue = request.headers.get(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 !== Method.Get || | ||
isNull(rangeValue) || | ||
request.headers.has(ConditionalHeader.IfRange) | ||
) return next(request); | ||
|
||
const response = await next(request); | ||
|
||
return withContentRange(response, { ranges: $ranges, rangeValue }); | ||
}; | ||
} | ||
|
||
export function range(options?: Options): Middleware { | ||
const ranges = options?.ranges ?? [new BytesRange() as Range<any>]; | ||
export function acceptRanges(unitLike?: UnitLike): Middleware { | ||
const rangeUnit = unitLike ?? RangeUnit.Bytes; | ||
|
||
return async (request, next) => { | ||
const response = await next(request); | ||
|
||
return withContentRange(request, response, { ranges }); | ||
return withAcceptRanges(response, rangeUnit); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,5 @@ | ||
import { type Middleware } from "./deps.ts"; | ||
import { withContentRange } from "./transform.ts"; | ||
import { BytesRange } from "./ranges/bytes.ts"; | ||
import type { Range } from "./types.ts"; | ||
// Copyright 2023-latest the httpland authors. All rights reserved. MIT license. | ||
// This module is browser compatible. | ||
|
||
interface Options { | ||
readonly ranges?: Iterable<Range>; | ||
} | ||
|
||
export default function rangeRequests(options?: Options): Middleware { | ||
const ranges = options?.ranges ?? [new BytesRange()]; | ||
|
||
return async (request, next) => { | ||
const response = await next(request); | ||
|
||
return withContentRange(request, response, { ranges }); | ||
}; | ||
} | ||
export { acceptRanges, contentRange, rangeRequest } from "./middleware.ts"; | ||
export { type Handler } from "./deps.ts"; |