curl/
error.rs

1use std::error;
2use std::ffi::{self, CStr};
3use std::fmt;
4use std::io;
5use std::str;
6
7/// An error returned from various "easy" operations.
8///
9/// This structure wraps a `CURLcode`.
10#[derive(Clone, PartialEq)]
11pub struct Error {
12    code: curl_sys::CURLcode,
13    extra: Option<Box<str>>,
14}
15
16impl Error {
17    /// Creates a new error from the underlying code returned by libcurl.
18    pub fn new(code: curl_sys::CURLcode) -> Error {
19        Error { code, extra: None }
20    }
21
22    /// Stores some extra information about this error inside this error.
23    ///
24    /// This is typically used with `take_error_buf` on the easy handles to
25    /// couple the extra `CURLOPT_ERRORBUFFER` information with an `Error` being
26    /// returned.
27    pub fn set_extra(&mut self, extra: String) {
28        self.extra = Some(extra.into());
29    }
30
31    /// Returns whether this error corresponds to CURLE_UNSUPPORTED_PROTOCOL.
32    pub fn is_unsupported_protocol(&self) -> bool {
33        self.code == curl_sys::CURLE_UNSUPPORTED_PROTOCOL
34    }
35
36    /// Returns whether this error corresponds to CURLE_FAILED_INIT.
37    pub fn is_failed_init(&self) -> bool {
38        self.code == curl_sys::CURLE_FAILED_INIT
39    }
40
41    /// Returns whether this error corresponds to CURLE_URL_MALFORMAT.
42    pub fn is_url_malformed(&self) -> bool {
43        self.code == curl_sys::CURLE_URL_MALFORMAT
44    }
45
46    // /// Returns whether this error corresponds to CURLE_NOT_BUILT_IN.
47    // pub fn is_not_built_in(&self) -> bool {
48    //     self.code == curl_sys::CURLE_NOT_BUILT_IN
49    // }
50
51    /// Returns whether this error corresponds to CURLE_COULDNT_RESOLVE_PROXY.
52    pub fn is_couldnt_resolve_proxy(&self) -> bool {
53        self.code == curl_sys::CURLE_COULDNT_RESOLVE_PROXY
54    }
55
56    /// Returns whether this error corresponds to CURLE_COULDNT_RESOLVE_HOST.
57    pub fn is_couldnt_resolve_host(&self) -> bool {
58        self.code == curl_sys::CURLE_COULDNT_RESOLVE_HOST
59    }
60
61    /// Returns whether this error corresponds to CURLE_COULDNT_CONNECT.
62    pub fn is_couldnt_connect(&self) -> bool {
63        self.code == curl_sys::CURLE_COULDNT_CONNECT
64    }
65
66    /// Returns whether this error corresponds to CURLE_REMOTE_ACCESS_DENIED.
67    pub fn is_remote_access_denied(&self) -> bool {
68        self.code == curl_sys::CURLE_REMOTE_ACCESS_DENIED
69    }
70
71    /// Returns whether this error corresponds to CURLE_PARTIAL_FILE.
72    pub fn is_partial_file(&self) -> bool {
73        self.code == curl_sys::CURLE_PARTIAL_FILE
74    }
75
76    /// Returns whether this error corresponds to CURLE_QUOTE_ERROR.
77    pub fn is_quote_error(&self) -> bool {
78        self.code == curl_sys::CURLE_QUOTE_ERROR
79    }
80
81    /// Returns whether this error corresponds to CURLE_HTTP_RETURNED_ERROR.
82    pub fn is_http_returned_error(&self) -> bool {
83        self.code == curl_sys::CURLE_HTTP_RETURNED_ERROR
84    }
85
86    /// Returns whether this error corresponds to CURLE_READ_ERROR.
87    pub fn is_read_error(&self) -> bool {
88        self.code == curl_sys::CURLE_READ_ERROR
89    }
90
91    /// Returns whether this error corresponds to CURLE_WRITE_ERROR.
92    pub fn is_write_error(&self) -> bool {
93        self.code == curl_sys::CURLE_WRITE_ERROR
94    }
95
96    /// Returns whether this error corresponds to CURLE_UPLOAD_FAILED.
97    pub fn is_upload_failed(&self) -> bool {
98        self.code == curl_sys::CURLE_UPLOAD_FAILED
99    }
100
101    /// Returns whether this error corresponds to CURLE_OUT_OF_MEMORY.
102    pub fn is_out_of_memory(&self) -> bool {
103        self.code == curl_sys::CURLE_OUT_OF_MEMORY
104    }
105
106    /// Returns whether this error corresponds to CURLE_OPERATION_TIMEDOUT.
107    pub fn is_operation_timedout(&self) -> bool {
108        self.code == curl_sys::CURLE_OPERATION_TIMEDOUT
109    }
110
111    /// Returns whether this error corresponds to CURLE_RANGE_ERROR.
112    pub fn is_range_error(&self) -> bool {
113        self.code == curl_sys::CURLE_RANGE_ERROR
114    }
115
116    /// Returns whether this error corresponds to CURLE_HTTP_POST_ERROR.
117    pub fn is_http_post_error(&self) -> bool {
118        self.code == curl_sys::CURLE_HTTP_POST_ERROR
119    }
120
121    /// Returns whether this error corresponds to CURLE_SSL_CONNECT_ERROR.
122    pub fn is_ssl_connect_error(&self) -> bool {
123        self.code == curl_sys::CURLE_SSL_CONNECT_ERROR
124    }
125
126    /// Returns whether this error corresponds to CURLE_BAD_DOWNLOAD_RESUME.
127    pub fn is_bad_download_resume(&self) -> bool {
128        self.code == curl_sys::CURLE_BAD_DOWNLOAD_RESUME
129    }
130
131    /// Returns whether this error corresponds to CURLE_FILE_COULDNT_READ_FILE.
132    pub fn is_file_couldnt_read_file(&self) -> bool {
133        self.code == curl_sys::CURLE_FILE_COULDNT_READ_FILE
134    }
135
136    /// Returns whether this error corresponds to CURLE_FUNCTION_NOT_FOUND.
137    pub fn is_function_not_found(&self) -> bool {
138        self.code == curl_sys::CURLE_FUNCTION_NOT_FOUND
139    }
140
141    /// Returns whether this error corresponds to CURLE_ABORTED_BY_CALLBACK.
142    pub fn is_aborted_by_callback(&self) -> bool {
143        self.code == curl_sys::CURLE_ABORTED_BY_CALLBACK
144    }
145
146    /// Returns whether this error corresponds to CURLE_BAD_FUNCTION_ARGUMENT.
147    pub fn is_bad_function_argument(&self) -> bool {
148        self.code == curl_sys::CURLE_BAD_FUNCTION_ARGUMENT
149    }
150
151    /// Returns whether this error corresponds to CURLE_INTERFACE_FAILED.
152    pub fn is_interface_failed(&self) -> bool {
153        self.code == curl_sys::CURLE_INTERFACE_FAILED
154    }
155
156    /// Returns whether this error corresponds to CURLE_TOO_MANY_REDIRECTS.
157    pub fn is_too_many_redirects(&self) -> bool {
158        self.code == curl_sys::CURLE_TOO_MANY_REDIRECTS
159    }
160
161    /// Returns whether this error corresponds to CURLE_UNKNOWN_OPTION.
162    pub fn is_unknown_option(&self) -> bool {
163        self.code == curl_sys::CURLE_UNKNOWN_OPTION
164    }
165
166    /// Returns whether this error corresponds to CURLE_PEER_FAILED_VERIFICATION.
167    pub fn is_peer_failed_verification(&self) -> bool {
168        self.code == curl_sys::CURLE_PEER_FAILED_VERIFICATION
169    }
170
171    /// Returns whether this error corresponds to CURLE_GOT_NOTHING.
172    pub fn is_got_nothing(&self) -> bool {
173        self.code == curl_sys::CURLE_GOT_NOTHING
174    }
175
176    /// Returns whether this error corresponds to CURLE_SSL_ENGINE_NOTFOUND.
177    pub fn is_ssl_engine_notfound(&self) -> bool {
178        self.code == curl_sys::CURLE_SSL_ENGINE_NOTFOUND
179    }
180
181    /// Returns whether this error corresponds to CURLE_SSL_ENGINE_SETFAILED.
182    pub fn is_ssl_engine_setfailed(&self) -> bool {
183        self.code == curl_sys::CURLE_SSL_ENGINE_SETFAILED
184    }
185
186    /// Returns whether this error corresponds to CURLE_SEND_ERROR.
187    pub fn is_send_error(&self) -> bool {
188        self.code == curl_sys::CURLE_SEND_ERROR
189    }
190
191    /// Returns whether this error corresponds to CURLE_RECV_ERROR.
192    pub fn is_recv_error(&self) -> bool {
193        self.code == curl_sys::CURLE_RECV_ERROR
194    }
195
196    /// Returns whether this error corresponds to CURLE_SSL_CERTPROBLEM.
197    pub fn is_ssl_certproblem(&self) -> bool {
198        self.code == curl_sys::CURLE_SSL_CERTPROBLEM
199    }
200
201    /// Returns whether this error corresponds to CURLE_SSL_CIPHER.
202    pub fn is_ssl_cipher(&self) -> bool {
203        self.code == curl_sys::CURLE_SSL_CIPHER
204    }
205
206    /// Returns whether this error corresponds to CURLE_SSL_CACERT.
207    pub fn is_ssl_cacert(&self) -> bool {
208        self.code == curl_sys::CURLE_SSL_CACERT
209    }
210
211    /// Returns whether this error corresponds to CURLE_BAD_CONTENT_ENCODING.
212    pub fn is_bad_content_encoding(&self) -> bool {
213        self.code == curl_sys::CURLE_BAD_CONTENT_ENCODING
214    }
215
216    /// Returns whether this error corresponds to CURLE_FILESIZE_EXCEEDED.
217    pub fn is_filesize_exceeded(&self) -> bool {
218        self.code == curl_sys::CURLE_FILESIZE_EXCEEDED
219    }
220
221    /// Returns whether this error corresponds to CURLE_USE_SSL_FAILED.
222    pub fn is_use_ssl_failed(&self) -> bool {
223        self.code == curl_sys::CURLE_USE_SSL_FAILED
224    }
225
226    /// Returns whether this error corresponds to CURLE_SEND_FAIL_REWIND.
227    pub fn is_send_fail_rewind(&self) -> bool {
228        self.code == curl_sys::CURLE_SEND_FAIL_REWIND
229    }
230
231    /// Returns whether this error corresponds to CURLE_SSL_ENGINE_INITFAILED.
232    pub fn is_ssl_engine_initfailed(&self) -> bool {
233        self.code == curl_sys::CURLE_SSL_ENGINE_INITFAILED
234    }
235
236    /// Returns whether this error corresponds to CURLE_LOGIN_DENIED.
237    pub fn is_login_denied(&self) -> bool {
238        self.code == curl_sys::CURLE_LOGIN_DENIED
239    }
240
241    /// Returns whether this error corresponds to CURLE_CONV_FAILED.
242    pub fn is_conv_failed(&self) -> bool {
243        self.code == curl_sys::CURLE_CONV_FAILED
244    }
245
246    /// Returns whether this error corresponds to CURLE_CONV_REQD.
247    pub fn is_conv_required(&self) -> bool {
248        self.code == curl_sys::CURLE_CONV_REQD
249    }
250
251    /// Returns whether this error corresponds to CURLE_SSL_CACERT_BADFILE.
252    pub fn is_ssl_cacert_badfile(&self) -> bool {
253        self.code == curl_sys::CURLE_SSL_CACERT_BADFILE
254    }
255
256    /// Returns whether this error corresponds to CURLE_SSL_CRL_BADFILE.
257    pub fn is_ssl_crl_badfile(&self) -> bool {
258        self.code == curl_sys::CURLE_SSL_CRL_BADFILE
259    }
260
261    /// Returns whether this error corresponds to CURLE_SSL_SHUTDOWN_FAILED.
262    pub fn is_ssl_shutdown_failed(&self) -> bool {
263        self.code == curl_sys::CURLE_SSL_SHUTDOWN_FAILED
264    }
265
266    /// Returns whether this error corresponds to CURLE_AGAIN.
267    pub fn is_again(&self) -> bool {
268        self.code == curl_sys::CURLE_AGAIN
269    }
270
271    /// Returns whether this error corresponds to CURLE_SSL_ISSUER_ERROR.
272    pub fn is_ssl_issuer_error(&self) -> bool {
273        self.code == curl_sys::CURLE_SSL_ISSUER_ERROR
274    }
275
276    /// Returns whether this error corresponds to CURLE_CHUNK_FAILED.
277    pub fn is_chunk_failed(&self) -> bool {
278        self.code == curl_sys::CURLE_CHUNK_FAILED
279    }
280
281    /// Returns whether this error corresponds to CURLE_HTTP2.
282    pub fn is_http2_error(&self) -> bool {
283        self.code == curl_sys::CURLE_HTTP2
284    }
285
286    /// Returns whether this error corresponds to CURLE_HTTP2_STREAM.
287    pub fn is_http2_stream_error(&self) -> bool {
288        self.code == curl_sys::CURLE_HTTP2_STREAM
289    }
290
291    // /// Returns whether this error corresponds to CURLE_NO_CONNECTION_AVAILABLE.
292    // pub fn is_no_connection_available(&self) -> bool {
293    //     self.code == curl_sys::CURLE_NO_CONNECTION_AVAILABLE
294    // }
295
296    /// Returns the value of the underlying error corresponding to libcurl.
297    pub fn code(&self) -> curl_sys::CURLcode {
298        self.code
299    }
300
301    /// Returns the general description of this error code, using curl's
302    /// builtin `strerror`-like functionality.
303    pub fn description(&self) -> &str {
304        unsafe {
305            let s = curl_sys::curl_easy_strerror(self.code);
306            assert!(!s.is_null());
307            str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
308        }
309    }
310
311    /// Returns the extra description of this error, if any is available.
312    pub fn extra_description(&self) -> Option<&str> {
313        self.extra.as_deref()
314    }
315}
316
317impl fmt::Display for Error {
318    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
319        let desc = self.description();
320        match self.extra {
321            Some(ref s) => write!(f, "[{}] {} ({})", self.code(), desc, s),
322            None => write!(f, "[{}] {}", self.code(), desc),
323        }
324    }
325}
326
327impl fmt::Debug for Error {
328    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
329        f.debug_struct("Error")
330            .field("description", &self.description())
331            .field("code", &self.code)
332            .field("extra", &self.extra)
333            .finish()
334    }
335}
336
337impl error::Error for Error {}
338
339/// An error returned from "share" operations.
340///
341/// This structure wraps a `CURLSHcode`.
342#[derive(Clone, PartialEq)]
343pub struct ShareError {
344    code: curl_sys::CURLSHcode,
345}
346
347impl ShareError {
348    /// Creates a new error from the underlying code returned by libcurl.
349    pub fn new(code: curl_sys::CURLSHcode) -> ShareError {
350        ShareError { code }
351    }
352
353    /// Returns whether this error corresponds to CURLSHE_BAD_OPTION.
354    pub fn is_bad_option(&self) -> bool {
355        self.code == curl_sys::CURLSHE_BAD_OPTION
356    }
357
358    /// Returns whether this error corresponds to CURLSHE_IN_USE.
359    pub fn is_in_use(&self) -> bool {
360        self.code == curl_sys::CURLSHE_IN_USE
361    }
362
363    /// Returns whether this error corresponds to CURLSHE_INVALID.
364    pub fn is_invalid(&self) -> bool {
365        self.code == curl_sys::CURLSHE_INVALID
366    }
367
368    /// Returns whether this error corresponds to CURLSHE_NOMEM.
369    pub fn is_nomem(&self) -> bool {
370        self.code == curl_sys::CURLSHE_NOMEM
371    }
372
373    // /// Returns whether this error corresponds to CURLSHE_NOT_BUILT_IN.
374    // pub fn is_not_built_in(&self) -> bool {
375    //     self.code == curl_sys::CURLSHE_NOT_BUILT_IN
376    // }
377
378    /// Returns the value of the underlying error corresponding to libcurl.
379    pub fn code(&self) -> curl_sys::CURLSHcode {
380        self.code
381    }
382
383    /// Returns curl's human-readable version of this error.
384    pub fn description(&self) -> &str {
385        unsafe {
386            let s = curl_sys::curl_share_strerror(self.code);
387            assert!(!s.is_null());
388            str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
389        }
390    }
391}
392
393impl fmt::Display for ShareError {
394    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
395        self.description().fmt(f)
396    }
397}
398
399impl fmt::Debug for ShareError {
400    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
401        write!(
402            f,
403            "ShareError {{ description: {:?}, code: {} }}",
404            self.description(),
405            self.code
406        )
407    }
408}
409
410impl error::Error for ShareError {}
411
412/// An error from "multi" operations.
413///
414/// THis structure wraps a `CURLMcode`.
415#[derive(Clone, PartialEq)]
416pub struct MultiError {
417    code: curl_sys::CURLMcode,
418}
419
420impl MultiError {
421    /// Creates a new error from the underlying code returned by libcurl.
422    pub fn new(code: curl_sys::CURLMcode) -> MultiError {
423        MultiError { code }
424    }
425
426    /// Returns whether this error corresponds to CURLM_BAD_HANDLE.
427    pub fn is_bad_handle(&self) -> bool {
428        self.code == curl_sys::CURLM_BAD_HANDLE
429    }
430
431    /// Returns whether this error corresponds to CURLM_BAD_EASY_HANDLE.
432    pub fn is_bad_easy_handle(&self) -> bool {
433        self.code == curl_sys::CURLM_BAD_EASY_HANDLE
434    }
435
436    /// Returns whether this error corresponds to CURLM_OUT_OF_MEMORY.
437    pub fn is_out_of_memory(&self) -> bool {
438        self.code == curl_sys::CURLM_OUT_OF_MEMORY
439    }
440
441    /// Returns whether this error corresponds to CURLM_INTERNAL_ERROR.
442    pub fn is_internal_error(&self) -> bool {
443        self.code == curl_sys::CURLM_INTERNAL_ERROR
444    }
445
446    /// Returns whether this error corresponds to CURLM_BAD_SOCKET.
447    pub fn is_bad_socket(&self) -> bool {
448        self.code == curl_sys::CURLM_BAD_SOCKET
449    }
450
451    /// Returns whether this error corresponds to CURLM_UNKNOWN_OPTION.
452    pub fn is_unknown_option(&self) -> bool {
453        self.code == curl_sys::CURLM_UNKNOWN_OPTION
454    }
455
456    /// Returns whether this error corresponds to CURLM_CALL_MULTI_PERFORM.
457    pub fn is_call_perform(&self) -> bool {
458        self.code == curl_sys::CURLM_CALL_MULTI_PERFORM
459    }
460
461    // /// Returns whether this error corresponds to CURLM_ADDED_ALREADY.
462    // pub fn is_added_already(&self) -> bool {
463    //     self.code == curl_sys::CURLM_ADDED_ALREADY
464    // }
465
466    /// Returns the value of the underlying error corresponding to libcurl.
467    pub fn code(&self) -> curl_sys::CURLMcode {
468        self.code
469    }
470
471    /// Returns curl's human-readable description of this error.
472    pub fn description(&self) -> &str {
473        unsafe {
474            let s = curl_sys::curl_multi_strerror(self.code);
475            assert!(!s.is_null());
476            str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap()
477        }
478    }
479}
480
481impl fmt::Display for MultiError {
482    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
483        self.description().fmt(f)
484    }
485}
486
487impl fmt::Debug for MultiError {
488    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
489        f.debug_struct("MultiError")
490            .field("description", &self.description())
491            .field("code", &self.code)
492            .finish()
493    }
494}
495
496impl error::Error for MultiError {}
497
498/// An error from "form add" operations.
499///
500/// THis structure wraps a `CURLFORMcode`.
501#[derive(Clone, PartialEq)]
502pub struct FormError {
503    code: curl_sys::CURLFORMcode,
504}
505
506impl FormError {
507    /// Creates a new error from the underlying code returned by libcurl.
508    pub fn new(code: curl_sys::CURLFORMcode) -> FormError {
509        FormError { code }
510    }
511
512    /// Returns whether this error corresponds to CURL_FORMADD_MEMORY.
513    pub fn is_memory(&self) -> bool {
514        self.code == curl_sys::CURL_FORMADD_MEMORY
515    }
516
517    /// Returns whether this error corresponds to CURL_FORMADD_OPTION_TWICE.
518    pub fn is_option_twice(&self) -> bool {
519        self.code == curl_sys::CURL_FORMADD_OPTION_TWICE
520    }
521
522    /// Returns whether this error corresponds to CURL_FORMADD_NULL.
523    pub fn is_null(&self) -> bool {
524        self.code == curl_sys::CURL_FORMADD_NULL
525    }
526
527    /// Returns whether this error corresponds to CURL_FORMADD_UNKNOWN_OPTION.
528    pub fn is_unknown_option(&self) -> bool {
529        self.code == curl_sys::CURL_FORMADD_UNKNOWN_OPTION
530    }
531
532    /// Returns whether this error corresponds to CURL_FORMADD_INCOMPLETE.
533    pub fn is_incomplete(&self) -> bool {
534        self.code == curl_sys::CURL_FORMADD_INCOMPLETE
535    }
536
537    /// Returns whether this error corresponds to CURL_FORMADD_ILLEGAL_ARRAY.
538    pub fn is_illegal_array(&self) -> bool {
539        self.code == curl_sys::CURL_FORMADD_ILLEGAL_ARRAY
540    }
541
542    /// Returns whether this error corresponds to CURL_FORMADD_DISABLED.
543    pub fn is_disabled(&self) -> bool {
544        self.code == curl_sys::CURL_FORMADD_DISABLED
545    }
546
547    /// Returns the value of the underlying error corresponding to libcurl.
548    pub fn code(&self) -> curl_sys::CURLFORMcode {
549        self.code
550    }
551
552    /// Returns a human-readable description of this error code.
553    pub fn description(&self) -> &str {
554        match self.code {
555            curl_sys::CURL_FORMADD_MEMORY => "allocation failure",
556            curl_sys::CURL_FORMADD_OPTION_TWICE => "one option passed twice",
557            curl_sys::CURL_FORMADD_NULL => "null pointer given for string",
558            curl_sys::CURL_FORMADD_UNKNOWN_OPTION => "unknown option",
559            curl_sys::CURL_FORMADD_INCOMPLETE => "form information not complete",
560            curl_sys::CURL_FORMADD_ILLEGAL_ARRAY => "illegal array in option",
561            curl_sys::CURL_FORMADD_DISABLED => {
562                "libcurl does not have support for this option compiled in"
563            }
564            _ => "unknown form error",
565        }
566    }
567}
568
569impl fmt::Display for FormError {
570    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
571        self.description().fmt(f)
572    }
573}
574
575impl fmt::Debug for FormError {
576    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
577        f.debug_struct("FormError")
578            .field("description", &self.description())
579            .field("code", &self.code)
580            .finish()
581    }
582}
583
584impl error::Error for FormError {}
585
586impl From<ffi::NulError> for Error {
587    fn from(_: ffi::NulError) -> Error {
588        Error {
589            code: curl_sys::CURLE_CONV_FAILED,
590            extra: None,
591        }
592    }
593}
594
595impl From<Error> for io::Error {
596    fn from(e: Error) -> io::Error {
597        io::Error::new(io::ErrorKind::Other, e)
598    }
599}
600
601impl From<ShareError> for io::Error {
602    fn from(e: ShareError) -> io::Error {
603        io::Error::new(io::ErrorKind::Other, e)
604    }
605}
606
607impl From<MultiError> for io::Error {
608    fn from(e: MultiError) -> io::Error {
609        io::Error::new(io::ErrorKind::Other, e)
610    }
611}
612
613impl From<FormError> for io::Error {
614    fn from(e: FormError) -> io::Error {
615        io::Error::new(io::ErrorKind::Other, e)
616    }
617}