avx_http/
error.rs

1//! Error types for avx-http
2
3use std::fmt;
4
5/// Result type alias for avx-http operations
6pub type Result<T> = std::result::Result<T, Error>;
7
8/// Error types for HTTP operations
9#[derive(Debug)]
10pub enum Error {
11    /// Invalid URL provided
12    InvalidUrl {
13        /// The invalid URL
14        url: String,
15        /// Reason why it's invalid
16        reason: String,
17    },
18
19    /// Connection failed
20    ConnectionFailed {
21        /// Host that failed to connect
22        host: String,
23        /// Underlying IO error
24        source: std::io::Error,
25    },
26
27    /// Connection timeout
28    ConnectionTimeout {
29        /// Host that timed out
30        host: String,
31    },
32
33    /// Too many connections
34    TooManyConnections {
35        /// Host with too many connections
36        host: String,
37        /// Maximum allowed connections
38        max: usize,
39    },
40
41    /// Request timeout
42    Timeout {
43        /// Duration that was exceeded
44        duration: std::time::Duration,
45    },
46
47    /// Invalid HTTP method
48    InvalidMethod {
49        /// The invalid method
50        method: String,
51    },
52
53    /// Invalid header
54    InvalidHeader {
55        /// Header name
56        name: String,
57        /// Header value
58        value: String,
59    },
60
61    /// HTTP status error
62    StatusError {
63        /// HTTP status code
64        status: u16,
65        /// Response body
66        body: String,
67    },
68
69    /// Body read error
70    BodyReadError {
71        /// Underlying IO error
72        source: std::io::Error,
73    },
74
75    /// JSON serialization/deserialization error
76    JsonError {
77        /// Error message
78        source: String,
79    },
80
81    /// Invalid configuration
82    InvalidConfig {
83        /// Error message
84        message: String,
85    },
86
87    /// Authentication error
88    AuthError {
89        /// Error message
90        message: String,
91    },
92
93    /// Internal error
94    Internal {
95        /// Error message
96        message: String,
97    },
98}
99
100impl fmt::Display for Error {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        match self {
103            Error::InvalidUrl { url, reason } => {
104                write!(f, "Invalid URL '{}': {}", url, reason)
105            }
106            Error::ConnectionFailed { host, source } => {
107                write!(f, "Failed to connect to {}: {}", host, source)
108            }
109            Error::ConnectionTimeout { host } => {
110                write!(f, "Connection to {} timed out", host)
111            }
112            Error::TooManyConnections { host, max } => {
113                write!(f, "Too many connections to {} (max: {})", host, max)
114            }
115            Error::Timeout { duration } => {
116                write!(f, "Request timed out after {:?}", duration)
117            }
118            Error::InvalidMethod { method } => {
119                write!(f, "Invalid HTTP method: {}", method)
120            }
121            Error::InvalidHeader { name, value } => {
122                write!(f, "Invalid header '{}': {}", name, value)
123            }
124            Error::StatusError { status, body } => {
125                write!(f, "HTTP error {}: {}", status, body)
126            }
127            Error::BodyReadError { source } => {
128                write!(f, "Failed to read response body: {}", source)
129            }
130            Error::JsonError { source } => {
131                write!(f, "JSON error: {}", source)
132            }
133            Error::InvalidConfig { message } => {
134                write!(f, "Invalid configuration: {}", message)
135            }
136            Error::AuthError { message } => {
137                write!(f, "Authentication error: {}", message)
138            }
139            Error::Internal { message } => {
140                write!(f, "Internal error: {}", message)
141            }
142        }
143    }
144}
145
146impl std::error::Error for Error {
147    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
148        match self {
149            Error::ConnectionFailed { source, .. } => Some(source),
150            Error::BodyReadError { source } => Some(source),
151            _ => None,
152        }
153    }
154}
155
156impl From<std::io::Error> for Error {
157    fn from(err: std::io::Error) -> Self {
158        Error::BodyReadError { source: err }
159    }
160}
161
162#[cfg(test)]
163mod tests {
164    use super::*;
165
166    #[test]
167    fn test_error_display() {
168        let err = Error::InvalidUrl {
169            url: "not-a-url".to_string(),
170            reason: "missing scheme".to_string(),
171        };
172        assert!(err.to_string().contains("Invalid URL"));
173        assert!(err.to_string().contains("not-a-url"));
174    }
175
176    #[test]
177    fn test_error_from_io() {
178        let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
179        let err: Error = io_err.into();
180        assert!(matches!(err, Error::BodyReadError { .. }));
181    }
182
183    #[test]
184    fn test_timeout_error() {
185        let err = Error::Timeout {
186            duration: std::time::Duration::from_secs(30),
187        };
188        assert!(err.to_string().contains("timed out"));
189        assert!(err.to_string().contains("30s"));
190    }
191}