Permalink
Browse files

async_wrap: add `asyncReset` to `TLSWrap`

When using an Agent for HTTPS, `TLSSocket`s are reused and need to
have the ability to `asyncReset` from JS.

PR-URL: #13092
Fixes: #13045
Reviewed-By: Andreas Madsen <amwebdk@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
  • Loading branch information...
refack committed May 18, 2017
1 parent 4a7b7e8 commit 6bfdeedce5529810dbe7c61bd712fc50174a19f1
Showing with 54 additions and 0 deletions.
  1. +1 −0 src/tls_wrap.cc
  2. +53 −0 test/parallel/test-async-wrap-GH13045.js
View
@@ -940,6 +940,7 @@ void TLSWrap::Initialize(Local<Object> target,
t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "TLSWrap"));
env->SetProtoMethod(t, "getAsyncId", AsyncWrap::GetAsyncId);
env->SetProtoMethod(t, "asyncReset", AsyncWrap::AsyncReset);
env->SetProtoMethod(t, "receive", Receive);
env->SetProtoMethod(t, "start", Start);
env->SetProtoMethod(t, "setVerifyMode", SetVerifyMode);
@@ -0,0 +1,53 @@
'use strict';
const common = require('../common');
// Refs: https://github.com/nodejs/node/issues/13045
// An HTTP Agent reuses a TLSSocket, and makes a failed call to `asyncReset`.
const assert = require('assert');
const https = require('https');
const fs = require('fs');
const serverOptions = {
key: fs.readFileSync(`${common.fixturesDir}/keys/agent1-key.pem`),
cert: fs.readFileSync(`${common.fixturesDir}/keys/agent1-cert.pem`),
ca: fs.readFileSync(`${common.fixturesDir}/keys/ca1-cert.pem`)
};
const server = https.createServer(serverOptions, common.mustCall((req, res) => {
res.end('hello world\n');
}, 2));
server.listen(0, common.mustCall(function() {
const port = this.address().port;
const clientOptions = {
agent: new https.Agent({
keepAlive: true,
rejectUnauthorized: false
}),
port: port
};
const req = https.get(clientOptions, common.mustCall((res) => {
assert.strictEqual(res.statusCode, 200);
res.on('error', (err) => assert.fail(err));
res.socket.on('error', (err) => assert.fail(err));
res.resume();
// drain the socket and wait for it to be free to reuse
res.socket.once('free', () => {
// This is the pain point. Internally the Agent will call
// `socket._handle.asyncReset()` and if the _handle does not implement
// `asyncReset` this will throw TypeError
const req2 = https.get(clientOptions, common.mustCall((res2) => {
assert.strictEqual(res.statusCode, 200);
res2.on('error', (err) => assert.fail(err));
res2.socket.on('error', (err) => assert.fail(err));
// this should be the end of the test
res2.destroy();
server.close();
}));
req2.on('error', (err) => assert.fail(err));
});
}));
req.on('error', (err) => assert.fail(err));
}));

0 comments on commit 6bfdeed

Please sign in to comment.