1use std::error;
2use std::ffi::{self, CStr};
3use std::fmt;
4use std::io;
5use std::str;
6
7#[derive(Clone, PartialEq)]
11pub struct Error {
12    code: curl_sys::CURLcode,
13    extra: Option<Box<str>>,
14}
15
16impl Error {
17    pub fn new(code: curl_sys::CURLcode) -> Error {
19        Error { code, extra: None }
20    }
21
22    pub fn set_extra(&mut self, extra: String) {
28        self.extra = Some(extra.into());
29    }
30
31    pub fn is_unsupported_protocol(&self) -> bool {
33        self.code == curl_sys::CURLE_UNSUPPORTED_PROTOCOL
34    }
35
36    pub fn is_failed_init(&self) -> bool {
38        self.code == curl_sys::CURLE_FAILED_INIT
39    }
40
41    pub fn is_url_malformed(&self) -> bool {
43        self.code == curl_sys::CURLE_URL_MALFORMAT
44    }
45
46    pub fn is_couldnt_resolve_proxy(&self) -> bool {
53        self.code == curl_sys::CURLE_COULDNT_RESOLVE_PROXY
54    }
55
56    pub fn is_couldnt_resolve_host(&self) -> bool {
58        self.code == curl_sys::CURLE_COULDNT_RESOLVE_HOST
59    }
60
61    pub fn is_couldnt_connect(&self) -> bool {
63        self.code == curl_sys::CURLE_COULDNT_CONNECT
64    }
65
66    pub fn is_remote_access_denied(&self) -> bool {
68        self.code == curl_sys::CURLE_REMOTE_ACCESS_DENIED
69    }
70
71    pub fn is_partial_file(&self) -> bool {
73        self.code == curl_sys::CURLE_PARTIAL_FILE
74    }
75
76    pub fn is_quote_error(&self) -> bool {
78        self.code == curl_sys::CURLE_QUOTE_ERROR
79    }
80
81    pub fn is_http_returned_error(&self) -> bool {
83        self.code == curl_sys::CURLE_HTTP_RETURNED_ERROR
84    }
85
86    pub fn is_read_error(&self) -> bool {
88        self.code == curl_sys::CURLE_READ_ERROR
89    }
90
91    pub fn is_write_error(&self) -> bool {
93        self.code == curl_sys::CURLE_WRITE_ERROR
94    }
95
96    pub fn is_upload_failed(&self) -> bool {
98        self.code == curl_sys::CURLE_UPLOAD_FAILED
99    }
100
101    pub fn is_out_of_memory(&self) -> bool {
103        self.code == curl_sys::CURLE_OUT_OF_MEMORY
104    }
105
106    pub fn is_operation_timedout(&self) -> bool {
108        self.code == curl_sys::CURLE_OPERATION_TIMEDOUT
109    }
110
111    pub fn is_range_error(&self) -> bool {
113        self.code == curl_sys::CURLE_RANGE_ERROR
114    }
115
116    pub fn is_http_post_error(&self) -> bool {
118        self.code == curl_sys::CURLE_HTTP_POST_ERROR
119    }
120
121    pub fn is_ssl_connect_error(&self) -> bool {
123        self.code == curl_sys::CURLE_SSL_CONNECT_ERROR
124    }
125
126    pub fn is_bad_download_resume(&self) -> bool {
128        self.code == curl_sys::CURLE_BAD_DOWNLOAD_RESUME
129    }
130
131    pub fn is_file_couldnt_read_file(&self) -> bool {
133        self.code == curl_sys::CURLE_FILE_COULDNT_READ_FILE
134    }
135
136    pub fn is_function_not_found(&self) -> bool {
138        self.code == curl_sys::CURLE_FUNCTION_NOT_FOUND
139    }
140
141    pub fn is_aborted_by_callback(&self) -> bool {
143        self.code == curl_sys::CURLE_ABORTED_BY_CALLBACK
144    }
145
146    pub fn is_bad_function_argument(&self) -> bool {
148        self.code == curl_sys::CURLE_BAD_FUNCTION_ARGUMENT
149    }
150
151    pub fn is_interface_failed(&self) -> bool {
153        self.code == curl_sys::CURLE_INTERFACE_FAILED
154    }
155
156    pub fn is_too_many_redirects(&self) -> bool {
158        self.code == curl_sys::CURLE_TOO_MANY_REDIRECTS
159    }
160
161    pub fn is_unknown_option(&self) -> bool {
163        self.code == curl_sys::CURLE_UNKNOWN_OPTION
164    }
165
166    pub fn is_peer_failed_verification(&self) -> bool {
168        self.code == curl_sys::CURLE_PEER_FAILED_VERIFICATION
169    }
170
171    pub fn is_got_nothing(&self) -> bool {
173        self.code == curl_sys::CURLE_GOT_NOTHING
174    }
175
176    pub fn is_ssl_engine_notfound(&self) -> bool {
178        self.code == curl_sys::CURLE_SSL_ENGINE_NOTFOUND
179    }
180
181    pub fn is_ssl_engine_setfailed(&self) -> bool {
183        self.code == curl_sys::CURLE_SSL_ENGINE_SETFAILED
184    }
185
186    pub fn is_send_error(&self) -> bool {
188        self.code == curl_sys::CURLE_SEND_ERROR
189    }
190
191    pub fn is_recv_error(&self) -> bool {
193        self.code == curl_sys::CURLE_RECV_ERROR
194    }
195
196    pub fn is_ssl_certproblem(&self) -> bool {
198        self.code == curl_sys::CURLE_SSL_CERTPROBLEM
199    }
200
201    pub fn is_ssl_cipher(&self) -> bool {
203        self.code == curl_sys::CURLE_SSL_CIPHER
204    }
205
206    pub fn is_ssl_cacert(&self) -> bool {
208        self.code == curl_sys::CURLE_SSL_CACERT
209    }
210
211    pub fn is_bad_content_encoding(&self) -> bool {
213        self.code == curl_sys::CURLE_BAD_CONTENT_ENCODING
214    }
215
216    pub fn is_filesize_exceeded(&self) -> bool {
218        self.code == curl_sys::CURLE_FILESIZE_EXCEEDED
219    }
220
221    pub fn is_use_ssl_failed(&self) -> bool {
223        self.code == curl_sys::CURLE_USE_SSL_FAILED
224    }
225
226    pub fn is_send_fail_rewind(&self) -> bool {
228        self.code == curl_sys::CURLE_SEND_FAIL_REWIND
229    }
230
231    pub fn is_ssl_engine_initfailed(&self) -> bool {
233        self.code == curl_sys::CURLE_SSL_ENGINE_INITFAILED
234    }
235
236    pub fn is_login_denied(&self) -> bool {
238        self.code == curl_sys::CURLE_LOGIN_DENIED
239    }
240
241    pub fn is_conv_failed(&self) -> bool {
243        self.code == curl_sys::CURLE_CONV_FAILED
244    }
245
246    pub fn is_conv_required(&self) -> bool {
248        self.code == curl_sys::CURLE_CONV_REQD
249    }
250
251    pub fn is_ssl_cacert_badfile(&self) -> bool {
253        self.code == curl_sys::CURLE_SSL_CACERT_BADFILE
254    }
255
256    pub fn is_ssl_crl_badfile(&self) -> bool {
258        self.code == curl_sys::CURLE_SSL_CRL_BADFILE
259    }
260
261    pub fn is_ssl_shutdown_failed(&self) -> bool {
263        self.code == curl_sys::CURLE_SSL_SHUTDOWN_FAILED
264    }
265
266    pub fn is_again(&self) -> bool {
268        self.code == curl_sys::CURLE_AGAIN
269    }
270
271    pub fn is_ssl_issuer_error(&self) -> bool {
273        self.code == curl_sys::CURLE_SSL_ISSUER_ERROR
274    }
275
276    pub fn is_chunk_failed(&self) -> bool {
278        self.code == curl_sys::CURLE_CHUNK_FAILED
279    }
280
281    pub fn is_http2_error(&self) -> bool {
283        self.code == curl_sys::CURLE_HTTP2
284    }
285
286    pub fn is_http2_stream_error(&self) -> bool {
288        self.code == curl_sys::CURLE_HTTP2_STREAM
289    }
290
291    pub fn code(&self) -> curl_sys::CURLcode {
298        self.code
299    }
300
301    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    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#[derive(Clone, PartialEq)]
343pub struct ShareError {
344    code: curl_sys::CURLSHcode,
345}
346
347impl ShareError {
348    pub fn new(code: curl_sys::CURLSHcode) -> ShareError {
350        ShareError { code }
351    }
352
353    pub fn is_bad_option(&self) -> bool {
355        self.code == curl_sys::CURLSHE_BAD_OPTION
356    }
357
358    pub fn is_in_use(&self) -> bool {
360        self.code == curl_sys::CURLSHE_IN_USE
361    }
362
363    pub fn is_invalid(&self) -> bool {
365        self.code == curl_sys::CURLSHE_INVALID
366    }
367
368    pub fn is_nomem(&self) -> bool {
370        self.code == curl_sys::CURLSHE_NOMEM
371    }
372
373    pub fn code(&self) -> curl_sys::CURLSHcode {
380        self.code
381    }
382
383    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#[derive(Clone, PartialEq)]
416pub struct MultiError {
417    code: curl_sys::CURLMcode,
418}
419
420impl MultiError {
421    pub fn new(code: curl_sys::CURLMcode) -> MultiError {
423        MultiError { code }
424    }
425
426    pub fn is_bad_handle(&self) -> bool {
428        self.code == curl_sys::CURLM_BAD_HANDLE
429    }
430
431    pub fn is_bad_easy_handle(&self) -> bool {
433        self.code == curl_sys::CURLM_BAD_EASY_HANDLE
434    }
435
436    pub fn is_out_of_memory(&self) -> bool {
438        self.code == curl_sys::CURLM_OUT_OF_MEMORY
439    }
440
441    pub fn is_internal_error(&self) -> bool {
443        self.code == curl_sys::CURLM_INTERNAL_ERROR
444    }
445
446    pub fn is_bad_socket(&self) -> bool {
448        self.code == curl_sys::CURLM_BAD_SOCKET
449    }
450
451    pub fn is_unknown_option(&self) -> bool {
453        self.code == curl_sys::CURLM_UNKNOWN_OPTION
454    }
455
456    pub fn is_call_perform(&self) -> bool {
458        self.code == curl_sys::CURLM_CALL_MULTI_PERFORM
459    }
460
461    pub fn code(&self) -> curl_sys::CURLMcode {
468        self.code
469    }
470
471    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#[derive(Clone, PartialEq)]
502pub struct FormError {
503    code: curl_sys::CURLFORMcode,
504}
505
506impl FormError {
507    pub fn new(code: curl_sys::CURLFORMcode) -> FormError {
509        FormError { code }
510    }
511
512    pub fn is_memory(&self) -> bool {
514        self.code == curl_sys::CURL_FORMADD_MEMORY
515    }
516
517    pub fn is_option_twice(&self) -> bool {
519        self.code == curl_sys::CURL_FORMADD_OPTION_TWICE
520    }
521
522    pub fn is_null(&self) -> bool {
524        self.code == curl_sys::CURL_FORMADD_NULL
525    }
526
527    pub fn is_unknown_option(&self) -> bool {
529        self.code == curl_sys::CURL_FORMADD_UNKNOWN_OPTION
530    }
531
532    pub fn is_incomplete(&self) -> bool {
534        self.code == curl_sys::CURL_FORMADD_INCOMPLETE
535    }
536
537    pub fn is_illegal_array(&self) -> bool {
539        self.code == curl_sys::CURL_FORMADD_ILLEGAL_ARRAY
540    }
541
542    pub fn is_disabled(&self) -> bool {
544        self.code == curl_sys::CURL_FORMADD_DISABLED
545    }
546
547    pub fn code(&self) -> curl_sys::CURLFORMcode {
549        self.code
550    }
551
552    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}