@@ -3440,44 +3440,56 @@ mod _ssl {
34403440 . as_mut ( )
34413441 . ok_or_else ( || vm. new_value_error ( "Connection not established" ) ) ?;
34423442
3443- // Unified write logic - no need to match on Client/Server anymore
3444- let mut writer = conn. writer ( ) ;
3445- writer
3446- . write_all ( data_bytes. as_ref ( ) )
3447- . map_err ( |e| vm. new_os_error ( format ! ( "Write failed: {e}" ) ) ) ?;
3443+ let is_bio = self . is_bio_mode ( ) ;
3444+ let data: & [ u8 ] = data_bytes. as_ref ( ) ;
34483445
3449- // Flush to get TLS-encrypted data (writer automatically flushed on drop)
3450- // Send encrypted data to socket
3451- if conn . wants_write ( ) {
3452- let is_bio = self . is_bio_mode ( ) ;
3446+ // Write data in chunks to avoid filling the internal TLS buffer
3447+ // rustls has a limited internal buffer, so we need to flush periodically
3448+ const CHUNK_SIZE : usize = 16384 ; // 16KB chunks (typical TLS record size)
3449+ let mut written = 0 ;
34533450
3454- if is_bio {
3455- // BIO mode: Write ALL pending TLS data to outgoing BIO
3456- // This prevents hangs where Python's ssl_io_loop waits for data
3457- self . write_pending_tls ( conn, vm) ?;
3458- } else {
3459- // Socket mode: Try once and may return SSLWantWriteError
3460- let mut buf = Vec :: new ( ) ;
3461- conn. write_tls ( & mut buf)
3462- . map_err ( |e| vm. new_os_error ( format ! ( "TLS write failed: {e}" ) ) ) ?;
3463-
3464- if !buf. is_empty ( ) {
3465- // Wait for socket to be ready for writing
3466- let timed_out = self . sock_wait_for_io_impl ( SelectKind :: Write , vm) ?;
3467- if timed_out {
3468- return Err ( vm. new_os_error ( "Write operation timed out" ) ) ;
3469- }
3451+ while written < data. len ( ) {
3452+ let chunk_end = std:: cmp:: min ( written + CHUNK_SIZE , data. len ( ) ) ;
3453+ let chunk = & data[ written..chunk_end] ;
3454+
3455+ // Write chunk to TLS layer
3456+ {
3457+ let mut writer = conn. writer ( ) ;
3458+ use std:: io:: Write ;
3459+ writer
3460+ . write_all ( chunk)
3461+ . map_err ( |e| vm. new_os_error ( format ! ( "Write failed: {e}" ) ) ) ?;
3462+ }
3463+
3464+ written = chunk_end;
3465+
3466+ // Flush TLS data to socket after each chunk
3467+ if conn. wants_write ( ) {
3468+ if is_bio {
3469+ self . write_pending_tls ( conn, vm) ?;
3470+ } else {
3471+ // Socket mode: flush all pending TLS data
3472+ while conn. wants_write ( ) {
3473+ let mut buf = Vec :: new ( ) ;
3474+ conn. write_tls ( & mut buf)
3475+ . map_err ( |e| vm. new_os_error ( format ! ( "TLS write failed: {e}" ) ) ) ?;
3476+
3477+ if !buf. is_empty ( ) {
3478+ let timed_out =
3479+ self . sock_wait_for_io_impl ( SelectKind :: Write , vm) ?;
3480+ if timed_out {
3481+ return Err ( vm. new_os_error ( "Write operation timed out" ) ) ;
3482+ }
34703483
3471- // Send encrypted data to socket
3472- // Convert BlockingIOError to SSLWantWriteError
3473- match self . sock_send ( buf , vm ) {
3474- Ok ( _ ) => { }
3475- Err ( e ) => {
3476- if is_blocking_io_error ( & e , vm ) {
3477- // Non-blocking socket would block - return SSLWantWriteError
3478- return Err ( create_ssl_want_write_error ( vm ) ) ;
3484+ match self . sock_send ( buf , vm ) {
3485+ Ok ( _ ) => { }
3486+ Err ( e ) => {
3487+ if is_blocking_io_error ( & e , vm ) {
3488+ return Err ( create_ssl_want_write_error ( vm ) ) ;
3489+ }
3490+ return Err ( e ) ;
3491+ }
34793492 }
3480- return Err ( e) ;
34813493 }
34823494 }
34833495 }
0 commit comments