@e-mc/request 0.3.2 → 0.4.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/http/host/index.js +333 -333
- package/index.js +2186 -2186
- package/package.json +3 -3
- package/util.js +148 -148
package/http/host/index.js
CHANGED
|
@@ -1,336 +1,336 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var _a, _b, _c, _d;
|
|
3
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
const tls = require("tls");
|
|
5
|
-
const types_1 = require("../../../types");
|
|
6
|
-
const kProtocol = Symbol('protocol');
|
|
7
|
-
const kSecure = Symbol('secure');
|
|
8
|
-
const kHostname = Symbol('hostname');
|
|
9
|
-
const kPort = Symbol('port');
|
|
10
|
-
const kOrigin = Symbol('origin');
|
|
11
|
-
const kVersion = Symbol('version');
|
|
12
|
-
const kVersionData = Symbol('versionData');
|
|
13
|
-
const kAltSvc = Symbol('altSvc');
|
|
14
|
-
const kAltSvcQueue = Symbol('altSvcQueue');
|
|
15
|
-
const kAltSvcError = Symbol('altSvcError');
|
|
16
|
-
const HOST_LOCAL = new Set(['localhost']);
|
|
17
|
-
const HOST_HTTP_1_1 = [];
|
|
18
|
-
const HOST_ALPN_H2C = [];
|
|
19
|
-
const HOST_ALPN_H2 = [];
|
|
20
|
-
(function () {
|
|
21
|
-
const nic = require('os').networkInterfaces();
|
|
22
|
-
for (const name in nic) {
|
|
23
|
-
for (const { address } of nic[name].filter(item => item.internal)) {
|
|
24
|
-
HOST_LOCAL.add(address);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
})();
|
|
28
|
-
class HttpHost {
|
|
29
|
-
static normalizeOrigin(value) {
|
|
30
|
-
return value.replace(/\/+$/, '') + (!/:\d+$/.test(value) ? ':' + (value.startsWith('https') ? '443' : '80') : '');
|
|
31
|
-
}
|
|
32
|
-
static formatBasicAuth(url) {
|
|
33
|
-
return url.username ? decodeURIComponent(url.username) + (url.password ? ':' + decodeURIComponent(url.password) : '') : '';
|
|
34
|
-
}
|
|
35
|
-
static getBasicAuth(url) {
|
|
36
|
-
const auth = HttpHost.formatBasicAuth(url);
|
|
37
|
-
if (auth) {
|
|
38
|
-
return { authorization: 'Basic ' + Buffer.from(auth, 'base64') };
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
static defineLocalHost(value) {
|
|
42
|
-
HOST_LOCAL.clear();
|
|
43
|
-
value.forEach(address => (0, types_1.isString)(address) && HOST_LOCAL.add(address.trim()));
|
|
44
|
-
}
|
|
45
|
-
static defineProtocolNegotiation(value) {
|
|
46
|
-
const { h2c, h2 } = value;
|
|
47
|
-
const http11 = value['http/1.1'];
|
|
48
|
-
if (Array.isArray(http11)) {
|
|
49
|
-
HOST_HTTP_1_1.push(...http11.map(address => this.normalizeOrigin(address.trim())));
|
|
50
|
-
}
|
|
51
|
-
if (Array.isArray(h2c)) {
|
|
52
|
-
HOST_ALPN_H2C.push(...h2c.map(address => this.normalizeOrigin(address.trim())));
|
|
53
|
-
}
|
|
54
|
-
if (Array.isArray(h2)) {
|
|
55
|
-
HOST_ALPN_H2.push(...h2.map(address => this.normalizeOrigin(address.trim())));
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
constructor(url, httpVersion = 1) {
|
|
59
|
-
this[_a] = [
|
|
60
|
-
[0, 0, 0, 1, -1],
|
|
61
|
-
[0, 0, 0, -1, -1]
|
|
62
|
-
];
|
|
63
|
-
this[_b] = [];
|
|
64
|
-
this[_c] = [];
|
|
65
|
-
this[_d] = [];
|
|
66
|
-
this._tlsConnect = null;
|
|
67
|
-
const { protocol, hostname } = url;
|
|
68
|
-
const secure = protocol === 'https:';
|
|
69
|
-
const port = url.port || (secure ? '443' : '80');
|
|
70
|
-
let address = hostname + ':' + port;
|
|
71
|
-
this[kProtocol] = protocol;
|
|
72
|
-
this[kSecure] = secure;
|
|
73
|
-
this[kHostname] = hostname;
|
|
74
|
-
this[kPort] = port;
|
|
75
|
-
this[kOrigin] = url.origin;
|
|
76
|
-
this.localhost = HOST_LOCAL.has(hostname);
|
|
77
|
-
if (protocol !== 'file:' && !HOST_HTTP_1_1.includes(address = protocol + '//' + address)) {
|
|
78
|
-
if (secure) {
|
|
79
|
-
this[kVersion] = HOST_ALPN_H2.includes(address) ? 2 : httpVersion;
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
if (HOST_ALPN_H2C.includes(address)) {
|
|
83
|
-
this[kVersion] = 2;
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
this[kVersion] = 1;
|
|
88
|
-
this[kVersionData].forEach(version => version[4 /* HOST_VERSION.ALT_SVC */] = 0);
|
|
89
|
-
}
|
|
90
|
-
async hasProtocol(version) {
|
|
91
|
-
if (version > 1) {
|
|
92
|
-
const data = this[kVersionData][version - 1];
|
|
93
|
-
if (!data || !this.secure) {
|
|
94
|
-
return 0 /* QUERY_RESULT.FAIL */;
|
|
95
|
-
}
|
|
96
|
-
const status = data[3 /* HOST_VERSION.ALPN */];
|
|
97
|
-
switch (status) {
|
|
98
|
-
case 0:
|
|
99
|
-
case 1:
|
|
100
|
-
return status;
|
|
101
|
-
default:
|
|
102
|
-
return this._tlsConnect || (this._tlsConnect = new Promise(resolve => {
|
|
103
|
-
const alpn = 'h' + version;
|
|
104
|
-
const socket = tls.connect(+this.port, this.hostname, { ALPNProtocols: [alpn], requestCert: true, rejectUnauthorized: false }, () => {
|
|
105
|
-
resolve(data[3 /* HOST_VERSION.ALPN */] = alpn === socket.alpnProtocol ? 1 /* QUERY_RESULT.OK */ : 0 /* QUERY_RESULT.FAIL */);
|
|
106
|
-
this._tlsConnect = null;
|
|
107
|
-
});
|
|
108
|
-
socket
|
|
109
|
-
.setNoDelay(false)
|
|
110
|
-
.setTimeout(5000 /* HOST.TIMEOUT */)
|
|
111
|
-
.on('timeout', () => {
|
|
112
|
-
if (this._tlsConnect) {
|
|
113
|
-
if (this.error(version) >= 10 /* HOST.MAX_ERROR */) {
|
|
114
|
-
resolve(data[3 /* HOST_VERSION.ALPN */] = 0 /* QUERY_RESULT.FAIL */);
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
resolve(2 /* QUERY_RESULT.TIMEOUT */);
|
|
118
|
-
}
|
|
119
|
-
this._tlsConnect = null;
|
|
120
|
-
}
|
|
121
|
-
socket.destroy();
|
|
122
|
-
})
|
|
123
|
-
.on('error', () => {
|
|
124
|
-
this.failed(version);
|
|
125
|
-
resolve(data[3 /* HOST_VERSION.ALPN */] = 0 /* QUERY_RESULT.FAIL */);
|
|
126
|
-
this._tlsConnect = null;
|
|
127
|
-
})
|
|
128
|
-
.end();
|
|
129
|
-
}));
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
return 1 /* QUERY_RESULT.OK */;
|
|
133
|
-
}
|
|
134
|
-
success(version, status) {
|
|
135
|
-
const data = this[kVersionData][version - 1];
|
|
136
|
-
return status ? data[0 /* HOST_VERSION.SUCCESS */] : ++data[0 /* HOST_VERSION.SUCCESS */];
|
|
137
|
-
}
|
|
138
|
-
failed(version, status) {
|
|
139
|
-
const data = this[kVersionData][version - 1];
|
|
140
|
-
if (status) {
|
|
141
|
-
return data[1 /* HOST_VERSION.FAILED */];
|
|
142
|
-
}
|
|
143
|
-
this.clearAltSvc(version);
|
|
144
|
-
return ++data[1 /* HOST_VERSION.FAILED */];
|
|
145
|
-
}
|
|
146
|
-
error(version, status) {
|
|
147
|
-
const data = this[kVersionData][version - 1];
|
|
148
|
-
if (status) {
|
|
149
|
-
return data[2 /* HOST_VERSION.ERROR */];
|
|
150
|
-
}
|
|
151
|
-
if (data[4 /* HOST_VERSION.ALT_SVC */] !== 2) {
|
|
152
|
-
this.closeAltSvc(true);
|
|
153
|
-
}
|
|
154
|
-
return ++data[2 /* HOST_VERSION.ERROR */];
|
|
155
|
-
}
|
|
156
|
-
upgrade(version, altSvc) {
|
|
157
|
-
if (altSvc && this.secure) {
|
|
158
|
-
if (altSvc === 'clear') {
|
|
159
|
-
this.clearAltSvc();
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
const data = this[kVersionData];
|
|
163
|
-
for (let i = data.length - 1; i >= version; --i) {
|
|
164
|
-
const host = data[i];
|
|
165
|
-
if (host[4 /* HOST_VERSION.ALT_SVC */] === 0) {
|
|
166
|
-
continue;
|
|
167
|
-
}
|
|
168
|
-
const increment = (flag) => {
|
|
169
|
-
host[4 /* HOST_VERSION.ALT_SVC */] = flag;
|
|
170
|
-
if (this[kVersion] < i + 1) {
|
|
171
|
-
this[kVersion] = i + 1;
|
|
172
|
-
return true;
|
|
173
|
-
}
|
|
174
|
-
return false;
|
|
175
|
-
};
|
|
176
|
-
const pattern = new RegExp(`h${i + 1}="([^:]*):(\\d+)"([^,]*)`, 'g');
|
|
177
|
-
const addresses = [];
|
|
178
|
-
const time = Date.now();
|
|
179
|
-
const hostname = this[kHostname];
|
|
180
|
-
let match;
|
|
181
|
-
while (match = pattern.exec(altSvc)) {
|
|
182
|
-
const port = match[2];
|
|
183
|
-
if (!match[1] && port === this.port) {
|
|
184
|
-
increment(2);
|
|
185
|
-
addresses.length = 0;
|
|
186
|
-
break;
|
|
187
|
-
}
|
|
188
|
-
const address = match[1] || hostname;
|
|
189
|
-
const ma = +(/ma=(\d+)/.exec(match[3])?.[1] || 86400);
|
|
190
|
-
if (!this[kAltSvcError].includes(`h${i + 1}:${address}:${port}`)) {
|
|
191
|
-
addresses.push([
|
|
192
|
-
address,
|
|
193
|
-
port,
|
|
194
|
-
ma >= 2592000 /* TIMEOUT.MA */ ? NaN : time + Math.min(ma * 1000 /* TIME.S */, 2147483647 /* TIMEOUT.LIMIT */),
|
|
195
|
-
i + 1,
|
|
196
|
-
match[3].includes('persist=1')
|
|
197
|
-
]);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
if (addresses.length) {
|
|
201
|
-
this.closeAltSvc();
|
|
202
|
-
this[kAltSvcQueue] = addresses.sort((a, b) => {
|
|
203
|
-
if (a[0] === hostname) {
|
|
204
|
-
return -1;
|
|
205
|
-
}
|
|
206
|
-
if (b[0] === hostname) {
|
|
207
|
-
return 1;
|
|
208
|
-
}
|
|
209
|
-
if (isNaN(a[2]) || a[2] > b[2]) {
|
|
210
|
-
return -1;
|
|
211
|
-
}
|
|
212
|
-
if (isNaN(b[2]) || a[2] < b[2]) {
|
|
213
|
-
return 1;
|
|
214
|
-
}
|
|
215
|
-
if (a[3] && !b[3]) {
|
|
216
|
-
return -1;
|
|
217
|
-
}
|
|
218
|
-
if (!a[3] && b[3]) {
|
|
219
|
-
return -1;
|
|
220
|
-
}
|
|
221
|
-
return 0;
|
|
222
|
-
});
|
|
223
|
-
if (increment(1)) {
|
|
224
|
-
this.nextAltSvc();
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
didAltSvc(version) {
|
|
231
|
-
return this[kVersionData][version][4 /* HOST_VERSION.ALT_SVC */] !== -1;
|
|
232
|
-
}
|
|
233
|
-
nextAltSvc() {
|
|
234
|
-
const queue = this[kAltSvcQueue].shift();
|
|
235
|
-
if (queue) {
|
|
236
|
-
const [hostname, port, expires, version] = queue;
|
|
237
|
-
const timeout = expires - Date.now();
|
|
238
|
-
if (timeout < 0) {
|
|
239
|
-
return this.nextAltSvc();
|
|
240
|
-
}
|
|
241
|
-
let timer = null;
|
|
242
|
-
if (!isNaN(timeout)) {
|
|
243
|
-
timer = setTimeout(() => {
|
|
244
|
-
if (!this.nextAltSvc()) {
|
|
245
|
-
this.version = 1;
|
|
246
|
-
}
|
|
247
|
-
}, timeout);
|
|
248
|
-
}
|
|
249
|
-
this[kAltSvc] = [hostname, port, timer, version, this.protocol + '//' + hostname + ':' + port];
|
|
250
|
-
return true;
|
|
251
|
-
}
|
|
252
|
-
return false;
|
|
253
|
-
}
|
|
254
|
-
closeAltSvc(error) {
|
|
255
|
-
const [hostname, port, timeout, version] = this[kAltSvc];
|
|
256
|
-
if (hostname) {
|
|
257
|
-
this[kAltSvc] = [];
|
|
258
|
-
if (timeout) {
|
|
259
|
-
clearTimeout(timeout);
|
|
260
|
-
}
|
|
261
|
-
if (error) {
|
|
262
|
-
this[kAltSvcError].push(`h${version}:${hostname}:${port}`);
|
|
263
|
-
return this.nextAltSvc();
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
return false;
|
|
267
|
-
}
|
|
268
|
-
clearAltSvc(version) {
|
|
269
|
-
if (version) {
|
|
270
|
-
if (this[kAltSvcQueue].length === 0) {
|
|
271
|
-
this.flagAltSvc(version, 0);
|
|
272
|
-
}
|
|
273
|
-
else if (!this.closeAltSvc(true)) {
|
|
274
|
-
this.flagAltSvc(version, -1);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
else {
|
|
278
|
-
this.closeAltSvc();
|
|
279
|
-
this[kAltSvcQueue] = [];
|
|
280
|
-
this[kAltSvcError] = [];
|
|
281
|
-
this[kVersionData].forEach(item => {
|
|
282
|
-
if (item[3 /* HOST_VERSION.ALPN */] !== 0) {
|
|
283
|
-
item[4 /* HOST_VERSION.ALT_SVC */] = -1;
|
|
284
|
-
}
|
|
285
|
-
});
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
flagAltSvc(version, value) {
|
|
289
|
-
this[kVersionData][version - 1][4 /* HOST_VERSION.ALT_SVC */] = value;
|
|
290
|
-
}
|
|
291
|
-
reset() {
|
|
292
|
-
this.clearAltSvc();
|
|
293
|
-
this[kVersionData].forEach((item, index) => {
|
|
294
|
-
item[0 /* HOST_VERSION.SUCCESS */] = 0;
|
|
295
|
-
item[1 /* HOST_VERSION.FAILED */] = 0;
|
|
296
|
-
item[2 /* HOST_VERSION.ERROR */] = 0;
|
|
297
|
-
if (index > 0) {
|
|
298
|
-
item[3 /* HOST_VERSION.ALPN */] = -1;
|
|
299
|
-
}
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
v2() {
|
|
303
|
-
return this[kVersion] === 2;
|
|
304
|
-
}
|
|
305
|
-
set version(value) {
|
|
306
|
-
switch (value) {
|
|
307
|
-
case 1:
|
|
308
|
-
case 2:
|
|
309
|
-
this.flagAltSvc(this[kVersion] = value, -1);
|
|
310
|
-
break;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
get version() {
|
|
314
|
-
return this[kVersion];
|
|
315
|
-
}
|
|
316
|
-
get protocol() {
|
|
317
|
-
return this[kProtocol];
|
|
318
|
-
}
|
|
319
|
-
get secure() {
|
|
320
|
-
return this[kSecure];
|
|
321
|
-
}
|
|
322
|
-
get hostname() {
|
|
323
|
-
return this[kAltSvc][0] || this[kHostname];
|
|
324
|
-
}
|
|
325
|
-
get port() {
|
|
326
|
-
return this[kAltSvc][1] || this[kPort];
|
|
327
|
-
}
|
|
328
|
-
get origin() {
|
|
329
|
-
return this[kAltSvc][4] || this[kOrigin];
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
_a = kVersionData, _b = kAltSvc, _c = kAltSvcQueue, _d = kAltSvcError;
|
|
333
|
-
exports.default = HttpHost;
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a, _b, _c, _d;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const tls = require("tls");
|
|
5
|
+
const types_1 = require("../../../types");
|
|
6
|
+
const kProtocol = Symbol('protocol');
|
|
7
|
+
const kSecure = Symbol('secure');
|
|
8
|
+
const kHostname = Symbol('hostname');
|
|
9
|
+
const kPort = Symbol('port');
|
|
10
|
+
const kOrigin = Symbol('origin');
|
|
11
|
+
const kVersion = Symbol('version');
|
|
12
|
+
const kVersionData = Symbol('versionData');
|
|
13
|
+
const kAltSvc = Symbol('altSvc');
|
|
14
|
+
const kAltSvcQueue = Symbol('altSvcQueue');
|
|
15
|
+
const kAltSvcError = Symbol('altSvcError');
|
|
16
|
+
const HOST_LOCAL = new Set(['localhost']);
|
|
17
|
+
const HOST_HTTP_1_1 = [];
|
|
18
|
+
const HOST_ALPN_H2C = [];
|
|
19
|
+
const HOST_ALPN_H2 = [];
|
|
20
|
+
(function () {
|
|
21
|
+
const nic = require('os').networkInterfaces();
|
|
22
|
+
for (const name in nic) {
|
|
23
|
+
for (const { address } of nic[name].filter(item => item.internal)) {
|
|
24
|
+
HOST_LOCAL.add(address);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
})();
|
|
28
|
+
class HttpHost {
|
|
29
|
+
static normalizeOrigin(value) {
|
|
30
|
+
return value.replace(/\/+$/, '') + (!/:\d+$/.test(value) ? ':' + (value.startsWith('https') ? '443' : '80') : '');
|
|
31
|
+
}
|
|
32
|
+
static formatBasicAuth(url) {
|
|
33
|
+
return url.username ? decodeURIComponent(url.username) + (url.password ? ':' + decodeURIComponent(url.password) : '') : '';
|
|
34
|
+
}
|
|
35
|
+
static getBasicAuth(url) {
|
|
36
|
+
const auth = HttpHost.formatBasicAuth(url);
|
|
37
|
+
if (auth) {
|
|
38
|
+
return { authorization: 'Basic ' + Buffer.from(auth, 'base64') };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
static defineLocalHost(value) {
|
|
42
|
+
HOST_LOCAL.clear();
|
|
43
|
+
value.forEach(address => (0, types_1.isString)(address) && HOST_LOCAL.add(address.trim()));
|
|
44
|
+
}
|
|
45
|
+
static defineProtocolNegotiation(value) {
|
|
46
|
+
const { h2c, h2 } = value;
|
|
47
|
+
const http11 = value['http/1.1'];
|
|
48
|
+
if (Array.isArray(http11)) {
|
|
49
|
+
HOST_HTTP_1_1.push(...http11.map(address => this.normalizeOrigin(address.trim())));
|
|
50
|
+
}
|
|
51
|
+
if (Array.isArray(h2c)) {
|
|
52
|
+
HOST_ALPN_H2C.push(...h2c.map(address => this.normalizeOrigin(address.trim())));
|
|
53
|
+
}
|
|
54
|
+
if (Array.isArray(h2)) {
|
|
55
|
+
HOST_ALPN_H2.push(...h2.map(address => this.normalizeOrigin(address.trim())));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
constructor(url, httpVersion = 1) {
|
|
59
|
+
this[_a] = [
|
|
60
|
+
[0, 0, 0, 1, -1],
|
|
61
|
+
[0, 0, 0, -1, -1]
|
|
62
|
+
];
|
|
63
|
+
this[_b] = [];
|
|
64
|
+
this[_c] = [];
|
|
65
|
+
this[_d] = [];
|
|
66
|
+
this._tlsConnect = null;
|
|
67
|
+
const { protocol, hostname } = url;
|
|
68
|
+
const secure = protocol === 'https:';
|
|
69
|
+
const port = url.port || (secure ? '443' : '80');
|
|
70
|
+
let address = hostname + ':' + port;
|
|
71
|
+
this[kProtocol] = protocol;
|
|
72
|
+
this[kSecure] = secure;
|
|
73
|
+
this[kHostname] = hostname;
|
|
74
|
+
this[kPort] = port;
|
|
75
|
+
this[kOrigin] = url.origin;
|
|
76
|
+
this.localhost = HOST_LOCAL.has(hostname);
|
|
77
|
+
if (protocol !== 'file:' && !HOST_HTTP_1_1.includes(address = protocol + '//' + address)) {
|
|
78
|
+
if (secure) {
|
|
79
|
+
this[kVersion] = HOST_ALPN_H2.includes(address) ? 2 : httpVersion;
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (HOST_ALPN_H2C.includes(address)) {
|
|
83
|
+
this[kVersion] = 2;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
this[kVersion] = 1;
|
|
88
|
+
this[kVersionData].forEach(version => version[4 /* HOST_VERSION.ALT_SVC */] = 0);
|
|
89
|
+
}
|
|
90
|
+
async hasProtocol(version) {
|
|
91
|
+
if (version > 1) {
|
|
92
|
+
const data = this[kVersionData][version - 1];
|
|
93
|
+
if (!data || !this.secure) {
|
|
94
|
+
return 0 /* QUERY_RESULT.FAIL */;
|
|
95
|
+
}
|
|
96
|
+
const status = data[3 /* HOST_VERSION.ALPN */];
|
|
97
|
+
switch (status) {
|
|
98
|
+
case 0:
|
|
99
|
+
case 1:
|
|
100
|
+
return status;
|
|
101
|
+
default:
|
|
102
|
+
return this._tlsConnect || (this._tlsConnect = new Promise(resolve => {
|
|
103
|
+
const alpn = 'h' + version;
|
|
104
|
+
const socket = tls.connect(+this.port, this.hostname, { ALPNProtocols: [alpn], requestCert: true, rejectUnauthorized: false }, () => {
|
|
105
|
+
resolve(data[3 /* HOST_VERSION.ALPN */] = alpn === socket.alpnProtocol ? 1 /* QUERY_RESULT.OK */ : 0 /* QUERY_RESULT.FAIL */);
|
|
106
|
+
this._tlsConnect = null;
|
|
107
|
+
});
|
|
108
|
+
socket
|
|
109
|
+
.setNoDelay(false)
|
|
110
|
+
.setTimeout(5000 /* HOST.TIMEOUT */)
|
|
111
|
+
.on('timeout', () => {
|
|
112
|
+
if (this._tlsConnect) {
|
|
113
|
+
if (this.error(version) >= 10 /* HOST.MAX_ERROR */) {
|
|
114
|
+
resolve(data[3 /* HOST_VERSION.ALPN */] = 0 /* QUERY_RESULT.FAIL */);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
resolve(2 /* QUERY_RESULT.TIMEOUT */);
|
|
118
|
+
}
|
|
119
|
+
this._tlsConnect = null;
|
|
120
|
+
}
|
|
121
|
+
socket.destroy();
|
|
122
|
+
})
|
|
123
|
+
.on('error', () => {
|
|
124
|
+
this.failed(version);
|
|
125
|
+
resolve(data[3 /* HOST_VERSION.ALPN */] = 0 /* QUERY_RESULT.FAIL */);
|
|
126
|
+
this._tlsConnect = null;
|
|
127
|
+
})
|
|
128
|
+
.end();
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return 1 /* QUERY_RESULT.OK */;
|
|
133
|
+
}
|
|
134
|
+
success(version, status) {
|
|
135
|
+
const data = this[kVersionData][version - 1];
|
|
136
|
+
return status ? data[0 /* HOST_VERSION.SUCCESS */] : ++data[0 /* HOST_VERSION.SUCCESS */];
|
|
137
|
+
}
|
|
138
|
+
failed(version, status) {
|
|
139
|
+
const data = this[kVersionData][version - 1];
|
|
140
|
+
if (status) {
|
|
141
|
+
return data[1 /* HOST_VERSION.FAILED */];
|
|
142
|
+
}
|
|
143
|
+
this.clearAltSvc(version);
|
|
144
|
+
return ++data[1 /* HOST_VERSION.FAILED */];
|
|
145
|
+
}
|
|
146
|
+
error(version, status) {
|
|
147
|
+
const data = this[kVersionData][version - 1];
|
|
148
|
+
if (status) {
|
|
149
|
+
return data[2 /* HOST_VERSION.ERROR */];
|
|
150
|
+
}
|
|
151
|
+
if (data[4 /* HOST_VERSION.ALT_SVC */] !== 2) {
|
|
152
|
+
this.closeAltSvc(true);
|
|
153
|
+
}
|
|
154
|
+
return ++data[2 /* HOST_VERSION.ERROR */];
|
|
155
|
+
}
|
|
156
|
+
upgrade(version, altSvc) {
|
|
157
|
+
if (altSvc && this.secure) {
|
|
158
|
+
if (altSvc === 'clear') {
|
|
159
|
+
this.clearAltSvc();
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const data = this[kVersionData];
|
|
163
|
+
for (let i = data.length - 1; i >= version; --i) {
|
|
164
|
+
const host = data[i];
|
|
165
|
+
if (host[4 /* HOST_VERSION.ALT_SVC */] === 0) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
const increment = (flag) => {
|
|
169
|
+
host[4 /* HOST_VERSION.ALT_SVC */] = flag;
|
|
170
|
+
if (this[kVersion] < i + 1) {
|
|
171
|
+
this[kVersion] = i + 1;
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
return false;
|
|
175
|
+
};
|
|
176
|
+
const pattern = new RegExp(`h${i + 1}="([^:]*):(\\d+)"([^,]*)`, 'g');
|
|
177
|
+
const addresses = [];
|
|
178
|
+
const time = Date.now();
|
|
179
|
+
const hostname = this[kHostname];
|
|
180
|
+
let match;
|
|
181
|
+
while (match = pattern.exec(altSvc)) {
|
|
182
|
+
const port = match[2];
|
|
183
|
+
if (!match[1] && port === this.port) {
|
|
184
|
+
increment(2);
|
|
185
|
+
addresses.length = 0;
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
const address = match[1] || hostname;
|
|
189
|
+
const ma = +(/ma=(\d+)/.exec(match[3])?.[1] || 86400);
|
|
190
|
+
if (!this[kAltSvcError].includes(`h${i + 1}:${address}:${port}`)) {
|
|
191
|
+
addresses.push([
|
|
192
|
+
address,
|
|
193
|
+
port,
|
|
194
|
+
ma >= 2592000 /* TIMEOUT.MA */ ? NaN : time + Math.min(ma * 1000 /* TIME.S */, 2147483647 /* TIMEOUT.LIMIT */),
|
|
195
|
+
i + 1,
|
|
196
|
+
match[3].includes('persist=1')
|
|
197
|
+
]);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (addresses.length) {
|
|
201
|
+
this.closeAltSvc();
|
|
202
|
+
this[kAltSvcQueue] = addresses.sort((a, b) => {
|
|
203
|
+
if (a[0] === hostname) {
|
|
204
|
+
return -1;
|
|
205
|
+
}
|
|
206
|
+
if (b[0] === hostname) {
|
|
207
|
+
return 1;
|
|
208
|
+
}
|
|
209
|
+
if (isNaN(a[2]) || a[2] > b[2]) {
|
|
210
|
+
return -1;
|
|
211
|
+
}
|
|
212
|
+
if (isNaN(b[2]) || a[2] < b[2]) {
|
|
213
|
+
return 1;
|
|
214
|
+
}
|
|
215
|
+
if (a[3] && !b[3]) {
|
|
216
|
+
return -1;
|
|
217
|
+
}
|
|
218
|
+
if (!a[3] && b[3]) {
|
|
219
|
+
return -1;
|
|
220
|
+
}
|
|
221
|
+
return 0;
|
|
222
|
+
});
|
|
223
|
+
if (increment(1)) {
|
|
224
|
+
this.nextAltSvc();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
didAltSvc(version) {
|
|
231
|
+
return this[kVersionData][version][4 /* HOST_VERSION.ALT_SVC */] !== -1;
|
|
232
|
+
}
|
|
233
|
+
nextAltSvc() {
|
|
234
|
+
const queue = this[kAltSvcQueue].shift();
|
|
235
|
+
if (queue) {
|
|
236
|
+
const [hostname, port, expires, version] = queue;
|
|
237
|
+
const timeout = expires - Date.now();
|
|
238
|
+
if (timeout < 0) {
|
|
239
|
+
return this.nextAltSvc();
|
|
240
|
+
}
|
|
241
|
+
let timer = null;
|
|
242
|
+
if (!isNaN(timeout)) {
|
|
243
|
+
timer = setTimeout(() => {
|
|
244
|
+
if (!this.nextAltSvc()) {
|
|
245
|
+
this.version = 1;
|
|
246
|
+
}
|
|
247
|
+
}, timeout);
|
|
248
|
+
}
|
|
249
|
+
this[kAltSvc] = [hostname, port, timer, version, this.protocol + '//' + hostname + ':' + port];
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
closeAltSvc(error) {
|
|
255
|
+
const [hostname, port, timeout, version] = this[kAltSvc];
|
|
256
|
+
if (hostname) {
|
|
257
|
+
this[kAltSvc] = [];
|
|
258
|
+
if (timeout) {
|
|
259
|
+
clearTimeout(timeout);
|
|
260
|
+
}
|
|
261
|
+
if (error) {
|
|
262
|
+
this[kAltSvcError].push(`h${version}:${hostname}:${port}`);
|
|
263
|
+
return this.nextAltSvc();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
clearAltSvc(version) {
|
|
269
|
+
if (version) {
|
|
270
|
+
if (this[kAltSvcQueue].length === 0) {
|
|
271
|
+
this.flagAltSvc(version, 0);
|
|
272
|
+
}
|
|
273
|
+
else if (!this.closeAltSvc(true)) {
|
|
274
|
+
this.flagAltSvc(version, -1);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
this.closeAltSvc();
|
|
279
|
+
this[kAltSvcQueue] = [];
|
|
280
|
+
this[kAltSvcError] = [];
|
|
281
|
+
this[kVersionData].forEach(item => {
|
|
282
|
+
if (item[3 /* HOST_VERSION.ALPN */] !== 0) {
|
|
283
|
+
item[4 /* HOST_VERSION.ALT_SVC */] = -1;
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
flagAltSvc(version, value) {
|
|
289
|
+
this[kVersionData][version - 1][4 /* HOST_VERSION.ALT_SVC */] = value;
|
|
290
|
+
}
|
|
291
|
+
reset() {
|
|
292
|
+
this.clearAltSvc();
|
|
293
|
+
this[kVersionData].forEach((item, index) => {
|
|
294
|
+
item[0 /* HOST_VERSION.SUCCESS */] = 0;
|
|
295
|
+
item[1 /* HOST_VERSION.FAILED */] = 0;
|
|
296
|
+
item[2 /* HOST_VERSION.ERROR */] = 0;
|
|
297
|
+
if (index > 0) {
|
|
298
|
+
item[3 /* HOST_VERSION.ALPN */] = -1;
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
v2() {
|
|
303
|
+
return this[kVersion] === 2;
|
|
304
|
+
}
|
|
305
|
+
set version(value) {
|
|
306
|
+
switch (value) {
|
|
307
|
+
case 1:
|
|
308
|
+
case 2:
|
|
309
|
+
this.flagAltSvc(this[kVersion] = value, -1);
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
get version() {
|
|
314
|
+
return this[kVersion];
|
|
315
|
+
}
|
|
316
|
+
get protocol() {
|
|
317
|
+
return this[kProtocol];
|
|
318
|
+
}
|
|
319
|
+
get secure() {
|
|
320
|
+
return this[kSecure];
|
|
321
|
+
}
|
|
322
|
+
get hostname() {
|
|
323
|
+
return this[kAltSvc][0] || this[kHostname];
|
|
324
|
+
}
|
|
325
|
+
get port() {
|
|
326
|
+
return this[kAltSvc][1] || this[kPort];
|
|
327
|
+
}
|
|
328
|
+
get origin() {
|
|
329
|
+
return this[kAltSvc][4] || this[kOrigin];
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
_a = kVersionData, _b = kAltSvc, _c = kAltSvcQueue, _d = kAltSvcError;
|
|
333
|
+
exports.default = HttpHost;
|
|
334
334
|
|
|
335
335
|
if (exports.default) {
|
|
336
336
|
module.exports = exports.default;
|