@gjsify/fetch 0.0.2

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.
Files changed (58) hide show
  1. package/README.md +9 -0
  2. package/lib/cjs/body.js +284 -0
  3. package/lib/cjs/errors/abort-error.js +28 -0
  4. package/lib/cjs/errors/base.js +36 -0
  5. package/lib/cjs/errors/fetch-error.js +40 -0
  6. package/lib/cjs/headers.js +231 -0
  7. package/lib/cjs/index.js +246 -0
  8. package/lib/cjs/request.js +306 -0
  9. package/lib/cjs/response.js +162 -0
  10. package/lib/cjs/types/index.js +17 -0
  11. package/lib/cjs/types/system-error.js +16 -0
  12. package/lib/cjs/utils/blob-from.js +124 -0
  13. package/lib/cjs/utils/get-search.js +30 -0
  14. package/lib/cjs/utils/is-redirect.js +26 -0
  15. package/lib/cjs/utils/is.js +47 -0
  16. package/lib/cjs/utils/multipart-parser.js +372 -0
  17. package/lib/cjs/utils/referrer.js +172 -0
  18. package/lib/esm/body.js +255 -0
  19. package/lib/esm/errors/abort-error.js +9 -0
  20. package/lib/esm/errors/base.js +17 -0
  21. package/lib/esm/errors/fetch-error.js +21 -0
  22. package/lib/esm/headers.js +202 -0
  23. package/lib/esm/index.js +224 -0
  24. package/lib/esm/request.js +281 -0
  25. package/lib/esm/response.js +133 -0
  26. package/lib/esm/types/index.js +1 -0
  27. package/lib/esm/types/system-error.js +1 -0
  28. package/lib/esm/utils/blob-from.js +101 -0
  29. package/lib/esm/utils/get-search.js +11 -0
  30. package/lib/esm/utils/is-redirect.js +7 -0
  31. package/lib/esm/utils/is.js +28 -0
  32. package/lib/esm/utils/multipart-parser.js +353 -0
  33. package/lib/esm/utils/referrer.js +153 -0
  34. package/package.json +53 -0
  35. package/src/body.ts +415 -0
  36. package/src/errors/abort-error.ts +10 -0
  37. package/src/errors/base.ts +20 -0
  38. package/src/errors/fetch-error.ts +26 -0
  39. package/src/headers.ts +279 -0
  40. package/src/index.spec.ts +13 -0
  41. package/src/index.ts +367 -0
  42. package/src/request.ts +396 -0
  43. package/src/response.ts +197 -0
  44. package/src/test.mts +6 -0
  45. package/src/types/index.ts +1 -0
  46. package/src/types/system-error.ts +11 -0
  47. package/src/utils/blob-from.ts +168 -0
  48. package/src/utils/get-search.ts +9 -0
  49. package/src/utils/is-redirect.ts +11 -0
  50. package/src/utils/is.ts +88 -0
  51. package/src/utils/multipart-parser.ts +448 -0
  52. package/src/utils/referrer.ts +350 -0
  53. package/test.gjs.js +34758 -0
  54. package/test.gjs.mjs +53177 -0
  55. package/test.node.js +1226 -0
  56. package/test.node.mjs +6294 -0
  57. package/tsconfig.json +19 -0
  58. package/tsconfig.types.json +8 -0
@@ -0,0 +1,350 @@
1
+ import { URL } from '@gjsify/deno-runtime/ext/url/00_url';
2
+
3
+ import { isIP } from 'net';
4
+ import Request from '../request.js';
5
+
6
+ /**
7
+ * @external URL
8
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/URL URL}
9
+ */
10
+
11
+ /**
12
+ * @module utils/referrer
13
+ * @private
14
+ */
15
+
16
+ /**
17
+ * @see {@link https://w3c.github.io/webappsec-referrer-policy/#strip-url Referrer Policy §8.4. Strip url for use as a referrer}
18
+ * @param url
19
+ * @param originOnly
20
+ */
21
+ export function stripURLForUseAsAReferrer(url: null | URL | "no-referrer", originOnly = false) {
22
+ // 1. If url is null, return no referrer.
23
+ if (url == null || url === "no-referrer") { // eslint-disable-line no-eq-null, eqeqeq
24
+ return 'no-referrer';
25
+ }
26
+
27
+ url = new URL(url);
28
+
29
+ // 2. If url's scheme is a local scheme, then return no referrer.
30
+ if (/^(about|blob|data):$/.test(url.protocol)) {
31
+ return 'no-referrer';
32
+ }
33
+
34
+ // 3. Set url's username to the empty string.
35
+ url.username = '';
36
+
37
+ // 4. Set url's password to null.
38
+ // Note: `null` appears to be a mistake as this actually results in the password being `"null"`.
39
+ url.password = '';
40
+
41
+ // 5. Set url's fragment to null.
42
+ // Note: `null` appears to be a mistake as this actually results in the fragment being `"#null"`.
43
+ url.hash = '';
44
+
45
+ // 6. If the origin-only flag is true, then:
46
+ if (originOnly) {
47
+ // 6.1. Set url's path to null.
48
+ // Note: `null` appears to be a mistake as this actually results in the path being `"/null"`.
49
+ url.pathname = '';
50
+
51
+ // 6.2. Set url's query to null.
52
+ // Note: `null` appears to be a mistake as this actually results in the query being `"?null"`.
53
+ url.search = '';
54
+ }
55
+
56
+ // 7. Return url.
57
+ return url;
58
+ }
59
+
60
+ /**
61
+ * @see {@link https://w3c.github.io/webappsec-referrer-policy/#enumdef-referrerpolicy enum ReferrerPolicy}
62
+ */
63
+ export const ReferrerPolicy = new Set([
64
+ '',
65
+ 'no-referrer',
66
+ 'no-referrer-when-downgrade',
67
+ 'same-origin',
68
+ 'origin',
69
+ 'strict-origin',
70
+ 'origin-when-cross-origin',
71
+ 'strict-origin-when-cross-origin',
72
+ 'unsafe-url'
73
+ ]);
74
+
75
+ /**
76
+ * @see {@link https://w3c.github.io/webappsec-referrer-policy/#default-referrer-policy default referrer policy}
77
+ */
78
+ export const DEFAULT_REFERRER_POLICY = 'strict-origin-when-cross-origin';
79
+
80
+ /**
81
+ * @see {@link https://w3c.github.io/webappsec-referrer-policy/#referrer-policies Referrer Policy §3. Referrer Policies}
82
+ * @param referrerPolicy
83
+ * @returns referrerPolicy
84
+ */
85
+ export function validateReferrerPolicy(referrerPolicy: ReferrerPolicy): ReferrerPolicy {
86
+ if (!ReferrerPolicy.has(referrerPolicy)) {
87
+ throw new TypeError(`Invalid referrerPolicy: ${referrerPolicy}`);
88
+ }
89
+
90
+ return referrerPolicy;
91
+ }
92
+
93
+ /**
94
+ * @see {@link https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy Referrer Policy §3.2. Is origin potentially trustworthy?}
95
+ * @param url
96
+ * @returns `true`: "Potentially Trustworthy", `false`: "Not Trustworthy"
97
+ */
98
+ export function isOriginPotentiallyTrustworthy(url: URL) {
99
+ // 1. If origin is an opaque origin, return "Not Trustworthy".
100
+ // Not applicable
101
+
102
+ // 2. Assert: origin is a tuple origin.
103
+ // Not for implementations
104
+
105
+ // 3. If origin's scheme is either "https" or "wss", return "Potentially Trustworthy".
106
+ if (/^(http|ws)s:$/.test(url.protocol)) {
107
+ return true;
108
+ }
109
+
110
+ // 4. If origin's host component matches one of the CIDR notations 127.0.0.0/8 or ::1/128 [RFC4632], return "Potentially Trustworthy".
111
+ const hostIp = url.host.replace(/(^\[)|(]$)/g, '');
112
+ const hostIPVersion = isIP(hostIp);
113
+
114
+ if (hostIPVersion === 4 && /^127\./.test(hostIp)) {
115
+ return true;
116
+ }
117
+
118
+ if (hostIPVersion === 6 && /^(((0+:){7})|(::(0+:){0,6}))0*1$/.test(hostIp)) {
119
+ return true;
120
+ }
121
+
122
+ // 5. If origin's host component is "localhost" or falls within ".localhost", and the user agent conforms to the name resolution rules in [let-localhost-be-localhost], return "Potentially Trustworthy".
123
+ // We are returning FALSE here because we cannot ensure conformance to
124
+ // let-localhost-be-loalhost (https://tools.ietf.org/html/draft-west-let-localhost-be-localhost)
125
+ if (url.host === 'localhost' || url.host.endsWith('.localhost')) {
126
+ return false;
127
+ }
128
+
129
+ // 6. If origin's scheme component is file, return "Potentially Trustworthy".
130
+ if (url.protocol === 'file:') {
131
+ return true;
132
+ }
133
+
134
+ // 7. If origin's scheme component is one which the user agent considers to be authenticated, return "Potentially Trustworthy".
135
+ // Not supported
136
+
137
+ // 8. If origin has been configured as a trustworthy origin, return "Potentially Trustworthy".
138
+ // Not supported
139
+
140
+ // 9. Return "Not Trustworthy".
141
+ return false;
142
+ }
143
+
144
+ /**
145
+ * @see {@link https://w3c.github.io/webappsec-secure-contexts/#is-url-trustworthy Referrer Policy §3.3. Is url potentially trustworthy?}
146
+ * @param url
147
+ * @returns `true`: "Potentially Trustworthy", `false`: "Not Trustworthy"
148
+ */
149
+ export function isUrlPotentiallyTrustworthy(url: URL | 'no-referrer') {
150
+ // 1. If url is "about:blank" or "about:srcdoc", return "Potentially Trustworthy".
151
+ if (/^about:(blank|srcdoc)$/.test(url.toString())) {
152
+ return true;
153
+ }
154
+
155
+ if(typeof url === 'string') {
156
+ url = new URL(url);
157
+ }
158
+
159
+ // 2. If url's scheme is "data", return "Potentially Trustworthy".
160
+ if (url.protocol === 'data:') {
161
+ return true;
162
+ }
163
+
164
+ // Note: The origin of blob: and filesystem: URLs is the origin of the context in which they were
165
+ // created. Therefore, blobs created in a trustworthy origin will themselves be potentially
166
+ // trustworthy.
167
+ if (/^(blob|filesystem):$/.test(url.protocol)) {
168
+ return true;
169
+ }
170
+
171
+ // 3. Return the result of executing §3.2 Is origin potentially trustworthy? on url's origin.
172
+ return isOriginPotentiallyTrustworthy(url);
173
+ }
174
+
175
+ /**
176
+ * Modifies the referrerURL to enforce any extra security policy considerations.
177
+ * @see {@link https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer Referrer Policy §8.3. Determine request's Referrer}, step 7
178
+ * @callback module:utils/referrer~referrerURLCallback
179
+ * @param {external:URL} referrerURL
180
+ * @returns {external:URL} modified referrerURL
181
+ */
182
+
183
+ /**
184
+ * Modifies the referrerOrigin to enforce any extra security policy considerations.
185
+ * @see {@link https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer Referrer Policy §8.3. Determine request's Referrer}, step 7
186
+ * @callback module:utils/referrer~referrerOriginCallback
187
+ * @param {external:URL} referrerOrigin
188
+ * @returns {external:URL} modified referrerOrigin
189
+ */
190
+
191
+ /**
192
+ * @see {@link https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer Referrer Policy §8.3. Determine request's Referrer}
193
+ * @param request
194
+ * @param {object} o
195
+ * @param {module:utils/referrer~referrerURLCallback} o.referrerURLCallback
196
+ * @param {module:utils/referrer~referrerOriginCallback} o.referrerOriginCallback
197
+ * @returns {external:URL} Request's referrer
198
+ */
199
+ export function determineRequestsReferrer(request: Request, obj: {referrerURLCallback?: (url: URL | 'no-referrer') => URL, referrerOriginCallback?: (url: URL | 'no-referrer') => URL} = {}): URL | string {
200
+
201
+ const {referrerURLCallback, referrerOriginCallback} = obj;
202
+
203
+ // There are 2 notes in the specification about invalid pre-conditions. We return null, here, for
204
+ // these cases:
205
+ // > Note: If request's referrer is "no-referrer", Fetch will not call into this algorithm.
206
+ // > Note: If request's referrer policy is the empty string, Fetch will not call into this
207
+ // > algorithm.
208
+ if (request.referrer === 'no-referrer' || request.referrerPolicy === '') {
209
+ return null;
210
+ }
211
+
212
+ // 1. Let policy be request's associated referrer policy.
213
+ const policy = request.referrerPolicy;
214
+
215
+ // 2. Let environment be request's client.
216
+ // not applicable to node.js
217
+
218
+ // 3. Switch on request's referrer:
219
+ if (request.referrer === 'about:client') {
220
+ return 'no-referrer';
221
+ }
222
+
223
+ // "a URL": Let referrerSource be request's referrer.
224
+ const referrerSource = new URL(request.referrer);
225
+
226
+ // 4. Let request's referrerURL be the result of stripping referrerSource for use as a referrer.
227
+ let referrerURL: URL | 'no-referrer' = stripURLForUseAsAReferrer(referrerSource);
228
+
229
+ // 5. Let referrerOrigin be the result of stripping referrerSource for use as a referrer, with the
230
+ // origin-only flag set to true.
231
+ let referrerOrigin: URL | 'no-referrer' = stripURLForUseAsAReferrer(referrerSource, true);
232
+
233
+ // 6. If the result of serializing referrerURL is a string whose length is greater than 4096, set
234
+ // referrerURL to referrerOrigin.
235
+ if (referrerURL.toString().length > 4096) {
236
+ referrerURL = referrerOrigin;
237
+ }
238
+
239
+ // 7. The user agent MAY alter referrerURL or referrerOrigin at this point to enforce arbitrary
240
+ // policy considerations in the interests of minimizing data leakage. For example, the user
241
+ // agent could strip the URL down to an origin, modify its host, replace it with an empty
242
+ // string, etc.
243
+ if (referrerURLCallback) {
244
+ referrerURL = referrerURLCallback(referrerURL);
245
+ }
246
+
247
+ if (referrerOriginCallback) {
248
+ referrerOrigin = referrerOriginCallback(referrerOrigin);
249
+ }
250
+
251
+ // 8.Execute the statements corresponding to the value of policy:
252
+ const currentURL = new URL(request.url);
253
+
254
+ switch (policy) {
255
+ case 'no-referrer':
256
+ return 'no-referrer';
257
+
258
+ case 'origin':
259
+ return referrerOrigin;
260
+
261
+ case 'unsafe-url':
262
+ return referrerURL;
263
+
264
+ case 'strict-origin':
265
+ // 1. If referrerURL is a potentially trustworthy URL and request's current URL is not a
266
+ // potentially trustworthy URL, then return no referrer.
267
+ if (isUrlPotentiallyTrustworthy(referrerURL) && !isUrlPotentiallyTrustworthy(currentURL)) {
268
+ return 'no-referrer';
269
+ }
270
+
271
+ // 2. Return referrerOrigin.
272
+ return referrerOrigin.toString();
273
+
274
+ case 'strict-origin-when-cross-origin':
275
+ // 1. If the origin of referrerURL and the origin of request's current URL are the same, then
276
+ // return referrerURL.
277
+ if ((referrerURL as URL).origin === currentURL.origin) {
278
+ return referrerURL;
279
+ }
280
+
281
+ // 2. If referrerURL is a potentially trustworthy URL and request's current URL is not a
282
+ // potentially trustworthy URL, then return no referrer.
283
+ if (isUrlPotentiallyTrustworthy(referrerURL) && !isUrlPotentiallyTrustworthy(currentURL)) {
284
+ return 'no-referrer';
285
+ }
286
+
287
+ // 3. Return referrerOrigin.
288
+ return referrerOrigin;
289
+
290
+ case 'same-origin':
291
+ // 1. If the origin of referrerURL and the origin of request's current URL are the same, then
292
+ // return referrerURL.
293
+ if ((referrerURL as URL).origin === currentURL.origin) {
294
+ return referrerURL;
295
+ }
296
+
297
+ // 2. Return no referrer.
298
+ return 'no-referrer';
299
+
300
+ case 'origin-when-cross-origin':
301
+ // 1. If the origin of referrerURL and the origin of request's current URL are the same, then
302
+ // return referrerURL.
303
+ if ((referrerURL as URL).origin === currentURL.origin) {
304
+ return referrerURL;
305
+ }
306
+
307
+ // Return referrerOrigin.
308
+ return referrerOrigin;
309
+
310
+ case 'no-referrer-when-downgrade':
311
+ // 1. If referrerURL is a potentially trustworthy URL and request's current URL is not a
312
+ // potentially trustworthy URL, then return no referrer.
313
+ if (isUrlPotentiallyTrustworthy(referrerURL as URL) && !isUrlPotentiallyTrustworthy(currentURL)) {
314
+ return 'no-referrer';
315
+ }
316
+
317
+ // 2. Return referrerURL.
318
+ return referrerURL;
319
+
320
+ default:
321
+ throw new TypeError(`Invalid referrerPolicy: ${policy}`);
322
+ }
323
+ }
324
+
325
+ /**
326
+ * @see {@link https://w3c.github.io/webappsec-referrer-policy/#parse-referrer-policy-from-header|Referrer Policy §8.1. Parse a referrer policy from a Referrer-Policy header}
327
+ * @param {Headers} headers Response headers
328
+ * @returns {string} policy
329
+ */
330
+ export function parseReferrerPolicyFromHeader(headers: Headers): ReferrerPolicy {
331
+ // 1. Let policy-tokens be the result of extracting header list values given `Referrer-Policy`
332
+ // and response’s header list.
333
+ const policyTokens = (headers.get('referrer-policy') || '').split(/[,\s]+/);
334
+
335
+ // 2. Let policy be the empty string.
336
+ let policy = '';
337
+
338
+ // 3. For each token in policy-tokens, if token is a referrer policy and token is not the empty
339
+ // string, then set policy to token.
340
+ // Note: This algorithm loops over multiple policy values to allow deployment of new policy
341
+ // values with fallbacks for older user agents, as described in § 11.1 Unknown Policy Values.
342
+ for (const token of policyTokens) {
343
+ if (token && ReferrerPolicy.has(token)) {
344
+ policy = token;
345
+ }
346
+ }
347
+
348
+ // 4. Return policy.
349
+ return policy as ReferrerPolicy;
350
+ }