@blamejs/pki 0.8.56 → 0.8.58
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/CHANGELOG.md +46 -0
- package/README.md +1 -1
- package/lib/guard-limits.js +13 -6
- package/lib/guard-parsed.js +23 -7
- package/lib/http-transport.js +256 -107
- package/lib/inspect.js +1 -1
- package/lib/lint.js +51 -3
- package/lib/ocsp.js +7 -0
- package/lib/oid.js +7 -0
- package/lib/schema-cms.js +113 -8
- package/lib/schema-ocsp.js +41 -6
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/http-transport.js
CHANGED
|
@@ -115,6 +115,47 @@ var _urlUsername = intrinsic.urlUsername;
|
|
|
115
115
|
var _urlPassword = intrinsic.urlPassword;
|
|
116
116
|
var _promiseResolve = intrinsic.uncurry(intrinsic.promiseResolve);
|
|
117
117
|
var _promiseReject = intrinsic.uncurry(intrinsic.promiseReject);
|
|
118
|
+
/** @internal The rest of the operations this module decides on, bound at load. Every one of them
|
|
119
|
+
* participates in a decision a socket is opened on: which scheme and host the request goes to,
|
|
120
|
+
* whether an address is private, which header a value is read under, how a body is sized and
|
|
121
|
+
* framed, and which TLS material a hop may carry. Read off the live prototype instead, a
|
|
122
|
+
* co-resident replacement answers the comparison rather than the value. */
|
|
123
|
+
var _charAt = intrinsic.uncurry(String.prototype.charAt);
|
|
124
|
+
var _charCodeAt = intrinsic.uncurry(String.prototype.charCodeAt);
|
|
125
|
+
var _strSlice = intrinsic.uncurry(String.prototype.slice);
|
|
126
|
+
var _strIndexOf = intrinsic.stringIndexOf;
|
|
127
|
+
var _toLowerCase = intrinsic.toLowerCase;
|
|
128
|
+
var _fromCharCode = intrinsic.fromCharCode;
|
|
129
|
+
var _isArray = intrinsic.isArray;
|
|
130
|
+
var _arrIndexOf = intrinsic.indexOf;
|
|
131
|
+
var _arrPush = intrinsic.push;
|
|
132
|
+
var _arrForEach = intrinsic.forEach;
|
|
133
|
+
var _isBuffer = intrinsic.isBuffer;
|
|
134
|
+
var _bufferFrom = intrinsic.bufferFrom;
|
|
135
|
+
var _bufferAlloc = intrinsic.bufferAlloc;
|
|
136
|
+
var _bufToString = intrinsic.bufToString;
|
|
137
|
+
var _byteLength = intrinsic.byteLength;
|
|
138
|
+
var _objectCreate = intrinsic.create;
|
|
139
|
+
var _objectAssign = intrinsic.assign;
|
|
140
|
+
var _objectKeys = intrinsic.keys;
|
|
141
|
+
var _getPrototypeOf = intrinsic.getPrototypeOf;
|
|
142
|
+
var _getOwnPropertyNames = intrinsic.getOwnPropertyNames;
|
|
143
|
+
var _getOwnPropertyDescriptor = intrinsic.getOwnPropertyDescriptor;
|
|
144
|
+
var _objectProto = intrinsic.ObjectProto;
|
|
145
|
+
var _arrayProto = intrinsic.ArrayProto;
|
|
146
|
+
var _hasOwn = intrinsic.hasOwn;
|
|
147
|
+
var _concatList = intrinsic.concatList;
|
|
148
|
+
var _taSet = intrinsic.typedArraySet;
|
|
149
|
+
var _bufferAllocUnsafe = Buffer.allocUnsafe;
|
|
150
|
+
/** @internal The three functions that actually open a connection, bound at load. Looked up on the
|
|
151
|
+
* module when the connection is made, a replacement installed afterwards sent a request prepared
|
|
152
|
+
* for one destination to another and handed the caller that peer's answer. */
|
|
153
|
+
var _httpsRequest = nodeHttps.request;
|
|
154
|
+
var _httpRequest = nodeHttp.request;
|
|
155
|
+
var _tlsConnect = nodeTls.connect;
|
|
156
|
+
var _netConnect = nodeNet.connect;
|
|
157
|
+
var _mathMin = intrinsic.min;
|
|
158
|
+
var _mathMax = intrinsic.max;
|
|
118
159
|
var frameworkError = require("./framework-error");
|
|
119
160
|
|
|
120
161
|
var TransportError = frameworkError.TransportError;
|
|
@@ -128,20 +169,30 @@ function _budget(value, key, dflt, max, E, code) {
|
|
|
128
169
|
return guard.limits.cap(value, key, dflt, { E: E, code: code, min: 1, max: max, label: key });
|
|
129
170
|
}
|
|
130
171
|
|
|
131
|
-
var _LATIN1_WS =
|
|
172
|
+
var _LATIN1_WS = _fromCharCode(0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x20, 0xa0);
|
|
173
|
+
|
|
174
|
+
/** @internal The received bytes, copied out at the length that was counted. The copy is its own
|
|
175
|
+
* allocation rather than a view, because the buffer it is taken from is reused as more data
|
|
176
|
+
* arrives. */
|
|
177
|
+
function _bodyCopy(buf, len) {
|
|
178
|
+
var out = _bufferAllocUnsafe(len);
|
|
179
|
+
_taSet(out, intrinsic.byteSlice(buf, 0, len), 0);
|
|
180
|
+
return out;
|
|
181
|
+
}
|
|
132
182
|
|
|
133
183
|
function _looksLikePemArmor(s) {
|
|
134
184
|
var i = 0;
|
|
135
|
-
while (i < s.length && _LATIN1_WS
|
|
136
|
-
return s
|
|
185
|
+
while (i < s.length && _strIndexOf(_LATIN1_WS, _charAt(s, i)) !== -1) i += 1;
|
|
186
|
+
return _strSlice(s, i, i + 11) === "-----BEGIN ";
|
|
137
187
|
}
|
|
138
188
|
function _wrap64Lines(s) {
|
|
139
189
|
var out = "";
|
|
140
|
-
for (var i = 0; i < s.length; i += 64) out += s
|
|
190
|
+
for (var i = 0; i < s.length; i += 64) out += _strSlice(s, i, i + 64) + "\n";
|
|
141
191
|
return out;
|
|
142
192
|
}
|
|
143
193
|
function _stripIpv6Brackets(s) {
|
|
144
|
-
return (s.length >= 2 && s
|
|
194
|
+
return (s.length >= 2 && _charAt(s, 0) === "[" && _charAt(s, s.length - 1) === "]")
|
|
195
|
+
? _strSlice(s, 1, s.length - 1) : s;
|
|
145
196
|
}
|
|
146
197
|
|
|
147
198
|
var TLS_EXPORTER_LABEL = "EXPORTER-Channel-Binding";
|
|
@@ -150,9 +201,9 @@ var TLS_EXPORTER_LENGTH = 32;
|
|
|
150
201
|
function _tlsExporter(socket, proto) {
|
|
151
202
|
if (proto !== "TLSv1.3" || !socket || typeof socket.exportKeyingMaterial !== "function") return null;
|
|
152
203
|
var out;
|
|
153
|
-
try { out = socket.exportKeyingMaterial(TLS_EXPORTER_LENGTH, TLS_EXPORTER_LABEL,
|
|
204
|
+
try { out = socket.exportKeyingMaterial(TLS_EXPORTER_LENGTH, TLS_EXPORTER_LABEL, _bufferAlloc(0)); }
|
|
154
205
|
catch (_ee) { return null; }
|
|
155
|
-
return (
|
|
206
|
+
return (_isBuffer(out) && out.length === TLS_EXPORTER_LENGTH) ? out : null;
|
|
156
207
|
}
|
|
157
208
|
|
|
158
209
|
function _tlsInfo(socket) {
|
|
@@ -182,10 +233,10 @@ function _peerChain(socket) {
|
|
|
182
233
|
var out = [];
|
|
183
234
|
var seen = [];
|
|
184
235
|
var cur = socket.getPeerCertificate(true);
|
|
185
|
-
while (cur &&
|
|
186
|
-
if (seen
|
|
187
|
-
seen
|
|
188
|
-
out
|
|
236
|
+
while (cur && _isBuffer(cur.raw) && out.length < constants.LIMITS.TLS_MAX_PEER_CHAIN) {
|
|
237
|
+
if (_arrIndexOf(seen, cur) !== -1) break;
|
|
238
|
+
_arrPush(seen, cur);
|
|
239
|
+
_arrPush(out, cur.raw);
|
|
189
240
|
cur = cur.issuerCertificate;
|
|
190
241
|
}
|
|
191
242
|
return out;
|
|
@@ -193,26 +244,31 @@ function _peerChain(socket) {
|
|
|
193
244
|
|
|
194
245
|
function _pemifyAnchor(a) {
|
|
195
246
|
if (typeof a === "string") return a;
|
|
196
|
-
if (
|
|
197
|
-
if (_looksLikePemArmor(a
|
|
198
|
-
var b64 = _wrap64Lines(a
|
|
247
|
+
if (_isBuffer(a)) {
|
|
248
|
+
if (_looksLikePemArmor(_bufToString(a, "latin1", 0, 64))) return a;
|
|
249
|
+
var b64 = _wrap64Lines(_bufToString(a, "base64"));
|
|
199
250
|
return "-----BEGIN CERTIFICATE-----\n" + b64 + "-----END CERTIFICATE-----\n";
|
|
200
251
|
}
|
|
201
252
|
return a;
|
|
202
253
|
}
|
|
203
254
|
function _pemifyAnchors(anchors) {
|
|
204
|
-
var list =
|
|
255
|
+
var list = _isArray(anchors) ? guard.list.copyMap(anchors, _pemifyAnchor) : [_pemifyAnchor(anchors)];
|
|
205
256
|
return list;
|
|
206
257
|
}
|
|
207
258
|
|
|
259
|
+
/** @internal The platform trust store is read through the provider bound at load. Looked up on the
|
|
260
|
+
* module at call time, a replacement installed after load answered with its own list and became the
|
|
261
|
+
* trust a `useSystemStore` connection is accepted under. */
|
|
262
|
+
var _getCACertificates = typeof nodeTls.getCACertificates === "function" ? nodeTls.getCACertificates : null;
|
|
263
|
+
|
|
208
264
|
var _systemCaCache = null;
|
|
209
265
|
function _systemCa() {
|
|
210
266
|
if (_systemCaCache !== null) return _systemCaCache;
|
|
211
267
|
var out = [];
|
|
212
|
-
if (
|
|
213
|
-
["system", "bundled"]
|
|
268
|
+
if (_getCACertificates !== null) {
|
|
269
|
+
_arrForEach(["system", "bundled"], function (t) {
|
|
214
270
|
// allow:swallow-unverified a store TYPE unsupported on this node is skipped; the other type
|
|
215
|
-
try { var c =
|
|
271
|
+
try { var c = intrinsic.apply(_getCACertificates, nodeTls, [t]); if (_isArray(c)) out = _concatList(out, c); } catch (_e) { }
|
|
216
272
|
});
|
|
217
273
|
}
|
|
218
274
|
_systemCaCache = out;
|
|
@@ -282,9 +338,19 @@ function _makeGuardedLookup(lookupFn) {
|
|
|
282
338
|
return function guardedLookup(hostname, options, callback) {
|
|
283
339
|
lookupFn(hostname, options || {}, function (err, address, family) {
|
|
284
340
|
if (err) return callback(err);
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
341
|
+
/** @internal Each address is read ONCE, the read is what gets classified, and the SNAPSHOT is
|
|
342
|
+
* what the socket layer is handed. Forwarding the list the resolver returned let the entry be
|
|
343
|
+
* read again after it was cleared: a `lookup` answering a public address to this check and a
|
|
344
|
+
* loopback one to the connection reached loopback with `blockPrivateAddresses` set. */
|
|
345
|
+
if (_isArray(address)) {
|
|
346
|
+
var checked = [];
|
|
347
|
+
for (var i = 0; i < address.length; i++) {
|
|
348
|
+
var entry = address[i];
|
|
349
|
+
var one = { address: entry && entry.address, family: entry && entry.family };
|
|
350
|
+
if (_isBlockedIp(one.address)) return callback(_blockedAddrErr(hostname, one.address));
|
|
351
|
+
checked[i] = one;
|
|
352
|
+
}
|
|
353
|
+
return callback(null, checked);
|
|
288
354
|
}
|
|
289
355
|
if (_isBlockedIp(address)) return callback(_blockedAddrErr(hostname, address));
|
|
290
356
|
return callback(null, address, family);
|
|
@@ -295,75 +361,81 @@ var _guardedLookup = _makeGuardedLookup(nodeDns.lookup);
|
|
|
295
361
|
|
|
296
362
|
function _hasSelfSigned(l) {
|
|
297
363
|
for (var i = 0; i + 4 <= l.length; i++) {
|
|
298
|
-
if (l
|
|
299
|
-
if (l
|
|
300
|
-
var mid = l
|
|
301
|
-
if (i + 4 < l.length && mid !== 0x0a && mid !== 0x0d && mid !== 0x2028 && mid !== 0x2029 && l
|
|
364
|
+
if (_charCodeAt(l, i) === 0x73 && _charCodeAt(l, i + 1) === 0x65 && _charCodeAt(l, i + 2) === 0x6c && _charCodeAt(l, i + 3) === 0x66) {
|
|
365
|
+
if (_strIndexOf(l, "signed", i + 4) === i + 4) return true;
|
|
366
|
+
var mid = _charCodeAt(l, i + 4);
|
|
367
|
+
if (i + 4 < l.length && mid !== 0x0a && mid !== 0x0d && mid !== 0x2028 && mid !== 0x2029 && _strIndexOf(l, "signed", i + 5) === i + 5) return true;
|
|
302
368
|
}
|
|
303
369
|
}
|
|
304
370
|
return false;
|
|
305
371
|
}
|
|
306
372
|
function _hasWordBounded(l, word) {
|
|
307
|
-
var at = l
|
|
373
|
+
var at = _strIndexOf(l, word);
|
|
308
374
|
while (at !== -1) {
|
|
309
|
-
var before = at === 0 || !_isLowerWordChar(l
|
|
375
|
+
var before = at === 0 || !_isLowerWordChar(_charCodeAt(l, at - 1));
|
|
310
376
|
var afterI = at + word.length;
|
|
311
|
-
var after = afterI === l.length || !_isLowerWordChar(l
|
|
377
|
+
var after = afterI === l.length || !_isLowerWordChar(_charCodeAt(l, afterI));
|
|
312
378
|
if (before && after) return true;
|
|
313
|
-
at = l
|
|
379
|
+
at = _strIndexOf(l, word, at + 1);
|
|
314
380
|
}
|
|
315
381
|
return false;
|
|
316
382
|
}
|
|
317
383
|
function _isLowerWordChar(c) { return (c >= 97 && c <= 122) || (c >= 48 && c <= 57) || c === 95; }
|
|
318
384
|
function _classifyError(e, C) {
|
|
319
385
|
if (e && e.pkiBlockedAddress) return C("blocked-address");
|
|
320
|
-
var s =
|
|
321
|
-
var l = s
|
|
322
|
-
if (l
|
|
323
|
-
l
|
|
324
|
-
if (l
|
|
325
|
-
l
|
|
386
|
+
var s = _stringOf((e && e.code) || "") + " " + _stringOf((e && e.message) || "");
|
|
387
|
+
var l = _toLowerCase(s);
|
|
388
|
+
if (_strIndexOf(l, "protocol_version") !== -1 || _strIndexOf(l, "unsupported_protocol") !== -1 || _strIndexOf(l, "version_too_low") !== -1 ||
|
|
389
|
+
_strIndexOf(l, "wrong_version") !== -1 || _strIndexOf(l, "no_protocols_available") !== -1 || _strIndexOf(l, "inappropriate_fallback") !== -1) return C("tls-floor");
|
|
390
|
+
if (_strIndexOf(l, "cert") !== -1 || _strIndexOf(l, "verify") !== -1 || _strIndexOf(l, "altname") !== -1 || _strIndexOf(l, "hostname") !== -1 ||
|
|
391
|
+
_strIndexOf(l, "depth_zero") !== -1 || _strIndexOf(l, "local_issuer") !== -1 || _strIndexOf(l, "handshake") !== -1 ||
|
|
326
392
|
_hasSelfSigned(l) || _hasWordBounded(l, "ssl") || _hasWordBounded(l, "tls")) return C("server-auth-failed");
|
|
327
393
|
return C("transport-error");
|
|
328
394
|
}
|
|
329
395
|
|
|
330
|
-
function _keySet(names) { var m =
|
|
396
|
+
function _keySet(names) { var m = _objectCreate(null); for (var i = 0; i < names.length; i++) m[names[i]] = true; return m; }
|
|
331
397
|
var PROXY_KEYS = _keySet(["url", "auth", "tls"]);
|
|
332
398
|
var PROXY_AUTH_KEYS = _keySet(["scheme", "username", "password", "allowMD5", "allowLegacyQop"]);
|
|
333
399
|
var PROXY_DIGEST_KNOBS = ["allowMD5", "allowLegacyQop"];
|
|
334
400
|
var PROXY_TLS_KEYS = _keySet(["anchors", "useSystemStore", "servername", "minVersion"]);
|
|
335
401
|
|
|
336
|
-
function _copyAnchor(a) { return (a !== null && typeof a === "object" && nodeUtil.types.isProxy(a)) ? a : (
|
|
402
|
+
function _copyAnchor(a) { return (a !== null && typeof a === "object" && nodeUtil.types.isProxy(a)) ? a : (_isBuffer(a) ? _bufferFrom(a) : a); }
|
|
337
403
|
function _noopProxyErr(code, message) { var e = new Error(message); e.code = code; e.isPkiError = true; return e; }
|
|
338
404
|
function _copyableRecord(p) {
|
|
339
405
|
if (!guard.identifier.isPlainRecord(p)) return false;
|
|
340
|
-
var proto =
|
|
341
|
-
if (proto !==
|
|
406
|
+
var proto = _getPrototypeOf(p);
|
|
407
|
+
if (proto !== _objectProto && proto !== null) return false;
|
|
342
408
|
if (Object.getOwnPropertySymbols(p).length !== 0) return false;
|
|
343
409
|
var ownEnumData = 0;
|
|
344
|
-
var names =
|
|
410
|
+
var names = _getOwnPropertyNames(p);
|
|
345
411
|
for (var i = 0; i < names.length; i++) {
|
|
346
|
-
var d =
|
|
412
|
+
var d = _getOwnPropertyDescriptor(p, names[i]);
|
|
347
413
|
if (!d.enumerable || d.get || d.set) return false;
|
|
348
414
|
ownEnumData++;
|
|
349
415
|
}
|
|
350
416
|
var readable = guard.identifier.readableNames(p, _noopProxyErr, "transport/bad-proxy", "opts.proxy");
|
|
351
417
|
if (readable.length !== ownEnumData) return false;
|
|
352
418
|
for (var j = 0; j < readable.length; j++) {
|
|
353
|
-
var rd =
|
|
419
|
+
var rd = _getOwnPropertyDescriptor(p, readable[j]);
|
|
354
420
|
if (!rd || !rd.enumerable || rd.get || rd.set) return false;
|
|
355
421
|
}
|
|
356
422
|
return true;
|
|
357
423
|
}
|
|
358
424
|
function _copyableArray(a) {
|
|
359
|
-
if (a === null || typeof a !== "object" || nodeUtil.types.isProxy(a) || !
|
|
425
|
+
if (a === null || typeof a !== "object" || nodeUtil.types.isProxy(a) || !_isArray(a) || _getPrototypeOf(a) !== _arrayProto) return false;
|
|
360
426
|
if (a.length > constants.LIMITS.PROXY_MAX_TLS_ANCHORS) return false;
|
|
361
427
|
if (Object.getOwnPropertySymbols(a).length !== 0) return false;
|
|
362
|
-
var names =
|
|
428
|
+
var names = _getOwnPropertyNames(a);
|
|
363
429
|
for (var i = 0; i < names.length; i++) {
|
|
364
|
-
var d =
|
|
430
|
+
var d = _getOwnPropertyDescriptor(a, names[i]);
|
|
365
431
|
if (d.get || d.set) return false;
|
|
366
432
|
}
|
|
433
|
+
/** @internal Every index has to be the array's OWN. A descriptor walk cannot see a HOLE, so a
|
|
434
|
+
* sparse list whose gap is answered by an accessor on `Array.prototype` passed this check and
|
|
435
|
+
* then read a different value at each read: the validation saw one anchor and the conversion
|
|
436
|
+
* used another. Reading by index is specified to consult the prototype at a hole, which is why
|
|
437
|
+
* the gap is refused here rather than read carefully later. */
|
|
438
|
+
for (var k = 0; k < a.length; k++) { if (!_hasOwn(a, k)) return false; }
|
|
367
439
|
return true;
|
|
368
440
|
}
|
|
369
441
|
function snapshotProxy(p) {
|
|
@@ -379,7 +451,7 @@ function snapshotProxy(p) {
|
|
|
379
451
|
for (var i = 0; i < a.length; i++) copied[i] = _copyAnchor(a[i]);
|
|
380
452
|
out.tls.anchors = copied;
|
|
381
453
|
} else if (typeof a === "string") out.tls.anchors = a;
|
|
382
|
-
else if (a !== null && typeof a === "object" && !nodeUtil.types.isProxy(a) &&
|
|
454
|
+
else if (a !== null && typeof a === "object" && !nodeUtil.types.isProxy(a) && _isBuffer(a)) out.tls.anchors = _bufferFrom(a);
|
|
383
455
|
}
|
|
384
456
|
return out;
|
|
385
457
|
} catch (_e) {
|
|
@@ -392,7 +464,8 @@ function snapshotProxy(p) {
|
|
|
392
464
|
* the parsed origin; they are passed in rather than read again here, so the authority this builds for
|
|
393
465
|
* the CONNECT target is the same authority the socket options were built from. */
|
|
394
466
|
function _validateProxy(request, defaults, E, C, originHost, originStatedPort, originScheme) {
|
|
395
|
-
var
|
|
467
|
+
var rawProxy = request.proxy;
|
|
468
|
+
var proxy = rawProxy !== undefined ? rawProxy : defaults.proxy;
|
|
396
469
|
if (proxy === undefined || proxy === null) return null;
|
|
397
470
|
guard.identifier.assertPlainRecord(proxy, E, C("bad-proxy"), "opts.proxy");
|
|
398
471
|
if (!_copyableRecord(proxy)) throw E(C("bad-proxy"), "opts.proxy must be a plain object with only own enumerable data properties");
|
|
@@ -443,21 +516,25 @@ function _validateProxy(request, defaults, E, C, originHost, originStatedPort, o
|
|
|
443
516
|
var pAnchors = ptls ? ptls.anchors : undefined;
|
|
444
517
|
if (pAnchors !== undefined && pAnchors !== null && typeof pAnchors === "object" && nodeUtil.types.isProxy(pAnchors)) throw E(C("bad-proxy"), "opts.proxy.tls.anchors must not be a Proxy");
|
|
445
518
|
var pUseSystem = ptls ? ptls.useSystemStore === true : false;
|
|
446
|
-
var pHasAnchors = pAnchors !== undefined && pAnchors !== null && !(
|
|
519
|
+
var pHasAnchors = pAnchors !== undefined && pAnchors !== null && !(_isArray(pAnchors) && pAnchors.length === 0);
|
|
447
520
|
if (!pHasAnchors && !pUseSystem) throw E(C("bad-proxy"), "an https proxy requires explicit tls trust: set proxy.tls.anchors or proxy.tls.useSystemStore");
|
|
448
521
|
if (pHasAnchors) {
|
|
449
|
-
if (
|
|
450
|
-
var pAnchorList =
|
|
522
|
+
if (_isArray(pAnchors) && !_copyableArray(pAnchors)) throw E(C("bad-proxy"), "opts.proxy.tls.anchors must be a plain array of PEM strings or DER Buffers");
|
|
523
|
+
var pAnchorList = _isArray(pAnchors) ? pAnchors : [pAnchors];
|
|
451
524
|
for (var pai = 0; pai < pAnchorList.length; pai++) {
|
|
452
525
|
var pan = pAnchorList[pai];
|
|
453
|
-
if ((pan !== null && typeof pan === "object" && nodeUtil.types.isProxy(pan)) || (typeof pan !== "string" && !
|
|
526
|
+
if ((pan !== null && typeof pan === "object" && nodeUtil.types.isProxy(pan)) || (typeof pan !== "string" && !_isBuffer(pan))) throw E(C("bad-proxy"), "opts.proxy.tls.anchors must be a PEM string or a DER Buffer (or an array of them)");
|
|
454
527
|
}
|
|
455
528
|
}
|
|
456
529
|
var pMinVersion = (ptls && ptls.minVersion !== undefined && ptls.minVersion !== null) ? ptls.minVersion : DEFAULT_MIN_VERSION;
|
|
457
530
|
if (pMinVersion !== "TLSv1.2" && pMinVersion !== "TLSv1.3") throw E(C("bad-proxy"), "proxy.tls.minVersion must be 'TLSv1.2' or 'TLSv1.3', got " + guard.text.showValue(pMinVersion));
|
|
458
531
|
var pCa = [];
|
|
459
|
-
|
|
460
|
-
|
|
532
|
+
/** @internal `concatList`, not the captured `concat`: `Array.prototype.concat` is specified to
|
|
533
|
+
* consult `Symbol.isConcatSpreadable` on each argument, so capturing the method leaves the
|
|
534
|
+
* SPREADING replaceable and an inherited hook replaced a validated anchor with another one in
|
|
535
|
+
* the CONNECT options. `concatList` copies own indexes and appends own indexes. */
|
|
536
|
+
if (pHasAnchors) pCa = _concatList(pCa, _pemifyAnchors(pAnchors));
|
|
537
|
+
if (pUseSystem) pCa = _concatList(pCa, _systemCa());
|
|
461
538
|
proxyTls = { ca: pCa.length ? pCa : undefined, minVersion: pMinVersion, servername: pServername };
|
|
462
539
|
}
|
|
463
540
|
|
|
@@ -472,7 +549,7 @@ function _validateProxy(request, defaults, E, C, originHost, originStatedPort, o
|
|
|
472
549
|
}
|
|
473
550
|
|
|
474
551
|
function _basicProxyHeader(auth) {
|
|
475
|
-
return "Basic " +
|
|
552
|
+
return "Basic " + _bufToString(_bufferFrom(auth.username + ":" + auth.password, "utf8"), "base64");
|
|
476
553
|
}
|
|
477
554
|
|
|
478
555
|
/** @internal The `Proxy-Authorization` value answering a proxy's `Proxy-Authenticate: Digest` challenge
|
|
@@ -501,10 +578,10 @@ function _digestProxyCredential(headers, pinfo, C, E) {
|
|
|
501
578
|
}, E);
|
|
502
579
|
}
|
|
503
580
|
function _proxyErrorClass(e, C) {
|
|
504
|
-
var code =
|
|
505
|
-
if (code
|
|
506
|
-
code
|
|
507
|
-
code
|
|
581
|
+
var code = _stringOf((e && e.code) || "");
|
|
582
|
+
if (_strIndexOf(code, "ERR_TLS") === 0 || _strIndexOf(code, "ERR_SSL") === 0 || _strIndexOf(code, "SSL") !== -1 ||
|
|
583
|
+
_strIndexOf(code, "CERT") !== -1 || _strIndexOf(code, "SELF_SIGNED") !== -1 || _strIndexOf(code, "VERIFY") !== -1 ||
|
|
584
|
+
_strIndexOf(code, "_SIGNATURE") !== -1 || _strIndexOf(code, "ALTNAME") !== -1) return C("proxy-tls-failed");
|
|
508
585
|
return C("proxy-connect-failed");
|
|
509
586
|
}
|
|
510
587
|
|
|
@@ -548,18 +625,22 @@ function _proxyErrorClass(e, C) {
|
|
|
548
625
|
*/
|
|
549
626
|
function httpsTransport(defaults) {
|
|
550
627
|
defaults = defaults || {};
|
|
551
|
-
|
|
628
|
+
/** @internal Each of these is read ONCE, into the value both the test and the use see, and the
|
|
629
|
+
* error factory a refusal is built from is one of them. */
|
|
630
|
+
var rawE = defaults.E;
|
|
631
|
+
var E = typeof rawE === "function" ? rawE : defaultE;
|
|
552
632
|
var prefix = defaults.errPrefix || "transport";
|
|
553
633
|
function C(name) { return prefix + "/" + name; }
|
|
554
634
|
/** @internal No prototype where no TLS was bound: an empty object literal inherits from
|
|
555
635
|
* `Object.prototype`, so a value installed there would answer for a setting nobody set, and one of
|
|
556
636
|
* the settings read from this record is the opt-in that turns away an unpinned server. */
|
|
557
|
-
var
|
|
637
|
+
var rawDefaultTls = defaults.tls;
|
|
638
|
+
var tlsDefaults = rawDefaultTls != null ? rawDefaultTls : intrinsic.create(null);
|
|
558
639
|
|
|
559
640
|
function _prepare(request) {
|
|
560
641
|
var url;
|
|
561
642
|
try { url = new _URL(_stringOf(request.url)); }
|
|
562
|
-
catch (e) { throw E(C("bad-url"), "the request URL did not parse: " +
|
|
643
|
+
catch (e) { throw E(C("bad-url"), "the request URL did not parse: " + _stringOf(request.url), e); }
|
|
563
644
|
/** @internal https is the floor, and `request.allowPlaintextHttp` is the one thing that moves
|
|
564
645
|
* it, per request and never as a default. It exists for the two objects whose integrity does
|
|
565
646
|
* not come from the transport: a CRL and an OCSP response are signed, their signatures are
|
|
@@ -578,10 +659,17 @@ function httpsTransport(defaults) {
|
|
|
578
659
|
throw E(C("insecure-url"), "transport requires https (RFC 7030 sec. 3.3), got " + scheme);
|
|
579
660
|
}
|
|
580
661
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
662
|
+
/** @internal Each setting is read ONCE, into the value the presence test and the use share. Read
|
|
663
|
+
* twice, the second read decided: a `tls` answering an object to the test and nothing to the use
|
|
664
|
+
* left `reqTls` undefined, and the anchor read on the next line threw a raw TypeError out of a
|
|
665
|
+
* public verb instead of this module's typed refusal. */
|
|
666
|
+
var rawReqTls = request.tls;
|
|
667
|
+
var reqTls = rawReqTls != null ? rawReqTls : intrinsic.create(null);
|
|
668
|
+
var rawAnchors = reqTls.anchors;
|
|
669
|
+
var anchors = rawAnchors !== undefined ? rawAnchors : tlsDefaults.anchors;
|
|
670
|
+
var rawUseSystem = reqTls.useSystemStore;
|
|
671
|
+
var useSystem = (rawUseSystem !== undefined ? rawUseSystem : tlsDefaults.useSystemStore) === true;
|
|
672
|
+
var hasAnchors = anchors !== undefined && anchors !== null && !(_isArray(anchors) && anchors.length === 0);
|
|
585
673
|
/** @internal A trust anchor is what makes an https server identifiable, so a request with
|
|
586
674
|
* neither an anchor nor the system store is refused rather than left unpinned. A plaintext hop
|
|
587
675
|
* negotiates no certificate, so there is nothing for an anchor to pin; what protects the object
|
|
@@ -590,8 +678,10 @@ function httpsTransport(defaults) {
|
|
|
590
678
|
throw E(C("no-trust-anchors"), "no explicit trust anchor and useSystemStore not set -- refusing an unpinned server (RFC 7030 sec. 3.6)");
|
|
591
679
|
}
|
|
592
680
|
|
|
593
|
-
var
|
|
594
|
-
var
|
|
681
|
+
var rawTimeout = request.timeout;
|
|
682
|
+
var timeout = _budget(rawTimeout !== undefined ? rawTimeout : defaults.timeout, "timeout", DEFAULT_TIMEOUT, MAX_TIMEOUT, E, C("bad-input"));
|
|
683
|
+
var rawMaxBytes = request.maxResponseBytes;
|
|
684
|
+
var maxBytes = _budget(rawMaxBytes !== undefined ? rawMaxBytes : defaults.maxResponseBytes, "maxResponseBytes", constants.LIMITS.HTTP_MAX_RESPONSE_BYTES, constants.LIMITS.HTTP_MAX_RESPONSE_BYTES, E, C("bad-input"));
|
|
595
685
|
|
|
596
686
|
var minVersion = reqTls.minVersion || tlsDefaults.minVersion || DEFAULT_MIN_VERSION;
|
|
597
687
|
if (minVersion !== "TLSv1.2" && minVersion !== "TLSv1.3") throw E(C("bad-input"), "tls.minVersion must be 'TLSv1.2' or 'TLSv1.3' (never below the floor), got " + minVersion);
|
|
@@ -601,12 +691,12 @@ function httpsTransport(defaults) {
|
|
|
601
691
|
if (!bodyIsFn && guard.bytes.isByteSource(body)) body = guard.bytes.source(body, E, C("bad-input"), "the request body");
|
|
602
692
|
|
|
603
693
|
var reqHeaders = guard.identifier.ownOptions(request.headers);
|
|
604
|
-
|
|
694
|
+
_arrForEach(_objectKeys(reqHeaders), function (k) { var lk = _toLowerCase(k); if (lk === "proxy-authorization" || lk === "proxy-connection") delete reqHeaders[k]; });
|
|
605
695
|
if (bodyIsFn) {
|
|
606
|
-
|
|
696
|
+
_arrForEach(_objectKeys(reqHeaders), function (k) { var lk = _toLowerCase(k); if (lk === "content-length" || lk === "transfer-encoding" || lk === "expect") delete reqHeaders[k]; });
|
|
607
697
|
} else if (body != null && body !== "") {
|
|
608
|
-
|
|
609
|
-
reqHeaders["Content-Length"] =
|
|
698
|
+
_arrForEach(_objectKeys(reqHeaders), function (k) { var lk = _toLowerCase(k); if (lk === "content-length" || lk === "transfer-encoding") delete reqHeaders[k]; });
|
|
699
|
+
reqHeaders["Content-Length"] = _byteLength(body);
|
|
610
700
|
}
|
|
611
701
|
|
|
612
702
|
var host = _stripIpv6Brackets(_urlHostname(url));
|
|
@@ -622,11 +712,23 @@ function httpsTransport(defaults) {
|
|
|
622
712
|
rejectUnauthorized: true,
|
|
623
713
|
agent: false,
|
|
624
714
|
};
|
|
625
|
-
var
|
|
626
|
-
var
|
|
627
|
-
var
|
|
628
|
-
|
|
629
|
-
|
|
715
|
+
var rawCert = reqTls.cert, rawKey = reqTls.key;
|
|
716
|
+
var cert = rawCert !== undefined ? rawCert : tlsDefaults.cert;
|
|
717
|
+
var key = rawKey !== undefined ? rawKey : tlsDefaults.key;
|
|
718
|
+
/** @internal The hook is read once and that one value is both type-checked and installed. Read
|
|
719
|
+
* twice, the type check passed on a function and something else was installed as the identity
|
|
720
|
+
* check this connection is accepted on. The transport's default is read ONLY where the request
|
|
721
|
+
* supplied no function of its own, because a per-request hook overrides it and reading it anyway
|
|
722
|
+
* runs an accessor the request opted out of. */
|
|
723
|
+
var rawCsi = reqTls.checkServerIdentity;
|
|
724
|
+
var callerCsi = null;
|
|
725
|
+
if (typeof rawCsi === "function") callerCsi = rawCsi;
|
|
726
|
+
else {
|
|
727
|
+
var rawDefaultCsi = tlsDefaults.checkServerIdentity;
|
|
728
|
+
if (typeof rawDefaultCsi === "function") callerCsi = rawDefaultCsi;
|
|
729
|
+
}
|
|
730
|
+
var rawSni = reqTls.servername;
|
|
731
|
+
var sni = (rawSni !== undefined ? rawSni : tlsDefaults.servername) || host;
|
|
630
732
|
/** @internal Typed here, the way `opts.proxy.tls.servername` is typed on the proxy arm. The value
|
|
631
733
|
* is read three times after this point and each read is a separate conversion: once to decide it
|
|
632
734
|
* is not an address literal, once by the TLS layer for the name sent in the handshake, and once
|
|
@@ -635,8 +737,8 @@ function httpsTransport(defaults) {
|
|
|
635
737
|
if (typeof sni !== "string") throw E(C("bad-input"), "tls.servername must be a string, got " + guard.text.showValue(sni));
|
|
636
738
|
if (sni && !_isIP(sni)) options.servername = sni;
|
|
637
739
|
var caList = [];
|
|
638
|
-
if (hasAnchors) caList = caList
|
|
639
|
-
if (useSystem) caList = caList
|
|
740
|
+
if (hasAnchors) caList = _concatList(caList, _pemifyAnchors(anchors));
|
|
741
|
+
if (useSystem) caList = _concatList(caList, _systemCa());
|
|
640
742
|
if (caList.length) options.ca = caList;
|
|
641
743
|
if (cert) options.cert = cert;
|
|
642
744
|
if (key) options.key = key;
|
|
@@ -666,7 +768,8 @@ function httpsTransport(defaults) {
|
|
|
666
768
|
if (typedProxyError) throw e;
|
|
667
769
|
throw E(C("bad-proxy"), "opts.proxy could not be validated", e);
|
|
668
770
|
}
|
|
669
|
-
var
|
|
771
|
+
var rawBlockPrivate = request.blockPrivateAddresses;
|
|
772
|
+
var blockPrivate = (rawBlockPrivate !== undefined ? rawBlockPrivate : defaults.blockPrivateAddresses) === true;
|
|
670
773
|
if (blockPrivate && proxyInfo) throw E(C("bad-proxy"), "blockPrivateAddresses cannot be enforced through a forward proxy, which resolves the origin itself and would reach a private origin the transport never checks; use a direct connection for a private-address-blocked fetch");
|
|
671
774
|
if (blockPrivate) {
|
|
672
775
|
if (_isBlockedIp(host)) throw E(C("blocked-address"), "refusing to connect to the private / loopback / link-local address literal " + host);
|
|
@@ -708,28 +811,60 @@ function httpsTransport(defaults) {
|
|
|
708
811
|
try {
|
|
709
812
|
/** @internal A plaintext request goes through `node:http`, which has no TLS options to
|
|
710
813
|
* ignore; `prep.plaintext` is set only where the scheme check let `http:` through. */
|
|
814
|
+
/** @internal The request function is the one bound at load, not the property looked up on
|
|
815
|
+
* the module when the request is made: a replacement installed afterwards sent a request
|
|
816
|
+
* prepared for one host to another and handed the caller that server's response. */
|
|
711
817
|
var client = prep.plaintext ? nodeHttp : nodeHttps;
|
|
712
|
-
|
|
818
|
+
var clientRequest = prep.plaintext ? _httpRequest : _httpsRequest;
|
|
819
|
+
/** @internal The socket is built here rather than by the agent node makes for the request.
|
|
820
|
+
* `agent: false` still leaves the construction on the agent prototype, so a replacement
|
|
821
|
+
* installed after load returned a connection to another destination and the request went
|
|
822
|
+
* out over it: measured, an `https:` request under `blockPrivateAddresses` reached a local
|
|
823
|
+
* plaintext listener, presented no certificate, and its body reached the caller. The
|
|
824
|
+
* options are the ones node computed for this hop, forwarded unchanged, so every TLS
|
|
825
|
+
* setting the request carries still applies; only the function that opens the socket is
|
|
826
|
+
* this module's. The tunnel path already supplies its own and keeps it. */
|
|
827
|
+
if (options.createConnection === undefined) {
|
|
828
|
+
options.createConnection = prep.plaintext
|
|
829
|
+
? function (opts) { return intrinsic.apply(_netConnect, nodeNet, [opts]); }
|
|
830
|
+
: function (opts) { return intrinsic.apply(_tlsConnect, nodeTls, [opts]); };
|
|
831
|
+
}
|
|
832
|
+
/** @internal `agent: false` is NOT no agent: node builds one from the default agent's
|
|
833
|
+
* constructor and that agent's own builder opens the socket, so the builder above was never
|
|
834
|
+
* reached. Left unset with a builder present, node skips the agent altogether, which is the
|
|
835
|
+
* same no-pooling behavior `agent: false` was there for. */
|
|
836
|
+
options.agent = undefined;
|
|
837
|
+
req = intrinsic.apply(clientRequest, client, [options, function (res) {
|
|
713
838
|
var tlsInfo = _tlsInfo(res.socket);
|
|
714
839
|
/** @internal Captured for consistency with the rest of the file, not because this gates
|
|
715
840
|
* anything: an understated `content-length` only skips this EARLY refusal, and the cap is
|
|
716
841
|
* enforced below on the bytes actually counted as they arrive. */
|
|
717
842
|
var declared = intrinsic.parseInt((res.headers || {})["content-length"], 10);
|
|
718
|
-
if (
|
|
719
|
-
var buf =
|
|
843
|
+
if (intrinsic.numberIsFinite(declared) && declared > prep.maxBytes) { fail(C("response-too-large"), "the declared content-length " + declared + " exceeds the " + prep.maxBytes + "-byte cap (RFC 7030 sec. 6)"); return; }
|
|
844
|
+
var buf = _bufferAllocUnsafe(0);
|
|
720
845
|
var len = 0;
|
|
721
846
|
var total = 0;
|
|
722
847
|
res.on("data", function (chunk) {
|
|
723
|
-
|
|
848
|
+
/** @internal The arriving chunk is measured ONCE, from its bytes rather than from a
|
|
849
|
+
* `length` property. Read four times off the chunk, a value answering one size to the
|
|
850
|
+
* cap and another to the accounting resolved a response LONGER than the bytes that
|
|
851
|
+
* arrived and longer than the cap allowed: measured, eight bytes under a cap of eight
|
|
852
|
+
* resolved as sixteen. `sizeOf` reads the view's own byte length. */
|
|
853
|
+
var n = intrinsic.sizeOf(chunk);
|
|
854
|
+
total += n;
|
|
724
855
|
if (total > prep.maxBytes) { fail(C("response-too-large"), "the response exceeded the " + prep.maxBytes + "-byte cap (RFC 7030 sec. 6)"); return; }
|
|
725
|
-
if (len +
|
|
726
|
-
var want =
|
|
727
|
-
var grown =
|
|
728
|
-
|
|
856
|
+
if (len + n > buf.length) {
|
|
857
|
+
var want = _mathMin(prep.maxBytes, _mathMax(buf.length ? buf.length * 2 : 8192, len + n));
|
|
858
|
+
var grown = _bufferAllocUnsafe(want);
|
|
859
|
+
/** @internal The bytes already received are moved, and the arriving chunk is placed,
|
|
860
|
+
* through the typed-array write bound at load. `Buffer.prototype.copy` read off the
|
|
861
|
+
* prototype decided what the response body holds: replaced after load, a response
|
|
862
|
+
* that arrived as one value reached the caller as another. */
|
|
863
|
+
_taSet(grown, intrinsic.byteSlice(buf, 0, len), 0);
|
|
729
864
|
buf = grown;
|
|
730
865
|
}
|
|
731
|
-
|
|
732
|
-
len +=
|
|
866
|
+
_taSet(buf, chunk, len);
|
|
867
|
+
len += n;
|
|
733
868
|
});
|
|
734
869
|
res.on("end", function () {
|
|
735
870
|
if (settled) return;
|
|
@@ -739,13 +874,21 @@ function httpsTransport(defaults) {
|
|
|
739
874
|
resolve({
|
|
740
875
|
status: res.statusCode,
|
|
741
876
|
headers: lower,
|
|
742
|
-
body
|
|
877
|
+
/** @internal The body is allocated at the counted length and written through the
|
|
878
|
+
* typed-array write, so neither the length nor the bytes come from an operation a
|
|
879
|
+
* replacement answers. Two earlier spellings were both steerable: a typed array's
|
|
880
|
+
* `subarray` builds its result through the SPECIES constructor, and `Buffer.from`
|
|
881
|
+
* handed an object reads that object's `valueOf` and `length`, which decided both
|
|
882
|
+
* what the body held and how long it was: measured, a response of eight bytes came
|
|
883
|
+
* back as 64 under a `maxResponseBytes` of 8. `byteSlice` reads the backing buffer,
|
|
884
|
+
* the byte offset and the length directly and builds the view itself. */
|
|
885
|
+
body: _bodyCopy(buf, len),
|
|
743
886
|
tls: tlsInfo,
|
|
744
887
|
});
|
|
745
888
|
});
|
|
746
889
|
res.on("error", function (e) { fail(C("transport-error"), "the response stream failed", e); });
|
|
747
|
-
});
|
|
748
|
-
req.on("error", function (e) { fail(_classifyError(e, C), "the request failed: " + ((e && e.message) ||
|
|
890
|
+
}]);
|
|
891
|
+
req.on("error", function (e) { fail(_classifyError(e, C), "the request failed: " + ((e && e.message) || _stringOf(e)), e); });
|
|
749
892
|
if (typeof prep.body === "function") {
|
|
750
893
|
req.once("socket", function (socket) {
|
|
751
894
|
function _writeBoundBody() {
|
|
@@ -758,9 +901,9 @@ function httpsTransport(defaults) {
|
|
|
758
901
|
else if (typeof b !== "string") { fail(C("bad-input"), "the request body callback must return bytes or a string; a missing return, null, or any other value is refused"); return; }
|
|
759
902
|
} catch (ve) { _settleReject(ve); return; }
|
|
760
903
|
try {
|
|
761
|
-
if (b !== "") { req.setHeader("Content-Length",
|
|
904
|
+
if (b !== "") { req.setHeader("Content-Length", _byteLength(b)); req.write(b); }
|
|
762
905
|
req.end();
|
|
763
|
-
} catch (e2) { fail(C("transport-error"), "the request body could not be written: " + ((e2 && e2.message) ||
|
|
906
|
+
} catch (e2) { fail(C("transport-error"), "the request body could not be written: " + ((e2 && e2.message) || _stringOf(e2)), e2); }
|
|
764
907
|
}, function (e) { fail(C("transport-error"), "the channel-binding body callback failed", e); });
|
|
765
908
|
}
|
|
766
909
|
if (socket.getFinished && socket.getFinished()) { _writeBoundBody(); return; }
|
|
@@ -770,7 +913,7 @@ function httpsTransport(defaults) {
|
|
|
770
913
|
if (prep.body != null && prep.body !== "") req.write(prep.body);
|
|
771
914
|
req.end();
|
|
772
915
|
}
|
|
773
|
-
} catch (e) { fail(C("transport-error"), "the request could not be initiated: " + ((e && e.message) ||
|
|
916
|
+
} catch (e) { fail(C("transport-error"), "the request could not be initiated: " + ((e && e.message) || _stringOf(e)), e); }
|
|
774
917
|
}
|
|
775
918
|
|
|
776
919
|
if (!prep.proxy) { issue(prep.options); return; }
|
|
@@ -783,9 +926,13 @@ function httpsTransport(defaults) {
|
|
|
783
926
|
var cr, done;
|
|
784
927
|
|
|
785
928
|
function issueConnect(credential) {
|
|
786
|
-
var pheaders =
|
|
929
|
+
var pheaders = _objectAssign(_objectCreate(null), { Host: pinfo.originAuthority, Connection: "keep-alive" });
|
|
787
930
|
if (credential) pheaders["Proxy-Authorization"] = credential;
|
|
788
|
-
|
|
931
|
+
/** @internal The CONNECT socket is opened the same way the request's is, and for the same
|
|
932
|
+
* reason: `agent: false` leaves the construction on the agent prototype, where a replacement
|
|
933
|
+
* can return a raw socket in place of the proxy's TLS connection. On this path that costs
|
|
934
|
+
* more than a redirected request, because the CONNECT carries `Proxy-Authorization`. */
|
|
935
|
+
var connectOpts = { host: pinfo.host, port: pinfo.port, method: "CONNECT", path: pinfo.originAuthority, headers: pheaders };
|
|
789
936
|
try {
|
|
790
937
|
if (pinfo.secure) {
|
|
791
938
|
connectOpts.ca = pinfo.proxyTls.ca;
|
|
@@ -794,11 +941,13 @@ function httpsTransport(defaults) {
|
|
|
794
941
|
var pIdentity = pinfo.proxyTls.servername || pinfo.host;
|
|
795
942
|
connectOpts.servername = (pIdentity && !_isIP(pIdentity)) ? pIdentity : "";
|
|
796
943
|
connectOpts.checkServerIdentity = function (host, cert) { return _checkServerIdentity(pIdentity, cert); };
|
|
797
|
-
|
|
944
|
+
connectOpts.createConnection = function (opts) { return intrinsic.apply(_tlsConnect, nodeTls, [opts]); };
|
|
945
|
+
cr = intrinsic.apply(_httpsRequest, nodeHttps, [connectOpts]);
|
|
798
946
|
} else {
|
|
799
|
-
|
|
947
|
+
connectOpts.createConnection = function (opts) { return intrinsic.apply(_netConnect, nodeNet, [opts]); };
|
|
948
|
+
cr = intrinsic.apply(_httpRequest, nodeHttp, [connectOpts]);
|
|
800
949
|
}
|
|
801
|
-
} catch (e) { fail(C("proxy-connect-failed"), "the CONNECT request could not be initiated: " + ((e && e.message) ||
|
|
950
|
+
} catch (e) { fail(C("proxy-connect-failed"), "the CONNECT request could not be initiated: " + ((e && e.message) || _stringOf(e)), e); return; }
|
|
802
951
|
creq = cr;
|
|
803
952
|
done = false;
|
|
804
953
|
cr.on("connect", function (res, socket) { onProxyResponse(res, socket); });
|
|
@@ -809,7 +958,7 @@ function httpsTransport(defaults) {
|
|
|
809
958
|
res.on("end", function () { });
|
|
810
959
|
onProxyResponse(res, null);
|
|
811
960
|
});
|
|
812
|
-
cr.on("error", function (e) { fail(pinfo.secure ? _proxyErrorClass(e, C) : C("proxy-connect-failed"), "the CONNECT request failed: " + ((e && e.message) ||
|
|
961
|
+
cr.on("error", function (e) { fail(pinfo.secure ? _proxyErrorClass(e, C) : C("proxy-connect-failed"), "the CONNECT request failed: " + ((e && e.message) || _stringOf(e)), e); });
|
|
813
962
|
cr.end();
|
|
814
963
|
}
|
|
815
964
|
|
|
@@ -821,18 +970,18 @@ function httpsTransport(defaults) {
|
|
|
821
970
|
if (socket && sc >= 200 && sc < 300) {
|
|
822
971
|
tunnelSocket = socket;
|
|
823
972
|
creq = null;
|
|
824
|
-
socket.on("error", function (e) { fail(_classifyError(e, C), "the tunnel socket failed: " + ((e && e.message) ||
|
|
973
|
+
socket.on("error", function (e) { fail(_classifyError(e, C), "the tunnel socket failed: " + ((e && e.message) || _stringOf(e)), e); });
|
|
825
974
|
var idHost = prep.options.servername || pinfo.originHost;
|
|
826
975
|
/** @internal A plaintext origin speaks HTTP over the tunnel the CONNECT opened, so the
|
|
827
976
|
* connection the request is issued on is that socket. Handing back a TLS wrapper would
|
|
828
977
|
* start a handshake against a server that does not speak TLS. */
|
|
829
978
|
if (prep.plaintext) {
|
|
830
|
-
issue(
|
|
979
|
+
issue(_objectAssign({}, prep.options, { createConnection: function () { return socket; } }));
|
|
831
980
|
return;
|
|
832
981
|
}
|
|
833
|
-
issue(
|
|
982
|
+
issue(_objectAssign({}, prep.options, {
|
|
834
983
|
createConnection: function () {
|
|
835
|
-
return
|
|
984
|
+
return intrinsic.apply(_tlsConnect, nodeTls, [{
|
|
836
985
|
socket: socket,
|
|
837
986
|
host: prep.options.hostname,
|
|
838
987
|
servername: prep.options.servername,
|
|
@@ -846,7 +995,7 @@ function httpsTransport(defaults) {
|
|
|
846
995
|
},
|
|
847
996
|
cert: prep.options.cert,
|
|
848
997
|
key: prep.options.key,
|
|
849
|
-
});
|
|
998
|
+
}]);
|
|
850
999
|
},
|
|
851
1000
|
}));
|
|
852
1001
|
return;
|
|
@@ -920,7 +1069,7 @@ function httpsTransport(defaults) {
|
|
|
920
1069
|
try { if (socket) socket.destroy(); } catch (_de) { /* allow:swallow-unverified the socket is being abandoned either way */ }
|
|
921
1070
|
fn(arg);
|
|
922
1071
|
}
|
|
923
|
-
try { socket =
|
|
1072
|
+
try { socket = intrinsic.apply(_tlsConnect, nodeTls, [connectOpts]); }
|
|
924
1073
|
catch (e) {
|
|
925
1074
|
reject(E(_classifyError(e, C), "the TLS connection failed: " + e.message, e));
|
|
926
1075
|
return;
|