@@ -8,8 +8,8 @@ const mem = std.mem;
8
8
const crypto = std .crypto ;
9
9
const assert = std .debug .assert ;
10
10
const Certificate = std .crypto .Certificate ;
11
- const Reader = std .io .Reader ;
12
- const Writer = std .io .Writer ;
11
+ const Reader = std .Io .Reader ;
12
+ const Writer = std .Io .Writer ;
13
13
14
14
const max_ciphertext_len = tls .max_ciphertext_len ;
15
15
const hmacExpandLabel = tls .hmacExpandLabel ;
@@ -27,6 +27,8 @@ reader: Reader,
27
27
28
28
/// The encrypted stream from the client to the server. Bytes are pushed here
29
29
/// via `writer`.
30
+ ///
31
+ /// The buffer is asserted to have capacity at least `min_buffer_len`.
30
32
output : * Writer ,
31
33
/// The plaintext stream from the client to the server.
32
34
writer : Writer ,
@@ -122,7 +124,6 @@ pub const Options = struct {
122
124
/// the amount of data expected, such as HTTP with the Content-Length header.
123
125
allow_truncation_attacks : bool = false ,
124
126
write_buffer : []u8 ,
125
- /// Asserted to have capacity at least `min_buffer_len`.
126
127
read_buffer : []u8 ,
127
128
/// Populated when `error.TlsAlert` is returned from `init`.
128
129
alert : ? * tls.Alert = null ,
@@ -185,6 +186,7 @@ const InitError = error{
185
186
/// `input` is asserted to have buffer capacity at least `min_buffer_len`.
186
187
pub fn init (input : * Reader , output : * Writer , options : Options ) InitError ! Client {
187
188
assert (input .buffer .len >= min_buffer_len );
189
+ assert (output .buffer .len >= min_buffer_len );
188
190
const host = switch (options .host ) {
189
191
.no_verification = > "" ,
190
192
.explicit = > | host | host ,
@@ -278,6 +280,7 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client
278
280
{
279
281
var iovecs : [2 ][]const u8 = .{ cleartext_header , host };
280
282
try output .writeVecAll (iovecs [0.. if (host .len == 0 ) 1 else 2 ]);
283
+ try output .flush ();
281
284
}
282
285
283
286
var tls_version : tls.ProtocolVersion = undefined ;
@@ -763,6 +766,7 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client
763
766
& client_verify_msg ,
764
767
};
765
768
try output .writeVecAll (& all_msgs_vec );
769
+ try output .flush ();
766
770
},
767
771
}
768
772
write_seq += 1 ;
@@ -828,6 +832,7 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client
828
832
& finished_msg ,
829
833
};
830
834
try output .writeVecAll (& all_msgs_vec );
835
+ try output .flush ();
831
836
832
837
const client_secret = hkdfExpandLabel (P .Hkdf , pv .master_secret , "c ap traffic" , & handshake_hash , P .Hash .digest_length );
833
838
const server_secret = hkdfExpandLabel (P .Hkdf , pv .master_secret , "s ap traffic" , & handshake_hash , P .Hash .digest_length );
@@ -877,7 +882,7 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client
877
882
.buffer = options .write_buffer ,
878
883
.vtable = &.{
879
884
.drain = drain ,
880
- .sendFile = Writer . unimplementedSendFile ,
885
+ .flush = flush ,
881
886
},
882
887
},
883
888
.tls_version = tls_version ,
@@ -911,31 +916,56 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client
911
916
912
917
fn drain (w : * Writer , data : []const []const u8 , splat : usize ) Writer.Error ! usize {
913
918
const c : * Client = @alignCast (@fieldParentPtr ("writer" , w ));
914
- if (true ) @panic ("update to use the buffer and flush" );
915
- const sliced_data = if (splat == 0 ) data [0.. data .len - | 1 ] else data ;
916
919
const output = c .output ;
917
920
const ciphertext_buf = try output .writableSliceGreedy (min_buffer_len );
918
- var total_clear : usize = 0 ;
919
921
var ciphertext_end : usize = 0 ;
920
- for (sliced_data ) | buf | {
921
- const prepared = prepareCiphertextRecord (c , ciphertext_buf [ciphertext_end .. ], buf , .application_data );
922
- total_clear += prepared .cleartext_len ;
923
- ciphertext_end += prepared .ciphertext_end ;
924
- if (total_clear < buf .len ) break ;
922
+ var total_clear : usize = 0 ;
923
+ done : {
924
+ {
925
+ const buf = w .buffered ();
926
+ const prepared = prepareCiphertextRecord (c , ciphertext_buf [ciphertext_end .. ], buf , .application_data );
927
+ total_clear += prepared .cleartext_len ;
928
+ ciphertext_end += prepared .ciphertext_end ;
929
+ if (prepared .cleartext_len < buf .len ) break :done ;
930
+ }
931
+ for (data [0 .. data .len - 1 ]) | buf | {
932
+ if (buf .len < min_buffer_len ) break :done ;
933
+ const prepared = prepareCiphertextRecord (c , ciphertext_buf [ciphertext_end .. ], buf , .application_data );
934
+ total_clear += prepared .cleartext_len ;
935
+ ciphertext_end += prepared .ciphertext_end ;
936
+ if (prepared .cleartext_len < buf .len ) break :done ;
937
+ }
938
+ const buf = data [data .len - 1 ];
939
+ for (0.. splat ) | _ | {
940
+ if (buf .len < min_buffer_len ) break :done ;
941
+ const prepared = prepareCiphertextRecord (c , ciphertext_buf [ciphertext_end .. ], buf , .application_data );
942
+ total_clear += prepared .cleartext_len ;
943
+ ciphertext_end += prepared .ciphertext_end ;
944
+ if (prepared .cleartext_len < buf .len ) break :done ;
945
+ }
925
946
}
926
947
output .advance (ciphertext_end );
927
- return total_clear ;
948
+ return w .consume (total_clear );
949
+ }
950
+
951
+ fn flush (w : * Writer ) Writer.Error ! void {
952
+ const c : * Client = @alignCast (@fieldParentPtr ("writer" , w ));
953
+ const output = c .output ;
954
+ const ciphertext_buf = try output .writableSliceGreedy (min_buffer_len );
955
+ const prepared = prepareCiphertextRecord (c , ciphertext_buf , w .buffered (), .application_data );
956
+ output .advance (prepared .ciphertext_end );
957
+ w .end = 0 ;
928
958
}
929
959
930
960
/// Sends a `close_notify` alert, which is necessary for the server to
931
961
/// distinguish between a properly finished TLS session, or a truncation
932
962
/// attack.
933
963
pub fn end (c : * Client ) Writer.Error ! void {
964
+ try flush (& c .writer );
934
965
const output = c .output ;
935
966
const ciphertext_buf = try output .writableSliceGreedy (min_buffer_len );
936
967
const prepared = prepareCiphertextRecord (c , ciphertext_buf , & tls .close_notify_alert , .alert );
937
- output .advance (prepared .cleartext_len );
938
- return prepared .ciphertext_end ;
968
+ output .advance (prepared .ciphertext_end );
939
969
}
940
970
941
971
fn prepareCiphertextRecord (
@@ -1045,7 +1075,7 @@ pub fn eof(c: Client) bool {
1045
1075
return c .received_close_notify ;
1046
1076
}
1047
1077
1048
- fn stream (r : * Reader , w : * Writer , limit : std.io .Limit ) Reader.StreamError ! usize {
1078
+ fn stream (r : * Reader , w : * Writer , limit : std.Io .Limit ) Reader.StreamError ! usize {
1049
1079
const c : * Client = @alignCast (@fieldParentPtr ("reader" , r ));
1050
1080
if (c .eof ()) return error .EndOfStream ;
1051
1081
const input = c .input ;
0 commit comments