@@ -3427,44 +3427,56 @@ mod _ssl {
34273427 . as_mut ( )
34283428 . ok_or_else ( || vm. new_value_error ( "Connection not established" ) ) ?;
34293429
3430- // Unified write logic - no need to match on Client/Server anymore
3431- let mut writer = conn. writer ( ) ;
3432- writer
3433- . write_all ( data_bytes. as_ref ( ) )
3434- . map_err ( |e| vm. new_os_error ( format ! ( "Write failed: {e}" ) ) ) ?;
3430+ let is_bio = self . is_bio_mode ( ) ;
3431+ let data: & [ u8 ] = data_bytes. as_ref ( ) ;
34353432
3436- // Flush to get TLS-encrypted data (writer automatically flushed on drop)
3437- // Send encrypted data to socket
3438- if conn . wants_write ( ) {
3439- let is_bio = self . is_bio_mode ( ) ;
3433+ // Write data in chunks to avoid filling the internal TLS buffer
3434+ // rustls has a limited internal buffer, so we need to flush periodically
3435+ const CHUNK_SIZE : usize = 16384 ; // 16KB chunks (typical TLS record size)
3436+ let mut written = 0 ;
34403437
3441- if is_bio {
3442- // BIO mode: Write ALL pending TLS data to outgoing BIO
3443- // This prevents hangs where Python's ssl_io_loop waits for data
3444- self . write_pending_tls ( conn, vm) ?;
3445- } else {
3446- // Socket mode: Try once and may return SSLWantWriteError
3447- let mut buf = Vec :: new ( ) ;
3448- conn. write_tls ( & mut buf)
3449- . map_err ( |e| vm. new_os_error ( format ! ( "TLS write failed: {e}" ) ) ) ?;
3450-
3451- if !buf. is_empty ( ) {
3452- // Wait for socket to be ready for writing
3453- let timed_out = self . sock_wait_for_io_impl ( SelectKind :: Write , vm) ?;
3454- if timed_out {
3455- return Err ( vm. new_os_error ( "Write operation timed out" ) ) ;
3456- }
3438+ while written < data. len ( ) {
3439+ let chunk_end = std:: cmp:: min ( written + CHUNK_SIZE , data. len ( ) ) ;
3440+ let chunk = & data[ writt
10000
en..chunk_end] ;
3441+
3442+ // Write chunk to TLS layer
3443+ {
3444+ let mut writer = conn. writer ( ) ;
3445+ use std:: io:: Write ;
3446+ writer
3447+ . write_all ( chunk)
3448+ . map_err ( |e| vm. new_os_error ( format ! ( "Write failed: {e}" ) ) ) ?;
3449+ }
3450+
3451+ written = chunk_end;
3452+
3453+ // Flush TLS data to socket after each chunk
3454+ if conn. wants_write ( ) {
3455+ if is_bio {
3456+ self . write_pending_tls ( conn, vm) ?;
3457+ } else {
3458+ // Socket mode: flush all pending TLS data
3459+ while conn. wants_write ( ) {
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+ let timed_out =
3466+ 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+ }
34573470
3458- // Send encrypted data to socket
3459- // Convert BlockingIOError to SSLWantWriteError
3460- match self . sock_send ( buf , vm ) {
3461- Ok ( _ ) => { }
3462- Err ( e ) => {
3463- if is_blocking_io_error ( & e , vm ) {
3464- // Non-blocking socket would block - return SSLWantWriteError
3465- return Err ( create_ssl_want_write_error ( vm ) ) ;
3471+ match self . sock_send ( buf , vm ) {
3472+ Ok ( _ ) => { }
3473+ Err ( e ) => {
3474+ if is_blocking_io_error ( & e , vm ) {
3475+ return Err ( create_ssl_want_write_error ( vm ) ) ;
3476+ }
3477+ return Err ( e ) ;
3478+ }
34663479 }
3467- return Err ( e) ;
34683480 }
34693481 }
34703482 }
0 commit comments