@helia/verified-fetch 1.1.3 → 1.2.1
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/dist/index.min.js +7 -7
- package/dist/src/types.d.ts +1 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/byte-range-context.d.ts +80 -0
- package/dist/src/utils/byte-range-context.d.ts.map +1 -0
- package/dist/src/utils/byte-range-context.js +277 -0
- package/dist/src/utils/byte-range-context.js.map +1 -0
- package/dist/src/utils/get-stream-from-async-iterable.js +1 -1
- package/dist/src/utils/parse-url-string.js +4 -4
- package/dist/src/utils/request-headers.d.ts +13 -0
- package/dist/src/utils/request-headers.d.ts.map +1 -0
- package/dist/src/utils/request-headers.js +62 -0
- package/dist/src/utils/request-headers.js.map +1 -0
- package/dist/src/utils/response-headers.d.ts +12 -0
- package/dist/src/utils/response-headers.d.ts.map +1 -0
- package/dist/src/utils/response-headers.js +37 -0
- package/dist/src/utils/response-headers.js.map +1 -0
- package/dist/src/utils/responses.d.ts +21 -4
- package/dist/src/utils/responses.d.ts.map +1 -1
- package/dist/src/utils/responses.js +58 -0
- package/dist/src/utils/responses.js.map +1 -1
- package/dist/src/verified-fetch.d.ts.map +1 -1
- package/dist/src/verified-fetch.js +60 -18
- package/dist/src/verified-fetch.js.map +1 -1
- package/package.json +1 -1
- package/src/types.ts +2 -0
- package/src/utils/byte-range-context.ts +301 -0
- package/src/utils/get-stream-from-async-iterable.ts +1 -1
- package/src/utils/parse-url-string.ts +4 -4
- package/src/utils/request-headers.ts +63 -0
- package/src/utils/response-headers.ts +42 -0
- package/src/utils/responses.ts +82 -4
- package/src/verified-fetch.ts +65 -21
package/dist/src/types.d.ts
CHANGED
package/dist/src/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,sBAAsB,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,aAAa,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAA"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,sBAAsB,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,aAAa,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAA;AAEtH,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,WAAW,GAAG,IAAI,GAAG,cAAc,CAAC,UAAU,CAAC,GAAG,IAAI,CAAA"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { SupportedBodyTypes } from '../types.js';
|
|
2
|
+
import type { ComponentLogger } from '@libp2p/interface';
|
|
3
|
+
export declare class ByteRangeContext {
|
|
4
|
+
private readonly headers?;
|
|
5
|
+
readonly isRangeRequest: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* This property is purposefully only set in `set fileSize` and should not be set directly.
|
|
8
|
+
*/
|
|
9
|
+
private _fileSize;
|
|
10
|
+
private _body;
|
|
11
|
+
private readonly rangeRequestHeader;
|
|
12
|
+
private readonly log;
|
|
13
|
+
private readonly requestRangeStart;
|
|
14
|
+
private readonly requestRangeEnd;
|
|
15
|
+
private byteStart;
|
|
16
|
+
private byteEnd;
|
|
17
|
+
private byteSize;
|
|
18
|
+
constructor(logger: ComponentLogger, headers?: HeadersInit | undefined);
|
|
19
|
+
setBody(body: SupportedBodyTypes): void;
|
|
20
|
+
getBody(): SupportedBodyTypes;
|
|
21
|
+
private getSlicedBody;
|
|
22
|
+
/**
|
|
23
|
+
* Sometimes, we need to set the fileSize explicitly because we can't calculate
|
|
24
|
+
* the size of the body (e.g. for unixfs content where we call .stat).
|
|
25
|
+
*
|
|
26
|
+
* This fileSize should otherwise only be called from `setBody`.
|
|
27
|
+
*/
|
|
28
|
+
setFileSize(size: number | bigint | null): void;
|
|
29
|
+
getFileSize(): number | null | undefined;
|
|
30
|
+
private isValidByteStart;
|
|
31
|
+
private isValidByteEnd;
|
|
32
|
+
/**
|
|
33
|
+
* We may get the values required to determine if this is a valid range request at different times
|
|
34
|
+
* so we need to calculate it when asked.
|
|
35
|
+
*/
|
|
36
|
+
get isValidRangeRequest(): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Given all the information we have, this function returns the offset that will be used when:
|
|
39
|
+
* 1. calling unixfs.cat
|
|
40
|
+
* 2. slicing the body
|
|
41
|
+
*/
|
|
42
|
+
get offset(): number;
|
|
43
|
+
/**
|
|
44
|
+
* Given all the information we have, this function returns the length that will be used when:
|
|
45
|
+
* 1. calling unixfs.cat
|
|
46
|
+
* 2. slicing the body
|
|
47
|
+
*/
|
|
48
|
+
get length(): number | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Converts a range request header into helia/unixfs supported range options
|
|
51
|
+
* 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
|
|
52
|
+
*
|
|
53
|
+
* 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.
|
|
54
|
+
*
|
|
55
|
+
* SUPPORTED:
|
|
56
|
+
* Range: bytes=<range-start>-<range-end>
|
|
57
|
+
* Range: bytes=<range-start>-
|
|
58
|
+
* 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.
|
|
59
|
+
*
|
|
60
|
+
* NOT SUPPORTED:
|
|
61
|
+
* Range: bytes=<range-start>-<range-end>, <range-start>-<range-end>
|
|
62
|
+
* Range: bytes=<range-start>-<range-end>, <range-start>-<range-end>, <range-start>-<range-end>
|
|
63
|
+
*
|
|
64
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range#directives
|
|
65
|
+
*/
|
|
66
|
+
private setOffsetDetails;
|
|
67
|
+
/**
|
|
68
|
+
* This function returns the value of the "content-range" header.
|
|
69
|
+
*
|
|
70
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range
|
|
71
|
+
*
|
|
72
|
+
* Returns a string representing the following content ranges:
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* - Content-Range: <unit> <byteStart>-<byteEnd>/<byteSize>
|
|
76
|
+
* - Content-Range: <unit> <byteStart>-<byteEnd>/*
|
|
77
|
+
*/
|
|
78
|
+
get contentRangeHeaderValue(): string;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=byte-range-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byte-range-context.d.ts","sourceRoot":"","sources":["../../../src/utils/byte-range-context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,KAAK,EAAE,eAAe,EAAU,MAAM,mBAAmB,CAAA;AAuChE,qBAAa,gBAAgB;IAgBW,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IAf/D,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,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAe;IACjD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAe;IAC/C,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,QAAQ,CAAoB;gBAEvB,MAAM,EAAE,eAAe,EAAmB,OAAO,CAAC,yBAAa;IAyBrE,OAAO,CAAE,IAAI,EAAE,kBAAkB,GAAG,IAAI;IAQxC,OAAO,IAAK,kBAAkB;IA4BrC,OAAO,CAAC,aAAa;IAOrB;;;;;OAKG;IACI,WAAW,CAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI;IAOhD,WAAW,IAAK,MAAM,GAAG,IAAI,GAAG,SAAS;IAIhD,OAAO,CAAC,gBAAgB;IAexB,OAAO,CAAC,cAAc;IAetB;;;OAGG;IACH,IAAW,mBAAmB,IAAK,OAAO,CAmCzC;IAED;;;;OAIG;IACH,IAAW,MAAM,IAAK,MAAM,CAE3B;IAED;;;;OAIG;IACH,IAAW,MAAM,IAAK,MAAM,GAAG,SAAS,CASvC;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,gBAAgB;IAoBxB;;;;;;;;;;OAUG;IAEH,IAAW,uBAAuB,IAAK,MAAM,CAW5C;CACF"}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { calculateByteRangeIndexes, getHeader } from './request-headers.js';
|
|
2
|
+
import { getContentRangeHeader } from './response-headers.js';
|
|
3
|
+
/**
|
|
4
|
+
* Gets the body size of a given body if it's possible to calculate it synchronously.
|
|
5
|
+
*/
|
|
6
|
+
function getBodySizeSync(body) {
|
|
7
|
+
if (typeof body === 'string') {
|
|
8
|
+
return body.length;
|
|
9
|
+
}
|
|
10
|
+
if (body instanceof ArrayBuffer || body instanceof Uint8Array) {
|
|
11
|
+
return body.byteLength;
|
|
12
|
+
}
|
|
13
|
+
if (body instanceof Blob) {
|
|
14
|
+
return body.size;
|
|
15
|
+
}
|
|
16
|
+
if (body instanceof ReadableStream) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
function getByteRangeFromHeader(rangeHeader) {
|
|
22
|
+
/**
|
|
23
|
+
* Range: bytes=<start>-<end> | bytes=<start2>- | bytes=-<end2>
|
|
24
|
+
*/
|
|
25
|
+
const match = rangeHeader.match(/^bytes=(?<start>\d+)?-(?<end>\d+)?$/);
|
|
26
|
+
if (match?.groups == null) {
|
|
27
|
+
throw new Error('Invalid range request');
|
|
28
|
+
}
|
|
29
|
+
const { start, end } = match.groups;
|
|
30
|
+
return { start, end };
|
|
31
|
+
}
|
|
32
|
+
export class ByteRangeContext {
|
|
33
|
+
headers;
|
|
34
|
+
isRangeRequest;
|
|
35
|
+
/**
|
|
36
|
+
* This property is purposefully only set in `set fileSize` and should not be set directly.
|
|
37
|
+
*/
|
|
38
|
+
_fileSize;
|
|
39
|
+
_body = null;
|
|
40
|
+
rangeRequestHeader;
|
|
41
|
+
log;
|
|
42
|
+
requestRangeStart;
|
|
43
|
+
requestRangeEnd;
|
|
44
|
+
byteStart;
|
|
45
|
+
byteEnd;
|
|
46
|
+
byteSize;
|
|
47
|
+
constructor(logger, headers) {
|
|
48
|
+
this.headers = headers;
|
|
49
|
+
this.log = logger.forComponent('helia:verified-fetch:byte-range-context');
|
|
50
|
+
this.rangeRequestHeader = getHeader(this.headers, 'Range');
|
|
51
|
+
if (this.rangeRequestHeader != null) {
|
|
52
|
+
this.isRangeRequest = true;
|
|
53
|
+
this.log.trace('range request detected');
|
|
54
|
+
try {
|
|
55
|
+
const { start, end } = getByteRangeFromHeader(this.rangeRequestHeader);
|
|
56
|
+
this.requestRangeStart = start != null ? parseInt(start) : null;
|
|
57
|
+
this.requestRangeEnd = end != null ? parseInt(end) : null;
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
this.log.error('error parsing range request header: %o', e);
|
|
61
|
+
this.requestRangeStart = null;
|
|
62
|
+
this.requestRangeEnd = null;
|
|
63
|
+
}
|
|
64
|
+
this.setOffsetDetails();
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
this.log.trace('no range request detected');
|
|
68
|
+
this.isRangeRequest = false;
|
|
69
|
+
this.requestRangeStart = null;
|
|
70
|
+
this.requestRangeEnd = null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
setBody(body) {
|
|
74
|
+
this._body = body;
|
|
75
|
+
// if fileSize was already set, don't recalculate it
|
|
76
|
+
this.setFileSize(this._fileSize ?? getBodySizeSync(body));
|
|
77
|
+
this.log.trace('set request body with fileSize %o', this._fileSize);
|
|
78
|
+
}
|
|
79
|
+
getBody() {
|
|
80
|
+
const body = this._body;
|
|
81
|
+
if (body == null) {
|
|
82
|
+
this.log.trace('body is null');
|
|
83
|
+
return body;
|
|
84
|
+
}
|
|
85
|
+
if (!this.isRangeRequest || !this.isValidRangeRequest) {
|
|
86
|
+
this.log.trace('returning body unmodified for non-range, or invalid range, request');
|
|
87
|
+
return body;
|
|
88
|
+
}
|
|
89
|
+
const byteStart = this.byteStart;
|
|
90
|
+
const byteEnd = this.byteEnd;
|
|
91
|
+
const byteSize = this.byteSize;
|
|
92
|
+
if (byteStart != null || byteEnd != null) {
|
|
93
|
+
this.log.trace('returning body with byteStart=%o, byteEnd=%o, byteSize=%o', byteStart, byteEnd, byteSize);
|
|
94
|
+
if (body instanceof ReadableStream) {
|
|
95
|
+
// stream should already be spliced by `unixfs.cat`
|
|
96
|
+
return body;
|
|
97
|
+
}
|
|
98
|
+
return this.getSlicedBody(body);
|
|
99
|
+
}
|
|
100
|
+
// we should not reach this point, but return body untouched.
|
|
101
|
+
this.log.error('returning unmodified body for valid range request');
|
|
102
|
+
return body;
|
|
103
|
+
}
|
|
104
|
+
// TODO: we should be able to use this.offset and this.length to slice the body
|
|
105
|
+
getSlicedBody(body) {
|
|
106
|
+
const offset = this.byteStart ?? 0;
|
|
107
|
+
const length = this.byteEnd == null ? undefined : this.byteEnd + 1;
|
|
108
|
+
this.log.trace('returning body with offset %o and length %o', offset, length);
|
|
109
|
+
return body.slice(offset, length);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Sometimes, we need to set the fileSize explicitly because we can't calculate
|
|
113
|
+
* the size of the body (e.g. for unixfs content where we call .stat).
|
|
114
|
+
*
|
|
115
|
+
* This fileSize should otherwise only be called from `setBody`.
|
|
116
|
+
*/
|
|
117
|
+
setFileSize(size) {
|
|
118
|
+
this._fileSize = size != null ? Number(size) : null;
|
|
119
|
+
this.log.trace('set _fileSize to %o', this._fileSize);
|
|
120
|
+
// when fileSize changes, we need to recalculate the offset details
|
|
121
|
+
this.setOffsetDetails();
|
|
122
|
+
}
|
|
123
|
+
getFileSize() {
|
|
124
|
+
return this._fileSize;
|
|
125
|
+
}
|
|
126
|
+
isValidByteStart() {
|
|
127
|
+
if (this.byteStart != null) {
|
|
128
|
+
if (this.byteStart < 0) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
if (this._fileSize != null && this.byteStart >= this._fileSize) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
if (this.byteEnd != null && this.byteStart > this.byteEnd) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
isValidByteEnd() {
|
|
141
|
+
if (this.byteEnd != null) {
|
|
142
|
+
if (this.byteEnd < 0) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
if (this._fileSize != null && this.byteEnd >= this._fileSize) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
if (this.byteStart != null && this.byteEnd < this.byteStart) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* We may get the values required to determine if this is a valid range request at different times
|
|
156
|
+
* so we need to calculate it when asked.
|
|
157
|
+
*/
|
|
158
|
+
get isValidRangeRequest() {
|
|
159
|
+
if (!this.isRangeRequest) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
if (this.requestRangeStart == null && this.requestRangeEnd == null) {
|
|
163
|
+
this.log.trace('invalid range request, range request values not provided');
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
if (!this.isValidByteStart()) {
|
|
167
|
+
this.log.trace('invalid range request, byteStart is less than 0 or greater than fileSize');
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
if (!this.isValidByteEnd()) {
|
|
171
|
+
this.log.trace('invalid range request, byteEnd is less than 0 or greater than fileSize');
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
if (this.requestRangeEnd != null && this.requestRangeStart != null) {
|
|
175
|
+
// we may not have enough info.. base check on requested bytes
|
|
176
|
+
if (this.requestRangeStart > this.requestRangeEnd) {
|
|
177
|
+
this.log.trace('invalid range request, start is greater than end');
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
else if (this.requestRangeStart < 0) {
|
|
181
|
+
this.log.trace('invalid range request, start is less than 0');
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
else if (this.requestRangeEnd < 0) {
|
|
185
|
+
this.log.trace('invalid range request, end is less than 0');
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (this.byteEnd == null && this.byteStart == null && this.byteSize == null) {
|
|
190
|
+
this.log.trace('invalid range request, could not calculate byteStart, byteEnd, or byteSize');
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Given all the information we have, this function returns the offset that will be used when:
|
|
197
|
+
* 1. calling unixfs.cat
|
|
198
|
+
* 2. slicing the body
|
|
199
|
+
*/
|
|
200
|
+
get offset() {
|
|
201
|
+
return this.byteStart ?? 0;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Given all the information we have, this function returns the length that will be used when:
|
|
205
|
+
* 1. calling unixfs.cat
|
|
206
|
+
* 2. slicing the body
|
|
207
|
+
*/
|
|
208
|
+
get length() {
|
|
209
|
+
if (this.byteEnd != null && this.byteStart != null && this.byteStart === this.byteEnd) {
|
|
210
|
+
return 1;
|
|
211
|
+
}
|
|
212
|
+
if (this.byteEnd != null) {
|
|
213
|
+
return this.byteEnd + 1;
|
|
214
|
+
}
|
|
215
|
+
return this.byteSize != null ? this.byteSize - 1 : undefined;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Converts a range request header into helia/unixfs supported range options
|
|
219
|
+
* 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
|
|
220
|
+
*
|
|
221
|
+
* 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.
|
|
222
|
+
*
|
|
223
|
+
* SUPPORTED:
|
|
224
|
+
* Range: bytes=<range-start>-<range-end>
|
|
225
|
+
* Range: bytes=<range-start>-
|
|
226
|
+
* 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.
|
|
227
|
+
*
|
|
228
|
+
* NOT SUPPORTED:
|
|
229
|
+
* Range: bytes=<range-start>-<range-end>, <range-start>-<range-end>
|
|
230
|
+
* Range: bytes=<range-start>-<range-end>, <range-start>-<range-end>, <range-start>-<range-end>
|
|
231
|
+
*
|
|
232
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range#directives
|
|
233
|
+
*/
|
|
234
|
+
setOffsetDetails() {
|
|
235
|
+
if (this.requestRangeStart == null && this.requestRangeEnd == null) {
|
|
236
|
+
this.log.trace('requestRangeStart and requestRangeEnd are null');
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
try {
|
|
240
|
+
const { start, end, byteSize } = calculateByteRangeIndexes(this.requestRangeStart ?? undefined, this.requestRangeEnd ?? undefined, this._fileSize ?? undefined);
|
|
241
|
+
this.log.trace('set byteStart to %o, byteEnd to %o, byteSize to %o', start, end, byteSize);
|
|
242
|
+
this.byteStart = start;
|
|
243
|
+
this.byteEnd = end;
|
|
244
|
+
this.byteSize = byteSize;
|
|
245
|
+
}
|
|
246
|
+
catch (e) {
|
|
247
|
+
this.log.error('error setting offset details: %o', e);
|
|
248
|
+
this.byteStart = undefined;
|
|
249
|
+
this.byteEnd = undefined;
|
|
250
|
+
this.byteSize = undefined;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* This function returns the value of the "content-range" header.
|
|
255
|
+
*
|
|
256
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range
|
|
257
|
+
*
|
|
258
|
+
* Returns a string representing the following content ranges:
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* - Content-Range: <unit> <byteStart>-<byteEnd>/<byteSize>
|
|
262
|
+
* - Content-Range: <unit> <byteStart>-<byteEnd>/*
|
|
263
|
+
*/
|
|
264
|
+
// - Content-Range: <unit> */<byteSize> // this is purposefully not in jsdoc block
|
|
265
|
+
get contentRangeHeaderValue() {
|
|
266
|
+
if (!this.isValidRangeRequest) {
|
|
267
|
+
this.log.error('cannot get contentRangeHeaderValue for invalid range request');
|
|
268
|
+
throw new Error('Invalid range request');
|
|
269
|
+
}
|
|
270
|
+
return getContentRangeHeader({
|
|
271
|
+
byteStart: this.byteStart,
|
|
272
|
+
byteEnd: this.byteEnd,
|
|
273
|
+
byteSize: this._fileSize ?? undefined
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
//# sourceMappingURL=byte-range-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byte-range-context.js","sourceRoot":"","sources":["../../../src/utils/byte-range-context.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,7 +7,7 @@ export async function getStreamFromAsyncIterable(iterator, path, logger, options
|
|
|
7
7
|
const reader = iterator[Symbol.asyncIterator]();
|
|
8
8
|
const { value: firstChunk, done } = await reader.next();
|
|
9
9
|
if (done === true) {
|
|
10
|
-
log.error('
|
|
10
|
+
log.error('no content found for path', path);
|
|
11
11
|
throw new Error('No content found');
|
|
12
12
|
}
|
|
13
13
|
const stream = new ReadableStream({
|
|
@@ -70,7 +70,7 @@ export async function parseUrlString({ urlString, ipns, logger }, options) {
|
|
|
70
70
|
}
|
|
71
71
|
else {
|
|
72
72
|
// protocol is ipns
|
|
73
|
-
log.trace('
|
|
73
|
+
log.trace('attempting to resolve PeerId for %s', cidOrPeerIdOrDnsLink);
|
|
74
74
|
let peerId = null;
|
|
75
75
|
try {
|
|
76
76
|
peerId = peerIdFromString(cidOrPeerIdOrDnsLink);
|
|
@@ -82,11 +82,11 @@ export async function parseUrlString({ urlString, ipns, logger }, options) {
|
|
|
82
82
|
}
|
|
83
83
|
catch (err) {
|
|
84
84
|
if (peerId == null) {
|
|
85
|
-
log.error('
|
|
85
|
+
log.error('could not parse PeerId string "%s"', cidOrPeerIdOrDnsLink, err);
|
|
86
86
|
errors.push(new TypeError(`Could not parse PeerId in ipns url "${cidOrPeerIdOrDnsLink}", ${err.message}`));
|
|
87
87
|
}
|
|
88
88
|
else {
|
|
89
|
-
log.error('
|
|
89
|
+
log.error('could not resolve PeerId %c', peerId, err);
|
|
90
90
|
errors.push(new TypeError(`Could not resolve PeerId "${cidOrPeerIdOrDnsLink}", ${err.message}`));
|
|
91
91
|
}
|
|
92
92
|
}
|
|
@@ -105,7 +105,7 @@ export async function parseUrlString({ urlString, ipns, logger }, options) {
|
|
|
105
105
|
ipnsCache.set(cidOrPeerIdOrDnsLink, resolveResult, 60 * 1000 * 2);
|
|
106
106
|
}
|
|
107
107
|
catch (err) {
|
|
108
|
-
log.error('
|
|
108
|
+
log.error('could not resolve DnsLink for "%s"', cidOrPeerIdOrDnsLink, err);
|
|
109
109
|
errors.push(err);
|
|
110
110
|
}
|
|
111
111
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare function getHeader(headers: HeadersInit | undefined, header: string): string | undefined;
|
|
2
|
+
/**
|
|
3
|
+
* Given two ints from a Range header, and potential fileSize, returns:
|
|
4
|
+
* 1. number of bytes the response should contain.
|
|
5
|
+
* 2. the start index of the range. // inclusive
|
|
6
|
+
* 3. the end index of the range. // inclusive
|
|
7
|
+
*/
|
|
8
|
+
export declare function calculateByteRangeIndexes(start: number | undefined, end: number | undefined, fileSize?: number): {
|
|
9
|
+
byteSize?: number;
|
|
10
|
+
start?: number;
|
|
11
|
+
end?: number;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=request-headers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-headers.d.ts","sourceRoot":"","sources":["../../../src/utils/request-headers.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAE,OAAO,EAAE,WAAW,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAiB/F;AAED;;;;;GAKG;AAEH,wBAAgB,yBAAyB,CAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAoCrK"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export function getHeader(headers, header) {
|
|
2
|
+
if (headers == null) {
|
|
3
|
+
return undefined;
|
|
4
|
+
}
|
|
5
|
+
if (headers instanceof Headers) {
|
|
6
|
+
return headers.get(header) ?? undefined;
|
|
7
|
+
}
|
|
8
|
+
if (Array.isArray(headers)) {
|
|
9
|
+
const entry = headers.find(([key]) => key.toLowerCase() === header.toLowerCase());
|
|
10
|
+
return entry?.[1];
|
|
11
|
+
}
|
|
12
|
+
const key = Object.keys(headers).find(k => k.toLowerCase() === header.toLowerCase());
|
|
13
|
+
if (key == null) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
return headers[key];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Given two ints from a Range header, and potential fileSize, returns:
|
|
20
|
+
* 1. number of bytes the response should contain.
|
|
21
|
+
* 2. the start index of the range. // inclusive
|
|
22
|
+
* 3. the end index of the range. // inclusive
|
|
23
|
+
*/
|
|
24
|
+
// eslint-disable-next-line complexity
|
|
25
|
+
export function calculateByteRangeIndexes(start, end, fileSize) {
|
|
26
|
+
if ((start ?? 0) > (end ?? Infinity)) {
|
|
27
|
+
throw new Error('Invalid range: Range-start index is greater than range-end index.');
|
|
28
|
+
}
|
|
29
|
+
if (start != null && (end ?? 0) >= (fileSize ?? Infinity)) {
|
|
30
|
+
throw new Error('Invalid range: Range-end index is greater than or equal to the size of the file.');
|
|
31
|
+
}
|
|
32
|
+
if (start == null && (end ?? 0) > (fileSize ?? Infinity)) {
|
|
33
|
+
throw new Error('Invalid range: Range-end index is greater than the size of the file.');
|
|
34
|
+
}
|
|
35
|
+
if (start != null && start < 0) {
|
|
36
|
+
throw new Error('Invalid range: Range-start index cannot be negative.');
|
|
37
|
+
}
|
|
38
|
+
if (start != null && end != null) {
|
|
39
|
+
return { byteSize: end - start + 1, start, end };
|
|
40
|
+
}
|
|
41
|
+
else if (start == null && end != null) {
|
|
42
|
+
// suffix byte range requested
|
|
43
|
+
if (fileSize == null) {
|
|
44
|
+
return { end };
|
|
45
|
+
}
|
|
46
|
+
if (end === fileSize) {
|
|
47
|
+
return { byteSize: fileSize, start: 0, end: fileSize - 1 };
|
|
48
|
+
}
|
|
49
|
+
return { byteSize: end, start: fileSize - end, end: fileSize - 1 };
|
|
50
|
+
}
|
|
51
|
+
else if (start != null && end == null) {
|
|
52
|
+
if (fileSize == null) {
|
|
53
|
+
// we only have the start index, and no fileSize, so we can't return a valid range.
|
|
54
|
+
return { start };
|
|
55
|
+
}
|
|
56
|
+
const end = fileSize - 1;
|
|
57
|
+
const byteSize = fileSize - start;
|
|
58
|
+
return { byteSize, start, end };
|
|
59
|
+
}
|
|
60
|
+
return { byteSize: fileSize, start: 0, end: fileSize != null ? fileSize - 1 : 0 };
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=request-headers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-headers.js","sourceRoot":"","sources":["../../../src/utils/request-headers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This function returns the value of the `Content-Range` header for a given range.
|
|
3
|
+
* If you know the total size of the body, pass it as `byteSize`
|
|
4
|
+
*
|
|
5
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range
|
|
6
|
+
*/
|
|
7
|
+
export declare function getContentRangeHeader({ byteStart, byteEnd, byteSize }: {
|
|
8
|
+
byteStart: number | undefined;
|
|
9
|
+
byteEnd: number | undefined;
|
|
10
|
+
byteSize: number | undefined;
|
|
11
|
+
}): string;
|
|
12
|
+
//# sourceMappingURL=response-headers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-headers.d.ts","sourceRoot":"","sources":["../../../src/utils/response-headers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAE,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE;IAAE,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GAAG,MAAM,CAmC7K"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This function returns the value of the `Content-Range` header for a given range.
|
|
3
|
+
* If you know the total size of the body, pass it as `byteSize`
|
|
4
|
+
*
|
|
5
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range
|
|
6
|
+
*/
|
|
7
|
+
export function getContentRangeHeader({ byteStart, byteEnd, byteSize }) {
|
|
8
|
+
const total = byteSize ?? '*'; // if we don't know the total size, we should use *
|
|
9
|
+
if ((byteEnd ?? 0) >= (byteSize ?? Infinity)) {
|
|
10
|
+
throw new Error('Invalid range: Range-end index is greater than or equal to the size of the file.');
|
|
11
|
+
}
|
|
12
|
+
if ((byteStart ?? 0) >= (byteSize ?? Infinity)) {
|
|
13
|
+
throw new Error('Invalid range: Range-start index is greater than or equal to the size of the file.');
|
|
14
|
+
}
|
|
15
|
+
if (byteStart != null && byteEnd == null) {
|
|
16
|
+
// only byteStart in range
|
|
17
|
+
if (byteSize == null) {
|
|
18
|
+
return `bytes */${total}`;
|
|
19
|
+
}
|
|
20
|
+
return `bytes ${byteStart}-${byteSize - 1}/${byteSize}`;
|
|
21
|
+
}
|
|
22
|
+
if (byteStart == null && byteEnd != null) {
|
|
23
|
+
// only byteEnd in range
|
|
24
|
+
if (byteSize == null) {
|
|
25
|
+
return `bytes */${total}`;
|
|
26
|
+
}
|
|
27
|
+
const end = byteSize - 1;
|
|
28
|
+
const start = end - byteEnd + 1;
|
|
29
|
+
return `bytes ${start}-${end}/${byteSize}`;
|
|
30
|
+
}
|
|
31
|
+
if (byteStart == null && byteEnd == null) {
|
|
32
|
+
// neither are provided, we can't return a valid range.
|
|
33
|
+
return `bytes */${total}`;
|
|
34
|
+
}
|
|
35
|
+
return `bytes ${byteStart}-${byteEnd}/${total}`;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=response-headers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-headers.js","sourceRoot":"","sources":["../../../src/utils/response-headers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAE,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAgG;IACnK,MAAM,KAAK,GAAG,QAAQ,IAAI,GAAG,CAAA,CAAC,mDAAmD;IAEjF,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,kFAAkF,CAAC,CAAA;IACrG,CAAC;IACD,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,oFAAoF,CAAC,CAAA;IACvG,CAAC;IAED,IAAI,SAAS,IAAI,IAAI,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QACzC,0BAA0B;QAC1B,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;YACrB,OAAO,WAAW,KAAK,EAAE,CAAA;QAC3B,CAAC;QACD,OAAO,SAAS,SAAS,IAAI,QAAQ,GAAG,CAAC,IAAI,QAAQ,EAAE,CAAA;IACzD,CAAC;IAED,IAAI,SAAS,IAAI,IAAI,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QACzC,wBAAwB;QACxB,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;YACrB,OAAO,WAAW,KAAK,EAAE,CAAA;QAC3B,CAAC;QACD,MAAM,GAAG,GAAG,QAAQ,GAAG,CAAC,CAAA;QACxB,MAAM,KAAK,GAAG,GAAG,GAAG,OAAO,GAAG,CAAC,CAAA;QAE/B,OAAO,SAAS,KAAK,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAA;IAC5C,CAAC;IAED,IAAI,SAAS,IAAI,IAAI,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QACzC,uDAAuD;QACvD,OAAO,WAAW,KAAK,EAAE,CAAA;IAC3B,CAAC;IAED,OAAO,SAAS,SAAS,IAAI,OAAO,IAAI,KAAK,EAAE,CAAA;AACjD,CAAC"}
|
|
@@ -1,9 +1,26 @@
|
|
|
1
|
+
import type { ByteRangeContext } from './byte-range-context';
|
|
2
|
+
import type { SupportedBodyTypes } from '../types.js';
|
|
3
|
+
import type { Logger } from '@libp2p/interface';
|
|
1
4
|
export interface ResponseOptions extends ResponseInit {
|
|
2
5
|
redirected?: boolean;
|
|
3
6
|
}
|
|
4
|
-
export declare function okResponse(url: string, body?:
|
|
5
|
-
export declare function
|
|
6
|
-
export declare function
|
|
7
|
-
export declare function
|
|
7
|
+
export declare function okResponse(url: string, body?: SupportedBodyTypes, init?: ResponseOptions): Response;
|
|
8
|
+
export declare function badGatewayResponse(url: string, body?: SupportedBodyTypes, init?: ResponseInit): Response;
|
|
9
|
+
export declare function notSupportedResponse(url: string, body?: SupportedBodyTypes, init?: ResponseInit): Response;
|
|
10
|
+
export declare function notAcceptableResponse(url: string, body?: SupportedBodyTypes, init?: ResponseInit): Response;
|
|
11
|
+
export declare function badRequestResponse(url: string, body?: SupportedBodyTypes, init?: ResponseInit): Response;
|
|
8
12
|
export declare function movedPermanentlyResponse(url: string, location: string, init?: ResponseInit): Response;
|
|
13
|
+
interface RangeOptions {
|
|
14
|
+
byteRangeContext: ByteRangeContext;
|
|
15
|
+
log?: Logger;
|
|
16
|
+
}
|
|
17
|
+
export declare function okRangeResponse(url: string, body: SupportedBodyTypes, { byteRangeContext, log }: RangeOptions, init?: ResponseOptions): Response;
|
|
18
|
+
/**
|
|
19
|
+
* We likely need to catch errors handled by upstream helia libraries if range-request throws an error. Some examples:
|
|
20
|
+
* * The range is out of bounds
|
|
21
|
+
* * The range is invalid
|
|
22
|
+
* * The range is not supported for the given type
|
|
23
|
+
*/
|
|
24
|
+
export declare function badRangeResponse(url: string, body?: SupportedBodyTypes, init?: ResponseInit): Response;
|
|
25
|
+
export {};
|
|
9
26
|
//# sourceMappingURL=responses.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"responses.d.ts","sourceRoot":"","sources":["../../../src/utils/responses.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"responses.d.ts","sourceRoot":"","sources":["../../../src/utils/responses.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAuB/C,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACnD,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,wBAAgB,UAAU,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,eAAe,GAAG,QAAQ,CAgBpG;AAED,wBAAgB,kBAAkB,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ,CAWzG;AAED,wBAAgB,oBAAoB,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ,CAY3G;AAED,wBAAgB,qBAAqB,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ,CAW5G;AAED,wBAAgB,kBAAkB,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ,CAWzG;AAED,wBAAgB,wBAAwB,CAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ,CAetG;AAED,UAAU,YAAY;IACpB,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,wBAAgB,eAAe,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,EAAE,EAAE,gBAAgB,EAAE,GAAG,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,eAAe,GAAG,QAAQ,CAkCjJ;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ,CAWvG"}
|