tls: allow client-side sockets to be half-opened#27836
tls: allow client-side sockets to be half-opened#27836lpinca wants to merge 2 commits intonodejs:masterfrom
Conversation
|
I didn't add the option in the list of options allowed for the |
a04d2ec to
e810a28
Compare
|
Is there a test somewhere that shows that half-open actually works? If there isn't, then I think there should be a test showing it working, not just that the option is passing through. There is a fair bit of back-an-forth in the TLS protocol, its not at all clear that a TCP socket allowing half-open will automatically have half-open semantics at the TLS layer. |
Added one in c6d8518. There is another for the server in https://github.com/nodejs/node/blob/77b9ce5/test/parallel/test-tls-server-parent-constructor-options.js |
bnoordhuis
left a comment
There was a problem hiding this comment.
Since this got another sign-off since Sam's comment... I agree with Sam that the semantics of { allowHalfOpen: true } in a TLS context are underspec'd, perhaps even nonsensical. That needs to be hashed out first. What is the expected behavior? What is the expected interaction between the TLS and TCP socket levels?
|
IIRC, TLS itself has half-close semantics in emulation of TCP's bi-directional close, it has a signed uni-directional finish alert (I forget the exact name) that goes each way. Its just I recall that while looking through the TLS tests that it wasn't clear to me that tests existed that checked this functionality. Also, openssl might need to write messages even when doing SSL_read, so its not impossible that admin records will be written back to the peer, even after receiving the signed read-close alert. All of which is just to say, that the existing code might be working perfectly with TLS half-close, and/or with TLS half-close on top of TCP half-close, but it does deserve a test. |
|
I've added a couple. Suggestions on what else should be tested are welcome. |
|
Expected behavior is to prevent |
sam-github
left a comment
There was a problem hiding this comment.
Two suggestions, but otherwise LGTM
There was a problem hiding this comment.
I suggest changing this to 'Bye'
There was a problem hiding this comment.
I was a bit thrown by the conditional, it seemed to me the test should know exactly whether socket.writable was true or false, but then I read the rest of the test and I see why. I suggest changing this to something like below:
if (chunk === 'Hello') {
socket.end(chunk);
} else {
assert(chunk === 'Bye');
assert(!socket.writable);
}
doc/api/tls.md
Outdated
There was a problem hiding this comment.
s/half-opened/half-open/.
ccc0c18 to
d1332da
Compare
d1332da to
aae8969
Compare
|
@bnoordhuis are you concerns still valid? |
|
I didn't re-review but I dismissed my old review. |
|
Ok, thanks. I will land this in 48 hours if there are no objections. |
There was a problem hiding this comment.
This assumes that you receive the string as a single chunk. Which is probably true nearly all of the time but it isn't guaranteed, it might be split across multiple chunks.
The only thing socket.setEncoding() does is ensure the stream won't emit partial multi-byte sequences.
There was a problem hiding this comment.
That is true and it is not an excuse but there are a lot of tests written like this. I would not add unneeded complexity unless the test turns out to be flaky.
There was a problem hiding this comment.
Also if the 'data' handler is not called with a chunk which is not 'Hello' or 'Bye', the assertion in the else branch will fail.
There was a problem hiding this comment.
Right, but our CI is really good at shaking out edge cases and debugging a failing test takes 10x as long as just writing it correctly in the first place.
There was a problem hiding this comment.
@bnoordhuis does this look better to you:
diff --git a/test/parallel/test-tls-connect-allow-half-open-option.js b/test/parallel/test-tls-connect-allow-half-open-option.js
index 129d1d1ced..1bc7eda1ca 100644
--- a/test/parallel/test-tls-connect-allow-half-open-option.js
+++ b/test/parallel/test-tls-connect-allow-half-open-option.js
@@ -21,6 +21,7 @@ const tls = require('tls');
assert.strictEqual(socket.allowHalfOpen, false);
}
+const hello = Buffer.from('Hello');
const server = tls.createServer({
key: fixtures.readKey('agent1-key.pem'),
@@ -28,15 +29,24 @@ const server = tls.createServer({
}, common.mustCall((socket) => {
server.close();
- socket.setEncoding('utf8');
- socket.on('data', common.mustCall((chunk) => {
- if (chunk === 'Hello') {
- socket.end(chunk);
+ const chunks = [];
+
+ socket.on('data', (chunk) => {
+ chunks.push(chunk);
+
+ const buf = Buffer.concat(chunks);
+
+ if (buf.equals(hello)) {
+ chunks.length = 0;
+ socket.end(buf);
} else {
- assert.strictEqual(chunk, 'Bye');
assert(!socket.writable);
}
- }, 2));
+ });
+
+ socket.on('end', common.mustCall(() => {
+ assert.deepStrictEqual(Buffer.concat(chunks), Buffer.from('Bye'));
+ }));
}));
server.listen(0, common.mustCall(() => {
@@ -45,19 +55,22 @@ server.listen(0, common.mustCall(() => {
rejectUnauthorized: false,
allowHalfOpen: true,
}, common.mustCall(() => {
- socket.on('data', common.mustCall((chunk) => {
- assert.strictEqual(chunk, 'Hello');
- }));
+ const chunks = [];
+
+ socket.on('data', (chunk) => {
+ chunks.push(chunk);
+ });
+
socket.on('end', common.mustCall(() => {
+ assert.deepStrictEqual(Buffer.concat(chunks), hello);
+
setTimeout(() => {
assert(socket.writable);
assert(socket.write('Bye'));
socket.end();
- }, 50);
+ }, 100);
}));
socket.write('Hello');
}));
-
- socket.setEncoding('utf8');
}));There was a problem hiding this comment.
Yep, that works. You can also keep the socket.setEncoding('utf8') and concatenate until you see the shibboleth.
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.
aae8969 to
3e89ac1
Compare
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>
|
Landed in c3b8e50. |
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>
Make
tls.connect()support anallowHalfOpenoption which specifieswhether or not to allow the connection to be half-opened when the
socketoption is not specified.Checklist
make -j4 test(UNIX), orvcbuild test(Windows) passes