@@ -22,11 +22,14 @@ mod cert;
2222// OpenSSL compatibility layer (abstracts rustls operations)
2323mod compat;
2424
25+ // SSL exception types (shared with openssl backend)
26+ mod error;
27+
2528pub ( 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 ) ) ]
3033mod _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:
0 commit comments