@gjsify/fetch 0.3.13 → 0.3.15
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/lib/esm/body.js +325 -303
- package/lib/esm/errors/abort-error.js +12 -7
- package/lib/esm/errors/base.js +19 -18
- package/lib/esm/errors/fetch-error.js +24 -19
- package/lib/esm/headers.js +188 -182
- package/lib/esm/index.js +223 -208
- package/lib/esm/register/fetch.js +12 -5
- package/lib/esm/register/xhr.js +6 -2
- package/lib/esm/request.js +279 -283
- package/lib/esm/response.js +152 -143
- package/lib/esm/types/index.js +1 -1
- package/lib/esm/types/system-error.js +3 -0
- package/lib/esm/utils/blob-from.js +2 -4
- package/lib/esm/utils/data-uri.js +31 -21
- package/lib/esm/utils/get-search.js +10 -9
- package/lib/esm/utils/is-redirect.js +18 -5
- package/lib/esm/utils/is.js +52 -20
- package/lib/esm/utils/multipart-parser.js +334 -338
- package/lib/esm/utils/referrer.js +189 -137
- package/lib/esm/utils/soup-helpers.js +23 -16
- package/lib/esm/xhr.js +234 -246
- package/package.json +11 -11
|
@@ -1,153 +1,205 @@
|
|
|
1
1
|
import { URL } from "@gjsify/url";
|
|
2
2
|
import { isIP } from "node:net";
|
|
3
|
+
|
|
4
|
+
//#region src/utils/referrer.ts
|
|
5
|
+
/**
|
|
6
|
+
* @external URL
|
|
7
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/URL URL}
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* @module utils/referrer
|
|
11
|
+
* @private
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* @see {@link https://w3c.github.io/webappsec-referrer-policy/#strip-url Referrer Policy §8.4. Strip url for use as a referrer}
|
|
15
|
+
* @param url
|
|
16
|
+
* @param originOnly
|
|
17
|
+
*/
|
|
3
18
|
function stripURLForUseAsAReferrer(url, originOnly = false) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
if (url == null || url === "no-referrer") {
|
|
20
|
+
return "no-referrer";
|
|
21
|
+
}
|
|
22
|
+
const u = new URL(url);
|
|
23
|
+
if (/^(about|blob|data):$/.test(u.protocol)) {
|
|
24
|
+
return "no-referrer";
|
|
25
|
+
}
|
|
26
|
+
u.username = "";
|
|
27
|
+
u.password = "";
|
|
28
|
+
u.hash = "";
|
|
29
|
+
if (originOnly) {
|
|
30
|
+
u.pathname = "";
|
|
31
|
+
u.search = "";
|
|
32
|
+
}
|
|
33
|
+
return u;
|
|
19
34
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
/**
|
|
36
|
+
* @see {@link https://w3c.github.io/webappsec-referrer-policy/#enumdef-referrerpolicy enum ReferrerPolicy}
|
|
37
|
+
*/
|
|
38
|
+
const ReferrerPolicy = new Set([
|
|
39
|
+
"",
|
|
40
|
+
"no-referrer",
|
|
41
|
+
"no-referrer-when-downgrade",
|
|
42
|
+
"same-origin",
|
|
43
|
+
"origin",
|
|
44
|
+
"strict-origin",
|
|
45
|
+
"origin-when-cross-origin",
|
|
46
|
+
"strict-origin-when-cross-origin",
|
|
47
|
+
"unsafe-url"
|
|
30
48
|
]);
|
|
49
|
+
/**
|
|
50
|
+
* @see {@link https://w3c.github.io/webappsec-referrer-policy/#default-referrer-policy default referrer policy}
|
|
51
|
+
*/
|
|
31
52
|
const DEFAULT_REFERRER_POLICY = "strict-origin-when-cross-origin";
|
|
53
|
+
/**
|
|
54
|
+
* @see {@link https://w3c.github.io/webappsec-referrer-policy/#referrer-policies Referrer Policy §3. Referrer Policies}
|
|
55
|
+
* @param referrerPolicy
|
|
56
|
+
* @returns referrerPolicy
|
|
57
|
+
*/
|
|
32
58
|
function validateReferrerPolicy(referrerPolicy) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
59
|
+
if (!ReferrerPolicy.has(referrerPolicy)) {
|
|
60
|
+
throw new TypeError(`Invalid referrerPolicy: ${referrerPolicy}`);
|
|
61
|
+
}
|
|
62
|
+
return referrerPolicy;
|
|
37
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* @see {@link https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy Referrer Policy §3.2. Is origin potentially trustworthy?}
|
|
66
|
+
* @param url
|
|
67
|
+
* @returns `true`: "Potentially Trustworthy", `false`: "Not Trustworthy"
|
|
68
|
+
*/
|
|
38
69
|
function isOriginPotentiallyTrustworthy(url) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
70
|
+
if (/^(http|ws)s:$/.test(url.protocol)) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
const hostIp = url.host.replace(/(^\[)|(]$)/g, "");
|
|
74
|
+
const hostIPVersion = isIP(hostIp);
|
|
75
|
+
if (hostIPVersion === 4 && /^127\./.test(hostIp)) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
if (hostIPVersion === 6 && /^(((0+:){7})|(::(0+:){0,6}))0*1$/.test(hostIp)) {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
if (url.host === "localhost" || url.host.endsWith(".localhost")) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
if (url.protocol === "file:") {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
57
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* @see {@link https://w3c.github.io/webappsec-secure-contexts/#is-url-trustworthy Referrer Policy §3.3. Is url potentially trustworthy?}
|
|
91
|
+
* @param url
|
|
92
|
+
* @returns `true`: "Potentially Trustworthy", `false`: "Not Trustworthy"
|
|
93
|
+
*/
|
|
58
94
|
function isUrlPotentiallyTrustworthy(url) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
95
|
+
if (/^about:(blank|srcdoc)$/.test(url.toString())) {
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
if (typeof url === "string") {
|
|
99
|
+
url = new URL(url);
|
|
100
|
+
}
|
|
101
|
+
if (url.protocol === "data:") {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
if (/^(blob|filesystem):$/.test(url.protocol)) {
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
return isOriginPotentiallyTrustworthy(url);
|
|
72
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Modifies the referrerURL to enforce any extra security policy considerations.
|
|
111
|
+
* @see {@link https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer Referrer Policy §8.3. Determine request's Referrer}, step 7
|
|
112
|
+
* @callback module:utils/referrer~referrerURLCallback
|
|
113
|
+
* @param {external:URL} referrerURL
|
|
114
|
+
* @returns {external:URL} modified referrerURL
|
|
115
|
+
*/
|
|
116
|
+
/**
|
|
117
|
+
* Modifies the referrerOrigin to enforce any extra security policy considerations.
|
|
118
|
+
* @see {@link https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer Referrer Policy §8.3. Determine request's Referrer}, step 7
|
|
119
|
+
* @callback module:utils/referrer~referrerOriginCallback
|
|
120
|
+
* @param {external:URL} referrerOrigin
|
|
121
|
+
* @returns {external:URL} modified referrerOrigin
|
|
122
|
+
*/
|
|
123
|
+
/**
|
|
124
|
+
* @see {@link https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer Referrer Policy §8.3. Determine request's Referrer}
|
|
125
|
+
* @param request
|
|
126
|
+
* @param {object} o
|
|
127
|
+
* @param {module:utils/referrer~referrerURLCallback} o.referrerURLCallback
|
|
128
|
+
* @param {module:utils/referrer~referrerOriginCallback} o.referrerOriginCallback
|
|
129
|
+
* @returns {external:URL} Request's referrer
|
|
130
|
+
*/
|
|
73
131
|
function determineRequestsReferrer(request, obj = {}) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
return referrerURL;
|
|
130
|
-
default:
|
|
131
|
-
throw new TypeError(`Invalid referrerPolicy: ${policy}`);
|
|
132
|
-
}
|
|
132
|
+
const { referrerURLCallback, referrerOriginCallback } = obj;
|
|
133
|
+
if (request.referrer === "no-referrer" || request.referrerPolicy === "") {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
const policy = request.referrerPolicy;
|
|
137
|
+
if (request.referrer === "about:client") {
|
|
138
|
+
return "no-referrer";
|
|
139
|
+
}
|
|
140
|
+
const referrerSource = new URL(request.referrer);
|
|
141
|
+
let referrerURL = stripURLForUseAsAReferrer(referrerSource);
|
|
142
|
+
let referrerOrigin = stripURLForUseAsAReferrer(referrerSource, true);
|
|
143
|
+
if (referrerURL.toString().length > 4096) {
|
|
144
|
+
referrerURL = referrerOrigin;
|
|
145
|
+
}
|
|
146
|
+
if (referrerURLCallback) {
|
|
147
|
+
referrerURL = referrerURLCallback(referrerURL);
|
|
148
|
+
}
|
|
149
|
+
if (referrerOriginCallback) {
|
|
150
|
+
referrerOrigin = referrerOriginCallback(referrerOrigin);
|
|
151
|
+
}
|
|
152
|
+
const currentURL = new URL(request.url);
|
|
153
|
+
switch (policy) {
|
|
154
|
+
case "no-referrer": return "no-referrer";
|
|
155
|
+
case "origin": return referrerOrigin;
|
|
156
|
+
case "unsafe-url": return referrerURL;
|
|
157
|
+
case "strict-origin":
|
|
158
|
+
if (isUrlPotentiallyTrustworthy(referrerURL) && !isUrlPotentiallyTrustworthy(currentURL)) {
|
|
159
|
+
return "no-referrer";
|
|
160
|
+
}
|
|
161
|
+
return referrerOrigin.toString();
|
|
162
|
+
case "strict-origin-when-cross-origin":
|
|
163
|
+
if (referrerURL.origin === currentURL.origin) {
|
|
164
|
+
return referrerURL;
|
|
165
|
+
}
|
|
166
|
+
if (isUrlPotentiallyTrustworthy(referrerURL) && !isUrlPotentiallyTrustworthy(currentURL)) {
|
|
167
|
+
return "no-referrer";
|
|
168
|
+
}
|
|
169
|
+
return referrerOrigin;
|
|
170
|
+
case "same-origin":
|
|
171
|
+
if (referrerURL.origin === currentURL.origin) {
|
|
172
|
+
return referrerURL;
|
|
173
|
+
}
|
|
174
|
+
return "no-referrer";
|
|
175
|
+
case "origin-when-cross-origin":
|
|
176
|
+
if (referrerURL.origin === currentURL.origin) {
|
|
177
|
+
return referrerURL;
|
|
178
|
+
}
|
|
179
|
+
return referrerOrigin;
|
|
180
|
+
case "no-referrer-when-downgrade":
|
|
181
|
+
if (isUrlPotentiallyTrustworthy(referrerURL) && !isUrlPotentiallyTrustworthy(currentURL)) {
|
|
182
|
+
return "no-referrer";
|
|
183
|
+
}
|
|
184
|
+
return referrerURL;
|
|
185
|
+
default: throw new TypeError(`Invalid referrerPolicy: ${policy}`);
|
|
186
|
+
}
|
|
133
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* @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}
|
|
190
|
+
* @param {Headers} headers Response headers
|
|
191
|
+
* @returns {string} policy
|
|
192
|
+
*/
|
|
134
193
|
function parseReferrerPolicyFromHeader(headers) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
194
|
+
const policyTokens = (headers.get("referrer-policy") || "").split(/[,\s]+/);
|
|
195
|
+
let policy = "";
|
|
196
|
+
for (const token of policyTokens) {
|
|
197
|
+
if (token && ReferrerPolicy.has(token)) {
|
|
198
|
+
policy = token;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return policy;
|
|
143
202
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
determineRequestsReferrer,
|
|
148
|
-
isOriginPotentiallyTrustworthy,
|
|
149
|
-
isUrlPotentiallyTrustworthy,
|
|
150
|
-
parseReferrerPolicyFromHeader,
|
|
151
|
-
stripURLForUseAsAReferrer,
|
|
152
|
-
validateReferrerPolicy
|
|
153
|
-
};
|
|
203
|
+
|
|
204
|
+
//#endregion
|
|
205
|
+
export { DEFAULT_REFERRER_POLICY, ReferrerPolicy, determineRequestsReferrer, isOriginPotentiallyTrustworthy, isUrlPotentiallyTrustworthy, parseReferrerPolicyFromHeader, stripURLForUseAsAReferrer, validateReferrerPolicy };
|
|
@@ -1,22 +1,29 @@
|
|
|
1
|
-
import GLib from "@girs/glib-2.0";
|
|
2
1
|
import { Readable } from "node:stream";
|
|
2
|
+
import GLib from "@girs/glib-2.0";
|
|
3
3
|
import { inputStreamAsyncIterator } from "@gjsify/utils";
|
|
4
|
+
|
|
5
|
+
//#region src/utils/soup-helpers.ts
|
|
6
|
+
/**
|
|
7
|
+
* Promise wrapper around `Soup.Session.send_async` / `send_finish`.
|
|
8
|
+
*/
|
|
4
9
|
async function soupSendAsync(session, msg, ioPriority = GLib.PRIORITY_DEFAULT, cancellable = null) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
return new Promise((resolve, reject) => {
|
|
11
|
+
session.send_async(msg, ioPriority, cancellable, (_self, asyncRes) => {
|
|
12
|
+
try {
|
|
13
|
+
const inputStream = session.send_finish(asyncRes);
|
|
14
|
+
resolve(inputStream);
|
|
15
|
+
} catch (error) {
|
|
16
|
+
reject(error);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
});
|
|
15
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Converts a `Gio.InputStream` to a Node.js `Readable` stream.
|
|
23
|
+
*/
|
|
16
24
|
function inputStreamToReadable(inputStream, options = {}) {
|
|
17
|
-
|
|
25
|
+
return Readable.from(inputStreamAsyncIterator(inputStream), options);
|
|
18
26
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
};
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
export { inputStreamToReadable, soupSendAsync };
|