1use std::ffi::CStr;
2use std::fmt;
3use std::str;
4
5use libc::{c_char, c_int};
6
7pub 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#[derive(Clone)]
17pub struct Protocols<'a> {
18 cur: *const *const c_char,
19 _inner: &'a Version,
20}
21
22impl Version {
23 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 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 pub fn version(&self) -> &str {
42 unsafe { crate::opt_str((*self.inner).version).unwrap() }
43 }
44
45 pub fn version_num(&self) -> u32 {
50 unsafe { (*self.inner).version_num as u32 }
51 }
52
53 pub fn vendored(&self) -> bool {
55 curl_sys::vendored()
56 }
57
58 pub fn host(&self) -> &str {
62 unsafe { crate::opt_str((*self.inner).host).unwrap() }
63 }
64
65 pub fn feature_ipv6(&self) -> bool {
67 self.flag(curl_sys::CURL_VERSION_IPV6)
68 }
69
70 pub fn feature_ssl(&self) -> bool {
72 self.flag(curl_sys::CURL_VERSION_SSL)
73 }
74
75 pub fn feature_libz(&self) -> bool {
77 self.flag(curl_sys::CURL_VERSION_LIBZ)
78 }
79
80 pub fn feature_ntlm(&self) -> bool {
82 self.flag(curl_sys::CURL_VERSION_NTLM)
83 }
84
85 pub fn feature_gss_negotiate(&self) -> bool {
87 self.flag(curl_sys::CURL_VERSION_GSSNEGOTIATE)
88 }
89
90 pub fn feature_debug(&self) -> bool {
92 self.flag(curl_sys::CURL_VERSION_DEBUG)
93 }
94
95 pub fn feature_spnego(&self) -> bool {
97 self.flag(curl_sys::CURL_VERSION_SPNEGO)
98 }
99
100 pub fn feature_largefile(&self) -> bool {
102 self.flag(curl_sys::CURL_VERSION_LARGEFILE)
103 }
104
105 pub fn feature_idn(&self) -> bool {
108 self.flag(curl_sys::CURL_VERSION_IDN)
109 }
110
111 pub fn feature_sspi(&self) -> bool {
113 self.flag(curl_sys::CURL_VERSION_SSPI)
114 }
115
116 pub fn feature_async_dns(&self) -> bool {
118 self.flag(curl_sys::CURL_VERSION_ASYNCHDNS)
119 }
120
121 pub fn feature_conv(&self) -> bool {
124 self.flag(curl_sys::CURL_VERSION_CONV)
125 }
126
127 pub fn feature_tlsauth_srp(&self) -> bool {
129 self.flag(curl_sys::CURL_VERSION_TLSAUTH_SRP)
130 }
131
132 pub fn feature_ntlm_wb(&self) -> bool {
135 self.flag(curl_sys::CURL_VERSION_NTLM_WB)
136 }
137
138 pub fn feature_unix_domain_socket(&self) -> bool {
140 self.flag(curl_sys::CURL_VERSION_UNIX_SOCKETS)
141 }
142
143 pub fn feature_https_proxy(&self) -> bool {
145 self.flag(curl_sys::CURL_VERSION_HTTPS_PROXY)
146 }
147
148 pub fn feature_http2(&self) -> bool {
150 self.flag(curl_sys::CURL_VERSION_HTTP2)
151 }
152
153 pub fn feature_http3(&self) -> bool {
155 self.flag(curl_sys::CURL_VERSION_HTTP3)
156 }
157
158 pub fn feature_brotli(&self) -> bool {
160 self.flag(curl_sys::CURL_VERSION_BROTLI)
161 }
162
163 pub fn feature_altsvc(&self) -> bool {
165 self.flag(curl_sys::CURL_VERSION_ALTSVC)
166 }
167
168 pub fn feature_zstd(&self) -> bool {
170 self.flag(curl_sys::CURL_VERSION_ZSTD)
171 }
172
173 pub fn feature_unicode(&self) -> bool {
175 self.flag(curl_sys::CURL_VERSION_UNICODE)
176 }
177
178 pub fn feature_hsts(&self) -> bool {
180 self.flag(curl_sys::CURL_VERSION_HSTS)
181 }
182
183 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 pub fn ssl_version(&self) -> Option<&str> {
195 unsafe { crate::opt_str((*self.inner).ssl_version) }
196 }
197
198 pub fn libz_version(&self) -> Option<&str> {
201 unsafe { crate::opt_str((*self.inner).libz_version) }
202 }
203
204 pub fn protocols(&self) -> Protocols<'_> {
207 unsafe {
208 Protocols {
209 _inner: self,
210 cur: (*self.inner).protocols,
211 }
212 }
213 }
214
215 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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}