Read TLS records from socket to rustls
(
conn: &mut TlsConnection,
data: PyObjectRef,
is_bio: bool,
vm: &VirtualMachine,
)
| 2000 | |
| 2001 | /// Read TLS records from socket to rustls |
| 2002 | fn ssl_read_tls_records( |
| 2003 | conn: &mut TlsConnection, |
| 2004 | data: PyObjectRef, |
| 2005 | is_bio: bool, |
| 2006 | vm: &VirtualMachine, |
| 2007 | ) -> SslResult<()> { |
| 2008 | // Convert PyObject to bytes-like (supports bytes, bytearray, etc.) |
| 2009 | let bytes = ArgBytesLike::try_from_object(vm, data) |
| 2010 | .map_err(|_| SslError::Syscall("Expected bytes-like object".to_string()))?; |
| 2011 | |
| 2012 | let bytes_data = bytes.borrow_buf(); |
| 2013 | |
| 2014 | if bytes_data.is_empty() { |
| 2015 | // different error for BIO vs socket mode |
| 2016 | if is_bio { |
| 2017 | // In BIO mode, no data means WANT_READ |
| 2018 | return Err(SslError::WantRead); |
| 2019 | } else { |
| 2020 | // In socket mode, empty recv() means TCP EOF (FIN received) |
| 2021 | // Need to distinguish: |
| 2022 | // 1. Clean shutdown: received TLS close_notify → return ZeroReturn (0 bytes) |
| 2023 | // 2. Unexpected EOF: no close_notify → return Eof (SSLEOFError) |
| 2024 | // |
| 2025 | // SSL_ERROR_ZERO_RETURN vs SSL_ERROR_EOF logic |
| 2026 | // CPython checks SSL_get_shutdown() & SSL_RECEIVED_SHUTDOWN |
| 2027 | // |
| 2028 | // Process any buffered TLS records (may contain close_notify) |
| 2029 | match conn.process_new_packets() { |
| 2030 | Ok(io_state) => { |
| 2031 | if io_state.peer_has_closed() { |
| 2032 | // Received close_notify - normal SSL closure (SSL_ERROR_ZERO_RETURN) |
| 2033 | return Err(SslError::ZeroReturn); |
| 2034 | } else { |
| 2035 | // No close_notify - ragged EOF (SSL_ERROR_EOF → SSLEOFError) |
| 2036 | // CPython raises SSLEOFError here, which SSLSocket.read() handles |
| 2037 | // based on suppress_ragged_eofs setting |
| 2038 | return Err(SslError::Eof); |
| 2039 | } |
| 2040 | } |
| 2041 | Err(e) => return Err(SslError::from_rustls(e)), |
| 2042 | } |
| 2043 | } |
| 2044 | } |
| 2045 | |
| 2046 | // Feed all received data to read_tls - loop to consume all data |
| 2047 | // read_tls may not consume all data in one call, and buffer may become full |
| 2048 | let mut offset = 0; |
| 2049 | while offset < bytes_data.len() { |
| 2050 | let remaining = &bytes_data[offset..]; |
| 2051 | let mut cursor = std::io::Cursor::new(remaining); |
| 2052 | |
| 2053 | match conn.read_tls(&mut cursor) { |
| 2054 | Ok(read_bytes) => { |
| 2055 | if read_bytes == 0 { |
| 2056 | // Buffer is full - process existing packets to make room |
| 2057 | conn.process_new_packets().map_err(SslError::from_rustls)?; |
| 2058 | |
| 2059 | // Try again - if we still can't consume, break |
no test coverage detected