diff options
author | Refael Ackermann <refack@gmail.com> | 2017-05-18 00:43:09 -0400 |
---|---|---|
committer | Refael Ackermann <refack@gmail.com> | 2017-05-19 23:27:44 -0400 |
commit | 6bfdeedce5529810dbe7c61bd712fc50174a19f1 (patch) | |
tree | 5dab6db1340525bca2ad3b23fad3f87ef8819110 | |
parent | 4a7b7e8097fcd43bd1823050607270530d05541b (diff) | |
download | node-new-6bfdeedce5529810dbe7c61bd712fc50174a19f1.tar.gz |
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>
-rw-r--r-- | src/tls_wrap.cc | 1 | ||||
-rw-r--r-- | test/parallel/test-async-wrap-GH13045.js | 53 |
2 files changed, 54 insertions, 0 deletions
diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc index 05349b2f55..e6de942371 100644 --- a/src/tls_wrap.cc +++ b/src/tls_wrap.cc @@ -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); diff --git a/test/parallel/test-async-wrap-GH13045.js b/test/parallel/test-async-wrap-GH13045.js new file mode 100644 index 0000000000..9fab1ee2ae --- /dev/null +++ b/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)); +})); |