Skip to content

Commit 521dc25

Browse files
apapirovskiMylesBorins
authored andcommitted
tls: properly track writeQueueSize during writes
Make writeQueueSize represent the actual size of the write queue within the TLS socket. Add tls test to confirm that bufferSize works as expected. Backport-PR-URL: #16420 PR-URL: #15791Fixes: #15005 Refs: #15006 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
1 parent b6ce918 commit 521dc25

4 files changed

Lines changed: 68 additions & 5 deletions

File tree

‎lib/_tls_wrap.js‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -401,9 +401,8 @@ TLSSocket.prototype._init = function(socket, wrap) {
401401
varssl=this._handle;
402402

403403
// lib/net.js expect this value to be non-zero if write hasn't been flushed
404-
// immediately
405-
// TODO(indutny): revise this solution, it might be 1 before handshake and
406-
// represent real writeQueueSize during regular writes.
404+
// immediately. After the handshake is done this will represent the actual
405+
// write queue size
407406
ssl.writeQueueSize=1;
408407

409408
this.server=options.server;

‎src/tls_wrap.cc‎

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ using v8::Exception;
2121
using v8::Function;
2222
using v8::FunctionCallbackInfo;
2323
using v8::FunctionTemplate;
24+
using v8::Integer;
2425
using v8::Local;
2526
using v8::Object;
2627
using v8::String;
@@ -276,6 +277,7 @@ void TLSWrap::EncOut() {
276277

277278
// No data to write
278279
if (BIO_pending(enc_out_) == 0) {
280+
UpdateWriteQueueSize();
279281
if (clear_in_->Length() == 0)
280282
InvokeQueued(0);
281283
return;
@@ -530,6 +532,18 @@ bool TLSWrap::IsClosing() {
530532
}
531533

532534

535+
uint32_tTLSWrap::UpdateWriteQueueSize(uint32_t write_queue_size) {
536+
HandleScope scope(env()->isolate());
537+
if (write_queue_size == 0)
538+
write_queue_size = BIO_pending(enc_out_);
539+
object()->Set(env()->context(),
540+
env()->write_queue_size_string(),
541+
Integer::NewFromUnsigned(env()->isolate(),
542+
write_queue_size)).FromJust();
543+
return write_queue_size;
544+
}
545+
546+
533547
intTLSWrap::ReadStart() {
534548
return stream_->ReadStart();
535549
}
@@ -570,8 +584,12 @@ int TLSWrap::DoWrite(WriteWrap* w,
570584
ClearOut();
571585
// However, if there is any data that should be written to the socket,
572586
// the callback should not be invoked immediately
573-
if (BIO_pending(enc_out_) == 0)
587+
if (BIO_pending(enc_out_) == 0) {
588+
// net.js expects writeQueueSize to be > 0 if the write isn't
589+
// immediately flushed
590+
UpdateWriteQueueSize(1);
574591
return stream_->DoWrite(w, bufs, count, send_handle);
592+
}
575593
}
576594

577595
// Queue callback to execute it on next tick
@@ -621,13 +639,15 @@ int TLSWrap::DoWrite(WriteWrap* w,
621639

622640
// Try writing data immediately
623641
EncOut();
642+
UpdateWriteQueueSize();
624643

625644
return0;
626645
}
627646

628647

629648
voidTLSWrap::OnAfterWriteImpl(WriteWrap* w, void* ctx) {
630-
// Intentionally empty
649+
TLSWrap* wrap = static_cast<TLSWrap*>(ctx);
650+
wrap->UpdateWriteQueueSize();
631651
}
632652

633653

‎src/tls_wrap.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ class TLSWrap : public AsyncWrap,
111111

112112
AsyncWrap* GetAsyncWrap() override;
113113
boolIsIPCPipe() override;
114+
uint32_tUpdateWriteQueueSize(uint32_t write_queue_size = 0);
114115

115116
// Resource implementation
116117
staticvoidOnAfterWriteImpl(WriteWrap* w, void* ctx);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
'use strict';
2+
constcommon=require('../common');
3+
if(!common.hasCrypto)
4+
common.skip('missing crypto');
5+
constassert=require('assert');
6+
constfixtures=require('../common/fixtures');
7+
consttls=require('tls');
8+
9+
constiter=10;
10+
constoverhead=30;
11+
12+
constserver=tls.createServer({
13+
key: fixtures.readKey('agent2-key.pem'),
14+
cert: fixtures.readKey('agent2-cert.pem')
15+
},common.mustCall((socket)=>{
16+
socket.on('readable',common.mustCallAtLeast(()=>{
17+
socket.read();
18+
},1));
19+
20+
socket.on('end',common.mustCall(()=>{
21+
server.close();
22+
}));
23+
}));
24+
25+
server.listen(0,common.mustCall(()=>{
26+
constclient=tls.connect({
27+
port: server.address().port,
28+
rejectUnauthorized: false
29+
},common.mustCall(()=>{
30+
assert.strictEqual(client.bufferSize,0);
31+
32+
for(leti=1;i<iter;i++){
33+
client.write('a');
34+
assert.strictEqual(client.bufferSize,i+overhead);
35+
}
36+
37+
client.on('finish',common.mustCall(()=>{
38+
assert.strictEqual(client.bufferSize,0);
39+
}));
40+
41+
client.end();
42+
}));
43+
}));

0 commit comments

Comments
 (0)