npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@httpland/range-request-middleware

v1.3.0

Published

HTTP range request middleware

Downloads

24

Readme

range-request-middleware

deno land deno doc GitHub release (latest by date) codecov GitHub

test NPM

HTTP range request middleware.

Handles range request and partial response.

Compliant with RFC 9110, 14. Range Requests

Usage

Upon receipt of a range request, if the response satisfies the range requirement, convert it to a partial response.

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");

yield:

HTTP/1.1 206
Content-Range: bytes 5-9/26
Accept-Ranges: bytes

fghij

Multi-range request

For multi-range request, response body will convert to a multipart content.

It compliant with RFC 9110, 14.6. Media Type multipart/byteranges.

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, 20-, -5" },
});
const response = await middleware(
  request,
  () => new Response("abcdefghijklmnopqrstuvwxyz"),
);

assertEquals(response.status, 206);
assertEquals(
  response.headers.get(
    "content-type",
  ),
  "multipart/byteranges; boundary=<boundary-delimiter>",
);
assertEquals(
  await response.text(),
  `--<boundary-delimiter>
Content-Type: text/plain;charset=UTF-8
Content-Range: 5-9/26

fghij
--<boundary-delimiter>
Content-Type: text/plain;charset=UTF-8
Content-Range: 20-25/26

uvwxyz
--<boundary-delimiter>
Content-Type: text/plain;charset=UTF-8
Content-Range: 21-25/26

vwxyz
--<boundary-delimiter>--`,
);

yield:

HTTP/1.1 206
Content-Type: multipart/byteranges; boundary=BOUNDARY
Accept-Ranges: bytes

--BOUNDARY
Content-Type: text/plain;charset=UTF-8
Content-Range: 5-9/26

fghij
--BOUNDARY
Content-Type: text/plain;charset=UTF-8
Content-Range: 20-25/26

uvwxyz
--BOUNDARY
Content-Type: text/plain;charset=UTF-8
Content-Range: 21-25/26

vwxyz
--BOUNDARY--

Conditions

There are several conditions that must be met in order for middleware to execute.

If the following conditions are not met, invalid and the response will not convert.

  • Request method is GET.
  • Request includes Range header
  • Request does not include If-Range header
  • Request Range header is valid syntax
  • Request Range header is valid semantics
  • Response status code is 200
  • Response does not include Content-Range header
  • Response does not include Accept-Ranges header or its value is not none
  • Response body is readable

Note that if there is an If-Range header, do nothing.

Unsatisfiable

If conditions is met and the following conditions are not met ,unsatisfiable, and it is not possible to meet partial response.

In this case, the handler response will convert to 416(Range Not Satisfiable) response.

A example of how unsatisfiable can happen:

If receive un unknown range unit.

import {
  type Handler,
  rangeRequest,
} from "https://deno.land/x/range_request_middleware@$VERSION/mod.ts";
import { assert, assertEquals } from "https://deno.land/std/testing/asserts.ts";

declare const handler: Handler;
const middleware = rangeRequest();
const response = await middleware(
  new Request("test:", { headers: { range: "<unknown-unit>=<other-range>" } }),
  handler,
);

assertEquals(response.status, 416);
assert(response.headers.has("content-range"));

Satisfiable

If the conditions and unsatisfiable are met, satisfiable, and the response will convert to 206(Partial Content) response.

Convert

Convert means a change without side effects.

For example, "convert a response to the 206 response" means to return a new response in which some or all of the following elements have been replaced from the original response.

  • HTTP Content
  • HTTP Status code
  • HTTP Headers(shallow marge)

Range

Range abstracts partial response.

Middleware factories can accept Range objects and implement own range request protocols.

Range is the following structure:

| Name | Type | Description | | --------- | ----------------------------------------------------------------------------------------- | ------------------------------------------- | | rangeUnit | string | Corresponding range unit. | | respond | (response: Response, context: RangesSpecifier) => Response | Promise<Response> | Return response from range request context. |

The middleware supports the following range request protocols by default:

BytesRange

bytes range unit is used to express subranges of a representation data's octet sequence.

ByteRange supports single and multiple range requests.

Compliant with RFC 9110, 14.1.2. Byte Ranges.

import {
  BytesRange,
  type IntRange,
  type SuffixRange,
} from "https://deno.land/x/range_request_middleware@$VERSION/mod.ts";
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";

const bytesRange = new BytesRange();
const rangeUnit = "bytes";
declare const initResponse: Response;
declare const rangeSet: [IntRange, SuffixRange];

const response = await bytesRange.respond(initResponse, {
  rangeUnit,
  rangeSet,
});

assertEquals(bytesRange.rangeUnit, rangeUnit);
assertEquals(response.status, 206);
assertEquals(
  response.headers.get("content-type"),
  "multipart/byteranges; boundary=<BOUNDARY>",
);

Effects

Middleware may make changes to the following HTTP messages:

  • HTTP Content
  • HTTP Headers
    • Accept-Ranges
    • Content-Range
    • Content-Type
  • HTTP Status code
    • 206(Partial Content)
    • 416(Range Not Satisfiable)

License

Copyright © 2023-present httpland.

Released under the MIT license