Skip to content

Commit 5f403fd

Browse files
committed
fix more flush
1 parent ef4bc84 commit 5f403fd

File tree

2 files changed

+34
-5
lines changed

2 files changed

+34
-5
lines changed

crates/stdlib/src/ssl.rs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2747,7 +2747,7 @@ mod _ssl {
27472747

27482748
/// Flush any pending TLS output data to the socket
27492749
/// This should be called before generating new TLS output
2750-
fn flush_pending_tls_output(&self, vm: &VirtualMachine) -> PyResult<()> {
2750+
pub(crate) fn flush_pending_tls_output(&self, vm: &VirtualMachine) -> PyResult<()> {
27512751
let mut pending = self.pending_tls_output.lock();
27522752
if pending.is_empty() {
27532753
return Ok(());
@@ -3919,7 +3919,8 @@ mod _ssl {
39193919
if current_state == ShutdownState::NotStarted {
39203920
// First, flush any pending TLS data BEFORE sending close_notify
39213921
// This ensures all application data is sent before the shutdown alert
3922-
self.flush_pending_tls_output(vm)?;
3922+
// Ignore errors - pending data will be sent with close_notify
3923+
let _ = self.flush_pending_tls_output(vm);
39233924

39243925
conn.send_close_notify();
39253926

@@ -3973,7 +3974,7 @@ mod _ssl {
39733974
if self.try_read_close_notify(conn, vm)? {
39743975
peer_closed = true;
39753976
}
3976-
} else if let Some(_timeout) = timeout_mode {
3977+
} else if let Some(timeout) = timeout_mode {
39773978
// All socket modes (blocking, timeout, non-blocking):
39783979
// Return immediately after sending our close_notify.
39793980
//
@@ -3989,7 +3990,24 @@ mod _ssl {
39893990
// This prevents data loss when rustls drains its buffer
39903991
// but the socket couldn't accept all data immediately
39913992
drop(conn_guard);
3992-
self.blocking_flush_all_pending(vm)?;
3993+
3994+
// Respect socket timeout settings for flushing pending TLS data
3995+
match timeout {
3996+
Some(0.0) => {
3997+
// Non-blocking: best-effort flush, ignore errors
3998+
// to avoid deadlock with asyncore-based servers
3999+
let _ = self.flush_pending_tls_output(vm);
4000+
}
4001+
Some(_t) => {
4002+
// Timeout mode: use flush with socket's timeout
4003+
// Errors (including timeout) are propagated to caller
4004+
self.flush_pending_tls_output(vm)?;
4005+
}
4006+
None => {
4007+
// Blocking mode: wait until all pending data is sent
4008+
self.blocking_flush_all_pending(vm)?;
4009+
}
4010+
}
39934011

39944012
*self.shutdown_state.lock() = ShutdownState::Completed;
39954013
*self.connection.lock() = None;
@@ -4022,7 +4040,8 @@ mod _ssl {
40224040
// Helper: Write all pending TLS data (including close_notify) to outgoing buffer/BIO
40234041
fn write_pending_tls(&self, conn: &mut TlsConnection, vm: &VirtualMachine) -> PyResult<()> {
40244042
// First, flush any previously pending TLS output
4025-
self.flush_pending_tls_output(vm)?;
4043+
// Ignore errors - they will be retried with the new data
4044+
let _ = self.flush_pending_tls_output(vm);
40264045

40274046
loop {
40284047
if !conn.wants_write() {

crates/stdlib/src/ssl/compat.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,6 +1011,10 @@ pub(super) fn is_blocking_io_error(err: &Py<PyBaseException>, vm: &VirtualMachin
10111011
/// until all data is sent. For non-blocking sockets, returns WantWrite
10121012
/// if no progress can be made.
10131013
fn send_all_bytes(socket: &PySSLSocket, buf: Vec<u8>, vm: &VirtualMachine) -> SslResult<()> {
1014+
// First, flush any previously pending TLS data
1015+
// Ignore errors - they will be saved in pending buffer and retried
1016+
let _ = socket.flush_pending_tls_output(vm);
1017+
10141018
if buf.is_empty() {
10151019
return Ok(());
10161020
}
@@ -1070,6 +1074,10 @@ fn handshake_write_loop(
10701074
) -> SslResult<bool> {
10711075
let mut made_progress = false;
10721076

1077+
// Flush any previously pending TLS data before generating new output
1078+
// Ignore errors - they will be saved in pending buffer and retried
1079+
let _ = socket.flush_pending_tls_output(vm);
1080+
10731081
while conn.wants_write() || force_initial_write {
10741082
if force_initial_write && !conn.wants_write() {
10751083
// No data to write on first iteration - break to avoid infinite loop
@@ -1297,6 +1305,8 @@ pub(super) fn ssl_do_handshake(
12971305
// Send close_notify on error
12981306
if !is_bio {
12991307
conn.send_close_notify();
1308+
// Flush any pending TLS data before sending close_notify
1309+
let _ = socket.flush_pending_tls_output(vm);
13001310
// Actually send the close_notify alert
13011311
if let Ok(alert_data) = ssl_write_tls_records(conn)
13021312
&& !alert_data.is_empty()

0 commit comments

Comments
 (0)