https: use `servername` in agent key
authorFedor Indutny <fedor@indutny.com>
Tue, 22 Dec 2015 18:22:52 +0000 (13:22 -0500)
committerMyles Borins <mborins@us.ibm.com>
Tue, 19 Jan 2016 19:52:32 +0000 (11:52 -0800)
https requests with different SNI values should not be sent over the
same connection, even if the `host` is the same. Server may want to
present different certificate or route the incoming TLS connection
differently, depending on the received servername extension.

Fix: https://github.com/nodejs/node/issues/3940
PR-URL: https://github.com/nodejs/node/pull/4389
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
lib/https.js
test/parallel/test-https-agent-sni.js [new file with mode: 0644]

index abe4a20..f13c1ff 100644 (file)
@@ -123,6 +123,10 @@ Agent.prototype.getName = function(options) {
   if (options.rejectUnauthorized !== undefined)
     name += options.rejectUnauthorized;
 
+  name += ':';
+  if (options.servername && options.servername !== options.host)
+    name += options.servername;
+
   return name;
 };
 
diff --git a/test/parallel/test-https-agent-sni.js b/test/parallel/test-https-agent-sni.js
new file mode 100644 (file)
index 0000000..117075f
--- /dev/null
@@ -0,0 +1,52 @@
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+
+if (!common.hasCrypto) {
+  console.log('1..0 # Skipped: missing crypto');
+  return;
+}
+const https = require('https');
+
+const fs = require('fs');
+
+const options = {
+  key: fs.readFileSync(common.fixturesDir + '/keys/agent1-key.pem'),
+  cert: fs.readFileSync(common.fixturesDir + '/keys/agent1-cert.pem')
+};
+
+const TOTAL = 4;
+var waiting = TOTAL;
+
+const server = https.Server(options, function(req, res) {
+  if (--waiting === 0) server.close();
+
+  res.writeHead(200, {
+    'x-sni': req.socket.servername
+  });
+  res.end('hello world');
+});
+
+server.listen(common.PORT, function() {
+  function expectResponse(id) {
+    return common.mustCall(function(res) {
+      res.resume();
+      assert.equal(res.headers['x-sni'], 'sni.' + id);
+    });
+  }
+
+  var agent = new https.Agent({
+    maxSockets: 1
+  });
+  for (var j = 0; j < TOTAL; j++) {
+    https.get({
+      agent: agent,
+
+      path: '/',
+      port: common.PORT,
+      host: '127.0.0.1',
+      servername: 'sni.' + j,
+      rejectUnauthorized: false
+    }, expectResponse(j));
+  }
+});