0
0
mirror of https://github.com/nodejs/node.git synced 2024-12-01 16:10:02 +01:00

tls: allow client-side sockets to be half-opened

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: https://github.com/nodejs/node/pull/27836
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Ouyang Yadong <oyydoibh@gmail.com>
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
This commit is contained in:
Luigi Pinca 2019-05-23 11:48:52 +02:00
parent f25bbf1255
commit c3b8e50143
4 changed files with 120 additions and 1 deletions

View File

@ -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.
@ -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:**

View File

@ -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
});
@ -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,

View File

@ -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');
}));

View File

@ -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);
}