From cb5b36c2319fc09e15a8ee25e9408469d8507365 Mon Sep 17 00:00:00 2001 From: "Stephen M. Coakley" Date: Wed, 23 Dec 2020 20:51:02 -0600 Subject: [PATCH] Remove curl error types from API --- src/agent.rs | 26 +++++---- src/client.rs | 4 +- src/error.rs | 142 ++++++++++++++++++++++++-------------------------- src/text.rs | 4 +- 4 files changed, 90 insertions(+), 86 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 64090e68..3aaefbd4 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -105,16 +105,22 @@ impl AgentBuilder { let mut multi = curl::multi::Multi::new(); if max_connections > 0 { - multi.set_max_total_connections(max_connections)?; + multi + .set_max_total_connections(max_connections) + .map_err(Error::from_any)?; } if max_connections_per_host > 0 { - multi.set_max_host_connections(max_connections_per_host)?; + multi + .set_max_host_connections(max_connections_per_host) + .map_err(Error::from_any)?; } // Only set maxconnects if greater than 0, because 0 actually means unlimited. if connection_cache_size > 0 { - multi.set_max_connects(connection_cache_size)?; + multi + .set_max_connects(connection_cache_size) + .map_err(Error::from_any)?; } let agent = AgentContext { @@ -318,8 +324,8 @@ impl AgentContext { ); // Register the request with curl. - let mut handle = self.multi.add2(request)?; - handle.set_token(id)?; + let mut handle = self.multi.add2(request).map_err(Error::from_any)?; + handle.set_token(id).map_err(Error::from_any)?; // Add the handle to our bookkeeping structure. entry.insert(handle); @@ -334,9 +340,9 @@ impl AgentContext { result: Result<(), curl::Error>, ) -> Result<(), Error> { let handle = self.requests.remove(token); - let mut handle = self.multi.remove2(handle)?; + let mut handle = self.multi.remove2(handle).map_err(Error::from_any)?; - handle.get_mut().set_result(result.map_err(Error::from)); + handle.get_mut().set_result(result.map_err(Error::from_any)); Ok(()) } @@ -445,7 +451,7 @@ impl AgentContext { #[tracing::instrument(level = "trace", skip(self))] fn dispatch(&mut self) -> Result<(), Error> { - self.multi.perform()?; + self.multi.perform().map_err(Error::from_any)?; // Collect messages from curl about requests that have completed, // whether successfully or with an error. @@ -488,7 +494,9 @@ impl AgentContext { self.dispatch()?; // Block until activity is detected or the timeout passes. - self.multi.wait(&mut wait_fds, WAIT_TIMEOUT)?; + self.multi + .wait(&mut wait_fds, WAIT_TIMEOUT) + .map_err(Error::from_any)?; // We might have woken up early from the notify fd, so drain the // socket to clear it. diff --git a/src/client.rs b/src/client.rs index 0516dc43..704f97cf 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1040,7 +1040,7 @@ impl HttpClient { curl::easy::Easy2, impl Future, Error>>, ), - Error, + curl::Error, > { // Prepare the request plumbing. // let (mut parts, body) = request.into_parts(); @@ -1202,7 +1202,7 @@ impl crate::interceptor::Invoke for &HttpClient { .unwrap_or(false); // Create and configure a curl easy handle to fulfil the request. - let (easy, future) = self.create_easy_handle(request)?; + let (easy, future) = self.create_easy_handle(request).map_err(Error::from_any)?; // Send the request to the agent to be executed. self.inner.agent.submit_request(easy)?; diff --git a/src/error.rs b/src/error.rs index 19988642..b2d4c85d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -172,6 +172,10 @@ impl Error { /// Statically cast a given error into an Isahc error, converting if /// necessary. + /// + /// This is useful for converting or creating errors from external types + /// without publicly implementing `From` over them and leaking them into our + /// API. pub(crate) fn from_any(error: E) -> Self where E: StdError + Send + Sync + 'static, @@ -179,6 +183,71 @@ impl Error { match_type! { => error, => error.into(), + => { + Self::with_context( + if error.is_ssl_certproblem() || error.is_ssl_cacert_badfile() { + ErrorKind::BadClientCertificate + } else if error.is_peer_failed_verification() + || error.is_ssl_cacert() + || error.is_ssl_cipher() + || error.is_ssl_issuer_error() + { + ErrorKind::BadServerCertificate + } else if error.is_interface_failed() { + ErrorKind::ClientInitialization + } else if error.is_couldnt_connect() || error.is_ssl_connect_error() { + ErrorKind::ConnectionFailed + } else if error.is_bad_content_encoding() || error.is_conv_failed() { + ErrorKind::InvalidContentEncoding + } else if error.is_login_denied() { + ErrorKind::InvalidCredentials + } else if error.is_url_malformed() { + ErrorKind::InvalidRequest + } else if error.is_couldnt_resolve_host() || error.is_couldnt_resolve_proxy() { + ErrorKind::NameResolution + } else if error.is_got_nothing() + || error.is_http2_error() + || error.is_http2_stream_error() + || error.is_unsupported_protocol() + || error.code() == curl_sys::CURLE_FTP_WEIRD_SERVER_REPLY + { + ErrorKind::ProtocolViolation + } else if error.is_send_error() + || error.is_recv_error() + || error.is_read_error() + || error.is_write_error() + || error.is_upload_failed() + || error.is_send_fail_rewind() + || error.is_aborted_by_callback() + || error.is_partial_file() + { + ErrorKind::Io + } else if error.is_ssl_engine_initfailed() + || error.is_ssl_engine_notfound() + || error.is_ssl_engine_setfailed() + { + ErrorKind::TlsEngine + } else if error.is_operation_timedout() { + ErrorKind::Timeout + } else if error.is_too_many_redirects() { + ErrorKind::TooManyRedirects + } else { + ErrorKind::Unknown + }, + error.extra_description().map(String::from), + error, + ) + }, + => { + Self::new( + if error.is_bad_socket() { + ErrorKind::Io + } else { + ErrorKind::Unknown + }, + error, + ) + }, error => Error::new(ErrorKind::Unknown, error), } } @@ -333,79 +402,6 @@ impl From for Error { } } -#[doc(hidden)] -impl From for Error { - fn from(error: curl::Error) -> Error { - Self::with_context( - if error.is_ssl_certproblem() || error.is_ssl_cacert_badfile() { - ErrorKind::BadClientCertificate - } else if error.is_peer_failed_verification() - || error.is_ssl_cacert() - || error.is_ssl_cipher() - || error.is_ssl_issuer_error() - { - ErrorKind::BadServerCertificate - } else if error.is_interface_failed() { - ErrorKind::ClientInitialization - } else if error.is_couldnt_connect() || error.is_ssl_connect_error() { - ErrorKind::ConnectionFailed - } else if error.is_bad_content_encoding() || error.is_conv_failed() { - ErrorKind::InvalidContentEncoding - } else if error.is_login_denied() { - ErrorKind::InvalidCredentials - } else if error.is_url_malformed() { - ErrorKind::InvalidRequest - } else if error.is_couldnt_resolve_host() || error.is_couldnt_resolve_proxy() { - ErrorKind::NameResolution - } else if error.is_got_nothing() - || error.is_http2_error() - || error.is_http2_stream_error() - || error.is_unsupported_protocol() - || error.code() == curl_sys::CURLE_FTP_WEIRD_SERVER_REPLY - { - ErrorKind::ProtocolViolation - } else if error.is_send_error() - || error.is_recv_error() - || error.is_read_error() - || error.is_write_error() - || error.is_upload_failed() - || error.is_send_fail_rewind() - || error.is_aborted_by_callback() - || error.is_partial_file() - { - ErrorKind::Io - } else if error.is_ssl_engine_initfailed() - || error.is_ssl_engine_notfound() - || error.is_ssl_engine_setfailed() - { - ErrorKind::TlsEngine - } else if error.is_operation_timedout() { - ErrorKind::Timeout - } else if error.is_too_many_redirects() { - ErrorKind::TooManyRedirects - } else { - ErrorKind::Unknown - }, - error.extra_description().map(String::from), - error, - ) - } -} - -#[doc(hidden)] -impl From for Error { - fn from(error: curl::MultiError) -> Error { - Self::new( - if error.is_bad_socket() { - ErrorKind::Io - } else { - ErrorKind::Unknown - }, - error, - ) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/text.rs b/src/text.rs index f0f7dcf6..39f67540 100644 --- a/src/text.rs +++ b/src/text.rs @@ -162,8 +162,8 @@ mod tests { fn utf8_decode() { let mut decoder = Decoder::new(encoding_rs::UTF_8); - assert_eq!(decoder.push(b"hello"), &[]); - assert_eq!(decoder.push(b" "), &[]); + assert_eq!(decoder.push(b"hello"), b""); + assert_eq!(decoder.push(b" "), b""); assert_eq!(decoder.finish(b"world"), "hello world"); }