Skip to content

Commit 517b55b

Browse files
committed
pyssl errors
1 parent 3791533 commit 517b55b

File tree

3 files changed

+99
-67
lines changed

3 files changed

+99
-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: 94 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,84 @@ 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)
218+
&& !vm.is_none(&strerror)
219+
{
220+
return strerror.str(vm);
221+
}
222+
223+
// Otherwise return str(args)
224+
exc.args().as_object().str(vm)
225+
}
209226
}
210227

211228
/// 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-
}
229+
#[pyattr]
230+
#[pyexception(name = "SSLCertVerificationError", base = "PySslError")]
231+
#[derive(Debug)]
232+
pub struct PySslCertVerificationError {}
233+
234+
#[pyexception]
235+
impl PySslCertVerificationError {}
223236

224237
/// 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-
}
238+
#[pyattr]
239+
#[pyexception(name = "SSLZeroReturnError", base = "PySslError")]
240+
#[derive(Debug)]
241+
pub struct PySslZeroReturnError {}
230242

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-
}
243+
#[pyexception]
244+
impl PySslZeroReturnError {}
237245

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-
}
246+
/// Non-blocking SSL socket needs to read more data.
247+
#[pyattr]
248+
#[pyexception(name = "SSLWantReadError", base = "PySslError")]
249+
#[derive(Debug)]
250+
pub struct PySslWantReadError {}
251+
252+
#[pyexception]
253+
impl PySslWantReadError {}
254+
255+
/// Non-blocking SSL socket needs to write more data.
256+
#[pyattr]
257+
#[pyexception(name = "SSLWantWriteError", base = "PySslError")]
258+
#[derive(Debug)]
259+
pub struct PySslWantWriteError {}
260+
261+
#[pyexception]
262+
impl PySslWantWriteError {}
244263

245264
/// 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-
}
265+
#[pyattr]
266+
#[pyexception(name = "SSLSyscallError", base = "PySslError")]
267+
#[derive(Debug)]
268+
pub struct PySslSyscallError {}
269+
270+
#[pyexception]
271+
impl PySslSyscallError {}
251272

252273
/// 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-
}
274+
#[pyattr]
275+
#[pyexception(name = "SSLEOFError", base = "PySslError")]
276+
#[derive(Debug)]
277+
pub struct PySslEOFError {}
278+
279+
#[pyexception]
280+
impl PySslEOFError {}
258281

259282
type OpensslVersionInfo = (u8, u8, u8, u8, u8);
260283
const fn parse_version_info(mut n: i64) -> OpensslVersionInfo {
@@ -617,7 +640,10 @@ mod _ssl {
617640
return Err(exceptions::cstring_error(vm));
618641
}
619642
self.builder().set_cipher_list(ciphers).map_err(|_| {
620-
vm.new_exception_msg(ssl_error(vm), "No cipher can be selected.".to_owned())
643+
vm.new_exception_msg(
644+
PySslError::class(&vm.ctx).to_owned(),
645+
"No cipher can be selected.".to_owned(),
646+
)
621647
})
622648
}
623649

@@ -744,13 +770,13 @@ mod _ssl {
744770

745771
if clear != 0 && sys::X509_VERIFY_PARAM_clear_flags(param, clear) == 0 {
746772
return Err(vm.new_exception_msg(
747-
ssl_error(vm),
773+
PySslError::class(&vm.ctx).to_owned(),
748774
"Failed to clear verify flags".to_owned(),
749775
));
750776
}
751777
if set != 0 && sys::X509_VERIFY_PARAM_set_flags(param, set) == 0 {
752778
return Err(vm.new_exception_msg(
753-
ssl_error(vm),
779+
PySslError::class(&vm.ctx).to_owned(),
754780
"Failed to set verify flags".to_owned(),
755781
));
756782
}
@@ -934,13 +960,13 @@ mod _ssl {
934960
// validate socket type and context protocol
935961
if !args.server_side && zelf.protocol == SslVersion::TlsServer {
936962
return Err(vm.new_exception_msg(
937-
ssl_error(vm),
963+
PySslError::class(&vm.ctx).to_owned(),
938964
"Cannot create a client socket with a PROTOCOL_TLS_SERVER context".to_owned(),
939965
));
940966
}
941967
if args.server_side && zelf.protocol == SslVersion::TlsClient {
942968
return Err(vm.new_exception_msg(
943-
ssl_error(vm),
969+
PySslError::class(&vm.ctx).to_owned(),
944970
"Cannot create a server socket with a PROTOCOL_TLS_CLIENT context".to_owned(),
945971
));
946972
}
@@ -1124,7 +1150,7 @@ mod _ssl {
11241150

11251151
fn socket_closed_error(vm: &VirtualMachine) -> PyBaseExceptionRef {
11261152
vm.new_exception_msg(
1127-
ssl_error(vm),
1153+
PySslError::class(&vm.ctx).to_owned(),
11281154
"Underlying socket has been closed.".to_owned(),
11291155
)
11301156
}
@@ -1390,7 +1416,7 @@ mod _ssl {
13901416
let result = unsafe { SSL_verify_client_post_handshake(stream.ssl().as_ptr()) };
13911417
if result == 0 {
13921418
Err(vm.new_exception_msg(
1393-
ssl_error(vm),
1419+
PySslError::class(&vm.ctx).to_owned(),
13941420
"Post-handshake authentication failed".to_owned(),
13951421
))
13961422
} else {
@@ -1422,7 +1448,7 @@ mod _ssl {
14221448
// Return the underlying socket
14231449
} else {
14241450
return Err(vm.new_exception_msg(
1425-
ssl_error(vm),
1451+
PySslError::class(&vm.ctx).to_owned(),
14261452
format!("SSL shutdown failed: error code {}", err),
14271453
));
14281454
}
@@ -1854,7 +1880,7 @@ mod _ssl {
18541880
fn write(&self, data: ArgBytesLike, vm: &VirtualMachine) -> PyResult<i32> {
18551881
if self.eof_written.load() {
18561882
return Err(vm.new_exception_msg(
1857-
ssl_error(vm),
1883+
PySslError::class(&vm.ctx).to_owned(),
18581884
"cannot write() after write_eof()".to_owned(),
18591885
));
18601886
}
@@ -1953,7 +1979,7 @@ mod _ssl {
19531979

19541980
#[track_caller]
19551981
fn convert_openssl_error(vm: &VirtualMachine, err: ErrorStack) -> PyBaseExceptionRef {
1956-
let cls = ssl_error(vm);
1982+
let cls = PySslError::class(&vm.ctx).to_owned();
19571983
match err.errors().last() {
19581984
Some(e) => {
19591985
let caller = std::panic::Location::caller();
@@ -2012,25 +2038,31 @@ mod _ssl {
20122038
let e = e.borrow();
20132039
let (cls, msg) = match e.code() {
20142040
ssl::ErrorCode::WANT_READ => (
2015-
vm.class("_ssl", "SSLWantReadError"),
2041+
PySslWantReadError::class(&vm.ctx).to_owned(),
20162042
"The operation did not complete (read)",
20172043
),
20182044
ssl::ErrorCode::WANT_WRITE => (
2019-
vm.class("_ssl", "SSLWantWriteError"),
2045+
PySslWantWriteError::class(&vm.ctx).to_owned(),
20202046
"The operation did not complete (write)",
20212047
),
20222048
ssl::ErrorCode::SYSCALL => match e.io_error() {
20232049
Some(io_err) => return io_err.to_pyexception(vm),
20242050
None => (
2025-
vm.class("_ssl", "SSLSyscallError"),
2051+
PySslSyscallError::class(&vm.ctx).to_owned(),
20262052
"EOF occurred in violation of protocol",
20272053
),
20282054
},
20292055
ssl::ErrorCode::SSL => match e.ssl_error() {
20302056
Some(e) => return convert_openssl_error(vm, e.clone()),
2031-
None => (ssl_error(vm), "A failure in the SSL library occurred"),
2057+
None => (
2058+
PySslError::class(&vm.ctx).to_owned(),
2059+
"A failure in the SSL library occurred",
2060+
),
20322061
},
2033-
_ => (ssl_error(vm), "A failure in the SSL library occurred"),
2062+
_ => (
2063+
PySslError::class(&vm.ctx).to_owned(),
2064+
"A failure in the SSL library occurred",
2065+
),
20342066
};
20352067
vm.new_exception_msg(cls, msg.to_owned())
20362068
}

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)