Skip to content

Commit

Permalink
tls: allow client-side sockets to be half-opened
Browse files Browse the repository at this point in the history
Make `tls.connect()` support an `allowHalfOpen` option which specifies
whether or not to allow the connection to be half-opened when the
`socket` option is not specified.

PR-URL: #27836
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Ouyang Yadong <oyydoibh@gmail.com>
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
  • Loading branch information
lpinca committed Aug 17, 2019
1 parent f25bbf1 commit c3b8e50
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 1 deletion.
7 changes: 7 additions & 0 deletions doc/api/tls.md
Original file line number Diff line number Diff line change
Expand Up @@ -1177,6 +1177,9 @@ being issued by trusted CA (`options.ca`).
<!-- YAML
added: v0.11.3
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/27836
description: Support the `allowHalfOpen` option.
- version: v12.4.0
pr-url: https://github.com/nodejs/node/pull/27816
description: The `hints` option is now supported.
Expand Down Expand Up @@ -1217,6 +1220,10 @@ changes:
Connection/disconnection/destruction of `socket` is the user's
responsibility; calling `tls.connect()` will not cause `net.connect()` to be
called.
* `allowHalfOpen` {boolean} If the `socket` option is missing, indicates
whether or not to allow the internally created socket to be half-open,
otherwise the option is ignored. See the `allowHalfOpen` option of
[`net.Socket`][] for details. **Default:** `false`.
* `rejectUnauthorized` {boolean} If not `false`, the server certificate is
verified against the list of supplied CAs. An `'error'` event is emitted if
verification fails; `err.code` contains the OpenSSL error code. **Default:**
Expand Down
3 changes: 2 additions & 1 deletion lib/_tls_wrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ function TLSSocket(socket, opts) {

net.Socket.call(this, {
handle: this._wrapHandle(wrap),
allowHalfOpen: socket && socket.allowHalfOpen,
allowHalfOpen: socket ? socket.allowHalfOpen : tlsOptions.allowHalfOpen,
readable: false,
writable: false
});
Expand Down Expand Up @@ -1403,6 +1403,7 @@ exports.connect = function connect(...args) {
const context = options.secureContext || tls.createSecureContext(options);

const tlssock = new TLSSocket(options.socket, {
allowHalfOpen: options.allowHalfOpen,
pipe: !!options.path,
secureContext: context,
isServer: false,
Expand Down
73 changes: 73 additions & 0 deletions test/parallel/test-tls-connect-allow-half-open-option.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
'use strict';

const common = require('../common');

// This test verifies that `tls.connect()` honors the `allowHalfOpen` option.

if (!common.hasCrypto)
common.skip('missing crypto');

const assert = require('assert');
const fixtures = require('../common/fixtures');
const tls = require('tls');

{
const socket = tls.connect({ lookup() {} });
assert.strictEqual(socket.allowHalfOpen, false);
}

{
const socket = tls.connect({ allowHalfOpen: false, lookup() {} });
assert.strictEqual(socket.allowHalfOpen, false);
}

const server = tls.createServer({
key: fixtures.readKey('agent1-key.pem'),
cert: fixtures.readKey('agent1-cert.pem'),
}, common.mustCall((socket) => {
server.close();

let message = '';

socket.setEncoding('utf8');
socket.on('data', (chunk) => {
message += chunk;

if (message === 'Hello') {
socket.end(message);
message = '';
}
});

socket.on('end', common.mustCall(() => {
assert.strictEqual(message, 'Bye');
}));
}));

server.listen(0, common.mustCall(() => {
const socket = tls.connect({
port: server.address().port,
rejectUnauthorized: false,
allowHalfOpen: true,
}, common.mustCall(() => {
let message = '';

socket.on('data', (chunk) => {
message += chunk;
});

socket.on('end', common.mustCall(() => {
assert.strictEqual(message, 'Hello');

setTimeout(() => {
assert(socket.writable);
assert(socket.write('Bye'));
socket.end();
}, 50);
}));

socket.write('Hello');
}));

socket.setEncoding('utf8');
}));
38 changes: 38 additions & 0 deletions test/parallel/test-tls-socket-allow-half-open-option.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
'use strict';

const common = require('../common');

// Test the `allowHalfOpen` option of the `tls.TLSSocket` constructor.

if (!common.hasCrypto)
common.skip('missing crypto');

const assert = require('assert');
const net = require('net');
const stream = require('stream');
const tls = require('tls');

{
// The option is ignored when the `socket` argument is a `net.Socket`.
const socket = new tls.TLSSocket(new net.Socket(), { allowHalfOpen: true });
assert.strictEqual(socket.allowHalfOpen, false);
}

{
// The option is ignored when the `socket` argument is a generic
// `stream.Duplex`.
const duplex = new stream.Duplex({ allowHalfOpen: false });
const socket = new tls.TLSSocket(duplex, { allowHalfOpen: true });
assert.strictEqual(socket.allowHalfOpen, false);
}

{
const socket = new tls.TLSSocket();
assert.strictEqual(socket.allowHalfOpen, false);
}

{
// The option is honored when the `socket` argument is not specified.
const socket = new tls.TLSSocket(undefined, { allowHalfOpen: true });
assert.strictEqual(socket.allowHalfOpen, true);
}

0 comments on commit c3b8e50

Please sign in to comment.