1 //! Errors for this module.
2 use std::cmp;
3 use std::fmt::{Display, Formatter, Result};
4 
5 use failure::Context;
6 
7 #[derive(Debug)]
8 /// Generic Error type over all errors in the bollard library
9 pub struct Error {
10     inner: Context<ErrorKind>,
11 }
12 
13 /// The type of error embedded in an Error.
14 #[derive(Debug, Fail)]
15 pub enum ErrorKind {
16     #[fail(display = "could not find DOCKER_CERT_PATH")]
17     /// Error emitted during client instantiation when the `DOCKER_CERT_PATH` environment variable
18     /// is invalid.
19     NoCertPathError,
20     #[fail(display = "API responded with a 404 not found: {}", message)]
21     /// Error emitted by the docker server, when it responds with a 404.
22     DockerResponseNotFoundError {
23         /// Message returned by the docker server.
24         message: String,
25     },
26     #[fail(
27         display = "Docker responded with status code {}: {}",
28         status_code, message
29     )]
30     /// Generic error emitted by the docker server.
31     DockerResponseServerError {
32         /// Status code returned by the docker server.
33         status_code: u16,
34         /// Message returned by the docker server.
35         message: String,
36     },
37     #[fail(display = "API queried with a bad parameter: {}", message)]
38     /// Error emitted by the docker server, when it responds with a 400.
39     DockerResponseBadParameterError {
40         /// Message returned by the docker server.
41         message: String,
42     },
43     #[fail(display = "API responded with a 409 conflict: {}", message)]
44     /// Error emitted by the docker server, when it responds with a 409.
45     DockerResponseConflictError {
46         /// Message returned by the docker server.
47         message: String,
48     },
49     #[fail(
50         display = "API responded with a 304, resource was not modified: {}",
51         message
52     )]
53     /// Error emitted by the docker server, when it responds with a 304.
54     DockerResponseNotModifiedError {
55         /// Message returned by the docker server.
56         message: String,
57     },
58     #[fail(display = "Failed to deserialize JSON: {}", message)]
59     /// Error facilitating debugging failed JSON parsing.
60     JsonDataError {
61         /// Short section of the json close to the error.
62         message: String,
63         /// Entire JSON payload.
64         contents: String,
65         /// Character sequence at error location.
66         column: usize,
67     },
68     #[fail(display = "Failed to parse API version: {}", api_version)]
69     /// Error emitted when the server version cannot be parsed when negotiating a version
70     APIVersionParseError {
71         /// The api version returned by the server.
72         api_version: String,
73     },
74     #[fail(display = "Failed to serialize JSON: {:?}", err)]
75     /// Error emitted when JSON fails to serialize.
76     JsonSerializeError {
77         /// The original error emitted by serde.
78         err: serde_json::Error,
79     },
80     #[fail(display = "Failed to deserialize JSON: {}: {:?}", content, err)]
81     /// Error emitted when JSON fails to deserialize.
82     JsonDeserializeError {
83         /// The original string that was being deserialized.
84         content: String,
85         /// The original error emitted by serde.
86         err: serde_json::Error,
87     },
88     #[fail(display = "UTF8 error: {}: {:?}", content, err)]
89     /// Error emitted when log output generates an I/O error.
90     StrParseError {
91         /// the bytes that failed
92         content: String,
93         /// The original error emitted.
94         err: std::str::Utf8Error,
95     },
96     #[fail(display = "I/O error: {:?}", err)]
97     /// Error emitted from an I/O error.
98     IOError {
99         /// The original error emitted.
100         err: std::io::Error,
101     },
102     #[fail(display = "Format error: {}: {:?}", content, err)]
103     /// Error emitted from a formatting error.
104     StrFmtError {
105         /// The original string that failed to format.
106         content: String,
107         /// The original error emitted.
108         err: std::fmt::Error,
109     },
110     #[fail(display = "HTTP error: {}: {:?}", builder, err)]
111     /// Error emitted from an HTTP error.
112     HttpClientError {
113         /// The client builder, formatted as a debug string.
114         builder: String,
115         /// The original error emitted.
116         err: http::Error,
117     },
118     #[fail(display = "Hyper error: {:?}", err)]
119     /// Error emitted from an HTTP error.
120     HyperResponseError {
121         /// The original error emitted.
122         err: hyper::Error,
123     },
124     /// Error emitted when a request times out.
125     #[fail(display = "Timeout error")]
126     RequestTimeoutError,
127     /// Error emitted when an SSL context fails to configure.
128     #[cfg(feature = "openssl")]
129     #[fail(display = "SSL error: {:?}", err)]
130     SSLError {
131         /// The original error emitted.
132         err: openssl::error::ErrorStack,
133     },
134     /// Error emitted when a TLS context fails to configure.
135     #[cfg(feature = "tls")]
136     #[fail(display = "TLS error: {:?}", err)]
137     TLSError {
138         /// The original error emitted.
139         err: native_tls::Error,
140     },
141 }
142 
143 impl Display for Error {
fmt(&self, f: &mut Formatter<'_>) -> Result144     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
145         match self.inner.get_context() {
146             ErrorKind::JsonDataError {
147                 message,
148                 contents,
149                 column,
150             } => {
151                 let backtrack_len: usize = 24;
152                 let peek_len: usize = 32;
153                 let description = "Failed to deserialize near ...";
154                 let from_start_length = column.checked_sub(backtrack_len).unwrap_or(0);
155                 write!(
156                     f,
157                     "{}{}...\n{}",
158                     description,
159                     &contents[from_start_length..cmp::min(contents.len(), column + peek_len)],
160                     message
161                 )
162             }
163             _ => Display::fmt(&self.inner, f),
164         }
165     }
166 }
167 
168 impl std::error::Error for Error {
source(&self) -> Option<&(dyn std::error::Error + 'static)>169     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
170         match self.inner.get_context() {
171             ErrorKind::JsonSerializeError { err, .. } => Some(err),
172             ErrorKind::JsonDeserializeError { err, .. } => Some(err),
173             ErrorKind::StrParseError { err, .. } => Some(err),
174             ErrorKind::IOError { err, .. } => Some(err),
175             ErrorKind::StrFmtError { err, .. } => Some(err),
176             ErrorKind::HttpClientError { err, .. } => Some(err),
177             ErrorKind::HyperResponseError { err, .. } => Some(err),
178             _ => None,
179         }
180     }
181 }
182 
183 impl Error {
184     /// yield the underlying error kind of this error.
kind(&self) -> &ErrorKind185     pub fn kind(&self) -> &ErrorKind {
186         self.inner.get_context()
187     }
188 }
189 
190 impl From<ErrorKind> for Error {
from(kind: ErrorKind) -> Error191     fn from(kind: ErrorKind) -> Error {
192         Error {
193             inner: Context::new(kind),
194         }
195     }
196 }
197 
198 impl From<Context<ErrorKind>> for Error {
from(inner: Context<ErrorKind>) -> Error199     fn from(inner: Context<ErrorKind>) -> Error {
200         Error { inner: inner }
201     }
202 }
203 
204 /// Needed due to tokio's Decoder implementation
205 impl From<std::io::Error> for Error {
from(err: std::io::Error) -> Error206     fn from(err: std::io::Error) -> Error {
207         Error {
208             inner: ErrorKind::IOError { err: err }.into(),
209         }
210     }
211 }
212