Browse Source

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: https://github.com/nodejs/node/pull/13092
Fixes: https://github.com/nodejs/node/issues/13045
Reviewed-By: Andreas Madsen <amwebdk@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
v6
Refael Ackermann 8 years ago
parent
commit
6bfdeedce5
  1. 1
      src/tls_wrap.cc
  2. 53
      test/parallel/test-async-wrap-GH13045.js

1
src/tls_wrap.cc

@ -940,6 +940,7 @@ void TLSWrap::Initialize(Local<Object> target,
t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "TLSWrap")); t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "TLSWrap"));
env->SetProtoMethod(t, "getAsyncId", AsyncWrap::GetAsyncId); env->SetProtoMethod(t, "getAsyncId", AsyncWrap::GetAsyncId);
env->SetProtoMethod(t, "asyncReset", AsyncWrap::AsyncReset);
env->SetProtoMethod(t, "receive", Receive); env->SetProtoMethod(t, "receive", Receive);
env->SetProtoMethod(t, "start", Start); env->SetProtoMethod(t, "start", Start);
env->SetProtoMethod(t, "setVerifyMode", SetVerifyMode); env->SetProtoMethod(t, "setVerifyMode", SetVerifyMode);

53
test/parallel/test-async-wrap-GH13045.js

@ -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));
}));
Loading…
Cancel
Save