summaryrefslogtreecommitdiffstats
path: root/third_party/rust/neqo-crypto/src/result.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/neqo-crypto/src/result.rs')
-rw-r--r--third_party/rust/neqo-crypto/src/result.rs133
1 files changed, 133 insertions, 0 deletions
diff --git a/third_party/rust/neqo-crypto/src/result.rs b/third_party/rust/neqo-crypto/src/result.rs
new file mode 100644
index 0000000000..e6148dd054
--- /dev/null
+++ b/third_party/rust/neqo-crypto/src/result.rs
@@ -0,0 +1,133 @@
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use crate::err::{
+ nspr, Error, PR_ErrorToName, PR_ErrorToString, PR_GetError, Res, PR_LANGUAGE_I_DEFAULT,
+};
+use crate::ssl;
+
+use std::ffi::CStr;
+
+pub fn result(rv: ssl::SECStatus) -> Res<()> {
+ let _ = result_helper(rv, false)?;
+ Ok(())
+}
+
+pub fn result_or_blocked(rv: ssl::SECStatus) -> Res<bool> {
+ result_helper(rv, true)
+}
+
+fn wrap_str_fn<F>(f: F, dflt: &str) -> String
+where
+ F: FnOnce() -> *const i8,
+{
+ unsafe {
+ let p = f();
+ if p.is_null() {
+ return dflt.to_string();
+ }
+ CStr::from_ptr(p).to_string_lossy().into_owned()
+ }
+}
+
+fn result_helper(rv: ssl::SECStatus, allow_blocked: bool) -> Res<bool> {
+ if rv == ssl::_SECStatus_SECSuccess {
+ return Ok(false);
+ }
+
+ let code = unsafe { PR_GetError() };
+ if allow_blocked && code == nspr::PR_WOULD_BLOCK_ERROR {
+ return Ok(true);
+ }
+
+ let name = wrap_str_fn(|| unsafe { PR_ErrorToName(code) }, "UNKNOWN_ERROR");
+ let desc = wrap_str_fn(
+ || unsafe { PR_ErrorToString(code, PR_LANGUAGE_I_DEFAULT) },
+ "...",
+ );
+ Err(Error::NssError { name, code, desc })
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{result, result_or_blocked};
+ use crate::err::{self, nspr, Error, PRErrorCode, PR_SetError};
+ use crate::ssl;
+ use test_fixture::fixture_init;
+
+ fn set_error_code(code: PRErrorCode) {
+ unsafe { PR_SetError(code, 0) };
+ }
+
+ #[test]
+ fn is_ok() {
+ assert!(result(ssl::SECSuccess).is_ok());
+ }
+
+ #[test]
+ fn is_err() {
+ // This code doesn't work without initializing NSS first.
+ fixture_init();
+
+ set_error_code(err::ssl::SSL_ERROR_BAD_MAC_READ);
+ let r = result(ssl::SECFailure);
+ assert!(r.is_err());
+ match r.unwrap_err() {
+ Error::NssError { name, code, desc } => {
+ assert_eq!(name, "SSL_ERROR_BAD_MAC_READ");
+ assert_eq!(code, -12273);
+ assert_eq!(
+ desc,
+ "SSL received a record with an incorrect Message Authentication Code."
+ );
+ }
+ _ => unreachable!(),
+ }
+ }
+
+ #[test]
+ fn is_err_zero_code() {
+ // This code doesn't work without initializing NSS first.
+ fixture_init();
+
+ set_error_code(0);
+ let r = result(ssl::SECFailure);
+ assert!(r.is_err());
+ match r.unwrap_err() {
+ Error::NssError { name, code, .. } => {
+ assert_eq!(name, "UNKNOWN_ERROR");
+ assert_eq!(code, 0);
+ // Note that we don't test |desc| here because that comes from
+ // strerror(0), which is platform-dependent.
+ }
+ _ => unreachable!(),
+ }
+ }
+
+ #[test]
+ fn blocked_as_error() {
+ // This code doesn't work without initializing NSS first.
+ fixture_init();
+
+ set_error_code(nspr::PR_WOULD_BLOCK_ERROR);
+ let r = result(ssl::SECFailure);
+ assert!(r.is_err());
+ match r.unwrap_err() {
+ Error::NssError { name, code, desc } => {
+ assert_eq!(name, "PR_WOULD_BLOCK_ERROR");
+ assert_eq!(code, -5998);
+ assert_eq!(desc, "The operation would have blocked");
+ }
+ _ => panic!("bad error type"),
+ }
+ }
+
+ #[test]
+ fn is_blocked() {
+ set_error_code(nspr::PR_WOULD_BLOCK_ERROR);
+ assert!(result_or_blocked(ssl::SECFailure).unwrap());
+ }
+}