| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 9a6b7e3 commit 95ba2cf
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -98,6 +98,10 @@ changes: | |||
| 98 | 98 | ||
| 99 | 99 | See [`Session Resumption`][] for information about TLS session reuse. | |
| 100 | 100 | ||
| 101 | + Requests that specify a custom `checkServerIdentity` option are not eligible | ||
| 102 | + for connection reuse or TLS session reuse by an `https.Agent`, unless the | ||
| 103 | + `checkServerIdentity` option was specified when constructing the Agent. | ||
| 104 | + | ||
| 101 | 105 | #### Event: `'keylog'` | |
| 102 | 106 | ||
| 103 | 107 | <!-- YAML | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -35,6 +35,7 @@ const { | |||
| 35 | 35 | ObjectSetPrototypeOf, | |
| 36 | 36 | ReflectApply, | |
| 37 | 37 | ReflectConstruct, | |
| 38 | + Symbol, | ||
| 38 | 39 | SymbolAsyncDispose, | |
| 39 | 40 | } = primordials; | |
| 40 | 41 | ||
@@ -48,6 +49,8 @@ const { ERR_PROXY_TUNNEL } = require('internal/errors').codes; | |||
| 48 | 49 | assertCrypto(); | |
| 49 | 50 | ||
| 50 | 51 | const tls = require('tls'); | |
| 52 | + const kPerRequestCheckServerIdentity = Symbol('per-request checkServerIdentity'); | ||
| 53 | + let perRequestCheckServerIdentityIndex = 0; | ||
| 51 | 54 | const { | |
| 52 | 55 | kProxyConfig, | |
| 53 | 56 | checkShouldUseProxy, | |
@@ -281,6 +284,8 @@ function establishTunnel(agent, socket, options, tunnelConfig, afterSocket) { | |||
| 281 | 284 | tunneldSocket.removeListener('error', onTLSHandshakeError); | |
| 282 | 285 | afterSocket(null, tunneldSocket); | |
| 283 | 286 | }); | |
| 287 | + if (requestOptions[kPerRequestCheckServerIdentity]) | ||
| 288 | + tunneldSocket[kPerRequestCheckServerIdentity] = true; | ||
| 284 | 289 | tunneldSocket.on('free', () => { | |
| 285 | 290 | debug('Propagate free event from tunneled socket to tunnel socket'); | |
| 286 | 291 | socket.emit('free'); | |
@@ -349,7 +354,9 @@ function createConnection(...args) { | |||
| 349 | 354 | ||
| 350 | 355 | debug('createConnection', options); | |
| 351 | 356 | ||
| 352 | - if (options._agentKey) { | ||
| 357 | + const reuseSession = options._agentKey && | ||
| 358 | + !options[kPerRequestCheckServerIdentity]; | ||
| 359 | + if (reuseSession) { | ||
| 353 | 360 | const session = this._getSession(options._agentKey); | |
| 354 | 361 | if (session) { | |
| 355 | 362 | debug('reuse session for %j', options._agentKey); | |
@@ -416,7 +423,10 @@ function createConnection(...args) { | |||
| 416 | 423 | socket[kWaitForProxyTunnel] = true; | |
| 417 | 424 | } | |
| 418 | 425 | ||
| 419 | - if (options._agentKey) { | ||
| 426 | + if (options[kPerRequestCheckServerIdentity]) | ||
| 427 | + socket[kPerRequestCheckServerIdentity] = true; | ||
| 428 | + | ||
| 429 | + if (reuseSession) { | ||
| 420 | 430 | // Cache new session for reuse | |
| 421 | 431 | socket.on('session', (session) => { | |
| 422 | 432 | this._cacheSession(options._agentKey, session); | |
@@ -471,6 +481,12 @@ function Agent(options) { | |||
| 471 | 481 | ObjectSetPrototypeOf(Agent.prototype, HttpAgent.prototype); | |
| 472 | 482 | ObjectSetPrototypeOf(Agent, HttpAgent); | |
| 473 | 483 | Agent.prototype.createConnection = createConnection; | |
| 484 | + Agent.prototype.keepSocketAlive = function keepSocketAlive(socket) { | ||
| 485 | + if (socket[kPerRequestCheckServerIdentity]) | ||
| 486 | + return false; | ||
| 487 | + | ||
| 488 | + return FunctionPrototypeCall(HttpAgent.prototype.keepSocketAlive, this, socket); | ||
| 489 | + }; | ||
| 474 | 490 | ||
| 475 | 491 | function getPfxAgentKey(pfx, passphrase) { | |
| 476 | 492 | if (!ArrayIsArray(pfx)) | |
@@ -579,6 +595,9 @@ Agent.prototype.getName = function getName(options = kEmptyObject) { | |||
| 579 | 595 | if (options.privateKeyEngine) | |
| 580 | 596 | name += options.privateKeyEngine; | |
| 581 | 597 | ||
| 598 | + if (options[kPerRequestCheckServerIdentity]) | ||
| 599 | + name += `:${options[kPerRequestCheckServerIdentity]}`; | ||
| 600 | + | ||
| 582 | 601 | return name; | |
| 583 | 602 | }; | |
| 584 | 603 | ||
@@ -619,6 +638,20 @@ Agent.prototype._evictSession = function _evictSession(key) { | |||
| 619 | 638 | ||
| 620 | 639 | const globalAgent = getGlobalAgent(getOptionValue('--use-env-proxy') ? process.env : undefined, Agent); | |
| 621 | 640 | ||
| 641 | + function hasAgentCheckServerIdentity(options) { | ||
| 642 | + let { agent } = options; | ||
| 643 | + if (agent === false) | ||
| 644 | + return false; | ||
| 645 | + | ||
| 646 | + if (agent === null || agent === undefined) { | ||
| 647 | + if (typeof options.createConnection === 'function') | ||
| 648 | + return false; | ||
| 649 | + agent = module.exports.globalAgent; | ||
| 650 | + } | ||
| 651 | + | ||
| 652 | + return agent?.options?.checkServerIdentity !== undefined; | ||
| 653 | + } | ||
| 654 | + | ||
| 622 | 655 | /** | |
| 623 | 656 | * Makes a request to a secure web server. | |
| 624 | 657 | * @param {...any} args | |
@@ -638,6 +671,13 @@ function request(...args) { | |||
| 638 | 671 | ObjectAssign(options, ArrayPrototypeShift(args)); | |
| 639 | 672 | } | |
| 640 | 673 | ||
| 674 | + if (options.checkServerIdentity !== undefined && | ||
| 675 | + options.checkServerIdentity !== tls.checkServerIdentity && | ||
| 676 | + !hasAgentCheckServerIdentity(options)) { | ||
| 677 | + options[kPerRequestCheckServerIdentity] = | ||
| 678 | + ++perRequestCheckServerIdentityIndex; | ||
| 679 | + } | ||
| 680 | + | ||
| 641 | 681 | options._defaultAgent = module.exports.globalAgent; | |
| 642 | 682 | ArrayPrototypeUnshift(args, options); | |
| 643 | 683 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,113 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + const common = require('../common'); | ||
| 3 | + if (!common.hasCrypto) | ||
| 4 | + common.skip('missing crypto'); | ||
| 5 | + | ||
| 6 | + const assert = require('assert'); | ||
| 7 | + const fixtures = require('../common/fixtures'); | ||
| 8 | + const https = require('https'); | ||
| 9 | + const { once } = require('events'); | ||
| 10 | + | ||
| 11 | + const key = fixtures.readKey('agent1-key.pem'); | ||
| 12 | + const cert = fixtures.readKey('agent1-cert.pem'); | ||
| 13 | + const ca = fixtures.readKey('ca1-cert.pem'); | ||
| 14 | + const expectedError = /rejected by callback/; | ||
| 15 | + | ||
| 16 | + function request(options) { | ||
| 17 | + return new Promise((resolve, reject) => { | ||
| 18 | + const req = https.get({ | ||
| 19 | + host: '127.0.0.1', | ||
| 20 | + servername: 'agent1', | ||
| 21 | + ca: [ca], | ||
| 22 | + ...options, | ||
| 23 | + }, (res) => { | ||
| 24 | + const socket = res.socket; | ||
| 25 | + res.resume(); | ||
| 26 | + res.on('end', () => resolve({ | ||
| 27 | + socket, | ||
| 28 | + reusedSocket: req.reusedSocket, | ||
| 29 | + })); | ||
| 30 | + }); | ||
| 31 | + | ||
| 32 | + req.on('error', reject); | ||
| 33 | + }); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + const server = https.createServer({ | ||
| 37 | + key, | ||
| 38 | + cert, | ||
| 39 | + minVersion: 'TLSv1.2', | ||
| 40 | + maxVersion: 'TLSv1.2', | ||
| 41 | + }, (req, res) => { | ||
| 42 | + res.end('ok'); | ||
| 43 | + }); | ||
| 44 | + | ||
| 45 | + (async function() { | ||
| 46 | + server.listen(0); | ||
| 47 | + await once(server, 'listening'); | ||
| 48 | + | ||
| 49 | + const port = server.address().port; | ||
| 50 | + let acceptCalls = 0; | ||
| 51 | + let rejectCalls = 0; | ||
| 52 | + const acceptingCheck = () => { | ||
| 53 | + acceptCalls++; | ||
| 54 | + }; | ||
| 55 | + const rejectingCheck = () => { | ||
| 56 | + rejectCalls++; | ||
| 57 | + return new Error('rejected by callback'); | ||
| 58 | + }; | ||
| 59 | + | ||
| 60 | + const sessionAgent = new https.Agent(); | ||
| 61 | + const keepAliveAgent = new https.Agent({ | ||
| 62 | + keepAlive: true, | ||
| 63 | + maxCachedSessions: 0, | ||
| 64 | + }); | ||
| 65 | + const agentLevelAgent = new https.Agent({ | ||
| 66 | + checkServerIdentity: acceptingCheck, | ||
| 67 | + }); | ||
| 68 | + | ||
| 69 | + try { | ||
| 70 | + await request({ | ||
| 71 | + port, | ||
| 72 | + agent: sessionAgent, | ||
| 73 | + checkServerIdentity: acceptingCheck, | ||
| 74 | + }); | ||
| 75 | + assert.deepStrictEqual(sessionAgent._sessionCache.map, {}); | ||
| 76 | + await assert.rejects(request({ | ||
| 77 | + port, | ||
| 78 | + agent: sessionAgent, | ||
| 79 | + checkServerIdentity: rejectingCheck, | ||
| 80 | + }), expectedError); | ||
| 81 | + | ||
| 82 | + await request({ | ||
| 83 | + port, | ||
| 84 | + agent: keepAliveAgent, | ||
| 85 | + checkServerIdentity: acceptingCheck, | ||
| 86 | + }); | ||
| 87 | + await assert.rejects(request({ | ||
| 88 | + port, | ||
| 89 | + agent: keepAliveAgent, | ||
| 90 | + checkServerIdentity: rejectingCheck, | ||
| 91 | + }), expectedError); | ||
| 92 | + | ||
| 93 | + const first = await request({ | ||
| 94 | + port, | ||
| 95 | + agent: agentLevelAgent, | ||
| 96 | + }); | ||
| 97 | + assert.strictEqual(first.socket.isSessionReused(), false); | ||
| 98 | + const second = await request({ | ||
| 99 | + port, | ||
| 100 | + agent: agentLevelAgent, | ||
| 101 | + }); | ||
| 102 | + assert.strictEqual(second.socket.isSessionReused(), true); | ||
| 103 | + | ||
| 104 | + assert.strictEqual(acceptCalls, 3); | ||
| 105 | + assert.strictEqual(rejectCalls, 2); | ||
| 106 | + } finally { | ||
| 107 | + sessionAgent.destroy(); | ||
| 108 | + keepAliveAgent.destroy(); | ||
| 109 | + agentLevelAgent.destroy(); | ||
| 110 | + server.close(); | ||
| 111 | + await once(server, 'close'); | ||
| 112 | + } | ||
| 113 | + })().then(common.mustCall()); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments