Skip to content

Commit 810fc12

Browse files
committed
pyssl errors
1 parent c8ff4b9 commit 810fc12

File tree

3 files changed

+97
-67
lines changed

3 files changed

+97
-67
lines changed

derive-impl/src/pyclass.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ pub(crate) fn impl_pyexception_impl(attr: PunctuatedNestedMeta, item: Item) -> R
619619
} else {
620620
quote! {
621621
#[pyslot]
622-
pub(crate) fn slot_new(
622+
pub fn slot_new(
623623
cls: ::rustpython_vm::builtins::PyTypeRef,
624624
args: ::rustpython_vm::function::FuncArgs,
625625
vm: &::rustpython_vm::VirtualMachine,
@@ -640,7 +640,7 @@ pub(crate) fn impl_pyexception_impl(attr: PunctuatedNestedMeta, item: Item) -> R
640640
quote! {
641641
#[pyslot]
642642
#[pymethod(name="__init__")]
643-
pub(crate) fn slot_init(
643+
pub fn slot_init(
644644
zelf: ::rustpython_vm::PyObjectRef,
645645
args: ::rustpython_vm::function::FuncArgs,
646646
vm: &::rustpython_vm::VirtualMachine,

stdlib/src/ssl.rs

Lines changed: 92 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,10 @@ mod _ssl {
3838
},
3939
socket::{self, PySocket},
4040
vm::{
41-
Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
42-
builtins::{PyBaseExceptionRef, PyBytesRef, PyListRef, PyStrRef, PyTypeRef, PyWeak},
41+
AsObject, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
42+
builtins::{
43+
PyBaseExceptionRef, PyBytesRef, PyListRef, PyOSError, PyStrRef, PyTypeRef, PyWeak,
44+
},
4345
class_or_notimplemented,
4446
convert::{ToPyException, ToPyObject},
4547
exceptions,
@@ -198,63 +200,82 @@ mod _ssl {
198200
parse_version_info(openssl_api_version)
199201
}
200202

203+
// SSL Exception Types
204+
201205
/// An error occurred in the SSL implementation.
202-
#[pyattr(name = "SSLError", once)]
203-
fn ssl_error(vm: &VirtualMachine) -> PyTypeRef {
204-
vm.ctx.new_exception_type(
205-
"ssl",
206-
"SSLError",
207-
Some(vec![vm.ctx.exceptions.os_error.to_owned()]),
208-
)
206+
#[pyattr]
207+
#[pyexception(name = "SSLError", base = "PyOSError")]
208+
#[derive(Debug)]
209+
pub struct PySslError {}
210+
211+
#[pyexception]
212+
impl PySslError {
213+
// Returns strerror attribute if available, otherwise str(args)
214+
#[pymethod]
215+
fn __str__(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyResult<PyStrRef> {
216+
// Try to get strerror attribute first (OSError compatibility)
217+
if let Ok(strerror) = exc.as_object().get_attr("strerror", vm) && !vm.is_none(&strerror) {
218+
return strerror.str(vm);
219+
}
220+
221+
// Otherwise return str(args)
222+
exc.args().as_object().str(vm)
223+
}
209224
}
210225

211226
/// A certificate could not be verified.
212-
#[pyattr(name = "SSLCertVerificationError", once)]
213-
fn ssl_cert_verification_error(vm: &VirtualMachine) -> PyTypeRef {
214-
vm.ctx.new_exception_type(
215-
"ssl",
216-
"SSLCertVerificationError",
217-
Some(vec![
218-
ssl_error(vm),
219-
vm.ctx.exceptions.value_error.to_owned(),
220-
]),
221-
)
222-
}
227+
#[pyattr]
228+
#[pyexception(name = "SSLCertVerificationError", base = "PySslError")]
229+
#[derive(Debug)]
230+
pub struct PySslCertVerificationError {}
231+
232+
#[pyexception]
233+
impl PySslCertVerificationError {}
223234

224235
/// SSL/TLS session closed cleanly.
225-
#[pyattr(name = "SSLZeroReturnError", once)]
226-
fn ssl_zero_return_error(vm: &VirtualMachine) -> PyTypeRef {
227-
vm.ctx
228-
.new_exception_type("ssl", "SSLZeroReturnError", Some(vec![ssl_error(vm)]))
229-
}
236+
#[pyattr]
237+
#[pyexception(name = "SSLZeroReturnError", base = "PySslError")]
238+
#[derive(Debug)]
239+
pub struct PySslZeroReturnError {}
230240

231-
/// Non-blocking SSL socket needs to read more data before the requested operation can be completed.
232-
#[pyattr(name = "SSLWantReadError", once)]
233-
fn ssl_want_read_error(vm: &VirtualMachine) -> PyTypeRef {
234-
vm.ctx
235-
.new_exception_type("ssl", "SSLWantReadError", Some(vec![ssl_error(vm)]))
236-
}
241+
#[pyexception]
242+
impl PySslZeroReturnError {}
237243

238-
/// Non-blocking SSL socket needs to write more data before the requested operation can be completed.
239-
#[pyattr(name = "SSLWantWriteError", once)]
240-
fn ssl_want_write_error(vm: &VirtualMachine) -> PyTypeRef {
241-
vm.ctx
242-
.new_exception_type("ssl", "SSLWantWriteError", Some(vec![ssl_error(vm)]))
243-
}
244+
/// Non-blocking SSL socket needs to read more data.
245+
#[pyattr]
246+
#[pyexception(name = "SSLWantReadError", base = "PySslError")]
247+
#[derive(Debug)]
248+
pub struct PySslWantReadError {}
249+
250+
#[pyexception]
251+
impl PySslWantReadError {}
252+
253+
/// Non-blocking SSL socket needs to write more data.
254+
#[pyattr]
255+
#[pyexception(name = "SSLWantWriteError", base = "PySslError")]
256+
#[derive(Debug)]
257+
pub struct PySslWantWriteError {}
258+
259+
#[pyexception]
260+
impl PySslWantWriteError {}
244261

245262
/// System error when attempting SSL operation.
246-
#[pyattr(name = "SSLSyscallError", once)]
247-
fn ssl_syscall_error(vm: &VirtualMachine) -> PyTypeRef {
248-
vm.ctx
249-
.new_exception_type("ssl", "SSLSyscallError", Some(vec![ssl_error(vm)]))
250-
}
263+
#[pyattr]
264+
#[pyexception(name = "SSLSyscallError", base = "PySslError")]
265+
#[derive(Debug)]
266+
pub struct PySslSyscallError {}
267+
268+
#[pyexception]
269+
impl PySslSyscallError {}
251270

252271
/// SSL/TLS connection terminated abruptly.
253-
#[pyattr(name = "SSLEOFError", once)]
254-
fn ssl_eof_error(vm: &VirtualMachine) -> PyTypeRef {
255-
vm.ctx
256-
.new_exception_type("ssl", "SSLEOFError", Some(vec![ssl_error(vm)]))
257-
}
272+
#[pyattr]
273+
#[pyexception(name = "SSLEOFError", base = "PySslError")]
274+
#[derive(Debug)]
275+
pub struct PySslEOFError {}
276+
277+
#[pyexception]
278+
impl PySslEOFError {}
258279

259280
type OpensslVersionInfo = (u8, u8, u8, u8, u8);
260281
const fn parse_version_info(mut n: i64) -> OpensslVersionInfo {
@@ -617,7 +638,10 @@ mod _ssl {
617638
return Err(exceptions::cstring_error(vm));
618639
}
619640
self.builder().set_cipher_list(ciphers).map_err(|_| {
620-
vm.new_exception_msg(ssl_error(vm), "No cipher can be selected.".to_owned())
641+
vm.new_exception_msg(
642+
PySslError::class(&vm.ctx).to_owned(),
643+
"No cipher can be selected.".to_owned(),
644+
)
621645
})
622646
}
623647

@@ -744,13 +768,13 @@ mod _ssl {
744768

745769
if clear != 0 && sys::X509_VERIFY_PARAM_clear_flags(param, clear) == 0 {
746770
return Err(vm.new_exception_msg(
747-
ssl_error(vm),
771+
PySslError::class(&vm.ctx).to_owned(),
748772
"Failed to clear verify flags".to_owned(),
749773
));
750774
}
751775
if set != 0 && sys::X509_VERIFY_PARAM_set_flags(param, set) == 0 {
752776
return Err(vm.new_exception_msg(
753-
ssl_error(vm),
777+
PySslError::class(&vm.ctx).to_owned(),
754778
"Failed to set verify flags".to_owned(),
755779
));
756780
}
@@ -934,13 +958,13 @@ mod _ssl {
934958
// validate socket type and context protocol
935959
if !args.server_side && zelf.protocol == SslVersion::TlsServer {
936960
return Err(vm.new_exception_msg(
937-
ssl_error(vm),
961+
PySslError::class(&vm.ctx).to_owned(),
938962
"Cannot create a client socket with a PROTOCOL_TLS_SERVER context".to_owned(),
939963
));
940964
}
941965
if args.server_side && zelf.protocol == SslVersion::TlsClient {
942966
return Err(vm.new_exception_msg(
943-
ssl_error(vm),
967+
PySslError::class(&vm.ctx).to_owned(),
944968
"Cannot create a server socket with a PROTOCOL_TLS_CLIENT context".to_owned(),
945969
));
946970
}
@@ -1124,7 +1148,7 @@ mod _ssl {
11241148

11251149
fn socket_closed_error(vm: &VirtualMachine) -> PyBaseExceptionRef {
11261150
vm.new_exception_msg(
1127-
ssl_error(vm),
1151+
PySslError::class(&vm.ctx).to_owned(),
11281152
"Underlying socket has been closed.".to_owned(),
11291153
)
11301154
}
@@ -1390,7 +1414,7 @@ mod _ssl {
13901414
let result = unsafe { SSL_verify_client_post_handshake(stream.ssl().as_ptr()) };
13911415
if result == 0 {
13921416
Err(vm.new_exception_msg(
1393-
ssl_error(vm),
1417+
PySslError::class(&vm.ctx).to_owned(),
13941418
"Post-handshake authentication failed".to_owned(),
13951419
))
13961420
} else {
@@ -1422,7 +1446,7 @@ mod _ssl {
14221446
// Return the underlying socket
14231447
} else {
14241448
return Err(vm.new_exception_msg(
1425-
ssl_error(vm),
1449+
PySslError::class(&vm.ctx).to_owned(),
14261450
format!("SSL shutdown failed: error code {}", err),
14271451
));
14281452
}
@@ -1854,7 +1878,7 @@ mod _ssl {
18541878
fn write(&self, data: ArgBytesLike, vm: &VirtualMachine) -> PyResult<i32> {
18551879
if self.eof_written.load() {
18561880
return Err(vm.new_exception_msg(
1857-
ssl_error(vm),
1881+
PySslError::class(&vm.ctx).to_owned(),
18581882
"cannot write() after write_eof()".to_owned(),
18591883
));
18601884
}
@@ -1953,7 +1977,7 @@ mod _ssl {
19531977

19541978
#[track_caller]
19551979
fn convert_openssl_error(vm: &VirtualMachine, err: ErrorStack) -> PyBaseExceptionRef {
1956-
let cls = ssl_error(vm);
1980+
let cls = PySslError::class(&vm.ctx).to_owned();
19571981
match err.errors().last() {
19581982
Some(e) => {
19591983
let caller = std::panic::Location::caller();
@@ -2012,25 +2036,31 @@ mod _ssl {
20122036
let e = e.borrow();
20132037
let (cls, msg) = match e.code() {
20142038
ssl::ErrorCode::WANT_READ => (
2015-
vm.class("_ssl", "SSLWantReadError"),
2039+
PySslWantReadError::class(&vm.ctx).to_owned(),
20162040
"The operation did not complete (read)",
20172041
),
20182042
ssl::ErrorCode::WANT_WRITE => (
2019-
vm.class("_ssl", "SSLWantWriteError"),
2043+
PySslWantWriteError::class(&vm.ctx).to_owned(),
20202044
"The operation did not complete (write)",
20212045
),
20222046
ssl::ErrorCode::SYSCALL => match e.io_error() {
20232047
Some(io_err) => return io_err.to_pyexception(vm),
20242048
None => (
2025-
vm.class("_ssl", "SSLSyscallError"),
2049+
PySslSyscallError::class(&vm.ctx).to_owned(),
20262050
"EOF occurred in violation of protocol",
20272051
),
20282052
},
20292053
ssl::ErrorCode::SSL => match e.ssl_error() {
20302054
Some(e) => return convert_openssl_error(vm, e.clone()),
2031-
None => (ssl_error(vm), "A failure in the SSL library occurred"),
2055+
None => (
2056+
PySslError::class(&vm.ctx).to_owned(),
2057+
"A failure in the SSL library occurred",
2058+
),
20322059
},
2033-
_ => (ssl_error(vm), "A failure in the SSL library occurred"),
2060+
_ => (
2061+
PySslError::class(&vm.ctx).to_owned(),
2062+
"A failure in the SSL library occurred",
2063+
),
20342064
};
20352065
vm.new_exception_msg(cls, msg.to_owned())
20362066
}

vm/src/exceptions.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1450,7 +1450,7 @@ pub(super) mod types {
14501450
}
14511451
#[cfg(not(target_arch = "wasm32"))]
14521452
#[pyslot]
1453-
fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
1453+
pub fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
14541454
// We need this method, because of how `CPython` copies `init`
14551455
// from `BaseException` in `SimpleExtendsException` macro.
14561456
// See: `BaseException_new`
@@ -1465,12 +1465,12 @@ pub(super) mod types {
14651465
}
14661466
#[cfg(target_arch = "wasm32")]
14671467
#[pyslot]
1468-
fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
1468+
pub fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
14691469
PyBaseException::slot_new(cls, args, vm)
14701470
}
14711471
#[pyslot]
14721472
#[pymethod(name = "__init__")]
1473-
fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
1473+
pub fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
14741474
let len = args.args.len();
14751475
let mut new_args = args;
14761476
if (3..=5).contains(&len) {

0 commit comments

Comments
 (0)