Skip to content

Commit 96f3a2d

Browse files
committed
shared error
1 parent a1a510f commit 96f3a2d

File tree

4 files changed

+146
-195
lines changed

4 files changed

+146
-195
lines changed

crates/stdlib/src/openssl.rs

Lines changed: 12 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
mod cert;
44

5+
// SSL exception types (shared with rustls backend)
6+
#[path = "ssl/error.rs"]
7+
mod ssl_error;
8+
59
// Conditional compilation for OpenSSL version-specific error codes
610
cfg_if::cfg_if! {
711
if #[cfg(ossl310)] {
@@ -45,9 +49,16 @@ cfg_if::cfg_if! {
4549
}
4650

4751
#[allow(non_upper_case_globals)]
48-
#[pymodule(with(cert::ssl_cert, ossl101, ossl111, windows))]
52+
#[pymodule(with(cert::ssl_cert, ssl_error::ssl_error, ossl101, ossl111, windows))]
4953
mod _ssl {
5054
use super::{bio, probe};
55+
56+
// Import error types used in this module (others are exposed via pymodule(with(...)))
57+
use super::ssl_error::{
58+
PySSLCertVerificationError as PySslCertVerificationError, PySSLEOFError as PySslEOFError,
59+
PySSLError as PySslError, PySSLWantReadError as PySslWantReadError,
60+
PySSLWantWriteError as PySslWantWriteError,
61+
};
5162
use crate::{
5263
common::lock::{
5364
PyMappedRwLockReadGuard, PyMutex, PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard,
@@ -300,92 +311,6 @@ mod _ssl {
300311
parse_version_info(openssl_api_version)
301312
}
302313

303-
// SSL Exception Types
304-
305-
/// An error occurred in the SSL implementation.
306-
#[pyattr]
307-
#[pyexception(name = "SSLError", base = PyOSError)]
308-
#[derive(Debug)]
309-
#[repr(transparent)]
310-
pub struct PySslError(PyOSError);
311-
312-
#[pyexception]
313-
impl PySslError {
314-
// Returns strerror attribute if available, otherwise str(args)
315-
#[pymethod]
316-
fn __str__(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyResult<PyStrRef> {
317-
// Try to get strerror attribute first (OSError compatibility)
318-
if let Ok(strerror) = exc.as_object().get_attr("strerror", vm)
319-
&& !vm.is_none(&strerror)
320-
{
321-
return strerror.str(vm);
322-
}
323-
324-
// Otherwise return str(args)
325-
exc.args().as_object().str(vm)
326-
}
327-
}
328-
329-
/// A certificate could not be verified.
330-
#[pyattr]
331-
#[pyexception(name = "SSLCertVerificationError", base = PySslError)]
332-
#[derive(Debug)]
333-
#[repr(transparent)]
334-
pub struct PySslCertVerificationError(PySslError);
335-
336-
#[pyexception]
337-
impl PySslCertVerificationError {}
338-
339-
/// SSL/TLS session closed cleanly.
340-
#[pyattr]
341-
#[pyexception(name = "SSLZeroReturnError", base = PySslError)]
342-
#[derive(Debug)]
343-
#[repr(transparent)]
344-
pub struct PySslZeroReturnError(PySslError);
345-
346-
#[pyexception]
347-
impl PySslZeroReturnError {}
348-
349-
/// Non-blocking SSL socket needs to read more data.
350-
#[pyattr]
351-
#[pyexception(name = "SSLWantReadError", base = PySslError)]
352-
#[derive(Debug)]
353-
#[repr(transparent)]
354-
pub struct PySslWantReadError(PySslError);
355-
356-
#[pyexception]
357-
impl PySslWantReadError {}
358-
359-
/// Non-blocking SSL socket needs to write more data.
360-
#[pyattr]
361-
#[pyexception(name = "SSLWantWriteError", base = PySslError)]
362-
#[derive(Debug)]
363-
#[repr(transparent)]
364-
pub struct PySslWantWriteError(PySslError);
365-
366-
#[pyexception]
367-
impl PySslWantWriteError {}
368-
369-
/// System error when attempting SSL operation.
370-
#[pyattr]
371-
#[pyexception(name = "SSLSyscallError", base = PySslError)]
372-
#[derive(Debug)]
373-
#[repr(transparent)]
374-
pub struct PySslSyscallError(PySslError);
375-
376-
#[pyexception]
377-
impl PySslSyscallError {}
378-
379-
/// SSL/TLS connection terminated abruptly.
380-
#[pyattr]
381-
#[pyexception(name = "SSLEOFError", base = PySslError)]
382-
#[derive(Debug)]
383-
#[repr(transparent)]
384-
pub struct PySslEOFError(PySslError);
385-
386-
#[pyexception]
387-
impl PySslEOFError {}
388-
389314
type OpensslVersionInfo = (u8, u8, u8, u8, u8);
390315
const fn parse_version_info(mut n: i64) -> OpensslVersionInfo {
391316
let status = (n & 0xF) as u8;

crates/stdlib/src/ssl.rs

Lines changed: 10 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,14 @@ mod cert;
2222
// OpenSSL compatibility layer (abstracts rustls operations)
2323
mod compat;
2424

25+
// SSL exception types (shared with openssl backend)
26+
mod error;
27+
2528
pub(crate) use _ssl::make_module;
2629

2730
#[allow(non_snake_case)]
2831
#[allow(non_upper_case_globals)]
29-
#[pymodule]
32+
#[pymodule(with(error::ssl_error))]
3033
mod _ssl {
3134
use crate::{
3235
common::{
@@ -37,15 +40,18 @@ mod _ssl {
3740
vm::{
3841
AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
3942
VirtualMachine,
40-
builtins::{
41-
PyBaseExceptionRef, PyBytesRef, PyListRef, PyOSError, PyStrRef, PyType, PyTypeRef,
42-
},
43+
builtins::{PyBaseExceptionRef, PyBytesRef, PyListRef, PyStrRef, PyType, PyTypeRef},
4344
convert::IntoPyException,
4445
function::{ArgBytesLike, ArgMemoryBuffer, FuncArgs, OptionalArg, PyComparisonValue},
4546
stdlib::warnings,
4647
types::{Comparable, Constructor, Hashable, PyComparisonOp, Representable},
4748
},
4849
};
50+
51+
// Import error types used in this module (others are exposed via pymodule(with(...)))
52+
use super::error::{
53+
PySSLEOFError, PySSLError, create_ssl_want_read_error, create_ssl_want_write_error,
54+
};
4955
use std::{
5056
collections::HashMap,
5157
sync::{
@@ -342,106 +348,6 @@ mod _ssl {
342348
#[pyattr]
343349
const ENCODING_PEM_AUX: i32 = 0x101; // PEM + 0x100
344350

345-
#[pyattr]
346-
#[pyexception(name = "SSLError", base = PyOSError)]
347-
#[derive(Debug)]
348-
#[repr(transparent)]
349-
pub struct PySSLError(PyOSError);
350-
351-
#[pyexception]
352-
impl PySSLError {
353-
// Returns strerror attribute if available, otherwise str(args)
354-
#[pymethod]
355-
fn __str__(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyResult<PyStrRef> {
356-
// Try to get strerror attribute first (OSError compatibility)
357-
if let Ok(strerror) = exc.as_object().get_attr("strerror", vm)
358-
&& !vm.is_none(&strerror)
359-
{
360-
return strerror.str(vm);
361-
}
362-
363-
// Otherwise return str(args)
364-
let args = exc.args();
365-
if args.len() == 1 {
366-
args.as_slice()[0].str(vm)
367-
} else {
368-
args.as_object().str(vm)
369-
}
370-
}
371-
}
372-
373-
#[pyattr]
374-
#[pyexception(name = "SSLZeroReturnError", base = PySSLError)]
375-
#[derive(Debug)]
376-
#[repr(transparent)]
377-
pub struct PySSLZeroReturnError(PySSLError);
378-
379-
#[pyexception]
380-
impl PySSLZeroReturnError {}
381-
382-
#[pyattr]
383-
#[pyexception(name = "SSLWantReadError", base = PySSLError, impl)]
384-
#[derive(Debug)]
385-
#[repr(transparent)]
386-
pub struct PySSLWantReadError(PySSLError);
387-
388-
#[pyattr]
389-
#[pyexception(name = "SSLWantWriteError", base = PySSLError, impl)]
390-
#[derive(Debug)]
391-
#[repr(transparent)]
392-
pub struct PySSLWantWriteError(PySSLError);
393-
394-
#[pyattr]
395-
#[pyexception(name = "SSLSyscallError", base = PySSLError, impl)]
396-
#[derive(Debug)]
397-
#[repr(transparent)]
398-
pub struct PySSLSyscallError(PySSLError);
399-
400-
#[pyattr]
401-
#[pyexception(name = "SSLEOFError", base = PySSLError, impl)]
402-
#[derive(Debug)]
403-
#[repr(transparent)]
404-
pub struct PySSLEOFError(PySSLError);
405-
406-
#[pyattr]
407-
#[pyexception(name = "SSLCertVerificationError", base = PySSLError, impl)]
408-
#[derive(Debug)]
409-
#[repr(transparent)]
410-
pub struct PySSLCertVerificationError(PySSLError);
411-
412-
// Helper functions to create SSL exceptions with proper errno attribute
413-
pub(super) fn create_ssl_want_read_error(vm: &VirtualMachine) -> PyRef<PyOSError> {
414-
vm.new_os_subtype_error(
415-
PySSLWantReadError::class(&vm.ctx).to_owned(),
416-
Some(SSL_ERROR_WANT_READ),
417-
"The operation did not complete (read)",
418-
)
419-
}
420-
421-
pub(super) fn create_ssl_want_write_error(vm: &VirtualMachine) -> PyRef<PyOSError> {
422-
vm.new_os_subtype_error(
423-
PySSLWantWriteError::class(&vm.ctx).to_owned(),
424-
Some(SSL_ERROR_WANT_WRITE),
425-
"The operation did not complete (write)",
426-
)
427-
}
428-
429-
pub(crate) fn create_ssl_eof_error(vm: &VirtualMachine) -> PyRef<PyOSError> {
430-
vm.new_os_subtype_error(
431-
PySSLEOFError::class(&vm.ctx).to_owned(),
432-
None,
433-
"EOF occurred in violation of protocol",
434-
)
435-
}
436-
437-
pub(crate) fn create_ssl_zero_return_error(vm: &VirtualMachine) -> PyRef<PyOSError> {
438-
vm.new_os_subtype_error(
439-
PySSLZeroReturnError::class(&vm.ctx).to_owned(),
440-
None,
441-
"TLS/SSL connection has been closed (EOF)",
442-
)
443-
}
444-
445351
/// Validate server hostname for TLS SNI
446352
///
447353
/// Checks that the hostname:

crates/stdlib/src/ssl/compat.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,13 @@ use rustpython_vm::{AsObject, Py, PyObjectRef, PyPayload, PyResult, TryFromObjec
3030
use std::io::Read;
3131
use std::sync::{Arc, Once};
3232

33-
// Import PySSLSocket and helper functions from parent module
34-
use super::_ssl::{
35-
PySSLCertVerificationError, PySSLError, PySSLSocket, create_ssl_eof_error,
36-
create_ssl_want_read_error, create_ssl_want_write_error, create_ssl_zero_return_error,
33+
// Import PySSLSocket from parent module
34+
use super::_ssl::PySSLSocket;
35+
36+
// Import error types and helper functions from error module
37+
use super::error::{
38+
PySSLCertVerificationError, PySSLError, create_ssl_eof_error, create_ssl_want_read_error,
39+
create_ssl_want_write_error, create_ssl_zero_return_error,
3740
};
3841

3942
// SSL Verification Flags

0 commit comments

Comments
 (0)