@@ -302,7 +302,7 @@ void TLSWrap::EncOut() {
302
302
// No encrypted output ready to write to the underlying stream.
303
303
if (BIO_pending (enc_out_) == 0 ) {
304
304
Debug (this , " No pending encrypted output" );
305
- if (pending_cleartext_input_.empty () ) {
305
+ if (pending_cleartext_input_.size () == 0 ) {
306
306
if (!in_dowrite_) {
307
307
Debug (this , " No pending cleartext input, not inside DoWrite()" );
308
308
InvokeQueued (0 );
@@ -573,28 +573,21 @@ void TLSWrap::ClearIn() {
573
573
return ;
574
574
}
575
575
576
- std::vector<uv_buf_t > buffers;
577
- buffers.swap (pending_cleartext_input_);
576
+ if (pending_cleartext_input_.size () == 0 ) {
577
+ Debug (this , " Returning from ClearIn(), no pending data" );
578
+ return ;
579
+ }
578
580
581
+ AllocatedBuffer data = std::move (pending_cleartext_input_);
579
582
crypto::MarkPopErrorOnReturn mark_pop_error_on_return;
580
583
581
- size_t i;
582
- int written = 0 ;
583
- for (i = 0 ; i < buffers.size (); ++i) {
584
- size_t avail = buffers[i].len ;
585
- char * data = buffers[i].base ;
586
- written = SSL_write (ssl_.get (), data, avail);
587
- Debug (this , " Writing %zu bytes, written = %d" , avail, written);
588
- CHECK (written == -1 || written == static_cast <int >(avail));
589
- if (written == -1 )
590
- break ;
591
- }
584
+ int written = SSL_write (ssl_.get (), data.data (), data.size ());
585
+ Debug (this , " Writing %zu bytes, written = %d" , data.size (), written);
586
+ CHECK (written == -1 || written == static_cast <int >(data.size ()));
592
587
593
588
// All written
594
- if (i == buffers. size () ) {
589
+ if (written != - 1 ) {
595
590
Debug (this , " Successfully wrote all data to SSL" );
596
- // We wrote all the buffers, so no writes failed (written < 0 on failure).
597
- CHECK_GE (written, 0 );
598
591
return ;
599
592
}
600
593
@@ -612,13 +605,10 @@ void TLSWrap::ClearIn() {
612
605
// .code/.function/.etc, if possible.
613
606
InvokeQueued (UV_EPROTO, error_str.c_str ());
614
607
} else {
615
- Debug (this , " Pushing back %zu buffers" , buffers.size () - i);
616
- // Push back the not-yet-written pending buffers into their queue.
617
- // This can be skipped in the error case because no further writes
618
- // would succeed anyway.
619
- pending_cleartext_input_.insert (pending_cleartext_input_.end (),
620
- buffers.begin () + i,
621
- buffers.end ());
608
+ Debug (this , " Pushing data back" );
609
+ // Push back the not-yet-written data. This can be skipped in the error
610
+ // case because no further writes would succeed anyway.
611
+ pending_cleartext_input_ = std::move (data);
622
612
}
623
613
624
614
return ;
@@ -705,14 +695,10 @@ int TLSWrap::DoWrite(WriteWrap* w,
705
695
return UV_EPROTO;
706
696
}
707
697
708
- bool empty = true ;
698
+ size_t length = 0 ;
709
699
size_t i;
710
- for (i = 0 ; i < count; i++) {
711
- if (bufs[i].len > 0 ) {
712
- empty = false ;
713
- break ;
714
- }
715
- }
700
+ for (i = 0 ; i < count; i++)
701
+ length += bufs[i].len ;
716
702
717
703
// We want to trigger a Write() on the underlying stream to drive the stream
718
704
// system, but don't want to encrypt empty buffers into a TLS frame, so see
@@ -724,7 +710,7 @@ int TLSWrap::DoWrite(WriteWrap* w,
724
710
// stream. Since the bufs are empty, it won't actually write non-TLS data
725
711
// onto the socket, we just want the side-effects. After, make sure the
726
712
// WriteWrap was accepted by the stream, or that we call Done() on it.
727
- if (empty ) {
713
+ if (length == 0 ) {
728
714
Debug (this , " Empty write" );
729
715
ClearOut ();
730
716
if (BIO_pending (enc_out_) == 0 ) {
@@ -748,23 +734,36 @@ int TLSWrap::DoWrite(WriteWrap* w,
748
734
current_write_ = w;
749
735
750
736
// Write encrypted data to underlying stream and call Done().
751
- if (empty ) {
737
+ if (length == 0 ) {
752
738
EncOut ();
753
739
return 0 ;
754
740
}
755
741
742
+ AllocatedBuffer data;
756
743
crypto::MarkPopErrorOnReturn mark_pop_error_on_return;
757
744
758
745
int written = 0 ;
759
- for (i = 0 ; i < count; i++) {
760
- written = SSL_write (ssl_.get (), bufs[i].base , bufs[i].len );
761
- CHECK (written == -1 || written == static_cast <int >(bufs[i].len ));
762
- Debug (this , " Writing %zu bytes, written = %d" , bufs[i].len , written);
763
- if (written == -1 )
764
- break ;
746
+ if (count != 1 ) {
747
+ data = env ()->AllocateManaged (length);
748
+ size_t offset = 0 ;
749
+ for (i = 0 ; i < count; i++) {
750
+ memcpy (data.data () + offset, bufs[i].base , bufs[i].len );
751
+ offset += bufs[i].len ;
752
+ }
753
+ written = SSL_write (ssl_.get (), data.data (), length);
754
+ } else {
755
+ // Only one buffer: try to write directly, only store if it fails
756
+ written = SSL_write (ssl_.get (), bufs[0 ].base , bufs[0 ].len );
757
+ if (written == -1 ) {
758
+ data = env ()->AllocateManaged (length);
759
+ memcpy (data.data (), bufs[0 ].base , bufs[0 ].len );
760
+ }
765
761
}
766
762
767
- if (i != count) {
763
+ CHECK (written == -1 || written == static_cast <int >(length));
764
+ Debug (this , " Writing %zu bytes, written = %d" , length, written);
765
+
766
+ if (written == -1 ) {
768
767
int err;
769
768
Local<Value> arg = GetSSLError (written, &err, &error_);
770
769
@@ -775,11 +774,10 @@ int TLSWrap::DoWrite(WriteWrap* w,
775
774
return UV_EPROTO;
776
775
}
777
776
778
- Debug (this , " Saving %zu buffers for later write" , count - i );
777
+ Debug (this , " Saving data for later write" );
779
778
// Otherwise, save unwritten data so it can be written later by ClearIn().
780
- pending_cleartext_input_.insert (pending_cleartext_input_.end (),
781
- &bufs[i],
782
- &bufs[count]);
779
+ CHECK_EQ (pending_cleartext_input_.size (), 0 );
780
+ pending_cleartext_input_ = std::move (data);
783
781
}
784
782
785
783
// Write any encrypted/handshake output that may be ready.
@@ -1082,7 +1080,9 @@ void TLSWrap::GetWriteQueueSize(const FunctionCallbackInfo<Value>& info) {
1082
1080
1083
1081
void TLSWrap::MemoryInfo (MemoryTracker* tracker) const {
1084
1082
tracker->TrackField (" error" , error_);
1085
- tracker->TrackField (" pending_cleartext_input" , pending_cleartext_input_);
1083
+ tracker->TrackFieldWithSize (" pending_cleartext_input" ,
1084
+ pending_cleartext_input_.size (),
1085
+ " AllocatedBuffer" );
1086
1086
if (enc_in_ != nullptr )
1087
1087
tracker->TrackField (" enc_in" , crypto::NodeBIO::FromBIO (enc_in_));
1088
1088
if (enc_out_ != nullptr )
0 commit comments