summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRefael Ackermann <refack@gmail.com>2017-05-18 00:43:09 -0400
committerRefael Ackermann <refack@gmail.com>2017-05-19 23:27:44 -0400
commit6bfdeedce5529810dbe7c61bd712fc50174a19f1 (patch)
tree5dab6db1340525bca2ad3b23fad3f87ef8819110
parent4a7b7e8097fcd43bd1823050607270530d05541b (diff)
downloadnode-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.cc1
-rw-r--r--test/parallel/test-async-wrap-GH13045.js53
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));
+}));