curl/
version.rs

1use std::ffi::CStr;
2use std::fmt;
3use std::str;
4
5use libc::{c_char, c_int};
6
7/// Version information about libcurl and the capabilities that it supports.
8pub struct Version {
9    inner: *mut curl_sys::curl_version_info_data,
10}
11
12unsafe impl Send for Version {}
13unsafe impl Sync for Version {}
14
15/// An iterator over the list of protocols a version supports.
16#[derive(Clone)]
17pub struct Protocols<'a> {
18    cur: *const *const c_char,
19    _inner: &'a Version,
20}
21
22impl Version {
23    /// Returns the libcurl version that this library is currently linked against.
24    pub fn num() -> &'static str {
25        unsafe {
26            let s = CStr::from_ptr(curl_sys::curl_version() as *const _);
27            str::from_utf8(s.to_bytes()).unwrap()
28        }
29    }
30
31    /// Returns the libcurl version that this library is currently linked against.
32    pub fn get() -> Version {
33        unsafe {
34            let ptr = curl_sys::curl_version_info(curl_sys::CURLVERSION_NOW);
35            assert!(!ptr.is_null());
36            Version { inner: ptr }
37        }
38    }
39
40    /// Returns the human readable version string,
41    pub fn version(&self) -> &str {
42        unsafe { crate::opt_str((*self.inner).version).unwrap() }
43    }
44
45    /// Returns a numeric representation of the version number
46    ///
47    /// This is a 24 bit number made up of the major number, minor, and then
48    /// patch number. For example 7.9.8 will return 0x070908.
49    pub fn version_num(&self) -> u32 {
50        unsafe { (*self.inner).version_num as u32 }
51    }
52
53    /// Returns true if this was built with the vendored version of libcurl.
54    pub fn vendored(&self) -> bool {
55        curl_sys::vendored()
56    }
57
58    /// Returns a human readable string of the host libcurl is built for.
59    ///
60    /// This is discovered as part of the build environment.
61    pub fn host(&self) -> &str {
62        unsafe { crate::opt_str((*self.inner).host).unwrap() }
63    }
64
65    /// Returns whether libcurl supports IPv6
66    pub fn feature_ipv6(&self) -> bool {
67        self.flag(curl_sys::CURL_VERSION_IPV6)
68    }
69
70    /// Returns whether libcurl supports SSL
71    pub fn feature_ssl(&self) -> bool {
72        self.flag(curl_sys::CURL_VERSION_SSL)
73    }
74
75    /// Returns whether libcurl supports HTTP deflate via libz
76    pub fn feature_libz(&self) -> bool {
77        self.flag(curl_sys::CURL_VERSION_LIBZ)
78    }
79
80    /// Returns whether libcurl supports HTTP NTLM
81    pub fn feature_ntlm(&self) -> bool {
82        self.flag(curl_sys::CURL_VERSION_NTLM)
83    }
84
85    /// Returns whether libcurl supports HTTP GSSNEGOTIATE
86    pub fn feature_gss_negotiate(&self) -> bool {
87        self.flag(curl_sys::CURL_VERSION_GSSNEGOTIATE)
88    }
89
90    /// Returns whether libcurl was built with debug capabilities
91    pub fn feature_debug(&self) -> bool {
92        self.flag(curl_sys::CURL_VERSION_DEBUG)
93    }
94
95    /// Returns whether libcurl was built with SPNEGO authentication
96    pub fn feature_spnego(&self) -> bool {
97        self.flag(curl_sys::CURL_VERSION_SPNEGO)
98    }
99
100    /// Returns whether libcurl was built with large file support
101    pub fn feature_largefile(&self) -> bool {
102        self.flag(curl_sys::CURL_VERSION_LARGEFILE)
103    }
104
105    /// Returns whether libcurl was built with support for IDNA, domain names
106    /// with international letters.
107    pub fn feature_idn(&self) -> bool {
108        self.flag(curl_sys::CURL_VERSION_IDN)
109    }
110
111    /// Returns whether libcurl was built with support for SSPI.
112    pub fn feature_sspi(&self) -> bool {
113        self.flag(curl_sys::CURL_VERSION_SSPI)
114    }
115
116    /// Returns whether libcurl was built with asynchronous name lookups.
117    pub fn feature_async_dns(&self) -> bool {
118        self.flag(curl_sys::CURL_VERSION_ASYNCHDNS)
119    }
120
121    /// Returns whether libcurl was built with support for character
122    /// conversions.
123    pub fn feature_conv(&self) -> bool {
124        self.flag(curl_sys::CURL_VERSION_CONV)
125    }
126
127    /// Returns whether libcurl was built with support for TLS-SRP.
128    pub fn feature_tlsauth_srp(&self) -> bool {
129        self.flag(curl_sys::CURL_VERSION_TLSAUTH_SRP)
130    }
131
132    /// Returns whether libcurl was built with support for NTLM delegation to
133    /// winbind helper.
134    pub fn feature_ntlm_wb(&self) -> bool {
135        self.flag(curl_sys::CURL_VERSION_NTLM_WB)
136    }
137
138    /// Returns whether libcurl was built with support for unix domain socket
139    pub fn feature_unix_domain_socket(&self) -> bool {
140        self.flag(curl_sys::CURL_VERSION_UNIX_SOCKETS)
141    }
142
143    /// Returns whether libcurl was built with support for HTTPS proxy.
144    pub fn feature_https_proxy(&self) -> bool {
145        self.flag(curl_sys::CURL_VERSION_HTTPS_PROXY)
146    }
147
148    /// Returns whether libcurl was built with support for HTTP2.
149    pub fn feature_http2(&self) -> bool {
150        self.flag(curl_sys::CURL_VERSION_HTTP2)
151    }
152
153    /// Returns whether libcurl was built with support for HTTP3.
154    pub fn feature_http3(&self) -> bool {
155        self.flag(curl_sys::CURL_VERSION_HTTP3)
156    }
157
158    /// Returns whether libcurl was built with support for Brotli.
159    pub fn feature_brotli(&self) -> bool {
160        self.flag(curl_sys::CURL_VERSION_BROTLI)
161    }
162
163    /// Returns whether libcurl was built with support for Alt-Svc.
164    pub fn feature_altsvc(&self) -> bool {
165        self.flag(curl_sys::CURL_VERSION_ALTSVC)
166    }
167
168    /// Returns whether libcurl was built with support for zstd
169    pub fn feature_zstd(&self) -> bool {
170        self.flag(curl_sys::CURL_VERSION_ZSTD)
171    }
172
173    /// Returns whether libcurl was built with support for unicode
174    pub fn feature_unicode(&self) -> bool {
175        self.flag(curl_sys::CURL_VERSION_UNICODE)
176    }
177
178    /// Returns whether libcurl was built with support for hsts
179    pub fn feature_hsts(&self) -> bool {
180        self.flag(curl_sys::CURL_VERSION_HSTS)
181    }
182
183    /// Returns whether libcurl was built with support for gsasl
184    pub fn feature_gsasl(&self) -> bool {
185        self.flag(curl_sys::CURL_VERSION_GSASL)
186    }
187
188    fn flag(&self, flag: c_int) -> bool {
189        unsafe { (*self.inner).features & flag != 0 }
190    }
191
192    /// Returns the version of OpenSSL that is used, or None if there is no SSL
193    /// support.
194    pub fn ssl_version(&self) -> Option<&str> {
195        unsafe { crate::opt_str((*self.inner).ssl_version) }
196    }
197
198    /// Returns the version of libz that is used, or None if there is no libz
199    /// support.
200    pub fn libz_version(&self) -> Option<&str> {
201        unsafe { crate::opt_str((*self.inner).libz_version) }
202    }
203
204    /// Returns an iterator over the list of protocols that this build of
205    /// libcurl supports.
206    pub fn protocols(&self) -> Protocols<'_> {
207        unsafe {
208            Protocols {
209                _inner: self,
210                cur: (*self.inner).protocols,
211            }
212        }
213    }
214
215    /// If available, the human readable version of ares that libcurl is linked
216    /// against.
217    pub fn ares_version(&self) -> Option<&str> {
218        unsafe {
219            if (*self.inner).age >= curl_sys::CURLVERSION_SECOND {
220                crate::opt_str((*self.inner).ares)
221            } else {
222                None
223            }
224        }
225    }
226
227    /// If available, the version of ares that libcurl is linked against.
228    pub fn ares_version_num(&self) -> Option<u32> {
229        unsafe {
230            if (*self.inner).age >= curl_sys::CURLVERSION_SECOND {
231                Some((*self.inner).ares_num as u32)
232            } else {
233                None
234            }
235        }
236    }
237
238    /// If available, the version of libidn that libcurl is linked against.
239    pub fn libidn_version(&self) -> Option<&str> {
240        unsafe {
241            if (*self.inner).age >= curl_sys::CURLVERSION_THIRD {
242                crate::opt_str((*self.inner).libidn)
243            } else {
244                None
245            }
246        }
247    }
248
249    /// If available, the version of iconv libcurl is linked against.
250    pub fn iconv_version_num(&self) -> Option<u32> {
251        unsafe {
252            if (*self.inner).age >= curl_sys::CURLVERSION_FOURTH {
253                Some((*self.inner).iconv_ver_num as u32)
254            } else {
255                None
256            }
257        }
258    }
259
260    /// If available, the version of libssh that libcurl is linked against.
261    pub fn libssh_version(&self) -> Option<&str> {
262        unsafe {
263            if (*self.inner).age >= curl_sys::CURLVERSION_FOURTH {
264                crate::opt_str((*self.inner).libssh_version)
265            } else {
266                None
267            }
268        }
269    }
270
271    /// If available, the version of brotli libcurl is linked against.
272    pub fn brotli_version_num(&self) -> Option<u32> {
273        unsafe {
274            if (*self.inner).age >= curl_sys::CURLVERSION_FIFTH {
275                Some((*self.inner).brotli_ver_num)
276            } else {
277                None
278            }
279        }
280    }
281
282    /// If available, the version of brotli libcurl is linked against.
283    pub fn brotli_version(&self) -> Option<&str> {
284        unsafe {
285            if (*self.inner).age >= curl_sys::CURLVERSION_FIFTH {
286                crate::opt_str((*self.inner).brotli_version)
287            } else {
288                None
289            }
290        }
291    }
292
293    /// If available, the version of nghttp2 libcurl is linked against.
294    pub fn nghttp2_version_num(&self) -> Option<u32> {
295        unsafe {
296            if (*self.inner).age >= curl_sys::CURLVERSION_SIXTH {
297                Some((*self.inner).nghttp2_ver_num)
298            } else {
299                None
300            }
301        }
302    }
303
304    /// If available, the version of nghttp2 libcurl is linked against.
305    pub fn nghttp2_version(&self) -> Option<&str> {
306        unsafe {
307            if (*self.inner).age >= curl_sys::CURLVERSION_SIXTH {
308                crate::opt_str((*self.inner).nghttp2_version)
309            } else {
310                None
311            }
312        }
313    }
314
315    /// If available, the version of quic libcurl is linked against.
316    pub fn quic_version(&self) -> Option<&str> {
317        unsafe {
318            if (*self.inner).age >= curl_sys::CURLVERSION_SIXTH {
319                crate::opt_str((*self.inner).quic_version)
320            } else {
321                None
322            }
323        }
324    }
325
326    /// If available, the built-in default of CURLOPT_CAINFO.
327    pub fn cainfo(&self) -> Option<&str> {
328        unsafe {
329            if (*self.inner).age >= curl_sys::CURLVERSION_SEVENTH {
330                crate::opt_str((*self.inner).cainfo)
331            } else {
332                None
333            }
334        }
335    }
336
337    /// If available, the built-in default of CURLOPT_CAPATH.
338    pub fn capath(&self) -> Option<&str> {
339        unsafe {
340            if (*self.inner).age >= curl_sys::CURLVERSION_SEVENTH {
341                crate::opt_str((*self.inner).capath)
342            } else {
343                None
344            }
345        }
346    }
347
348    /// If avaiable, the numeric zstd version
349    ///
350    /// Represented as `(MAJOR << 24) | (MINOR << 12) | PATCH`
351    pub fn zstd_ver_num(&self) -> Option<u32> {
352        unsafe {
353            if (*self.inner).age >= curl_sys::CURLVERSION_EIGHTH {
354                Some((*self.inner).zstd_ver_num)
355            } else {
356                None
357            }
358        }
359    }
360
361    /// If available, the human readable version of zstd
362    pub fn zstd_version(&self) -> Option<&str> {
363        unsafe {
364            if (*self.inner).age >= curl_sys::CURLVERSION_EIGHTH {
365                crate::opt_str((*self.inner).zstd_version)
366            } else {
367                None
368            }
369        }
370    }
371
372    /// If available, the human readable version of hyper
373    pub fn hyper_version(&self) -> Option<&str> {
374        unsafe {
375            if (*self.inner).age >= curl_sys::CURLVERSION_NINTH {
376                crate::opt_str((*self.inner).hyper_version)
377            } else {
378                None
379            }
380        }
381    }
382
383    /// If available, the human readable version of hyper
384    pub fn gsasl_version(&self) -> Option<&str> {
385        unsafe {
386            if (*self.inner).age >= curl_sys::CURLVERSION_TENTH {
387                crate::opt_str((*self.inner).gsasl_version)
388            } else {
389                None
390            }
391        }
392    }
393}
394
395impl fmt::Debug for Version {
396    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
397        let mut f = f.debug_struct("Version");
398        f.field("version", &self.version())
399            .field("rust_crate_version", &env!("CARGO_PKG_VERSION"))
400            .field("rust_sys_crate_version", &curl_sys::rust_crate_version())
401            .field("vendored", &self.vendored())
402            .field("host", &self.host())
403            .field("feature_ipv6", &self.feature_ipv6())
404            .field("feature_ssl", &self.feature_ssl())
405            .field("feature_libz", &self.feature_libz())
406            .field("feature_ntlm", &self.feature_ntlm())
407            .field("feature_gss_negotiate", &self.feature_gss_negotiate())
408            .field("feature_debug", &self.feature_debug())
409            .field("feature_spnego", &self.feature_spnego())
410            .field("feature_largefile", &self.feature_largefile())
411            .field("feature_idn", &self.feature_idn())
412            .field("feature_sspi", &self.feature_sspi())
413            .field("feature_async_dns", &self.feature_async_dns())
414            .field("feature_conv", &self.feature_conv())
415            .field("feature_tlsauth_srp", &self.feature_tlsauth_srp())
416            .field("feature_ntlm_wb", &self.feature_ntlm_wb())
417            .field(
418                "feature_unix_domain_socket",
419                &self.feature_unix_domain_socket(),
420            )
421            .field("feature_https_proxy", &self.feature_https_proxy())
422            .field("feature_altsvc", &self.feature_altsvc())
423            .field("feature_zstd", &self.feature_zstd())
424            .field("feature_unicode", &self.feature_unicode())
425            .field("feature_http3", &self.feature_http3())
426            .field("feature_http2", &self.feature_http2())
427            .field("feature_gsasl", &self.feature_gsasl())
428            .field("feature_brotli", &self.feature_brotli());
429
430        if let Some(s) = self.ssl_version() {
431            f.field("ssl_version", &s);
432        }
433        if let Some(s) = self.libz_version() {
434            f.field("libz_version", &s);
435        }
436        if let Some(s) = self.ares_version() {
437            f.field("ares_version", &s);
438        }
439        if let Some(s) = self.libidn_version() {
440            f.field("libidn_version", &s);
441        }
442        if let Some(s) = self.iconv_version_num() {
443            f.field("iconv_version_num", &format!("{:x}", s));
444        }
445        if let Some(s) = self.libssh_version() {
446            f.field("libssh_version", &s);
447        }
448        if let Some(s) = self.brotli_version_num() {
449            f.field("brotli_version_num", &format!("{:x}", s));
450        }
451        if let Some(s) = self.brotli_version() {
452            f.field("brotli_version", &s);
453        }
454        if let Some(s) = self.nghttp2_version_num() {
455            f.field("nghttp2_version_num", &format!("{:x}", s));
456        }
457        if let Some(s) = self.nghttp2_version() {
458            f.field("nghttp2_version", &s);
459        }
460        if let Some(s) = self.quic_version() {
461            f.field("quic_version", &s);
462        }
463        if let Some(s) = self.zstd_ver_num() {
464            f.field("zstd_ver_num", &format!("{:x}", s));
465        }
466        if let Some(s) = self.zstd_version() {
467            f.field("zstd_version", &s);
468        }
469        if let Some(s) = self.cainfo() {
470            f.field("cainfo", &s);
471        }
472        if let Some(s) = self.capath() {
473            f.field("capath", &s);
474        }
475        if let Some(s) = self.hyper_version() {
476            f.field("hyper_version", &s);
477        }
478        if let Some(s) = self.gsasl_version() {
479            f.field("gsasl_version", &s);
480        }
481
482        f.field("protocols", &self.protocols().collect::<Vec<_>>());
483
484        f.finish()
485    }
486}
487
488impl<'a> Iterator for Protocols<'a> {
489    type Item = &'a str;
490
491    fn next(&mut self) -> Option<&'a str> {
492        unsafe {
493            if (*self.cur).is_null() {
494                return None;
495            }
496            let ret = crate::opt_str(*self.cur).unwrap();
497            self.cur = self.cur.offset(1);
498            Some(ret)
499        }
500    }
501}
502
503impl<'a> fmt::Debug for Protocols<'a> {
504    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
505        f.debug_list().entries(self.clone()).finish()
506    }
507}