Skip to content

Commit e156c2a

Browse files
committed
docs: add README
1 parent 7e789a1 commit e156c2a

File tree

1 file changed

+201
-0
lines changed

1 file changed

+201
-0
lines changed

README.md

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
# range-middleware
2+
3+
[![deno land](http://img.shields.io/badge/available%20on-deno.land/x-lightgrey.svg?logo=deno)](https://deno.land/x/range_middleware)
4+
[![deno doc](https://doc.deno.land/badge.svg)](https://doc.deno.land/https/deno.land/x/range_middleware/mod.ts)
5+
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/httpland/range-middleware)](https://github.com/httpland/range-middleware/releases)
6+
[![codecov](https://codecov.io/github/httpland/range-middleware/branch/main/graph/badge.svg?token=MNFZEQH8OK)](https://codecov.io/gh/httpland/range-middleware)
7+
[![GitHub](https://img.shields.io/github/license/httpland/range-middleware)](https://github.com/httpland/range-middleware/blob/main/LICENSE)
8+
9+
[![test](https://github.com/httpland/range-middleware/actions/workflows/test.yaml/badge.svg)](https://github.com/httpland/range-middleware/actions/workflows/test.yaml)
10+
[![NPM](https://nodei.co/npm/@httpland/range-middleware.png?mini=true)](https://nodei.co/npm/@httpland/range-middleware/)
11+
12+
HTTP Range Requests middleware.
13+
14+
## What
15+
16+
Handles range request and partial response.
17+
18+
This allows handlers to enable partial responses.
19+
20+
Compliant with
21+
[RFC 9110, 14. Range Requests](https://www.rfc-editor.org/rfc/rfc9110#section-14)
22+
23+
## Usage
24+
25+
Upon receipt of a range request, if the response [satisfies](#satisfiable) the
26+
range requirement [converts](#conversion) it to a partial response.
27+
28+
Headers and status code will be modified accordingly.
29+
30+
```ts
31+
import { range } from "https://deno.land/x/range_middleware/mod.ts";
32+
import {
33+
assert,
34+
assertEquals,
35+
assertThrows,
36+
} from "https://deno.land/[email protected]/testing/asserts.ts";
37+
38+
const middleware = range();
39+
const rangeRequest = new Request("test:", {
40+
headers: { range: "bytes=5-9" },
41+
});
42+
const response = await middleware(
43+
rangeRequest,
44+
() => new Response("abcdefghijklmnopqrstuvwxyz"),
45+
);
46+
47+
assertEquals(response.status, 206);
48+
assertEquals(response.headers.get("content-range", "bytes 5-9/26"));
49+
assertEquals(await response.text(), "fghij");
50+
```
51+
52+
## Multi-range request
53+
54+
For multi-range request, this will be converted to a multipart message body with
55+
`multipart/byteranges`.
56+
57+
```ts
58+
import { range } from "https://deno.land/x/range_middleware@$VERSION/mod.ts";
59+
import {
60+
assert,
61+
assertEquals,
62+
assertThrows,
63+
} from "https://deno.land/[email protected]/testing/asserts.ts";
64+
65+
const middleware = range();
66+
const rangeRequest = new Request("test:", {
67+
headers: { range: "bytes=5-9, 20-, -5" },
68+
});
69+
const response = await middleware(
70+
rangeRequest,
71+
() => new Response("abcdefghijklmnopqrstuvwxyz"),
72+
);
73+
74+
assertEquals(response.status, 206);
75+
assertEquals(
76+
response.headers.get(
77+
"content-type",
78+
"multipart/byteranges; boundary=<boundary-delimiter>",
79+
),
80+
);
81+
assertEquals(
82+
await response.text(),
83+
`--<boundary-delimiter>
84+
Content-Type: text/plain;charset=UTF-8
85+
Content-Range: 5-9/26
86+
87+
fghij
88+
--<boundary-delimiter>
89+
Content-Type: text/plain;charset=UTF-8
90+
Content-Range: 20-25/26
91+
92+
uvwxyz
93+
--<boundary-delimiter>
94+
Content-Type: text/plain;charset=UTF-8
95+
Content-Range: 21-25/26
96+
97+
vwxyz
98+
--<boundary-delimiter>--`,
99+
);
100+
```
101+
102+
## Conditions
103+
104+
There are several conditions that must be met in order for middleware to
105+
execute.
106+
107+
If the following conditions are **not met**,
108+
[invalid](https://www.rfc-editor.org/rfc/rfc9110#section-14.2-6) and the
109+
response is not modified in any way.
110+
111+
- Request method is `GET`.
112+
- Request does not have an `If-Range` header
113+
- Request has a `Range` header
114+
- Request `Range` header is valid syntax
115+
- Request `Range` header is valid semantics
116+
- Response status code is `200`.
117+
- Response `Content-Type` header is present
118+
- Response has `Accept-Ranges` header is not present, or if present, its value
119+
is not `none`.
120+
- The body of the Response is readable.
121+
122+
Note that if there is an `If-Range` header, do nothing.
123+
124+
## Unsatisfiable
125+
126+
If [conditions](#conditions) is met and the following conditions are **not met**
127+
,[unsatisfiable](https://www.rfc-editor.org/rfc/rfc9110#section-14.1.1-12), and
128+
it is not possible to meet partial response.
129+
130+
- If a valid
131+
[ranges-specifier](https://www.rfc-editor.org/rfc/rfc9110#rule.ranges-specifier)
132+
contains at least one satisfactory
133+
[range-spec](https://www.rfc-editor.org/rfc/rfc9110#rule.ranges-specifier), as
134+
defined in the indicated
135+
[range-unit](https://www.rfc-editor.org/rfc/rfc9110#range.units)
136+
137+
In this case, the handler response is [converted](#conversion) to
138+
[416(Range Not Satisfiable)](https://www.rfc-editor.org/rfc/rfc9110#status.416)
139+
response.
140+
141+
A example of how unsatisfiable can happen:
142+
143+
We receive `<range-unit>` and `<range-specifier>` as `Range` headers, which
144+
conform to the syntax but are not supported.
145+
146+
```ts
147+
import { range } from "https://deno.land/x/range_middleware@$VERSION/mod.ts";
148+
import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts";
149+
declare const handler = () => Response;
150+
151+
const middleware = range();
152+
const response = await middleware(
153+
new Request("test:", { headers: { range: "<unknown-unit>=<other-range>" } }),
154+
handler,
155+
);
156+
157+
assertEquals(response.status, 416);
158+
```
159+
160+
## Satisfiable
161+
162+
If the [conditions](#conditions) and [unsatisfiable](#unsatisfiable) are met,
163+
[satisfiable](https://www.rfc-editor.org/rfc/rfc9110#satisfiable), and partial
164+
response is made.
165+
166+
### Conversion
167+
168+
Conversion refers to changing the handler response to the appropriate response.
169+
170+
Specifically, the handler response and the appropriate response are shallow
171+
merged with the appropriate response taking priority over the handler response.
172+
173+
Shallow merge targets are as follows:
174+
175+
- HTTP Status code
176+
- HTTP Content
177+
- HTTP Headers
178+
179+
If status code or body conflicts, it will be replaced by its value in the
180+
appropriate response.
181+
182+
If header fields conflict, the header will be replaced by its value in the
183+
appropriate response header.
184+
185+
## Effects
186+
187+
Middleware may make changes to the following HTTP messages:
188+
189+
- HTTP Content
190+
- HTTP Headers
191+
- Content-Range
192+
- Content-Type
193+
- HTTP Status code
194+
- 206(Partial Content)
195+
- 416(Range Not Satisfiable)
196+
197+
## License
198+
199+
Copyright © 2023-present [httpland](https://github.com/httpland).
200+
201+
Released under the [MIT](./LICENSE) license

0 commit comments

Comments
 (0)