@helia/verified-fetch 4.1.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -40
- package/dist/index.min.js +73 -534
- package/dist/index.min.js.map +4 -4
- package/dist/src/constants.d.ts +2 -0
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +2 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/index.d.ts +162 -68
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +11 -43
- package/dist/src/index.js.map +1 -1
- package/dist/src/plugins/index.d.ts +0 -5
- package/dist/src/plugins/index.d.ts.map +1 -1
- package/dist/src/plugins/index.js +0 -4
- package/dist/src/plugins/index.js.map +1 -1
- package/dist/src/plugins/plugin-base.d.ts +8 -9
- package/dist/src/plugins/plugin-base.d.ts.map +1 -1
- package/dist/src/plugins/plugin-base.js +5 -6
- package/dist/src/plugins/plugin-base.js.map +1 -1
- package/dist/src/plugins/plugin-handle-car.d.ts +3 -3
- package/dist/src/plugins/plugin-handle-car.d.ts.map +1 -1
- package/dist/src/plugins/plugin-handle-car.js +38 -39
- package/dist/src/plugins/plugin-handle-car.js.map +1 -1
- package/dist/src/plugins/plugin-handle-ipld.d.ts +12 -0
- package/dist/src/plugins/plugin-handle-ipld.d.ts.map +1 -0
- package/dist/src/plugins/plugin-handle-ipld.js +83 -0
- package/dist/src/plugins/plugin-handle-ipld.js.map +1 -0
- package/dist/src/plugins/plugin-handle-ipns-record.d.ts +3 -3
- package/dist/src/plugins/plugin-handle-ipns-record.d.ts.map +1 -1
- package/dist/src/plugins/plugin-handle-ipns-record.js +25 -34
- package/dist/src/plugins/plugin-handle-ipns-record.js.map +1 -1
- package/dist/src/plugins/plugin-handle-tar.d.ts +3 -3
- package/dist/src/plugins/plugin-handle-tar.d.ts.map +1 -1
- package/dist/src/plugins/plugin-handle-tar.js +20 -22
- package/dist/src/plugins/plugin-handle-tar.js.map +1 -1
- package/dist/src/plugins/plugin-handle-unixfs.d.ts +14 -0
- package/dist/src/plugins/plugin-handle-unixfs.d.ts.map +1 -0
- package/dist/src/plugins/plugin-handle-unixfs.js +180 -0
- package/dist/src/plugins/plugin-handle-unixfs.js.map +1 -0
- package/dist/src/plugins/types.d.ts +1 -77
- package/dist/src/plugins/types.d.ts.map +1 -1
- package/dist/src/url-resolver.d.ts +29 -11
- package/dist/src/url-resolver.d.ts.map +1 -1
- package/dist/src/url-resolver.js +152 -74
- package/dist/src/url-resolver.js.map +1 -1
- package/dist/src/utils/content-type-parser.d.ts.map +1 -1
- package/dist/src/utils/content-type-parser.js +4 -3
- package/dist/src/utils/content-type-parser.js.map +1 -1
- package/dist/src/utils/content-types.d.ts +26 -0
- package/dist/src/utils/content-types.d.ts.map +1 -0
- package/dist/src/utils/content-types.js +137 -0
- package/dist/src/utils/content-types.js.map +1 -0
- package/dist/src/utils/convert-output.d.ts +17 -0
- package/dist/src/utils/convert-output.d.ts.map +1 -0
- package/dist/src/utils/convert-output.js +176 -0
- package/dist/src/utils/convert-output.js.map +1 -0
- package/dist/src/utils/error-to-response.d.ts +3 -0
- package/dist/src/utils/error-to-response.d.ts.map +1 -0
- package/dist/src/utils/error-to-response.js +40 -0
- package/dist/src/utils/error-to-response.js.map +1 -0
- package/dist/src/utils/get-content-disposition-filename.d.ts +1 -1
- package/dist/src/utils/get-content-disposition-filename.d.ts.map +1 -1
- package/dist/src/utils/get-content-disposition-filename.js +4 -0
- package/dist/src/utils/get-content-disposition-filename.js.map +1 -1
- package/dist/src/utils/get-e-tag.d.ts +20 -15
- package/dist/src/utils/get-e-tag.d.ts.map +1 -1
- package/dist/src/utils/get-e-tag.js +8 -22
- package/dist/src/utils/get-e-tag.js.map +1 -1
- package/dist/src/utils/get-offset-and-length.d.ts +12 -2
- package/dist/src/utils/get-offset-and-length.d.ts.map +1 -1
- package/dist/src/utils/get-offset-and-length.js +63 -21
- package/dist/src/utils/get-offset-and-length.js.map +1 -1
- package/dist/src/utils/get-range-header.d.ts +22 -0
- package/dist/src/utils/get-range-header.d.ts.map +1 -0
- package/dist/src/utils/get-range-header.js +69 -0
- package/dist/src/utils/get-range-header.js.map +1 -0
- package/dist/src/utils/parse-url-string.d.ts +2 -1
- package/dist/src/utils/parse-url-string.d.ts.map +1 -1
- package/dist/src/utils/parse-url-string.js +46 -71
- package/dist/src/utils/parse-url-string.js.map +1 -1
- package/dist/src/utils/resource-to-cache-key.d.ts +3 -3
- package/dist/src/utils/resource-to-cache-key.js +5 -5
- package/dist/src/utils/resource-to-cache-key.js.map +1 -1
- package/dist/src/utils/response-headers.d.ts +4 -14
- package/dist/src/utils/response-headers.d.ts.map +1 -1
- package/dist/src/utils/response-headers.js +36 -36
- package/dist/src/utils/response-headers.js.map +1 -1
- package/dist/src/utils/responses.d.ts +30 -11
- package/dist/src/utils/responses.d.ts.map +1 -1
- package/dist/src/utils/responses.js +146 -39
- package/dist/src/utils/responses.js.map +1 -1
- package/dist/src/verified-fetch.d.ts +16 -15
- package/dist/src/verified-fetch.d.ts.map +1 -1
- package/dist/src/verified-fetch.js +307 -236
- package/dist/src/verified-fetch.js.map +1 -1
- package/dist/typedoc-urls.json +64 -45
- package/package.json +4 -3
- package/src/constants.ts +3 -0
- package/src/index.ts +203 -71
- package/src/plugins/index.ts +0 -6
- package/src/plugins/plugin-base.ts +8 -10
- package/src/plugins/plugin-handle-car.ts +48 -46
- package/src/plugins/plugin-handle-ipld.ts +93 -0
- package/src/plugins/plugin-handle-ipns-record.ts +31 -41
- package/src/plugins/plugin-handle-tar.ts +25 -29
- package/src/plugins/plugin-handle-unixfs.ts +217 -0
- package/src/plugins/types.ts +0 -86
- package/src/url-resolver.ts +197 -83
- package/src/utils/content-type-parser.ts +4 -3
- package/src/utils/content-types.ts +159 -0
- package/src/utils/convert-output.ts +187 -0
- package/src/utils/error-to-response.ts +49 -0
- package/src/utils/get-content-disposition-filename.ts +7 -1
- package/src/utils/get-e-tag.ts +26 -35
- package/src/utils/get-offset-and-length.ts +75 -21
- package/src/utils/get-range-header.ts +107 -0
- package/src/utils/parse-url-string.ts +51 -80
- package/src/utils/resource-to-cache-key.ts +5 -5
- package/src/utils/response-headers.ts +40 -41
- package/src/utils/responses.ts +186 -45
- package/src/verified-fetch.ts +359 -267
- package/dist/src/plugins/plugin-handle-byte-range-context.d.ts +0 -14
- package/dist/src/plugins/plugin-handle-byte-range-context.d.ts.map +0 -1
- package/dist/src/plugins/plugin-handle-byte-range-context.js +0 -25
- package/dist/src/plugins/plugin-handle-byte-range-context.js.map +0 -1
- package/dist/src/plugins/plugin-handle-cbor.d.ts +0 -17
- package/dist/src/plugins/plugin-handle-cbor.d.ts.map +0 -1
- package/dist/src/plugins/plugin-handle-cbor.js +0 -94
- package/dist/src/plugins/plugin-handle-cbor.js.map +0 -1
- package/dist/src/plugins/plugin-handle-dag-cbor-html-preview.d.ts +0 -27
- package/dist/src/plugins/plugin-handle-dag-cbor-html-preview.d.ts.map +0 -1
- package/dist/src/plugins/plugin-handle-dag-cbor-html-preview.js +0 -279
- package/dist/src/plugins/plugin-handle-dag-cbor-html-preview.js.map +0 -1
- package/dist/src/plugins/plugin-handle-dag-cbor.d.ts +0 -17
- package/dist/src/plugins/plugin-handle-dag-cbor.d.ts.map +0 -1
- package/dist/src/plugins/plugin-handle-dag-cbor.js +0 -66
- package/dist/src/plugins/plugin-handle-dag-cbor.js.map +0 -1
- package/dist/src/plugins/plugin-handle-dag-pb.d.ts +0 -17
- package/dist/src/plugins/plugin-handle-dag-pb.d.ts.map +0 -1
- package/dist/src/plugins/plugin-handle-dag-pb.js +0 -209
- package/dist/src/plugins/plugin-handle-dag-pb.js.map +0 -1
- package/dist/src/plugins/plugin-handle-dag-walk.d.ts +0 -21
- package/dist/src/plugins/plugin-handle-dag-walk.d.ts.map +0 -1
- package/dist/src/plugins/plugin-handle-dag-walk.js +0 -95
- package/dist/src/plugins/plugin-handle-dag-walk.js.map +0 -1
- package/dist/src/plugins/plugin-handle-dir-index-html.d.ts +0 -10
- package/dist/src/plugins/plugin-handle-dir-index-html.d.ts.map +0 -1
- package/dist/src/plugins/plugin-handle-dir-index-html.js +0 -59
- package/dist/src/plugins/plugin-handle-dir-index-html.js.map +0 -1
- package/dist/src/plugins/plugin-handle-json.d.ts +0 -12
- package/dist/src/plugins/plugin-handle-json.d.ts.map +0 -1
- package/dist/src/plugins/plugin-handle-json.js +0 -73
- package/dist/src/plugins/plugin-handle-json.js.map +0 -1
- package/dist/src/plugins/plugin-handle-raw.d.ts +0 -9
- package/dist/src/plugins/plugin-handle-raw.d.ts.map +0 -1
- package/dist/src/plugins/plugin-handle-raw.js +0 -92
- package/dist/src/plugins/plugin-handle-raw.js.map +0 -1
- package/dist/src/plugins/plugins.d.ts +0 -6
- package/dist/src/plugins/plugins.d.ts.map +0 -1
- package/dist/src/plugins/plugins.js +0 -6
- package/dist/src/plugins/plugins.js.map +0 -1
- package/dist/src/utils/byte-range-context.d.ts +0 -103
- package/dist/src/utils/byte-range-context.d.ts.map +0 -1
- package/dist/src/utils/byte-range-context.js +0 -504
- package/dist/src/utils/byte-range-context.js.map +0 -1
- package/dist/src/utils/dag-cbor-to-safe-json.d.ts +0 -15
- package/dist/src/utils/dag-cbor-to-safe-json.d.ts.map +0 -1
- package/dist/src/utils/dag-cbor-to-safe-json.js +0 -54
- package/dist/src/utils/dag-cbor-to-safe-json.js.map +0 -1
- package/dist/src/utils/dir-index-html.d.ts +0 -19
- package/dist/src/utils/dir-index-html.d.ts.map +0 -1
- package/dist/src/utils/dir-index-html.js +0 -438
- package/dist/src/utils/dir-index-html.js.map +0 -1
- package/dist/src/utils/get-peer-id-from-string.d.ts +0 -3
- package/dist/src/utils/get-peer-id-from-string.d.ts.map +0 -1
- package/dist/src/utils/get-peer-id-from-string.js +0 -10
- package/dist/src/utils/get-peer-id-from-string.js.map +0 -1
- package/dist/src/utils/get-resolved-accept-header.d.ts +0 -9
- package/dist/src/utils/get-resolved-accept-header.d.ts.map +0 -1
- package/dist/src/utils/get-resolved-accept-header.js +0 -27
- package/dist/src/utils/get-resolved-accept-header.js.map +0 -1
- package/dist/src/utils/get-stream-from-async-iterable.d.ts +0 -9
- package/dist/src/utils/get-stream-from-async-iterable.d.ts.map +0 -1
- package/dist/src/utils/get-stream-from-async-iterable.js +0 -43
- package/dist/src/utils/get-stream-from-async-iterable.js.map +0 -1
- package/dist/src/utils/handle-redirects.d.ts +0 -16
- package/dist/src/utils/handle-redirects.d.ts.map +0 -1
- package/dist/src/utils/handle-redirects.js +0 -84
- package/dist/src/utils/handle-redirects.js.map +0 -1
- package/dist/src/utils/is-accept-explicit.d.ts +0 -15
- package/dist/src/utils/is-accept-explicit.d.ts.map +0 -1
- package/dist/src/utils/is-accept-explicit.js +0 -26
- package/dist/src/utils/is-accept-explicit.js.map +0 -1
- package/dist/src/utils/request-headers.d.ts +0 -13
- package/dist/src/utils/request-headers.d.ts.map +0 -1
- package/dist/src/utils/request-headers.js +0 -63
- package/dist/src/utils/request-headers.js.map +0 -1
- package/dist/src/utils/select-output-type.d.ts +0 -17
- package/dist/src/utils/select-output-type.d.ts.map +0 -1
- package/dist/src/utils/select-output-type.js +0 -153
- package/dist/src/utils/select-output-type.js.map +0 -1
- package/dist/src/utils/tlru.d.ts +0 -15
- package/dist/src/utils/tlru.d.ts.map +0 -1
- package/dist/src/utils/tlru.js +0 -34
- package/dist/src/utils/tlru.js.map +0 -1
- package/dist/src/utils/walk-path.d.ts +0 -27
- package/dist/src/utils/walk-path.d.ts.map +0 -1
- package/dist/src/utils/walk-path.js +0 -45
- package/dist/src/utils/walk-path.js.map +0 -1
- package/src/plugins/plugin-handle-byte-range-context.ts +0 -30
- package/src/plugins/plugin-handle-cbor.ts +0 -107
- package/src/plugins/plugin-handle-dag-cbor-html-preview.ts +0 -295
- package/src/plugins/plugin-handle-dag-cbor.ts +0 -83
- package/src/plugins/plugin-handle-dag-pb.ts +0 -248
- package/src/plugins/plugin-handle-dag-walk.ts +0 -110
- package/src/plugins/plugin-handle-dir-index-html.ts +0 -72
- package/src/plugins/plugin-handle-json.ts +0 -80
- package/src/plugins/plugin-handle-raw.ts +0 -110
- package/src/plugins/plugins.ts +0 -5
- package/src/utils/byte-range-context.ts +0 -597
- package/src/utils/dag-cbor-to-safe-json.ts +0 -63
- package/src/utils/dir-index-html.ts +0 -505
- package/src/utils/get-peer-id-from-string.ts +0 -12
- package/src/utils/get-resolved-accept-header.ts +0 -42
- package/src/utils/get-stream-from-async-iterable.ts +0 -49
- package/src/utils/handle-redirects.ts +0 -109
- package/src/utils/is-accept-explicit.ts +0 -38
- package/src/utils/request-headers.ts +0 -65
- package/src/utils/select-output-type.ts +0 -175
- package/src/utils/tlru.ts +0 -42
- package/src/utils/walk-path.ts +0 -68
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-handle-raw.js","sourceRoot":"","sources":["../../../src/plugins/plugin-handle-raw.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Export extension (non-default) plugins here
|
|
3
|
-
*/
|
|
4
|
-
export { DirIndexHtmlPlugin, dirIndexHtmlPluginFactory } from './plugin-handle-dir-index-html.js';
|
|
5
|
-
export { DagCborHtmlPreviewPlugin, dagCborHtmlPreviewPluginFactory } from './plugin-handle-dag-cbor-html-preview.js';
|
|
6
|
-
//# sourceMappingURL=plugins.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.d.ts","sourceRoot":"","sources":["../../../src/plugins/plugins.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAA;AACjG,OAAO,EAAE,wBAAwB,EAAE,+BAA+B,EAAE,MAAM,0CAA0C,CAAA"}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Export extension (non-default) plugins here
|
|
3
|
-
*/
|
|
4
|
-
export { DirIndexHtmlPlugin, dirIndexHtmlPluginFactory } from './plugin-handle-dir-index-html.js';
|
|
5
|
-
export { DagCborHtmlPreviewPlugin, dagCborHtmlPreviewPluginFactory } from './plugin-handle-dag-cbor-html-preview.js';
|
|
6
|
-
//# sourceMappingURL=plugins.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.js","sourceRoot":"","sources":["../../../src/plugins/plugins.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAA;AACjG,OAAO,EAAE,wBAAwB,EAAE,+BAA+B,EAAE,MAAM,0CAA0C,CAAA"}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import type { SupportedBodyTypes } from '../index.js';
|
|
2
|
-
import type { Logger } from '@libp2p/interface';
|
|
3
|
-
interface RequestRange {
|
|
4
|
-
start: number | undefined;
|
|
5
|
-
end: number | undefined;
|
|
6
|
-
}
|
|
7
|
-
interface ByteRange extends RequestRange {
|
|
8
|
-
size: number | undefined;
|
|
9
|
-
}
|
|
10
|
-
export declare class ByteRangeContext {
|
|
11
|
-
private readonly headers?;
|
|
12
|
-
readonly isRangeRequest: boolean;
|
|
13
|
-
/**
|
|
14
|
-
* This property is purposefully only set in `set fileSize` and should not be set directly.
|
|
15
|
-
*/
|
|
16
|
-
private _fileSize;
|
|
17
|
-
private _body;
|
|
18
|
-
private readonly rangeRequestHeader;
|
|
19
|
-
private readonly log;
|
|
20
|
-
/**
|
|
21
|
-
* multiPartBoundary is required for multipart responses
|
|
22
|
-
*/
|
|
23
|
-
private readonly multiPartBoundary?;
|
|
24
|
-
private readonly requestRanges;
|
|
25
|
-
private byteRanges;
|
|
26
|
-
readonly isMultiRangeRequest: boolean;
|
|
27
|
-
private _isValidRangeRequest;
|
|
28
|
-
constructor(logger: Logger, headers?: HeadersInit | undefined);
|
|
29
|
-
getByteRanges(): ByteRange[];
|
|
30
|
-
/**
|
|
31
|
-
* You can pass a function when you need to support multi-range requests but have your own slicing logic, such as in the case of dag-pb/unixfs.
|
|
32
|
-
*
|
|
33
|
-
* @param bodyOrProvider - A supported body type or a function that returns a supported body type.
|
|
34
|
-
* @param contentType - The content type of the body.
|
|
35
|
-
*/
|
|
36
|
-
setBody(bodyOrProvider: SupportedBodyTypes | ((range: ByteRange) => AsyncGenerator<Uint8Array, void, unknown>), contentType?: string): void;
|
|
37
|
-
getBody(responseContentType?: string): SupportedBodyTypes;
|
|
38
|
-
private getSlicedBody;
|
|
39
|
-
/**
|
|
40
|
-
* Sometimes, we need to set the fileSize explicitly because we can't calculate
|
|
41
|
-
* the size of the body (e.g. for unixfs content where we call .stat).
|
|
42
|
-
*
|
|
43
|
-
* This fileSize should otherwise only be called from `setBody`.
|
|
44
|
-
*/
|
|
45
|
-
setFileSize(size: number | bigint | null): void;
|
|
46
|
-
getFileSize(): number | null | undefined;
|
|
47
|
-
private isValidByteStart;
|
|
48
|
-
private isValidByteEnd;
|
|
49
|
-
private isValidByteRange;
|
|
50
|
-
/**
|
|
51
|
-
* We may get the values required to determine if this is a valid range request at different times
|
|
52
|
-
* so we need to calculate it when asked.
|
|
53
|
-
*/
|
|
54
|
-
get isValidRangeRequest(): boolean;
|
|
55
|
-
/**
|
|
56
|
-
* Given all the information we have, this function returns the length that will be used when:
|
|
57
|
-
* 1. calling unixfs.cat
|
|
58
|
-
* 2. slicing the body
|
|
59
|
-
*/
|
|
60
|
-
getLength(range?: ByteRange): number | undefined;
|
|
61
|
-
/**
|
|
62
|
-
* Converts a range request header into helia/unixfs supported range options
|
|
63
|
-
* Note that the gateway specification says we "MAY" support multiple ranges (https://specs.ipfs.tech/http-gateways/path-gateway/#range-request-header) but we don't
|
|
64
|
-
*
|
|
65
|
-
* Also note that @helia/unixfs and ipfs-unixfs-exporter expect length and offset to be numbers, the range header is a string, and the size of the resource is likely a bigint.
|
|
66
|
-
*
|
|
67
|
-
* SUPPORTED:
|
|
68
|
-
* Range: bytes=<range-start>-<range-end>
|
|
69
|
-
* Range: bytes=<range-start>-
|
|
70
|
-
* Range: bytes=-<suffix-length> // must pass size so we can calculate the offset. suffix-length is the number of bytes from the end of the file.
|
|
71
|
-
* Range: bytes=<range-start>-<range-end>, <range-start>-<range-end>
|
|
72
|
-
* Range: bytes=<range-start>-<range-end>, <range-start>-<range-end>, <range-start>-<range-end>
|
|
73
|
-
*
|
|
74
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range#directives
|
|
75
|
-
*/
|
|
76
|
-
private setOffsetDetails;
|
|
77
|
-
/**
|
|
78
|
-
* Helper to convert a SliceableBody to a Uint8Array
|
|
79
|
-
*/
|
|
80
|
-
private convertToUint8Array;
|
|
81
|
-
private getMultipartBody;
|
|
82
|
-
private getSlicedBodyForRange;
|
|
83
|
-
/**
|
|
84
|
-
* Returns the content type for the response.
|
|
85
|
-
* For multipart ranges, this will be multipart/byteranges with a boundary.
|
|
86
|
-
*/
|
|
87
|
-
getContentType(): string | undefined;
|
|
88
|
-
/**
|
|
89
|
-
* This function returns the value of the "content-range" header.
|
|
90
|
-
*
|
|
91
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range
|
|
92
|
-
*
|
|
93
|
-
* Returns a string representing the following content ranges:
|
|
94
|
-
*
|
|
95
|
-
* @example
|
|
96
|
-
* - Content-Range: <unit> <byteStart>-<byteEnd>/<byteSize>
|
|
97
|
-
* - Content-Range: <unit> <byteStart>-<byteEnd>/*
|
|
98
|
-
*/
|
|
99
|
-
get contentRangeHeaderValue(): string;
|
|
100
|
-
private createRangeStream;
|
|
101
|
-
}
|
|
102
|
-
export {};
|
|
103
|
-
//# sourceMappingURL=byte-range-context.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"byte-range-context.d.ts","sourceRoot":"","sources":["../../../src/utils/byte-range-context.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAI/C,UAAU,YAAY;IACpB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CACxB;AAED,UAAU,SAAU,SAAQ,YAAY;IACtC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;CACzB;AAuDD,qBAAa,gBAAgB;IAqBE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IApBtD,SAAgB,cAAc,EAAE,OAAO,CAAA;IAEvC;;OAEG;IACH,OAAO,CAAC,SAAS,CAA2B;IAC5C,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAoB;IACvD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAQ;IAC3C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA0D;IACxF,OAAO,CAAC,UAAU,CAAkB;IACpC,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAQ;IAG7C,OAAO,CAAC,oBAAoB,CAAiB;gBAEhC,MAAM,EAAE,MAAM,EAAmB,OAAO,CAAC,EAAE,WAAW,YAAA;IA8B5D,aAAa,IAAK,SAAS,EAAE;IAIpC;;;;;OAKG;IACI,OAAO,CACZ,cAAc,EAAE,kBAAkB,GAAG,CAAC,CAAC,KAAK,EAAE,SAAS,KAAK,cAAc,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,EACtG,WAAW,GAAE,MAAmC,GAC/C,IAAI;IAaA,OAAO,CAAE,mBAAmB,CAAC,EAAE,MAAM,GAAG,kBAAkB;IAsCjE,OAAO,CAAC,aAAa;IA+BrB;;;;;OAKG;IACI,WAAW,CAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI;IAQhD,WAAW,IAAK,MAAM,GAAG,IAAI,GAAG,SAAS;IAIhD,OAAO,CAAC,gBAAgB;IAexB,OAAO,CAAC,cAAc;IAkBtB,OAAO,CAAC,gBAAgB;IAcxB;;;OAGG;IACH,IAAW,mBAAmB,IAAK,OAAO,CAuBzC;IAcD;;;;OAIG;IACI,SAAS,CAAE,KAAK,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS;IA0BxD;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,gBAAgB;IAwBxB;;OAEG;YACW,mBAAmB;YAwBjB,gBAAgB;IAyChC,OAAO,CAAC,qBAAqB;IAwB7B;;;OAGG;IACI,cAAc,IAAK,MAAM,GAAG,SAAS;IAO5C;;;;;;;;;;OAUG;IAEH,IAAW,uBAAuB,IAAK,MAAM,CAuB5C;IAGD,OAAO,CAAC,iBAAiB;CA8D1B"}
|
|
@@ -1,504 +0,0 @@
|
|
|
1
|
-
import toBrowserReadableStream from 'it-to-browser-readablestream';
|
|
2
|
-
import { InvalidRangeError } from '../errors.js';
|
|
3
|
-
import { calculateByteRangeIndexes, getHeader } from './request-headers.js';
|
|
4
|
-
import { getContentRangeHeader } from './response-headers.js';
|
|
5
|
-
/**
|
|
6
|
-
* Gets the body size of a given body if it's possible to calculate it synchronously.
|
|
7
|
-
*/
|
|
8
|
-
function getBodySizeSync(body) {
|
|
9
|
-
if (typeof body === 'string') {
|
|
10
|
-
return body.length;
|
|
11
|
-
}
|
|
12
|
-
if (body instanceof ArrayBuffer || body instanceof Uint8Array) {
|
|
13
|
-
return body.byteLength;
|
|
14
|
-
}
|
|
15
|
-
if (body instanceof Blob) {
|
|
16
|
-
return body.size;
|
|
17
|
-
}
|
|
18
|
-
if (body instanceof ReadableStream) {
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
|
-
function getByteRangeFromHeader(rangeHeader) {
|
|
24
|
-
/**
|
|
25
|
-
* Range: bytes=<start>-<end> | bytes=<start2>- | bytes=-<end2> | bytes=<start1>-<end1>,<start2>-<end2>,...
|
|
26
|
-
*/
|
|
27
|
-
if (!rangeHeader.startsWith('bytes=')) {
|
|
28
|
-
throw new InvalidRangeError('Invalid range request');
|
|
29
|
-
}
|
|
30
|
-
const rangesStr = rangeHeader.substring(6); // Remove "bytes=" prefix
|
|
31
|
-
const rangeParts = rangesStr.split(',').map(part => part.trim());
|
|
32
|
-
const ranges = [];
|
|
33
|
-
for (const part of rangeParts) {
|
|
34
|
-
const match = part.match(/^(?<start>\d+)?-(?<end>\d+)?$/);
|
|
35
|
-
if (match?.groups == null) {
|
|
36
|
-
throw new InvalidRangeError(`Invalid range specification: ${part}`);
|
|
37
|
-
}
|
|
38
|
-
const { start, end } = match.groups;
|
|
39
|
-
ranges.push({
|
|
40
|
-
start: start ?? null,
|
|
41
|
-
end: end ?? null
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
if (ranges.length === 0) {
|
|
45
|
-
throw new InvalidRangeError('No valid ranges found');
|
|
46
|
-
}
|
|
47
|
-
return { ranges };
|
|
48
|
-
}
|
|
49
|
-
export class ByteRangeContext {
|
|
50
|
-
headers;
|
|
51
|
-
isRangeRequest;
|
|
52
|
-
/**
|
|
53
|
-
* This property is purposefully only set in `set fileSize` and should not be set directly.
|
|
54
|
-
*/
|
|
55
|
-
_fileSize;
|
|
56
|
-
_body = null;
|
|
57
|
-
rangeRequestHeader;
|
|
58
|
-
log;
|
|
59
|
-
/**
|
|
60
|
-
* multiPartBoundary is required for multipart responses
|
|
61
|
-
*/
|
|
62
|
-
multiPartBoundary;
|
|
63
|
-
requestRanges = [];
|
|
64
|
-
byteRanges = [];
|
|
65
|
-
isMultiRangeRequest = false;
|
|
66
|
-
// to be set by isValidRangeRequest so that we don't need to re-check the byteRanges
|
|
67
|
-
_isValidRangeRequest = false;
|
|
68
|
-
constructor(logger, headers) {
|
|
69
|
-
this.headers = headers;
|
|
70
|
-
this.log = logger.newScope('byte-range-context');
|
|
71
|
-
this.rangeRequestHeader = getHeader(this.headers, 'Range');
|
|
72
|
-
if (this.rangeRequestHeader != null) {
|
|
73
|
-
this.isRangeRequest = true;
|
|
74
|
-
this.log.trace('range request detected');
|
|
75
|
-
try {
|
|
76
|
-
const { ranges } = getByteRangeFromHeader(this.rangeRequestHeader);
|
|
77
|
-
this.isMultiRangeRequest = ranges.length > 1;
|
|
78
|
-
this.requestRanges = ranges.map(range => ({
|
|
79
|
-
start: range.start != null ? parseInt(range.start) : null,
|
|
80
|
-
end: range.end != null ? parseInt(range.end) : null
|
|
81
|
-
}));
|
|
82
|
-
this.multiPartBoundary = `multipart_byteranges_${Math.floor(Math.random() * 1000000000)}`;
|
|
83
|
-
}
|
|
84
|
-
catch (e) {
|
|
85
|
-
this.log.error('error parsing range request header - %e', e);
|
|
86
|
-
this.requestRanges = [];
|
|
87
|
-
}
|
|
88
|
-
this.setOffsetDetails();
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
this.log.trace('no range request detected');
|
|
92
|
-
this.isRangeRequest = false;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
getByteRanges() {
|
|
96
|
-
return this.byteRanges;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* You can pass a function when you need to support multi-range requests but have your own slicing logic, such as in the case of dag-pb/unixfs.
|
|
100
|
-
*
|
|
101
|
-
* @param bodyOrProvider - A supported body type or a function that returns a supported body type.
|
|
102
|
-
* @param contentType - The content type of the body.
|
|
103
|
-
*/
|
|
104
|
-
setBody(bodyOrProvider, contentType = 'application/octet-stream') {
|
|
105
|
-
if (typeof bodyOrProvider === 'function') {
|
|
106
|
-
this._body = this.createRangeStream(bodyOrProvider, contentType);
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
this._body = bodyOrProvider;
|
|
110
|
-
// if fileSize was already set, don't recalculate it
|
|
111
|
-
this.setFileSize(this._fileSize ?? getBodySizeSync(bodyOrProvider));
|
|
112
|
-
}
|
|
113
|
-
this.log.trace('set request body with fileSize %o', this._fileSize);
|
|
114
|
-
}
|
|
115
|
-
getBody(responseContentType) {
|
|
116
|
-
const body = this._body;
|
|
117
|
-
if (body == null) {
|
|
118
|
-
this.log.trace('body is null');
|
|
119
|
-
return body;
|
|
120
|
-
}
|
|
121
|
-
if (!this.isRangeRequest || !this.isValidRangeRequest) {
|
|
122
|
-
this.log.trace('returning body unmodified for non-range, or invalid range, request');
|
|
123
|
-
return body;
|
|
124
|
-
}
|
|
125
|
-
if (this.isMultiRangeRequest) {
|
|
126
|
-
if (this._body instanceof ReadableStream) {
|
|
127
|
-
return this._body;
|
|
128
|
-
}
|
|
129
|
-
return toBrowserReadableStream(this.getMultipartBody(responseContentType));
|
|
130
|
-
}
|
|
131
|
-
// Single range request handling
|
|
132
|
-
if (this.byteRanges.length > 0) {
|
|
133
|
-
const range = this.byteRanges[0];
|
|
134
|
-
if (body instanceof ReadableStream) {
|
|
135
|
-
// stream should already be spliced by `unixfs.cat`
|
|
136
|
-
// TODO: if the content is not unixfs and unixfs.cat was not called, we need to slice the body here.
|
|
137
|
-
return body;
|
|
138
|
-
}
|
|
139
|
-
if (range.start != null || range.end != null) {
|
|
140
|
-
this.log.trace('returning body with byteStart=%o, byteEnd=%o, byteSize=%o', range.start, range.end, range.size);
|
|
141
|
-
}
|
|
142
|
-
return this.getSlicedBody(body, range);
|
|
143
|
-
}
|
|
144
|
-
// we should not reach this point, but return body untouched.
|
|
145
|
-
this.log.error('returning unmodified body for valid range request');
|
|
146
|
-
return body;
|
|
147
|
-
}
|
|
148
|
-
getSlicedBody(body, range) {
|
|
149
|
-
const offset = range.start ?? 0;
|
|
150
|
-
// Calculate the correct number of bytes to return
|
|
151
|
-
// For a range like bytes=1000-2000, we want exactly 1001 bytes
|
|
152
|
-
let length;
|
|
153
|
-
if (range.end != null && range.start != null) {
|
|
154
|
-
// Exact number of bytes is (end - start + 1) due to inclusive ranges
|
|
155
|
-
length = range.end - range.start + 1;
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
length = undefined;
|
|
159
|
-
}
|
|
160
|
-
this.log.trace('slicing body with offset=%o and length=%o', offset, length);
|
|
161
|
-
if (typeof body === 'string') {
|
|
162
|
-
// String slicing works with start and end indices
|
|
163
|
-
return body.slice(offset, length !== undefined ? offset + length : undefined);
|
|
164
|
-
}
|
|
165
|
-
else if (body instanceof Blob) {
|
|
166
|
-
// Blob.slice takes start and end positions
|
|
167
|
-
return body.slice(offset, length !== undefined ? offset + length : undefined);
|
|
168
|
-
}
|
|
169
|
-
else if (body instanceof ArrayBuffer || body instanceof Uint8Array) {
|
|
170
|
-
// ArrayBuffer.slice and Uint8Array.slice take start and end positions
|
|
171
|
-
return body.slice(offset, length !== undefined ? offset + length : undefined);
|
|
172
|
-
}
|
|
173
|
-
// This should never happen due to type constraints
|
|
174
|
-
return body;
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Sometimes, we need to set the fileSize explicitly because we can't calculate
|
|
178
|
-
* the size of the body (e.g. for unixfs content where we call .stat).
|
|
179
|
-
*
|
|
180
|
-
* This fileSize should otherwise only be called from `setBody`.
|
|
181
|
-
*/
|
|
182
|
-
setFileSize(size) {
|
|
183
|
-
this._fileSize = size != null ? Number(size) : null;
|
|
184
|
-
this._isValidRangeRequest = false; // body has changed, so we need to re-validate the byte ranges
|
|
185
|
-
this.log.trace('set _fileSize to %o', this._fileSize);
|
|
186
|
-
// when fileSize changes, we need to recalculate the offset details
|
|
187
|
-
this.setOffsetDetails();
|
|
188
|
-
}
|
|
189
|
-
getFileSize() {
|
|
190
|
-
return this._fileSize;
|
|
191
|
-
}
|
|
192
|
-
isValidByteStart(byteStart, byteEnd) {
|
|
193
|
-
if (byteStart != null) {
|
|
194
|
-
if (byteStart < 0) {
|
|
195
|
-
return false;
|
|
196
|
-
}
|
|
197
|
-
if (this._fileSize != null && byteStart >= this._fileSize) {
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
|
-
if (byteEnd != null && byteStart > byteEnd) {
|
|
201
|
-
return false;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
return true;
|
|
205
|
-
}
|
|
206
|
-
isValidByteEnd(byteStart, byteEnd) {
|
|
207
|
-
if (byteEnd != null) {
|
|
208
|
-
if (byteEnd < 0) {
|
|
209
|
-
this.log.trace('invalid range request, byteEnd is less than 0');
|
|
210
|
-
return false;
|
|
211
|
-
}
|
|
212
|
-
if (this._fileSize != null && byteEnd >= this._fileSize) {
|
|
213
|
-
this.log.trace('invalid range request, byteEnd is greater than fileSize');
|
|
214
|
-
return false;
|
|
215
|
-
}
|
|
216
|
-
if (byteStart != null && byteEnd < byteStart) {
|
|
217
|
-
this.log.trace('invalid range request, byteEnd is less than byteStart');
|
|
218
|
-
return false;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
return true;
|
|
222
|
-
}
|
|
223
|
-
isValidByteRange(range) {
|
|
224
|
-
this.log.trace('validating byte range: %o', range);
|
|
225
|
-
if (range.start != null && !this.isValidByteStart(range.start, range.end)) {
|
|
226
|
-
this.log.trace('invalid range request, byteStart is less than 0 or greater than fileSize');
|
|
227
|
-
return false;
|
|
228
|
-
}
|
|
229
|
-
if (range.end != null && !this.isValidByteEnd(range.start, range.end)) {
|
|
230
|
-
this.log.trace('invalid range request, byteEnd is less than 0 or greater than fileSize');
|
|
231
|
-
return false;
|
|
232
|
-
}
|
|
233
|
-
return true;
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* We may get the values required to determine if this is a valid range request at different times
|
|
237
|
-
* so we need to calculate it when asked.
|
|
238
|
-
*/
|
|
239
|
-
get isValidRangeRequest() {
|
|
240
|
-
if (this._isValidRangeRequest) {
|
|
241
|
-
// prevent unnecessary re-validation of each byte range
|
|
242
|
-
return true;
|
|
243
|
-
}
|
|
244
|
-
if (!this.isRangeRequest) {
|
|
245
|
-
return false;
|
|
246
|
-
}
|
|
247
|
-
if (this.byteRanges.length === 0) {
|
|
248
|
-
this.log.trace('invalid range request, no valid ranges');
|
|
249
|
-
return false;
|
|
250
|
-
}
|
|
251
|
-
const isValid = this.byteRanges.every(range => this.isValidByteRange(range));
|
|
252
|
-
if (!isValid) {
|
|
253
|
-
this.log.trace('invalid range request, not all ranges are valid');
|
|
254
|
-
return false;
|
|
255
|
-
}
|
|
256
|
-
this._isValidRangeRequest = true;
|
|
257
|
-
return true;
|
|
258
|
-
}
|
|
259
|
-
// /**
|
|
260
|
-
// * Given all the information we have, this function returns the offset that will be used when:
|
|
261
|
-
// * 1. calling unixfs.cat
|
|
262
|
-
// * 2. slicing the body
|
|
263
|
-
// */
|
|
264
|
-
// public offset (range: ByteRange): number {
|
|
265
|
-
// if (this.byteRanges.length > 0) {
|
|
266
|
-
// return this.byteRanges[0].start ?? 0
|
|
267
|
-
// }
|
|
268
|
-
// return 0
|
|
269
|
-
// }
|
|
270
|
-
/**
|
|
271
|
-
* Given all the information we have, this function returns the length that will be used when:
|
|
272
|
-
* 1. calling unixfs.cat
|
|
273
|
-
* 2. slicing the body
|
|
274
|
-
*/
|
|
275
|
-
getLength(range) {
|
|
276
|
-
if (!this.isValidRangeRequest) {
|
|
277
|
-
this.log.error('cannot get length for invalid range request');
|
|
278
|
-
return undefined;
|
|
279
|
-
}
|
|
280
|
-
if (this.isMultiRangeRequest && range == null) {
|
|
281
|
-
/**
|
|
282
|
-
* The content-length for a multi-range request is the sum of the lengths of all the ranges, plus the boundaries and part headers and newlines.
|
|
283
|
-
*/
|
|
284
|
-
// TODO: figure out a way to calculate the correct content-length for multi-range requests' response.
|
|
285
|
-
return undefined;
|
|
286
|
-
}
|
|
287
|
-
range ??= this.byteRanges[0];
|
|
288
|
-
this.log.trace('getting length for range: %o', range);
|
|
289
|
-
if (range.end != null && range.start != null) {
|
|
290
|
-
// For a range like bytes=1000-2000, we want a length of 1001 bytes
|
|
291
|
-
return range.end - range.start + 1;
|
|
292
|
-
}
|
|
293
|
-
if (range.end != null) {
|
|
294
|
-
return range.end + 1;
|
|
295
|
-
}
|
|
296
|
-
return range.size;
|
|
297
|
-
}
|
|
298
|
-
/**
|
|
299
|
-
* Converts a range request header into helia/unixfs supported range options
|
|
300
|
-
* Note that the gateway specification says we "MAY" support multiple ranges (https://specs.ipfs.tech/http-gateways/path-gateway/#range-request-header) but we don't
|
|
301
|
-
*
|
|
302
|
-
* Also note that @helia/unixfs and ipfs-unixfs-exporter expect length and offset to be numbers, the range header is a string, and the size of the resource is likely a bigint.
|
|
303
|
-
*
|
|
304
|
-
* SUPPORTED:
|
|
305
|
-
* Range: bytes=<range-start>-<range-end>
|
|
306
|
-
* Range: bytes=<range-start>-
|
|
307
|
-
* Range: bytes=-<suffix-length> // must pass size so we can calculate the offset. suffix-length is the number of bytes from the end of the file.
|
|
308
|
-
* Range: bytes=<range-start>-<range-end>, <range-start>-<range-end>
|
|
309
|
-
* Range: bytes=<range-start>-<range-end>, <range-start>-<range-end>, <range-start>-<range-end>
|
|
310
|
-
*
|
|
311
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range#directives
|
|
312
|
-
*/
|
|
313
|
-
setOffsetDetails() {
|
|
314
|
-
if (this.requestRanges.length === 0) {
|
|
315
|
-
this.log.trace('no request ranges defined');
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
try {
|
|
319
|
-
// Calculate byte ranges for all requests
|
|
320
|
-
this.byteRanges = this.requestRanges.map(range => {
|
|
321
|
-
const { start, end, byteSize } = calculateByteRangeIndexes(range.start ?? undefined, range.end ?? undefined, this._fileSize ?? undefined);
|
|
322
|
-
return { start, end, size: byteSize };
|
|
323
|
-
});
|
|
324
|
-
this.log.trace('set byte ranges: %o', this.byteRanges);
|
|
325
|
-
}
|
|
326
|
-
catch (e) {
|
|
327
|
-
this.log.error('error setting offset details: %o', e);
|
|
328
|
-
this.byteRanges = [];
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
/**
|
|
332
|
-
* Helper to convert a SliceableBody to a Uint8Array
|
|
333
|
-
*/
|
|
334
|
-
async convertToUint8Array(content) {
|
|
335
|
-
if (typeof content === 'string') {
|
|
336
|
-
return new TextEncoder().encode(content);
|
|
337
|
-
}
|
|
338
|
-
if ('arrayBuffer' in content && typeof content.arrayBuffer === 'function') {
|
|
339
|
-
// This is a Blob
|
|
340
|
-
const buffer = await content.arrayBuffer();
|
|
341
|
-
return new Uint8Array(buffer);
|
|
342
|
-
}
|
|
343
|
-
if ('byteLength' in content && !('buffer' in content)) {
|
|
344
|
-
// This is an ArrayBuffer
|
|
345
|
-
return new Uint8Array(content);
|
|
346
|
-
}
|
|
347
|
-
if ('buffer' in content && 'byteLength' in content && 'byteOffset' in content) {
|
|
348
|
-
// This is a Uint8Array
|
|
349
|
-
return content;
|
|
350
|
-
}
|
|
351
|
-
throw new Error('Unsupported content type for multipart response');
|
|
352
|
-
}
|
|
353
|
-
async *getMultipartBody(responseContentType = 'application/octet-stream') {
|
|
354
|
-
const body = this._body;
|
|
355
|
-
if (body instanceof ReadableStream) {
|
|
356
|
-
// in the case of unixfs, the body is a readable stream, and setBody is called with a function that returns a readable stream that generates the
|
|
357
|
-
// correct multipartBody.. so we just return that body.
|
|
358
|
-
return body;
|
|
359
|
-
}
|
|
360
|
-
if (body === null) {
|
|
361
|
-
throw new Error('Cannot create multipart body from null');
|
|
362
|
-
}
|
|
363
|
-
const encoder = new TextEncoder();
|
|
364
|
-
for (const range of this.byteRanges) {
|
|
365
|
-
if (range.start === undefined || range.end === undefined) {
|
|
366
|
-
continue;
|
|
367
|
-
}
|
|
368
|
-
// Calculate part headers
|
|
369
|
-
const partHeaderString = `\r\n--${this.multiPartBoundary}\r\n` +
|
|
370
|
-
`Content-Type: ${responseContentType}\r\n` +
|
|
371
|
-
`Content-Range: ${getContentRangeHeader({
|
|
372
|
-
byteStart: range.start,
|
|
373
|
-
byteEnd: range.end,
|
|
374
|
-
byteSize: this._fileSize ?? undefined
|
|
375
|
-
})}\r\n\r\n`;
|
|
376
|
-
// Convert header to Uint8Array
|
|
377
|
-
yield encoder.encode(partHeaderString);
|
|
378
|
-
// Get content for this range and convert to Uint8Array
|
|
379
|
-
const slicedContent = this.getSlicedBodyForRange(body, range.start, range.end);
|
|
380
|
-
yield await this.convertToUint8Array(slicedContent);
|
|
381
|
-
}
|
|
382
|
-
// Add final this.multiPartBoundary
|
|
383
|
-
yield encoder.encode(`\r\n--${this.multiPartBoundary}--`);
|
|
384
|
-
}
|
|
385
|
-
getSlicedBodyForRange(body, start, end) {
|
|
386
|
-
// Calculate the correct number of bytes to return
|
|
387
|
-
// For a range like bytes=1000-2000, we want exactly 1001 bytes
|
|
388
|
-
const offset = start;
|
|
389
|
-
const length = end - start + 1;
|
|
390
|
-
this.log.trace('slicing body with offset=%o and length=%o', offset, length);
|
|
391
|
-
if (typeof body === 'string') {
|
|
392
|
-
return body.slice(offset, offset + length);
|
|
393
|
-
}
|
|
394
|
-
else if (body instanceof Blob) {
|
|
395
|
-
return body.slice(offset, offset + length);
|
|
396
|
-
}
|
|
397
|
-
else if (body instanceof ArrayBuffer || body instanceof Uint8Array) {
|
|
398
|
-
return body.slice(offset, offset + length);
|
|
399
|
-
}
|
|
400
|
-
else {
|
|
401
|
-
// This should never happen due to type constraints
|
|
402
|
-
return body;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
/**
|
|
406
|
-
* Returns the content type for the response.
|
|
407
|
-
* For multipart ranges, this will be multipart/byteranges with a boundary.
|
|
408
|
-
*/
|
|
409
|
-
getContentType() {
|
|
410
|
-
if (this.isMultiRangeRequest && this.isValidRangeRequest) {
|
|
411
|
-
return `multipart/byteranges; boundary=${this.multiPartBoundary}`;
|
|
412
|
-
}
|
|
413
|
-
return undefined;
|
|
414
|
-
}
|
|
415
|
-
/**
|
|
416
|
-
* This function returns the value of the "content-range" header.
|
|
417
|
-
*
|
|
418
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range
|
|
419
|
-
*
|
|
420
|
-
* Returns a string representing the following content ranges:
|
|
421
|
-
*
|
|
422
|
-
* @example
|
|
423
|
-
* - Content-Range: <unit> <byteStart>-<byteEnd>/<byteSize>
|
|
424
|
-
* - Content-Range: <unit> <byteStart>-<byteEnd>/*
|
|
425
|
-
*/
|
|
426
|
-
// - Content-Range: <unit> */<byteSize> // this is purposefully not in jsdoc block
|
|
427
|
-
get contentRangeHeaderValue() {
|
|
428
|
-
// For multipart responses, this will be included in each part
|
|
429
|
-
// So this method is only used for single-range responses
|
|
430
|
-
if (!this.isValidRangeRequest) {
|
|
431
|
-
this.log.error('cannot get contentRangeHeaderValue for invalid range request');
|
|
432
|
-
throw new InvalidRangeError('Invalid range request');
|
|
433
|
-
}
|
|
434
|
-
if (this.isMultiRangeRequest) {
|
|
435
|
-
this.log.error('contentRangeHeaderValue should not be called for multipart responses');
|
|
436
|
-
throw new InvalidRangeError('Content-Range header not applicable for multipart responses');
|
|
437
|
-
}
|
|
438
|
-
if (this.byteRanges.length > 0) {
|
|
439
|
-
const range = this.byteRanges[0];
|
|
440
|
-
return getContentRangeHeader({
|
|
441
|
-
byteStart: range.start,
|
|
442
|
-
byteEnd: range.end,
|
|
443
|
-
byteSize: this._fileSize ?? undefined
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
|
-
throw new InvalidRangeError('No valid ranges found');
|
|
447
|
-
}
|
|
448
|
-
// Unified method to create a stream for either single or multi-range requests
|
|
449
|
-
createRangeStream(contentProvider, contentType) {
|
|
450
|
-
const encoder = new TextEncoder();
|
|
451
|
-
const byteRanges = this.byteRanges;
|
|
452
|
-
const multiPartBoundary = this.multiPartBoundary;
|
|
453
|
-
const fileSize = this._fileSize;
|
|
454
|
-
const log = this.log;
|
|
455
|
-
const isMultiRangeRequest = this.isMultiRangeRequest;
|
|
456
|
-
if (byteRanges.length === 0) {
|
|
457
|
-
// TODO: create a stream with a range of *
|
|
458
|
-
log.error('Cannot create range stream with no byte ranges');
|
|
459
|
-
throw new InvalidRangeError('No valid ranges found');
|
|
460
|
-
}
|
|
461
|
-
return new ReadableStream({
|
|
462
|
-
async start(controller) {
|
|
463
|
-
try {
|
|
464
|
-
// For multi-range requests, we need to handle multiple parts with headers
|
|
465
|
-
for (const range of byteRanges) {
|
|
466
|
-
// Write part header for multipart responses
|
|
467
|
-
if (isMultiRangeRequest) {
|
|
468
|
-
const partHeader = `\r\n--${multiPartBoundary}\r\n` +
|
|
469
|
-
`Content-Type: ${contentType}\r\n` +
|
|
470
|
-
`Content-Range: ${getContentRangeHeader({
|
|
471
|
-
byteStart: range.start,
|
|
472
|
-
byteEnd: range.end,
|
|
473
|
-
byteSize: fileSize ?? undefined
|
|
474
|
-
})}\r\n\r\n`;
|
|
475
|
-
controller.enqueue(encoder.encode(partHeader));
|
|
476
|
-
}
|
|
477
|
-
// Get and stream content for this range
|
|
478
|
-
try {
|
|
479
|
-
// Get content for this range
|
|
480
|
-
const rangeContent = contentProvider(range);
|
|
481
|
-
for await (const chunk of rangeContent) {
|
|
482
|
-
controller.enqueue(chunk);
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
catch (err) {
|
|
486
|
-
log.error('Error processing range %o: %o', range, err);
|
|
487
|
-
throw err; // Re-throw to be caught by the outer try/catch
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
if (isMultiRangeRequest) {
|
|
491
|
-
// Write final boundary for multipart
|
|
492
|
-
controller.enqueue(encoder.encode(`\r\n--${multiPartBoundary}--`));
|
|
493
|
-
}
|
|
494
|
-
controller.close();
|
|
495
|
-
}
|
|
496
|
-
catch (err) {
|
|
497
|
-
log.error('Error processing range(s) - %e', err);
|
|
498
|
-
controller.error(err);
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
//# sourceMappingURL=byte-range-context.js.map
|