From def52d06b194ef3b11fbddccf309c12605616146 Mon Sep 17 00:00:00 2001 From: "Jeong, YunWon" <69878+youknowone@users.noreply.github.com> Date: Sun, 6 Sep 2026 23:11:02 +0900 Subject: [PATCH] ssl: cap rustls unsent output at 4 KiB (#8660) Keep BIO writes from filling asyncio's socket transport past its high-water mark when SO_SNDBUF is small. Drop the Unix skip on test_sendfile_ssl_pre_and_post_data. Assisted-by: Claude --- Lib/test/test_asyncio/test_sendfile.py | 12 ------------ crates/stdlib/src/ssl.rs | 10 ++++++++-- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_asyncio/test_sendfile.py b/Lib/test/test_asyncio/test_sendfile.py index 6c198addb..a95e7d086 100644 --- a/Lib/test/test_asyncio/test_sendfile.py +++ b/Lib/test/test_asyncio/test_sendfile.py @@ -625,10 +625,6 @@ else: def create_event_loop(self): return asyncio.SelectorEventLoop(selectors.EpollSelector()) - @unittest.skipIf(sys.platform != "win32", "TODO: RUSTPYTHON; Flaky on CI") - def test_sendfile_ssl_pre_and_post_data(self): - return super().test_sendfile_ssl_pre_and_post_data() - if hasattr(selectors, 'PollSelector'): class PollEventLoopTests(SendfileTestsBase, test_utils.TestCase): @@ -636,10 +632,6 @@ else: def create_event_loop(self): return asyncio.SelectorEventLoop(selectors.PollSelector()) - @unittest.skipIf(sys.platform != "win32", "TODO: RUSTPYTHON; Flaky on CI") - def test_sendfile_ssl_pre_and_post_data(self): - return super().test_sendfile_ssl_pre_and_post_data() - # Should always exist. class SelectEventLoopTests(SendfileTestsBase, test_utils.TestCase): @@ -647,10 +639,6 @@ else: def create_event_loop(self): return asyncio.SelectorEventLoop(selectors.SelectSelector()) - @unittest.skipIf(sys.platform != "win32", "TODO: RUSTPYTHON; Flaky on CI") - def test_sendfile_ssl_pre_and_post_data(self): - return super().test_sendfile_ssl_pre_and_post_data() - if __name__ == '__main__': unittest.main() diff --git a/crates/stdlib/src/ssl.rs b/crates/stdlib/src/ssl.rs index bd072d45d..7db36f6c4 100644 --- a/crates/stdlib/src/ssl.rs +++ b/crates/stdlib/src/ssl.rs @@ -99,6 +99,10 @@ mod _ssl { }; use sha2::{Digest, Sha256}; + /// Caps unsent TLS so BIO writes stay inside asyncio's 64 KiB + /// socket-transport high-water mark when SO_SNDBUF is small. + const TLS_IO_BUFFER_LIMIT: Option = Some(4 * 1024); + // Import certificate operations module use super::cert; use super::chain::{self, VerifiedChainBuilder}; @@ -3238,7 +3242,8 @@ mod _ssl { // particular connection's mutable keylog routing. Arc::make_mut(&mut config_arc).key_log = self.key_log.clone(); match accepted.into_connection(config_arc) { - Ok(conn) => { + Ok(mut conn) => { + conn.set_buffer_limit(TLS_IO_BUFFER_LIMIT); *conn_guard = Some(Connection::Server(conn)); *self.state.lock() = TlsState::Handshaking; } @@ -3381,9 +3386,10 @@ mod _ssl { *self.client_config.write() = Some(config.clone()); *self.client_session_store.write() = Some(session_store); - let conn = ClientConnection::new(config, server_name).map_err(|e| { + let mut conn = ClientConnection::new(config, server_name).map_err(|e| { vm.new_value_error(format!("Failed to create client connection: {e}")) })?; + conn.set_buffer_limit(TLS_IO_BUFFER_LIMIT); *conn_guard = Some(Connection::Client(conn)); }