use std::cell::RefCell;
+use std::convert::TryFrom;
+use std::ffi::{CStr, CString};
+use std::fmt;
+use std::io::{self, SeekFrom, Write};
+use std::path::Path;
+use std::ptr;
+use std::slice;
+use std::str;
+use std::time::Duration;
+
+use curl_sys;
+use libc::{self, c_char, c_double, c_int, c_long, c_ulong, c_void, size_t};
+use socket2::Socket;
+
+use crate::easy::form;
+use crate::easy::list;
+use crate::easy::windows;
+use crate::easy::{Form, List};
+use crate::panic;
+use crate::Error;
+
+pub trait Handler {
+ fn write(&mut self, data: &[u8]) -> Result<usize, WriteError> {
+ Ok(data.len())
+ }
+
+ fn read(&mut self, data: &mut [u8]) -> Result<usize, ReadError> {
+ let _ = data; Ok(0)
+ }
+
+ fn seek(&mut self, whence: SeekFrom) -> SeekResult {
+ let _ = whence; SeekResult::CantSeek
+ }
+
+ fn debug(&mut self, kind: InfoType, data: &[u8]) {
+ debug(kind, data)
+ }
+
+ fn header(&mut self, data: &[u8]) -> bool {
+ let _ = data; true
+ }
+
+ fn progress(&mut self, dltotal: f64, dlnow: f64, ultotal: f64, ulnow: f64) -> bool {
+ let _ = (dltotal, dlnow, ultotal, ulnow); true
+ }
+
+ fn ssl_ctx(&mut self, cx: *mut c_void) -> Result<(), Error> {
+ ssl_ctx(cx)
+ }
+
+ fn open_socket(
+ &mut self,
+ family: c_int,
+ socktype: c_int,
+ protocol: c_int,
+ ) -> Option<curl_sys::curl_socket_t> {
+ return Socket::new(family.into(), socktype.into(), Some(protocol.into()))
+ .ok()
+ .map(cvt);
+
+ #[cfg(unix)]
+ fn cvt(socket: Socket) -> curl_sys::curl_socket_t {
+ use std::os::unix::prelude::*;
+ socket.into_raw_fd()
+ }
+
+ #[cfg(windows)]
+ fn cvt(socket: Socket) -> curl_sys::curl_socket_t {
+ use std::os::windows::prelude::*;
+ socket.into_raw_socket()
+ }
+ }
+}
+
+pub fn debug(kind: InfoType, data: &[u8]) {
+ let out = io::stderr();
+ let prefix = match kind {
+ InfoType::Text => "*",
+ InfoType::HeaderIn => "<",
+ InfoType::HeaderOut => ">",
+ InfoType::DataIn | InfoType::SslDataIn => "{",
+ InfoType::DataOut | InfoType::SslDataOut => "}",
+ };
+ let mut out = out.lock();
+ drop(write!(out, "{} ", prefix));
+ match str::from_utf8(data) {
+ Ok(s) => drop(out.write_all(s.as_bytes())),
+ Err(_) => drop(writeln!(out, "({} bytes of data)", data.len())),
+ }
+}
+
+pub fn ssl_ctx(cx: *mut c_void) -> Result<(), Error> {
+ windows::add_certs_to_context(cx);
+ Ok(())
+}
+
+pub struct Easy2<H> {
+ inner: Box<Inner<H>>,
+}
+
+struct Inner<H> {
+ handle: *mut curl_sys::CURL,
+ header_list: Option<List>,
+ resolve_list: Option<List>,
+ connect_to_list: Option<List>,
+ form: Option<Form>,
+ error_buf: RefCell<Vec<u8>>,
+ handler: H,
+}
+
+unsafe impl<H: Send> Send for Inner<H> {}
+
+#[non_exhaustive]
+#[allow(missing_docs)]
+#[derive(Debug, Clone, Copy)]
+pub enum ProxyType {
+ Http = curl_sys::CURLPROXY_HTTP as isize,
+ Http1 = curl_sys::CURLPROXY_HTTP_1_0 as isize,
+ Socks4 = curl_sys::CURLPROXY_SOCKS4 as isize,
+ Socks5 = curl_sys::CURLPROXY_SOCKS5 as isize,
+ Socks4a = curl_sys::CURLPROXY_SOCKS4A as isize,
+ Socks5Hostname = curl_sys::CURLPROXY_SOCKS5_HOSTNAME as isize,
+}
+
+#[non_exhaustive]
+#[allow(missing_docs)]
+#[derive(Debug, Clone, Copy)]
+pub enum TimeCondition {
+ None = curl_sys::CURL_TIMECOND_NONE as isize,
+ IfModifiedSince = curl_sys::CURL_TIMECOND_IFMODSINCE as isize,
+ IfUnmodifiedSince = curl_sys::CURL_TIMECOND_IFUNMODSINCE as isize,
+ LastModified = curl_sys::CURL_TIMECOND_LASTMOD as isize,
+}
+
+#[non_exhaustive]
+#[allow(missing_docs)]
+#[derive(Debug, Clone, Copy)]
+pub enum IpResolve {
+ V4 = curl_sys::CURL_IPRESOLVE_V4 as isize,
+ V6 = curl_sys::CURL_IPRESOLVE_V6 as isize,
+ Any = curl_sys::CURL_IPRESOLVE_WHATEVER as isize,
+}
+
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy)]
+pub enum HttpVersion {
+ Any = curl_sys::CURL_HTTP_VERSION_NONE as isize,
+
+ V10 = curl_sys::CURL_HTTP_VERSION_1_0 as isize,
+
+ V11 = curl_sys::CURL_HTTP_VERSION_1_1 as isize,
+
+ V2 = curl_sys::CURL_HTTP_VERSION_2_0 as isize,
+
+ V2TLS = curl_sys::CURL_HTTP_VERSION_2TLS as isize,
+
+ V2PriorKnowledge = curl_sys::CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE as isize,
+
+ V3 = curl_sys::CURL_HTTP_VERSION_3 as isize,
+}
+
+#[non_exhaustive]
+#[allow(missing_docs)]
+#[derive(Debug, Clone, Copy)]
+pub enum SslVersion {
+ Default = curl_sys::CURL_SSLVERSION_DEFAULT as isize,
+ Tlsv1 = curl_sys::CURL_SSLVERSION_TLSv1 as isize,
+ Sslv2 = curl_sys::CURL_SSLVERSION_SSLv2 as isize,
+ Sslv3 = curl_sys::CURL_SSLVERSION_SSLv3 as isize,
+ Tlsv10 = curl_sys::CURL_SSLVERSION_TLSv1_0 as isize,
+ Tlsv11 = curl_sys::CURL_SSLVERSION_TLSv1_1 as isize,
+ Tlsv12 = curl_sys::CURL_SSLVERSION_TLSv1_2 as isize,
+ Tlsv13 = curl_sys::CURL_SSLVERSION_TLSv1_3 as isize,
+}
+
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy)]
+pub enum SeekResult {
+ Ok = curl_sys::CURL_SEEKFUNC_OK as isize,
+
+ Fail = curl_sys::CURL_SEEKFUNC_FAIL as isize,
+
+ CantSeek = curl_sys::CURL_SEEKFUNC_CANTSEEK as isize,
+}
+
+#[non_exhaustive]
+#[derive(Debug, Clone, Copy)]
+pub enum InfoType {
+ Text,
+
+ HeaderIn,
+
+ HeaderOut,
+
+ DataIn,
+
+ DataOut,
+
+ SslDataIn,
+
+ SslDataOut,
+}
+
+#[non_exhaustive]
+#[derive(Debug)]
+pub enum ReadError {
+ Abort,
+
+ Pause,
+}
+
+#[non_exhaustive]
+#[derive(Debug)]
+pub enum WriteError {
+ Pause,
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum NetRc {
+ Ignored = curl_sys::CURL_NETRC_IGNORED as isize,
+
+ Optional = curl_sys::CURL_NETRC_OPTIONAL as isize,
+
+ Required = curl_sys::CURL_NETRC_REQUIRED as isize,
+}
+
+#[derive(Clone)]
+pub struct Auth {
+ bits: c_long,
+}
+
+#[derive(Clone)]
+pub struct SslOpt {
+ bits: c_long,
+}
+pub struct PostRedirections {
+ bits: c_ulong,
+}
+
+impl<H: Handler> Easy2<H> {
+ pub fn new(handler: H) -> Easy2<H> {
+ crate::init();
+ unsafe {
+ let handle = curl_sys::curl_easy_init();
+ assert!(!handle.is_null());
+ let mut ret = Easy2 {
+ inner: Box::new(Inner {
+ handle,
+ header_list: None,
+ resolve_list: None,
+ connect_to_list: None,
+ form: None,
+ error_buf: RefCell::new(vec![0; curl_sys::CURL_ERROR_SIZE]),
+ handler,
+ }),
+ };
+ ret.default_configure();
+ ret
+ }
+ }
+
+ pub fn reset(&mut self) {
+ unsafe {
+ curl_sys::curl_easy_reset(self.inner.handle);
+ }
+ self.default_configure();
+ }
+
+ fn default_configure(&mut self) {
+ self.setopt_ptr(
+ curl_sys::CURLOPT_ERRORBUFFER,
+ self.inner.error_buf.borrow().as_ptr() as *const _,
+ )
+ .expect("failed to set error buffer");
+ let _ = self.signal(false);
+ self.ssl_configure();
+
+ let ptr = &*self.inner as *const _ as *const _;
+
+ let cb: extern "C" fn(*mut c_char, size_t, size_t, *mut c_void) -> size_t = header_cb::<H>;
+ self.setopt_ptr(curl_sys::CURLOPT_HEADERFUNCTION, cb as *const _)
+ .expect("failed to set header callback");
+ self.setopt_ptr(curl_sys::CURLOPT_HEADERDATA, ptr)
+ .expect("failed to set header callback");
+
+ let cb: curl_sys::curl_write_callback = write_cb::<H>;
+ self.setopt_ptr(curl_sys::CURLOPT_WRITEFUNCTION, cb as *const _)
+ .expect("failed to set write callback");
+ self.setopt_ptr(curl_sys::CURLOPT_WRITEDATA, ptr)
+ .expect("failed to set write callback");
+
+ let cb: curl_sys::curl_read_callback = read_cb::<H>;
+ self.setopt_ptr(curl_sys::CURLOPT_READFUNCTION, cb as *const _)
+ .expect("failed to set read callback");
+ self.setopt_ptr(curl_sys::CURLOPT_READDATA, ptr)
+ .expect("failed to set read callback");
+
+ let cb: curl_sys::curl_seek_callback = seek_cb::<H>;
+ self.setopt_ptr(curl_sys::CURLOPT_SEEKFUNCTION, cb as *const _)
+ .expect("failed to set seek callback");
+ self.setopt_ptr(curl_sys::CURLOPT_SEEKDATA, ptr)
+ .expect("failed to set seek callback");
+
+ let cb: curl_sys::curl_progress_callback = progress_cb::<H>;
+ self.setopt_ptr(curl_sys::CURLOPT_PROGRESSFUNCTION, cb as *const _)
+ .expect("failed to set progress callback");
+ self.setopt_ptr(curl_sys::CURLOPT_PROGRESSDATA, ptr)
+ .expect("failed to set progress callback");
+
+ let cb: curl_sys::curl_debug_callback = debug_cb::<H>;
+ self.setopt_ptr(curl_sys::CURLOPT_DEBUGFUNCTION, cb as *const _)
+ .expect("failed to set debug callback");
+ self.setopt_ptr(curl_sys::CURLOPT_DEBUGDATA, ptr)
+ .expect("failed to set debug callback");
+
+ let cb: curl_sys::curl_ssl_ctx_callback = ssl_ctx_cb::<H>;
+ drop(self.setopt_ptr(curl_sys::CURLOPT_SSL_CTX_FUNCTION, cb as *const _));
+ drop(self.setopt_ptr(curl_sys::CURLOPT_SSL_CTX_DATA, ptr));
+
+ let cb: curl_sys::curl_opensocket_callback = opensocket_cb::<H>;
+ self.setopt_ptr(curl_sys::CURLOPT_OPENSOCKETFUNCTION, cb as *const _)
+ .expect("failed to set open socket callback");
+ self.setopt_ptr(curl_sys::CURLOPT_OPENSOCKETDATA, ptr)
+ .expect("failed to set open socket callback");
+ }
+
+ #[cfg(need_openssl_probe)]
+ fn ssl_configure(&mut self) {
+ use std::sync::Once;
+
+ static mut PROBE: Option<::openssl_probe::ProbeResult> = None;
+ static INIT: Once = Once::new();
+
+ INIT.call_once(|| unsafe {
+ PROBE = Some(::openssl_probe::probe());
+ });
+ let probe = unsafe { PROBE.as_ref().unwrap() };
+
+ if let Some(ref path) = probe.cert_file {
+ let _ = self.cainfo(path);
+ }
+ if let Some(ref path) = probe.cert_dir {
+ let _ = self.capath(path);
+ }
+ }
+
+ #[cfg(not(need_openssl_probe))]
+ fn ssl_configure(&mut self) {}
+}
+
+impl<H> Easy2<H> {
+ pub fn verbose(&mut self, verbose: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_VERBOSE, verbose as c_long)
+ }
+
+ pub fn show_header(&mut self, show: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_HEADER, show as c_long)
+ }
+
+ pub fn progress(&mut self, progress: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_NOPROGRESS, (!progress) as c_long)
+ }
+
+ pub fn signal(&mut self, signal: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_NOSIGNAL, (!signal) as c_long)
+ }
+
+ pub fn wildcard_match(&mut self, m: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_WILDCARDMATCH, m as c_long)
+ }
+
+ pub fn unix_socket(&mut self, unix_domain_socket: &str) -> Result<(), Error> {
+ let socket = CString::new(unix_domain_socket)?;
+ self.setopt_str(curl_sys::CURLOPT_UNIX_SOCKET_PATH, &socket)
+ }
+
+ pub fn unix_socket_path<P: AsRef<Path>>(&mut self, path: Option<P>) -> Result<(), Error> {
+ if let Some(path) = path {
+ self.setopt_path(curl_sys::CURLOPT_UNIX_SOCKET_PATH, path.as_ref())
+ } else {
+ self.setopt_ptr(curl_sys::CURLOPT_UNIX_SOCKET_PATH, 0 as _)
+ }
+ }
+
+ #[cfg(target_os = "linux")]
+ pub fn abstract_unix_socket(&mut self, addr: &[u8]) -> Result<(), Error> {
+ let addr = CString::new(addr)?;
+ self.setopt_str(curl_sys::CURLOPT_ABSTRACT_UNIX_SOCKET, &addr)
+ }
+
+ pub fn get_ref(&self) -> &H {
+ &self.inner.handler
+ }
+
+ pub fn get_mut(&mut self) -> &mut H {
+ &mut self.inner.handler
+ }
+
+ pub fn fail_on_error(&mut self, fail: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_FAILONERROR, fail as c_long)
+ }
+
+ pub fn url(&mut self, url: &str) -> Result<(), Error> {
+ let url = CString::new(url)?;
+ self.setopt_str(curl_sys::CURLOPT_URL, &url)
+ }
+
+ pub fn port(&mut self, port: u16) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_PORT, port as c_long)
+ }
+
+ pub fn connect_to(&mut self, list: List) -> Result<(), Error> {
+ let ptr = list::raw(&list);
+ self.inner.connect_to_list = Some(list);
+ self.setopt_ptr(curl_sys::CURLOPT_CONNECT_TO, ptr as *const _)
+ }
+
+ pub fn path_as_is(&mut self, as_is: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_PATH_AS_IS, as_is as c_long)
+ }
+
+ pub fn proxy(&mut self, url: &str) -> Result<(), Error> {
+ let url = CString::new(url)?;
+ self.setopt_str(curl_sys::CURLOPT_PROXY, &url)
+ }
+
+ pub fn proxy_port(&mut self, port: u16) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_PROXYPORT, port as c_long)
+ }
+
+ pub fn proxy_cainfo(&mut self, cainfo: &str) -> Result<(), Error> {
+ let cainfo = CString::new(cainfo)?;
+ self.setopt_str(curl_sys::CURLOPT_PROXY_CAINFO, &cainfo)
+ }
+
+ pub fn proxy_capath<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> {
+ self.setopt_path(curl_sys::CURLOPT_PROXY_CAPATH, path.as_ref())
+ }
+
+ pub fn proxy_sslcert(&mut self, sslcert: &str) -> Result<(), Error> {
+ let sslcert = CString::new(sslcert)?;
+ self.setopt_str(curl_sys::CURLOPT_PROXY_SSLCERT, &sslcert)
+ }
+
+ pub fn proxy_sslcert_type(&mut self, kind: &str) -> Result<(), Error> {
+ let kind = CString::new(kind)?;
+ self.setopt_str(curl_sys::CURLOPT_PROXY_SSLCERTTYPE, &kind)
+ }
+
+ pub fn proxy_sslcert_blob(&mut self, blob: &[u8]) -> Result<(), Error> {
+ self.setopt_blob(curl_sys::CURLOPT_PROXY_SSLCERT_BLOB, blob)
+ }
+
+ pub fn proxy_sslkey(&mut self, sslkey: &str) -> Result<(), Error> {
+ let sslkey = CString::new(sslkey)?;
+ self.setopt_str(curl_sys::CURLOPT_PROXY_SSLKEY, &sslkey)
+ }
+
+ pub fn proxy_sslkey_type(&mut self, kind: &str) -> Result<(), Error> {
+ let kind = CString::new(kind)?;
+ self.setopt_str(curl_sys::CURLOPT_PROXY_SSLKEYTYPE, &kind)
+ }
+
+ pub fn proxy_sslkey_blob(&mut self, blob: &[u8]) -> Result<(), Error> {
+ self.setopt_blob(curl_sys::CURLOPT_PROXY_SSLKEY_BLOB, blob)
+ }
+
+ pub fn proxy_key_password(&mut self, password: &str) -> Result<(), Error> {
+ let password = CString::new(password)?;
+ self.setopt_str(curl_sys::CURLOPT_PROXY_KEYPASSWD, &password)
+ }
+
+ pub fn proxy_type(&mut self, kind: ProxyType) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_PROXYTYPE, kind as c_long)
+ }
+
+ pub fn noproxy(&mut self, skip: &str) -> Result<(), Error> {
+ let skip = CString::new(skip)?;
+ self.setopt_str(curl_sys::CURLOPT_NOPROXY, &skip)
+ }
+
+ pub fn http_proxy_tunnel(&mut self, tunnel: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_HTTPPROXYTUNNEL, tunnel as c_long)
+ }
+
+ pub fn interface(&mut self, interface: &str) -> Result<(), Error> {
+ let s = CString::new(interface)?;
+ self.setopt_str(curl_sys::CURLOPT_INTERFACE, &s)
+ }
+
+ pub fn set_local_port(&mut self, port: u16) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_LOCALPORT, port as c_long)
+ }
+
+ pub fn local_port_range(&mut self, range: u16) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_LOCALPORTRANGE, range as c_long)
+ }
+
+ pub fn dns_servers(&mut self, servers: &str) -> Result<(), Error> {
+ let s = CString::new(servers)?;
+ self.setopt_str(curl_sys::CURLOPT_DNS_SERVERS, &s)
+ }
+
+ pub fn dns_cache_timeout(&mut self, dur: Duration) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_DNS_CACHE_TIMEOUT, dur.as_secs() as c_long)
+ }
+
+ pub fn doh_url(&mut self, url: Option<&str>) -> Result<(), Error> {
+ if let Some(url) = url {
+ let url = CString::new(url)?;
+ self.setopt_str(curl_sys::CURLOPT_DOH_URL, &url)
+ } else {
+ self.setopt_ptr(curl_sys::CURLOPT_DOH_URL, ptr::null())
+ }
+ }
+
+ pub fn doh_ssl_verify_peer(&mut self, verify: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_DOH_SSL_VERIFYPEER, verify.into())
+ }
+
+ pub fn doh_ssl_verify_host(&mut self, verify: bool) -> Result<(), Error> {
+ self.setopt_long(
+ curl_sys::CURLOPT_DOH_SSL_VERIFYHOST,
+ if verify { 2 } else { 0 },
+ )
+ }
+
+ pub fn doh_ssl_verify_status(&mut self, verify: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_DOH_SSL_VERIFYSTATUS, verify.into())
+ }
+
+ pub fn buffer_size(&mut self, size: usize) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_BUFFERSIZE, size as c_long)
+ }
+
+ pub fn upload_buffer_size(&mut self, size: usize) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_UPLOAD_BUFFERSIZE, size as c_long)
+ }
+
+ pub fn tcp_nodelay(&mut self, enable: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_TCP_NODELAY, enable as c_long)
+ }
+
+ pub fn tcp_keepalive(&mut self, enable: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_TCP_KEEPALIVE, enable as c_long)
+ }
+
+ pub fn tcp_keepidle(&mut self, amt: Duration) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_TCP_KEEPIDLE, amt.as_secs() as c_long)
+ }
+
+ pub fn tcp_keepintvl(&mut self, amt: Duration) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_TCP_KEEPINTVL, amt.as_secs() as c_long)
+ }
+
+ pub fn address_scope(&mut self, scope: u32) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_ADDRESS_SCOPE, scope as c_long)
+ }
+
+ pub fn username(&mut self, user: &str) -> Result<(), Error> {
+ let user = CString::new(user)?;
+ self.setopt_str(curl_sys::CURLOPT_USERNAME, &user)
+ }
+
+ pub fn password(&mut self, pass: &str) -> Result<(), Error> {
+ let pass = CString::new(pass)?;
+ self.setopt_str(curl_sys::CURLOPT_PASSWORD, &pass)
+ }
+
+ pub fn http_auth(&mut self, auth: &Auth) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_HTTPAUTH, auth.bits)
+ }
+
+ pub fn aws_sigv4(&mut self, param: &str) -> Result<(), Error> {
+ let param = CString::new(param)?;
+ self.setopt_str(curl_sys::CURLOPT_AWS_SIGV4, ¶m)
+ }
+
+ pub fn proxy_username(&mut self, user: &str) -> Result<(), Error> {
+ let user = CString::new(user)?;
+ self.setopt_str(curl_sys::CURLOPT_PROXYUSERNAME, &user)
+ }
+
+ pub fn proxy_password(&mut self, pass: &str) -> Result<(), Error> {
+ let pass = CString::new(pass)?;
+ self.setopt_str(curl_sys::CURLOPT_PROXYPASSWORD, &pass)
+ }
+
+ pub fn proxy_auth(&mut self, auth: &Auth) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_PROXYAUTH, auth.bits)
+ }
+
+ pub fn netrc(&mut self, netrc: NetRc) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_NETRC, netrc as c_long)
+ }
+
+ pub fn autoreferer(&mut self, enable: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_AUTOREFERER, enable as c_long)
+ }
+
+ pub fn accept_encoding(&mut self, encoding: &str) -> Result<(), Error> {
+ let encoding = CString::new(encoding)?;
+ self.setopt_str(curl_sys::CURLOPT_ACCEPT_ENCODING, &encoding)
+ }
+
+ pub fn transfer_encoding(&mut self, enable: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_TRANSFER_ENCODING, enable as c_long)
+ }
+
+ pub fn follow_location(&mut self, enable: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_FOLLOWLOCATION, enable as c_long)
+ }
+
+ pub fn unrestricted_auth(&mut self, enable: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_UNRESTRICTED_AUTH, enable as c_long)
+ }
+
+ pub fn max_redirections(&mut self, max: u32) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_MAXREDIRS, max as c_long)
+ }
+
+ pub fn post_redirections(&mut self, redirects: &PostRedirections) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_POSTREDIR, redirects.bits as c_long)
+ }
+
+ pub fn put(&mut self, enable: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_PUT, enable as c_long)
+ }
+
+ pub fn post(&mut self, enable: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_POST, enable as c_long)
+ }
+
+ pub fn post_fields_copy(&mut self, data: &[u8]) -> Result<(), Error> {
+ self.post_field_size(data.len() as u64)?;
+ self.setopt_ptr(curl_sys::CURLOPT_COPYPOSTFIELDS, data.as_ptr() as *const _)
+ }
+
+ pub fn post_field_size(&mut self, size: u64) -> Result<(), Error> {
+ self.setopt_ptr(curl_sys::CURLOPT_POSTFIELDS, ptr::null())?;
+ self.setopt_off_t(
+ curl_sys::CURLOPT_POSTFIELDSIZE_LARGE,
+ size as curl_sys::curl_off_t,
+ )
+ }
+
+ pub fn httppost(&mut self, form: Form) -> Result<(), Error> {
+ self.setopt_ptr(curl_sys::CURLOPT_HTTPPOST, form::raw(&form) as *const _)?;
+ self.inner.form = Some(form);
+ Ok(())
+ }
+
+ pub fn referer(&mut self, referer: &str) -> Result<(), Error> {
+ let referer = CString::new(referer)?;
+ self.setopt_str(curl_sys::CURLOPT_REFERER, &referer)
+ }
+
+ pub fn useragent(&mut self, useragent: &str) -> Result<(), Error> {
+ let useragent = CString::new(useragent)?;
+ self.setopt_str(curl_sys::CURLOPT_USERAGENT, &useragent)
+ }
+
+ pub fn http_headers(&mut self, list: List) -> Result<(), Error> {
+ let ptr = list::raw(&list);
+ self.inner.header_list = Some(list);
+ self.setopt_ptr(curl_sys::CURLOPT_HTTPHEADER, ptr as *const _)
+ }
+
+ pub fn cookie(&mut self, cookie: &str) -> Result<(), Error> {
+ let cookie = CString::new(cookie)?;
+ self.setopt_str(curl_sys::CURLOPT_COOKIE, &cookie)
+ }
+
+ pub fn cookie_file<P: AsRef<Path>>(&mut self, file: P) -> Result<(), Error> {
+ self.setopt_path(curl_sys::CURLOPT_COOKIEFILE, file.as_ref())
+ }
+
+ pub fn cookie_jar<P: AsRef<Path>>(&mut self, file: P) -> Result<(), Error> {
+ self.setopt_path(curl_sys::CURLOPT_COOKIEJAR, file.as_ref())
+ }
+
+ pub fn cookie_session(&mut self, session: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_COOKIESESSION, session as c_long)
+ }
+
+ pub fn cookie_list(&mut self, cookie: &str) -> Result<(), Error> {
+ let cookie = CString::new(cookie)?;
+ self.setopt_str(curl_sys::CURLOPT_COOKIELIST, &cookie)
+ }
+
+ pub fn get(&mut self, enable: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_HTTPGET, enable as c_long)
+ }
+
+ pub fn ignore_content_length(&mut self, ignore: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_IGNORE_CONTENT_LENGTH, ignore as c_long)
+ }
+
+ pub fn http_content_decoding(&mut self, enable: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_HTTP_CONTENT_DECODING, enable as c_long)
+ }
+
+ pub fn http_transfer_decoding(&mut self, enable: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_HTTP_TRANSFER_DECODING, enable as c_long)
+ }
+
+ pub fn range(&mut self, range: &str) -> Result<(), Error> {
+ let range = CString::new(range)?;
+ self.setopt_str(curl_sys::CURLOPT_RANGE, &range)
+ }
+
+ pub fn resume_from(&mut self, from: u64) -> Result<(), Error> {
+ self.setopt_off_t(
+ curl_sys::CURLOPT_RESUME_FROM_LARGE,
+ from as curl_sys::curl_off_t,
+ )
+ }
+
+ pub fn custom_request(&mut self, request: &str) -> Result<(), Error> {
+ let request = CString::new(request)?;
+ self.setopt_str(curl_sys::CURLOPT_CUSTOMREQUEST, &request)
+ }
+
+ pub fn fetch_filetime(&mut self, fetch: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_FILETIME, fetch as c_long)
+ }
+
+ pub fn nobody(&mut self, enable: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_NOBODY, enable as c_long)
+ }
+
+ pub fn in_filesize(&mut self, size: u64) -> Result<(), Error> {
+ self.setopt_off_t(
+ curl_sys::CURLOPT_INFILESIZE_LARGE,
+ size as curl_sys::curl_off_t,
+ )
+ }
+
+ pub fn upload(&mut self, enable: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_UPLOAD, enable as c_long)
+ }
+
+ pub fn max_filesize(&mut self, size: u64) -> Result<(), Error> {
+ self.setopt_off_t(
+ curl_sys::CURLOPT_MAXFILESIZE_LARGE,
+ size as curl_sys::curl_off_t,
+ )
+ }
+
+ pub fn time_condition(&mut self, cond: TimeCondition) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_TIMECONDITION, cond as c_long)
+ }
+
+ pub fn time_value(&mut self, val: i64) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_TIMEVALUE, val as c_long)
+ }
+
+ pub fn timeout(&mut self, timeout: Duration) -> Result<(), Error> {
+ let ms = timeout.as_millis();
+ match c_long::try_from(ms) {
+ Ok(amt) => self.setopt_long(curl_sys::CURLOPT_TIMEOUT_MS, amt),
+ Err(_) => {
+ let amt = c_long::try_from(ms / 1000)
+ .map_err(|_| Error::new(curl_sys::CURLE_BAD_FUNCTION_ARGUMENT))?;
+ self.setopt_long(curl_sys::CURLOPT_TIMEOUT, amt)
+ }
+ }
+ }
+
+ pub fn low_speed_limit(&mut self, limit: u32) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_LOW_SPEED_LIMIT, limit as c_long)
+ }
+
+ pub fn low_speed_time(&mut self, dur: Duration) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_LOW_SPEED_TIME, dur.as_secs() as c_long)
+ }
+
+ pub fn max_send_speed(&mut self, speed: u64) -> Result<(), Error> {
+ self.setopt_off_t(
+ curl_sys::CURLOPT_MAX_SEND_SPEED_LARGE,
+ speed as curl_sys::curl_off_t,
+ )
+ }
+
+ pub fn max_recv_speed(&mut self, speed: u64) -> Result<(), Error> {
+ self.setopt_off_t(
+ curl_sys::CURLOPT_MAX_RECV_SPEED_LARGE,
+ speed as curl_sys::curl_off_t,
+ )
+ }
+
+ pub fn max_connects(&mut self, max: u32) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_MAXCONNECTS, max as c_long)
+ }
+
+ pub fn maxage_conn(&mut self, max_age: Duration) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_MAXAGE_CONN, max_age.as_secs() as c_long)
+ }
+
+ pub fn fresh_connect(&mut self, enable: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_FRESH_CONNECT, enable as c_long)
+ }
+
+ pub fn forbid_reuse(&mut self, enable: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_FORBID_REUSE, enable as c_long)
+ }
+
+ pub fn connect_timeout(&mut self, timeout: Duration) -> Result<(), Error> {
+ let ms = timeout.as_millis();
+ match c_long::try_from(ms) {
+ Ok(amt) => self.setopt_long(curl_sys::CURLOPT_CONNECTTIMEOUT_MS, amt),
+ Err(_) => {
+ let amt = c_long::try_from(ms / 1000)
+ .map_err(|_| Error::new(curl_sys::CURLE_BAD_FUNCTION_ARGUMENT))?;
+ self.setopt_long(curl_sys::CURLOPT_CONNECTTIMEOUT, amt)
+ }
+ }
+ }
+
+ pub fn ip_resolve(&mut self, resolve: IpResolve) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_IPRESOLVE, resolve as c_long)
+ }
+
+ pub fn resolve(&mut self, list: List) -> Result<(), Error> {
+ let ptr = list::raw(&list);
+ self.inner.resolve_list = Some(list);
+ self.setopt_ptr(curl_sys::CURLOPT_RESOLVE, ptr as *const _)
+ }
+
+ pub fn connect_only(&mut self, enable: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_CONNECT_ONLY, enable as c_long)
+ }
+
+ pub fn ssl_cert<P: AsRef<Path>>(&mut self, cert: P) -> Result<(), Error> {
+ self.setopt_path(curl_sys::CURLOPT_SSLCERT, cert.as_ref())
+ }
+
+ pub fn ssl_cert_blob(&mut self, blob: &[u8]) -> Result<(), Error> {
+ self.setopt_blob(curl_sys::CURLOPT_SSLCERT_BLOB, blob)
+ }
+
+ pub fn ssl_cert_type(&mut self, kind: &str) -> Result<(), Error> {
+ let kind = CString::new(kind)?;
+ self.setopt_str(curl_sys::CURLOPT_SSLCERTTYPE, &kind)
+ }
+
+ pub fn ssl_key<P: AsRef<Path>>(&mut self, key: P) -> Result<(), Error> {
+ self.setopt_path(curl_sys::CURLOPT_SSLKEY, key.as_ref())
+ }
+
+ pub fn ssl_key_blob(&mut self, blob: &[u8]) -> Result<(), Error> {
+ self.setopt_blob(curl_sys::CURLOPT_SSLKEY_BLOB, blob)
+ }
+
+ pub fn ssl_key_type(&mut self, kind: &str) -> Result<(), Error> {
+ let kind = CString::new(kind)?;
+ self.setopt_str(curl_sys::CURLOPT_SSLKEYTYPE, &kind)
+ }
+
+ pub fn key_password(&mut self, password: &str) -> Result<(), Error> {
+ let password = CString::new(password)?;
+ self.setopt_str(curl_sys::CURLOPT_KEYPASSWD, &password)
+ }
+
+ pub fn ssl_cainfo_blob(&mut self, blob: &[u8]) -> Result<(), Error> {
+ self.setopt_blob(curl_sys::CURLOPT_CAINFO_BLOB, blob)
+ }
+
+ pub fn proxy_ssl_cainfo_blob(&mut self, blob: &[u8]) -> Result<(), Error> {
+ self.setopt_blob(curl_sys::CURLOPT_PROXY_CAINFO_BLOB, blob)
+ }
+
+ pub fn ssl_engine(&mut self, engine: &str) -> Result<(), Error> {
+ let engine = CString::new(engine)?;
+ self.setopt_str(curl_sys::CURLOPT_SSLENGINE, &engine)
+ }
+
+ pub fn ssl_engine_default(&mut self, enable: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_SSLENGINE_DEFAULT, enable as c_long)
+ }
+
+ pub fn http_version(&mut self, version: HttpVersion) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_HTTP_VERSION, version as c_long)
+ }
+
+ pub fn ssl_version(&mut self, version: SslVersion) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_SSLVERSION, version as c_long)
+ }
+
+ pub fn proxy_ssl_version(&mut self, version: SslVersion) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_PROXY_SSLVERSION, version as c_long)
+ }
+
+ pub fn ssl_min_max_version(
+ &mut self,
+ min_version: SslVersion,
+ max_version: SslVersion,
+ ) -> Result<(), Error> {
+ let version = (min_version as c_long) | ((max_version as c_long) << 16);
+ self.setopt_long(curl_sys::CURLOPT_SSLVERSION, version)
+ }
+
+ pub fn proxy_ssl_min_max_version(
+ &mut self,
+ min_version: SslVersion,
+ max_version: SslVersion,
+ ) -> Result<(), Error> {
+ let version = (min_version as c_long) | ((max_version as c_long) << 16);
+ self.setopt_long(curl_sys::CURLOPT_PROXY_SSLVERSION, version)
+ }
+
+ pub fn ssl_verify_host(&mut self, verify: bool) -> Result<(), Error> {
+ let val = if verify { 2 } else { 0 };
+ self.setopt_long(curl_sys::CURLOPT_SSL_VERIFYHOST, val)
+ }
+
+ pub fn proxy_ssl_verify_host(&mut self, verify: bool) -> Result<(), Error> {
+ let val = if verify { 2 } else { 0 };
+ self.setopt_long(curl_sys::CURLOPT_PROXY_SSL_VERIFYHOST, val)
+ }
+
+ pub fn ssl_verify_peer(&mut self, verify: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_SSL_VERIFYPEER, verify as c_long)
+ }
+
+ pub fn proxy_ssl_verify_peer(&mut self, verify: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_PROXY_SSL_VERIFYPEER, verify as c_long)
+ }
+
+ pub fn cainfo<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> {
+ self.setopt_path(curl_sys::CURLOPT_CAINFO, path.as_ref())
+ }
+
+ pub fn issuer_cert<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> {
+ self.setopt_path(curl_sys::CURLOPT_ISSUERCERT, path.as_ref())
+ }
+
+ pub fn proxy_issuer_cert<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> {
+ self.setopt_path(curl_sys::CURLOPT_PROXY_ISSUERCERT, path.as_ref())
+ }
+
+ pub fn issuer_cert_blob(&mut self, blob: &[u8]) -> Result<(), Error> {
+ self.setopt_blob(curl_sys::CURLOPT_ISSUERCERT_BLOB, blob)
+ }
+
+ pub fn proxy_issuer_cert_blob(&mut self, blob: &[u8]) -> Result<(), Error> {
+ self.setopt_blob(curl_sys::CURLOPT_PROXY_ISSUERCERT_BLOB, blob)
+ }
+
+ pub fn capath<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> {
+ self.setopt_path(curl_sys::CURLOPT_CAPATH, path.as_ref())
+ }
+
+ pub fn crlfile<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> {
+ self.setopt_path(curl_sys::CURLOPT_CRLFILE, path.as_ref())
+ }
+
+ pub fn proxy_crlfile<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> {
+ self.setopt_path(curl_sys::CURLOPT_PROXY_CRLFILE, path.as_ref())
+ }
+
+ pub fn certinfo(&mut self, enable: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_CERTINFO, enable as c_long)
+ }
+
+ pub fn pinned_public_key(&mut self, pubkey: &str) -> Result<(), Error> {
+ let key = CString::new(pubkey)?;
+ self.setopt_str(curl_sys::CURLOPT_PINNEDPUBLICKEY, &key)
+ }
+
+ pub fn random_file<P: AsRef<Path>>(&mut self, p: P) -> Result<(), Error> {
+ self.setopt_path(curl_sys::CURLOPT_RANDOM_FILE, p.as_ref())
+ }
+
+ pub fn egd_socket<P: AsRef<Path>>(&mut self, p: P) -> Result<(), Error> {
+ self.setopt_path(curl_sys::CURLOPT_EGDSOCKET, p.as_ref())
+ }
+
+ pub fn ssl_cipher_list(&mut self, ciphers: &str) -> Result<(), Error> {
+ let ciphers = CString::new(ciphers)?;
+ self.setopt_str(curl_sys::CURLOPT_SSL_CIPHER_LIST, &ciphers)
+ }
+
+ pub fn proxy_ssl_cipher_list(&mut self, ciphers: &str) -> Result<(), Error> {
+ let ciphers = CString::new(ciphers)?;
+ self.setopt_str(curl_sys::CURLOPT_PROXY_SSL_CIPHER_LIST, &ciphers)
+ }
+
+ pub fn ssl_sessionid_cache(&mut self, enable: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_SSL_SESSIONID_CACHE, enable as c_long)
+ }
+
+ pub fn ssl_options(&mut self, bits: &SslOpt) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_SSL_OPTIONS, bits.bits)
+ }
+
+ pub fn proxy_ssl_options(&mut self, bits: &SslOpt) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_PROXY_SSL_OPTIONS, bits.bits)
+ }
+
+ pub fn expect_100_timeout(&mut self, timeout: Duration) -> Result<(), Error> {
+ let ms = timeout.as_secs() * 1000 + timeout.subsec_millis() as u64;
+ self.setopt_long(curl_sys::CURLOPT_EXPECT_100_TIMEOUT_MS, ms as c_long)
+ }
+
+ pub fn time_condition_unmet(&self) -> Result<bool, Error> {
+ self.getopt_long(curl_sys::CURLINFO_CONDITION_UNMET)
+ .map(|r| r != 0)
+ }
+
+ pub fn effective_url(&self) -> Result<Option<&str>, Error> {
+ self.getopt_str(curl_sys::CURLINFO_EFFECTIVE_URL)
+ }
+
+ pub fn effective_url_bytes(&self) -> Result<Option<&[u8]>, Error> {
+ self.getopt_bytes(curl_sys::CURLINFO_EFFECTIVE_URL)
+ }
+
+ pub fn response_code(&self) -> Result<u32, Error> {
+ self.getopt_long(curl_sys::CURLINFO_RESPONSE_CODE)
+ .map(|c| c as u32)
+ }
+
+ pub fn http_connectcode(&self) -> Result<u32, Error> {
+ self.getopt_long(curl_sys::CURLINFO_HTTP_CONNECTCODE)
+ .map(|c| c as u32)
+ }
+
+ pub fn filetime(&self) -> Result<Option<i64>, Error> {
+ self.getopt_long(curl_sys::CURLINFO_FILETIME).map(|r| {
+ if r == -1 {
+ None
+ } else {
+ Some(r as i64)
+ }
+ })
+ }
+
+ pub fn download_size(&self) -> Result<f64, Error> {
+ self.getopt_double(curl_sys::CURLINFO_SIZE_DOWNLOAD)
+ .map(|r| r as f64)
+ }
+
+ pub fn upload_size(&self) -> Result<f64, Error> {
+ self.getopt_double(curl_sys::CURLINFO_SIZE_UPLOAD)
+ .map(|r| r as f64)
+ }
+
+ pub fn content_length_download(&self) -> Result<f64, Error> {
+ self.getopt_double(curl_sys::CURLINFO_CONTENT_LENGTH_DOWNLOAD)
+ .map(|r| r as f64)
+ }
+
+ pub fn total_time(&self) -> Result<Duration, Error> {
+ self.getopt_double(curl_sys::CURLINFO_TOTAL_TIME)
+ .map(double_seconds_to_duration)
+ }
+
+ pub fn namelookup_time(&self) -> Result<Duration, Error> {
+ self.getopt_double(curl_sys::CURLINFO_NAMELOOKUP_TIME)
+ .map(double_seconds_to_duration)
+ }
+
+ pub fn connect_time(&self) -> Result<Duration, Error> {
+ self.getopt_double(curl_sys::CURLINFO_CONNECT_TIME)
+ .map(double_seconds_to_duration)
+ }
+
+ pub fn appconnect_time(&self) -> Result<Duration, Error> {
+ self.getopt_double(curl_sys::CURLINFO_APPCONNECT_TIME)
+ .map(double_seconds_to_duration)
+ }
+
+ pub fn pretransfer_time(&self) -> Result<Duration, Error> {
+ self.getopt_double(curl_sys::CURLINFO_PRETRANSFER_TIME)
+ .map(double_seconds_to_duration)
+ }
+
+ pub fn starttransfer_time(&self) -> Result<Duration, Error> {
+ self.getopt_double(curl_sys::CURLINFO_STARTTRANSFER_TIME)
+ .map(double_seconds_to_duration)
+ }
+
+ pub fn redirect_time(&self) -> Result<Duration, Error> {
+ self.getopt_double(curl_sys::CURLINFO_REDIRECT_TIME)
+ .map(double_seconds_to_duration)
+ }
+
+ pub fn redirect_count(&self) -> Result<u32, Error> {
+ self.getopt_long(curl_sys::CURLINFO_REDIRECT_COUNT)
+ .map(|c| c as u32)
+ }
+
+ pub fn redirect_url(&self) -> Result<Option<&str>, Error> {
+ self.getopt_str(curl_sys::CURLINFO_REDIRECT_URL)
+ }
+
+ pub fn redirect_url_bytes(&self) -> Result<Option<&[u8]>, Error> {
+ self.getopt_bytes(curl_sys::CURLINFO_REDIRECT_URL)
+ }
+
+ pub fn header_size(&self) -> Result<u64, Error> {
+ self.getopt_long(curl_sys::CURLINFO_HEADER_SIZE)
+ .map(|c| c as u64)
+ }
+
+ pub fn request_size(&self) -> Result<u64, Error> {
+ self.getopt_long(curl_sys::CURLINFO_REQUEST_SIZE)
+ .map(|c| c as u64)
+ }
+
+ pub fn content_type(&self) -> Result<Option<&str>, Error> {
+ self.getopt_str(curl_sys::CURLINFO_CONTENT_TYPE)
+ }
+
+ pub fn content_type_bytes(&self) -> Result<Option<&[u8]>, Error> {
+ self.getopt_bytes(curl_sys::CURLINFO_CONTENT_TYPE)
+ }
+
+ pub fn os_errno(&self) -> Result<i32, Error> {
+ self.getopt_long(curl_sys::CURLINFO_OS_ERRNO)
+ .map(|c| c as i32)
+ }
+
+ pub fn primary_ip(&self) -> Result<Option<&str>, Error> {
+ self.getopt_str(curl_sys::CURLINFO_PRIMARY_IP)
+ }
+
+ pub fn primary_port(&self) -> Result<u16, Error> {
+ self.getopt_long(curl_sys::CURLINFO_PRIMARY_PORT)
+ .map(|c| c as u16)
+ }
+
+ pub fn local_ip(&self) -> Result<Option<&str>, Error> {
+ self.getopt_str(curl_sys::CURLINFO_LOCAL_IP)
+ }
+
+ pub fn local_port(&self) -> Result<u16, Error> {
+ self.getopt_long(curl_sys::CURLINFO_LOCAL_PORT)
+ .map(|c| c as u16)
+ }
+
+ pub fn cookies(&mut self) -> Result<List, Error> {
+ unsafe {
+ let mut list = ptr::null_mut();
+ let rc = curl_sys::curl_easy_getinfo(
+ self.inner.handle,
+ curl_sys::CURLINFO_COOKIELIST,
+ &mut list,
+ );
+ self.cvt(rc)?;
+ Ok(list::from_raw(list))
+ }
+ }
+
+ pub fn pipewait(&mut self, wait: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_PIPEWAIT, wait as c_long)
+ }
+
+ pub fn http_09_allowed(&mut self, allow: bool) -> Result<(), Error> {
+ self.setopt_long(curl_sys::CURLOPT_HTTP09_ALLOWED, allow as c_long)
+ }
+
+ pub fn perform(&self) -> Result<(), Error> {
+ let ret = unsafe { self.cvt(curl_sys::curl_easy_perform(self.inner.handle)) };
+ panic::propagate();
+ ret
+ }
+
+ #[cfg(feature = "upkeep_7_62_0")]
+ pub fn upkeep(&self) -> Result<(), Error> {
+ let ret = unsafe { self.cvt(curl_sys::curl_easy_upkeep(self.inner.handle)) };
+ panic::propagate();
+ return ret;
+ }
+
+ pub fn unpause_read(&self) -> Result<(), Error> {
+ unsafe {
+ let rc = curl_sys::curl_easy_pause(self.inner.handle, curl_sys::CURLPAUSE_RECV_CONT);
+ self.cvt(rc)
+ }
+ }
+
+ pub fn unpause_write(&self) -> Result<(), Error> {
+ unsafe {
+ let rc = curl_sys::curl_easy_pause(self.inner.handle, curl_sys::CURLPAUSE_SEND_CONT);
+ self.cvt(rc)
+ }
+ }
+
+ pub fn url_encode(&mut self, s: &[u8]) -> String {
+ if s.is_empty() {
+ return String::new();
+ }
+ unsafe {
+ let p = curl_sys::curl_easy_escape(
+ self.inner.handle,
+ s.as_ptr() as *const _,
+ s.len() as c_int,
+ );
+ assert!(!p.is_null());
+ let ret = str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap();
+ let ret = String::from(ret);
+ curl_sys::curl_free(p as *mut _);
+ ret
+ }
+ }
+
+ pub fn url_decode(&mut self, s: &str) -> Vec<u8> {
+ if s.is_empty() {
+ return Vec::new();
+ }
+
+ let mut iter = s.chars().rev();
+ let orig_len = s.len();
+ let mut data;
+ let mut s = s;
+ if iter.next() == Some('%') || iter.next() == Some('%') || iter.next() == Some('%') {
+ data = s.to_string();
+ data.push(0u8 as char);
+ s = &data[..];
+ }
+ unsafe {
+ let mut len = 0;
+ let p = curl_sys::curl_easy_unescape(
+ self.inner.handle,
+ s.as_ptr() as *const _,
+ orig_len as c_int,
+ &mut len,
+ );
+ assert!(!p.is_null());
+ let slice = slice::from_raw_parts(p as *const u8, len as usize);
+ let ret = slice.to_vec();
+ curl_sys::curl_free(p as *mut _);
+ ret
+ }
+ }
+
+ pub fn recv(&mut self, data: &mut [u8]) -> Result<usize, Error> {
+ unsafe {
+ let mut n = 0;
+ let r = curl_sys::curl_easy_recv(
+ self.inner.handle,
+ data.as_mut_ptr() as *mut _,
+ data.len(),
+ &mut n,
+ );
+ if r == curl_sys::CURLE_OK {
+ Ok(n)
+ } else {
+ Err(Error::new(r))
+ }
+ }
+ }
+
+ pub fn send(&mut self, data: &[u8]) -> Result<usize, Error> {
+ unsafe {
+ let mut n = 0;
+ let rc = curl_sys::curl_easy_send(
+ self.inner.handle,
+ data.as_ptr() as *const _,
+ data.len(),
+ &mut n,
+ );
+ self.cvt(rc)?;
+ Ok(n)
+ }
+ }
+
+ pub fn raw(&self) -> *mut curl_sys::CURL {
+ self.inner.handle
+ }
+
+ #[cfg(unix)]
+ fn setopt_path(&mut self, opt: curl_sys::CURLoption, val: &Path) -> Result<(), Error> {
+ use std::os::unix::prelude::*;
+ let s = CString::new(val.as_os_str().as_bytes())?;
+ self.setopt_str(opt, &s)
+ }
+
+ #[cfg(windows)]
+ fn setopt_path(&mut self, opt: curl_sys::CURLoption, val: &Path) -> Result<(), Error> {
+ match val.to_str() {
+ Some(s) => self.setopt_str(opt, &CString::new(s)?),
+ None => Err(Error::new(curl_sys::CURLE_CONV_FAILED)),
+ }
+ }
+
+ fn setopt_long(&mut self, opt: curl_sys::CURLoption, val: c_long) -> Result<(), Error> {
+ unsafe { self.cvt(curl_sys::curl_easy_setopt(self.inner.handle, opt, val)) }
+ }
+
+ fn setopt_str(&mut self, opt: curl_sys::CURLoption, val: &CStr) -> Result<(), Error> {
+ self.setopt_ptr(opt, val.as_ptr())
+ }
+
+ fn setopt_ptr(&self, opt: curl_sys::CURLoption, val: *const c_char) -> Result<(), Error> {
+ unsafe { self.cvt(curl_sys::curl_easy_setopt(self.inner.handle, opt, val)) }
+ }
+
+ fn setopt_off_t(
+ &mut self,
+ opt: curl_sys::CURLoption,
+ val: curl_sys::curl_off_t,
+ ) -> Result<(), Error> {
+ unsafe {
+ let rc = curl_sys::curl_easy_setopt(self.inner.handle, opt, val);
+ self.cvt(rc)
+ }
+ }
+
+ fn setopt_blob(&mut self, opt: curl_sys::CURLoption, val: &[u8]) -> Result<(), Error> {
+ let blob = curl_sys::curl_blob {
+ data: val.as_ptr() as *const c_void as *mut c_void,
+ len: val.len(),
+ flags: curl_sys::CURL_BLOB_COPY,
+ };
+ let blob_ptr = &blob as *const curl_sys::curl_blob;
+ unsafe { self.cvt(curl_sys::curl_easy_setopt(self.inner.handle, opt, blob_ptr)) }
+ }
+
+ fn getopt_bytes(&self, opt: curl_sys::CURLINFO) -> Result<Option<&[u8]>, Error> {
+ unsafe {
+ let p = self.getopt_ptr(opt)?;
+ if p.is_null() {
+ Ok(None)
+ } else {
+ Ok(Some(CStr::from_ptr(p).to_bytes()))
+ }
+ }
+ }
+
+ fn getopt_ptr(&self, opt: curl_sys::CURLINFO) -> Result<*const c_char, Error> {
+ unsafe {
+ let mut p = ptr::null();
+ let rc = curl_sys::curl_easy_getinfo(self.inner.handle, opt, &mut p);
+ self.cvt(rc)?;
+ Ok(p)
+ }
+ }
+
+ fn getopt_str(&self, opt: curl_sys::CURLINFO) -> Result<Option<&str>, Error> {
+ match self.getopt_bytes(opt) {
+ Ok(None) => Ok(None),
+ Err(e) => Err(e),
+ Ok(Some(bytes)) => match str::from_utf8(bytes) {
+ Ok(s) => Ok(Some(s)),
+ Err(_) => Err(Error::new(curl_sys::CURLE_CONV_FAILED)),
+ },
+ }
+ }
+
+ fn getopt_long(&self, opt: curl_sys::CURLINFO) -> Result<c_long, Error> {
+ unsafe {
+ let mut p = 0;
+ let rc = curl_sys::curl_easy_getinfo(self.inner.handle, opt, &mut p);
+ self.cvt(rc)?;
+ Ok(p)
+ }
+ }
+
+ fn getopt_double(&self, opt: curl_sys::CURLINFO) -> Result<c_double, Error> {
+ unsafe {
+ let mut p = 0 as c_double;
+ let rc = curl_sys::curl_easy_getinfo(self.inner.handle, opt, &mut p);
+ self.cvt(rc)?;
+ Ok(p)
+ }
+ }
+
+ pub fn take_error_buf(&self) -> Option<String> {
+ let mut buf = self.inner.error_buf.borrow_mut();
+ if buf[0] == 0 {
+ return None;
+ }
+ let pos = buf.iter().position(|i| *i == 0).unwrap_or(buf.len());
+ let msg = String::from_utf8_lossy(&buf[..pos]).into_owned();
+ buf[0] = 0;
+ Some(msg)
+ }
+
+ fn cvt(&self, rc: curl_sys::CURLcode) -> Result<(), Error> {
+ if rc == curl_sys::CURLE_OK {
+ return Ok(());
+ }
+ let mut err = Error::new(rc);
+ if let Some(msg) = self.take_error_buf() {
+ err.set_extra(msg);
+ }
+ Err(err)
+ }
+}
+
+impl<H: fmt::Debug> fmt::Debug for Easy2<H> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("Easy")
+ .field("handle", &self.inner.handle)
+ .field("handler", &self.inner.handler)
+ .finish()
+ }
+}
+
+impl<H> Drop for Easy2<H> {
+ fn drop(&mut self) {
+ unsafe {
+ curl_sys::curl_easy_cleanup(self.inner.handle);
+ }
+ }
+}
+
+extern "C" fn header_cb<H: Handler>(
+ buffer: *mut c_char,
+ size: size_t,
+ nitems: size_t,
+ userptr: *mut c_void,
+) -> size_t {
+ let keep_going = panic::catch(|| unsafe {
+ let data = slice::from_raw_parts(buffer as *const u8, size * nitems);
+ (*(userptr as *mut Inner<H>)).handler.header(data)
+ })
+ .unwrap_or(false);
+ if keep_going {
+ size * nitems
+ } else {
+ !0
+ }
+}
+
+extern "C" fn write_cb<H: Handler>(
+ ptr: *mut c_char,
+ size: size_t,
+ nmemb: size_t,
+ data: *mut c_void,
+) -> size_t {
+ panic::catch(|| unsafe {
+ let input = slice::from_raw_parts(ptr as *const u8, size * nmemb);
+ match (*(data as *mut Inner<H>)).handler.write(input) {
+ Ok(s) => s,
+ Err(WriteError::Pause) => curl_sys::CURL_WRITEFUNC_PAUSE,
+ }
+ })
+ .unwrap_or(!0)
+}
+
+extern "C" fn read_cb<H: Handler>(
+ ptr: *mut c_char,
+ size: size_t,
+ nmemb: size_t,
+ data: *mut c_void,
+) -> size_t {
+ panic::catch(|| unsafe {
+ let input = slice::from_raw_parts_mut(ptr as *mut u8, size * nmemb);
+ match (*(data as *mut Inner<H>)).handler.read(input) {
+ Ok(s) => s,
+ Err(ReadError::Pause) => curl_sys::CURL_READFUNC_PAUSE,
+ Err(ReadError::Abort) => curl_sys::CURL_READFUNC_ABORT,
+ }
+ })
+ .unwrap_or(!0)
+}
+
+extern "C" fn seek_cb<H: Handler>(
+ data: *mut c_void,
+ offset: curl_sys::curl_off_t,
+ origin: c_int,
+) -> c_int {
+ panic::catch(|| unsafe {
+ let from = if origin == libc::SEEK_SET {
+ SeekFrom::Start(offset as u64)
+ } else {
+ panic!("unknown origin from libcurl: {}", origin);
+ };
+ (*(data as *mut Inner<H>)).handler.seek(from) as c_int
+ })
+ .unwrap_or(!0)
+}
+
+extern "C" fn progress_cb<H: Handler>(
+ data: *mut c_void,
+ dltotal: c_double,
+ dlnow: c_double,
+ ultotal: c_double,
+ ulnow: c_double,
+) -> c_int {
+ let keep_going = panic::catch(|| unsafe {
+ (*(data as *mut Inner<H>))
+ .handler
+ .progress(dltotal, dlnow, ultotal, ulnow)
+ })
+ .unwrap_or(false);
+ if keep_going {
+ 0
+ } else {
+ 1
+ }
+}
+
+extern "C" fn debug_cb<H: Handler>(
+ _handle: *mut curl_sys::CURL,
+ kind: curl_sys::curl_infotype,
+ data: *mut c_char,
+ size: size_t,
+ userptr: *mut c_void,
+) -> c_int {
+ panic::catch(|| unsafe {
+ let data = slice::from_raw_parts(data as *const u8, size);
+ let kind = match kind {
+ curl_sys::CURLINFO_TEXT => InfoType::Text,
+ curl_sys::CURLINFO_HEADER_IN => InfoType::HeaderIn,
+ curl_sys::CURLINFO_HEADER_OUT => InfoType::HeaderOut,
+ curl_sys::CURLINFO_DATA_IN => InfoType::DataIn,
+ curl_sys::CURLINFO_DATA_OUT => InfoType::DataOut,
+ curl_sys::CURLINFO_SSL_DATA_IN => InfoType::SslDataIn,
+ curl_sys::CURLINFO_SSL_DATA_OUT => InfoType::SslDataOut,
+ _ => return,
+ };
+ (*(userptr as *mut Inner<H>)).handler.debug(kind, data)
+ });
+ 0
+}
+
+extern "C" fn ssl_ctx_cb<H: Handler>(
+ _handle: *mut curl_sys::CURL,
+ ssl_ctx: *mut c_void,
+ data: *mut c_void,
+) -> curl_sys::CURLcode {
+ let res = panic::catch(|| unsafe {
+ match (*(data as *mut Inner<H>)).handler.ssl_ctx(ssl_ctx) {
+ Ok(()) => curl_sys::CURLE_OK,
+ Err(e) => e.code(),
+ }
+ });
+ res.unwrap_or(curl_sys::CURLE_SSL_CONNECT_ERROR)
+}
+
+extern "C" fn opensocket_cb<H: Handler>(
+ data: *mut c_void,
+ _purpose: curl_sys::curlsocktype,
+ address: *mut curl_sys::curl_sockaddr,
+) -> curl_sys::curl_socket_t {
+ let res = panic::catch(|| unsafe {
+ (*(data as *mut Inner<H>))
+ .handler
+ .open_socket((*address).family, (*address).socktype, (*address).protocol)
+ .unwrap_or(curl_sys::CURL_SOCKET_BAD)
+ });
+ res.unwrap_or(curl_sys::CURL_SOCKET_BAD)
+}
+
+fn double_seconds_to_duration(seconds: f64) -> Duration {
+ let whole_seconds = seconds.trunc() as u64;
+ let nanos = seconds.fract() * 1_000_000_000f64;
+ Duration::new(whole_seconds, nanos as u32)
+}
+
+#[test]
+fn double_seconds_to_duration_whole_second() {
+ let dur = double_seconds_to_duration(1.0);
+ assert_eq!(dur.as_secs(), 1);
+ assert_eq!(dur.subsec_nanos(), 0);
+}
+
+#[test]
+fn double_seconds_to_duration_sub_second1() {
+ let dur = double_seconds_to_duration(0.0);
+ assert_eq!(dur.as_secs(), 0);
+ assert_eq!(dur.subsec_nanos(), 0);
+}
+
+#[test]
+fn double_seconds_to_duration_sub_second2() {
+ let dur = double_seconds_to_duration(0.5);
+ assert_eq!(dur.as_secs(), 0);
+ assert_eq!(dur.subsec_nanos(), 500_000_000);
+}
+
+impl Auth {
+ pub fn new() -> Auth {
+ Auth { bits: 0 }
+ }
+
+ pub fn basic(&mut self, on: bool) -> &mut Auth {
+ self.flag(curl_sys::CURLAUTH_BASIC, on)
+ }
+
+ pub fn digest(&mut self, on: bool) -> &mut Auth {
+ self.flag(curl_sys::CURLAUTH_DIGEST, on)
+ }
+
+ pub fn digest_ie(&mut self, on: bool) -> &mut Auth {
+ self.flag(curl_sys::CURLAUTH_DIGEST_IE, on)
+ }
+
+ pub fn gssnegotiate(&mut self, on: bool) -> &mut Auth {
+ self.flag(curl_sys::CURLAUTH_GSSNEGOTIATE, on)
+ }
+
+ pub fn ntlm(&mut self, on: bool) -> &mut Auth {
+ self.flag(curl_sys::CURLAUTH_NTLM, on)
+ }
+
+ pub fn ntlm_wb(&mut self, on: bool) -> &mut Auth {
+ self.flag(curl_sys::CURLAUTH_NTLM_WB, on)
+ }
+
+ pub fn aws_sigv4(&mut self, on: bool) -> &mut Auth {
+ self.flag(curl_sys::CURLAUTH_AWS_SIGV4, on)
+ }
+
+ pub fn auto(&mut self, on: bool) -> &mut Auth {
+ self.flag(curl_sys::CURLAUTH_ANY, on)
+ }
+
+ fn flag(&mut self, bit: c_ulong, on: bool) -> &mut Auth {
+ if on {
+ self.bits |= bit as c_long;
+ } else {
+ self.bits &= !bit as c_long;
+ }
+ self
+ }
+}
+
+impl fmt::Debug for Auth {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let bits = self.bits as c_ulong;
+ f.debug_struct("Auth")
+ .field("basic", &(bits & curl_sys::CURLAUTH_BASIC != 0))
+ .field("digest", &(bits & curl_sys::CURLAUTH_DIGEST != 0))
+ .field("digest_ie", &(bits & curl_sys::CURLAUTH_DIGEST_IE != 0))
+ .field(
+ "gssnegotiate",
+ &(bits & curl_sys::CURLAUTH_GSSNEGOTIATE != 0),
+ )
+ .field("ntlm", &(bits & curl_sys::CURLAUTH_NTLM != 0))
+ .field("ntlm_wb", &(bits & curl_sys::CURLAUTH_NTLM_WB != 0))
+ .field("aws_sigv4", &(bits & curl_sys::CURLAUTH_AWS_SIGV4 != 0))
+ .finish()
+ }
+}
+
+impl SslOpt {
+ pub fn new() -> SslOpt {
+ SslOpt { bits: 0 }
+ }
+
+ pub fn auto_client_cert(&mut self, on: bool) -> &mut SslOpt {
+ self.flag(curl_sys::CURLSSLOPT_AUTO_CLIENT_CERT, on)
+ }
+
+ pub fn native_ca(&mut self, on: bool) -> &mut SslOpt {
+ self.flag(curl_sys::CURLSSLOPT_NATIVE_CA, on)
+ }
+
+ pub fn revoke_best_effort(&mut self, on: bool) -> &mut SslOpt {
+ self.flag(curl_sys::CURLSSLOPT_REVOKE_BEST_EFFORT, on)
+ }
+
+ pub fn no_partial_chain(&mut self, on: bool) -> &mut SslOpt {
+ self.flag(curl_sys::CURLSSLOPT_NO_PARTIALCHAIN, on)
+ }
+
+ pub fn no_revoke(&mut self, on: bool) -> &mut SslOpt {
+ self.flag(curl_sys::CURLSSLOPT_NO_REVOKE, on)
+ }
+
+ pub fn allow_beast(&mut self, on: bool) -> &mut SslOpt {
+ self.flag(curl_sys::CURLSSLOPT_ALLOW_BEAST, on)
+ }
+
+ fn flag(&mut self, bit: c_long, on: bool) -> &mut SslOpt {
+ if on {
+ self.bits |= bit as c_long;
+ } else {
+ self.bits &= !bit as c_long;
+ }
+ self
+ }
+}
+
+impl fmt::Debug for SslOpt {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("SslOpt")
+ .field(
+ "no_revoke",
+ &(self.bits & curl_sys::CURLSSLOPT_NO_REVOKE != 0),
+ )
+ .field(
+ "allow_beast",
+ &(self.bits & curl_sys::CURLSSLOPT_ALLOW_BEAST != 0),
+ )
+ .finish()
+ }
+}
+
+impl PostRedirections {
+ pub fn new() -> PostRedirections {
+ PostRedirections { bits: 0 }
+ }
+
+ pub fn redirect_301(&mut self, on: bool) -> &mut PostRedirections {
+ self.flag(curl_sys::CURL_REDIR_POST_301, on)
+ }
+
+ pub fn redirect_302(&mut self, on: bool) -> &mut PostRedirections {
+ self.flag(curl_sys::CURL_REDIR_POST_302, on)
+ }
+
+ pub fn redirect_303(&mut self, on: bool) -> &mut PostRedirections {
+ self.flag(curl_sys::CURL_REDIR_POST_303, on)
+ }
+
+ pub fn redirect_all(&mut self, on: bool) -> &mut PostRedirections {
+ self.flag(curl_sys::CURL_REDIR_POST_ALL, on)
+ }
+
+ fn flag(&mut self, bit: c_ulong, on: bool) -> &mut PostRedirections {
+ if on {
+ self.bits |= bit;
+ } else {
+ self.bits &= !bit;
+ }
+ self
+ }
+}
+
+impl fmt::Debug for PostRedirections {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("PostRedirections")
+ .field(
+ "redirect_301",
+ &(self.bits & curl_sys::CURL_REDIR_POST_301 != 0),
+ )
+ .field(
+ "redirect_302",
+ &(self.bits & curl_sys::CURL_REDIR_POST_302 != 0),
+ )
+ .field(
+ "redirect_303",
+ &(self.bits & curl_sys::CURL_REDIR_POST_303 != 0),
+ )
+ .finish()
+ }
+}
+