1 | use std::cell::RefCell; |
2 | use std::ffi::{CStr, CString}; |
3 | use std::fmt; |
4 | use std::io::{self, SeekFrom, Write}; |
5 | use std::path::Path; |
6 | use std::ptr; |
7 | use std::slice; |
8 | use std::str; |
9 | use std::time::Duration; |
10 | |
11 | use curl_sys; |
12 | use libc::{self, c_char, c_double, c_int, c_long, c_ulong, c_void, size_t}; |
13 | use socket2::Socket; |
14 | |
15 | use crate::easy::form; |
16 | use crate::easy::list; |
17 | use crate::easy::windows; |
18 | use crate::easy::{Form, List}; |
19 | use crate::panic; |
20 | use crate::Error; |
21 | |
22 | /// A trait for the various callbacks used by libcurl to invoke user code. |
23 | /// |
24 | /// This trait represents all operations that libcurl can possibly invoke a |
25 | /// client for code during an HTTP transaction. Each callback has a default |
26 | /// "noop" implementation, the same as in libcurl. Types implementing this trait |
27 | /// may simply override the relevant functions to learn about the callbacks |
28 | /// they're interested in. |
29 | /// |
30 | /// # Examples |
31 | /// |
32 | /// ``` |
33 | /// use curl::easy::{Easy2, Handler, WriteError}; |
34 | /// |
35 | /// struct Collector(Vec<u8>); |
36 | /// |
37 | /// impl Handler for Collector { |
38 | /// fn write(&mut self, data: &[u8]) -> Result<usize, WriteError> { |
39 | /// self.0.extend_from_slice(data); |
40 | /// Ok(data.len()) |
41 | /// } |
42 | /// } |
43 | /// |
44 | /// let mut easy = Easy2::new(Collector(Vec::new())); |
45 | /// easy.get(true).unwrap(); |
46 | /// easy.url("https://www.rust-lang.org/" ).unwrap(); |
47 | /// easy.perform().unwrap(); |
48 | /// |
49 | /// assert_eq!(easy.response_code().unwrap(), 200); |
50 | /// let contents = easy.get_ref(); |
51 | /// println!("{}" , String::from_utf8_lossy(&contents.0)); |
52 | /// ``` |
53 | pub trait Handler { |
54 | /// Callback invoked whenever curl has downloaded data for the application. |
55 | /// |
56 | /// This callback function gets called by libcurl as soon as there is data |
57 | /// received that needs to be saved. |
58 | /// |
59 | /// The callback function will be passed as much data as possible in all |
60 | /// invokes, but you must not make any assumptions. It may be one byte, it |
61 | /// may be thousands. If `show_header` is enabled, which makes header data |
62 | /// get passed to the write callback, you can get up to |
63 | /// `CURL_MAX_HTTP_HEADER` bytes of header data passed into it. This |
64 | /// usually means 100K. |
65 | /// |
66 | /// This function may be called with zero bytes data if the transferred file |
67 | /// is empty. |
68 | /// |
69 | /// The callback should return the number of bytes actually taken care of. |
70 | /// If that amount differs from the amount passed to your callback function, |
71 | /// it'll signal an error condition to the library. This will cause the |
72 | /// transfer to get aborted and the libcurl function used will return |
73 | /// an error with `is_write_error`. |
74 | /// |
75 | /// If your callback function returns `Err(WriteError::Pause)` it will cause |
76 | /// this transfer to become paused. See `unpause_write` for further details. |
77 | /// |
78 | /// By default data is sent into the void, and this corresponds to the |
79 | /// `CURLOPT_WRITEFUNCTION` and `CURLOPT_WRITEDATA` options. |
80 | fn write(&mut self, data: &[u8]) -> Result<usize, WriteError> { |
81 | Ok(data.len()) |
82 | } |
83 | |
84 | /// Read callback for data uploads. |
85 | /// |
86 | /// This callback function gets called by libcurl as soon as it needs to |
87 | /// read data in order to send it to the peer - like if you ask it to upload |
88 | /// or post data to the server. |
89 | /// |
90 | /// Your function must then return the actual number of bytes that it stored |
91 | /// in that memory area. Returning 0 will signal end-of-file to the library |
92 | /// and cause it to stop the current transfer. |
93 | /// |
94 | /// If you stop the current transfer by returning 0 "pre-maturely" (i.e |
95 | /// before the server expected it, like when you've said you will upload N |
96 | /// bytes and you upload less than N bytes), you may experience that the |
97 | /// server "hangs" waiting for the rest of the data that won't come. |
98 | /// |
99 | /// The read callback may return `Err(ReadError::Abort)` to stop the |
100 | /// current operation immediately, resulting in a `is_aborted_by_callback` |
101 | /// error code from the transfer. |
102 | /// |
103 | /// The callback can return `Err(ReadError::Pause)` to cause reading from |
104 | /// this connection to pause. See `unpause_read` for further details. |
105 | /// |
106 | /// By default data not input, and this corresponds to the |
107 | /// `CURLOPT_READFUNCTION` and `CURLOPT_READDATA` options. |
108 | /// |
109 | /// Note that the lifetime bound on this function is `'static`, but that |
110 | /// is often too restrictive. To use stack data consider calling the |
111 | /// `transfer` method and then using `read_function` to configure a |
112 | /// callback that can reference stack-local data. |
113 | fn read(&mut self, data: &mut [u8]) -> Result<usize, ReadError> { |
114 | drop(data); |
115 | Ok(0) |
116 | } |
117 | |
118 | /// User callback for seeking in input stream. |
119 | /// |
120 | /// This function gets called by libcurl to seek to a certain position in |
121 | /// the input stream and can be used to fast forward a file in a resumed |
122 | /// upload (instead of reading all uploaded bytes with the normal read |
123 | /// function/callback). It is also called to rewind a stream when data has |
124 | /// already been sent to the server and needs to be sent again. This may |
125 | /// happen when doing a HTTP PUT or POST with a multi-pass authentication |
126 | /// method, or when an existing HTTP connection is reused too late and the |
127 | /// server closes the connection. |
128 | /// |
129 | /// The callback function must return `SeekResult::Ok` on success, |
130 | /// `SeekResult::Fail` to cause the upload operation to fail or |
131 | /// `SeekResult::CantSeek` to indicate that while the seek failed, libcurl |
132 | /// is free to work around the problem if possible. The latter can sometimes |
133 | /// be done by instead reading from the input or similar. |
134 | /// |
135 | /// By default data this option is not set, and this corresponds to the |
136 | /// `CURLOPT_SEEKFUNCTION` and `CURLOPT_SEEKDATA` options. |
137 | fn seek(&mut self, whence: SeekFrom) -> SeekResult { |
138 | drop(whence); |
139 | SeekResult::CantSeek |
140 | } |
141 | |
142 | /// Specify a debug callback |
143 | /// |
144 | /// `debug_function` replaces the standard debug function used when |
145 | /// `verbose` is in effect. This callback receives debug information, |
146 | /// as specified in the type argument. |
147 | /// |
148 | /// By default this option is not set and corresponds to the |
149 | /// `CURLOPT_DEBUGFUNCTION` and `CURLOPT_DEBUGDATA` options. |
150 | fn debug(&mut self, kind: InfoType, data: &[u8]) { |
151 | debug(kind, data) |
152 | } |
153 | |
154 | /// Callback that receives header data |
155 | /// |
156 | /// This function gets called by libcurl as soon as it has received header |
157 | /// data. The header callback will be called once for each header and only |
158 | /// complete header lines are passed on to the callback. Parsing headers is |
159 | /// very easy using this. If this callback returns `false` it'll signal an |
160 | /// error to the library. This will cause the transfer to get aborted and |
161 | /// the libcurl function in progress will return `is_write_error`. |
162 | /// |
163 | /// A complete HTTP header that is passed to this function can be up to |
164 | /// CURL_MAX_HTTP_HEADER (100K) bytes. |
165 | /// |
166 | /// It's important to note that the callback will be invoked for the headers |
167 | /// of all responses received after initiating a request and not just the |
168 | /// final response. This includes all responses which occur during |
169 | /// authentication negotiation. If you need to operate on only the headers |
170 | /// from the final response, you will need to collect headers in the |
171 | /// callback yourself and use HTTP status lines, for example, to delimit |
172 | /// response boundaries. |
173 | /// |
174 | /// When a server sends a chunked encoded transfer, it may contain a |
175 | /// trailer. That trailer is identical to a HTTP header and if such a |
176 | /// trailer is received it is passed to the application using this callback |
177 | /// as well. There are several ways to detect it being a trailer and not an |
178 | /// ordinary header: 1) it comes after the response-body. 2) it comes after |
179 | /// the final header line (CR LF) 3) a Trailer: header among the regular |
180 | /// response-headers mention what header(s) to expect in the trailer. |
181 | /// |
182 | /// For non-HTTP protocols like FTP, POP3, IMAP and SMTP this function will |
183 | /// get called with the server responses to the commands that libcurl sends. |
184 | /// |
185 | /// By default this option is not set and corresponds to the |
186 | /// `CURLOPT_HEADERFUNCTION` and `CURLOPT_HEADERDATA` options. |
187 | fn header(&mut self, data: &[u8]) -> bool { |
188 | drop(data); |
189 | true |
190 | } |
191 | |
192 | /// Callback to progress meter function |
193 | /// |
194 | /// This function gets called by libcurl instead of its internal equivalent |
195 | /// with a frequent interval. While data is being transferred it will be |
196 | /// called very frequently, and during slow periods like when nothing is |
197 | /// being transferred it can slow down to about one call per second. |
198 | /// |
199 | /// The callback gets told how much data libcurl will transfer and has |
200 | /// transferred, in number of bytes. The first argument is the total number |
201 | /// of bytes libcurl expects to download in this transfer. The second |
202 | /// argument is the number of bytes downloaded so far. The third argument is |
203 | /// the total number of bytes libcurl expects to upload in this transfer. |
204 | /// The fourth argument is the number of bytes uploaded so far. |
205 | /// |
206 | /// Unknown/unused argument values passed to the callback will be set to |
207 | /// zero (like if you only download data, the upload size will remain 0). |
208 | /// Many times the callback will be called one or more times first, before |
209 | /// it knows the data sizes so a program must be made to handle that. |
210 | /// |
211 | /// Returning `false` from this callback will cause libcurl to abort the |
212 | /// transfer and return `is_aborted_by_callback`. |
213 | /// |
214 | /// If you transfer data with the multi interface, this function will not be |
215 | /// called during periods of idleness unless you call the appropriate |
216 | /// libcurl function that performs transfers. |
217 | /// |
218 | /// `progress` must be set to `true` to make this function actually get |
219 | /// called. |
220 | /// |
221 | /// By default this function calls an internal method and corresponds to |
222 | /// `CURLOPT_PROGRESSFUNCTION` and `CURLOPT_PROGRESSDATA`. |
223 | fn progress(&mut self, dltotal: f64, dlnow: f64, ultotal: f64, ulnow: f64) -> bool { |
224 | drop((dltotal, dlnow, ultotal, ulnow)); |
225 | true |
226 | } |
227 | |
228 | /// Callback to SSL context |
229 | /// |
230 | /// This callback function gets called by libcurl just before the |
231 | /// initialization of an SSL connection after having processed all |
232 | /// other SSL related options to give a last chance to an |
233 | /// application to modify the behaviour of the SSL |
234 | /// initialization. The `ssl_ctx` parameter is actually a pointer |
235 | /// to the SSL library's SSL_CTX. If an error is returned from the |
236 | /// callback no attempt to establish a connection is made and the |
237 | /// perform operation will return the callback's error code. |
238 | /// |
239 | /// This function will get called on all new connections made to a |
240 | /// server, during the SSL negotiation. The SSL_CTX pointer will |
241 | /// be a new one every time. |
242 | /// |
243 | /// To use this properly, a non-trivial amount of knowledge of |
244 | /// your SSL library is necessary. For example, you can use this |
245 | /// function to call library-specific callbacks to add additional |
246 | /// validation code for certificates, and even to change the |
247 | /// actual URI of a HTTPS request. |
248 | /// |
249 | /// By default this function calls an internal method and |
250 | /// corresponds to `CURLOPT_SSL_CTX_FUNCTION` and |
251 | /// `CURLOPT_SSL_CTX_DATA`. |
252 | /// |
253 | /// Note that this callback is not guaranteed to be called, not all versions |
254 | /// of libcurl support calling this callback. |
255 | fn ssl_ctx(&mut self, cx: *mut c_void) -> Result<(), Error> { |
256 | // By default, if we're on an OpenSSL enabled libcurl and we're on |
257 | // Windows, add the system's certificate store to OpenSSL's certificate |
258 | // store. |
259 | ssl_ctx(cx) |
260 | } |
261 | |
262 | /// Callback to open sockets for libcurl. |
263 | /// |
264 | /// This callback function gets called by libcurl instead of the socket(2) |
265 | /// call. The callback function should return the newly created socket |
266 | /// or `None` in case no connection could be established or another |
267 | /// error was detected. Any additional `setsockopt(2)` calls can of course |
268 | /// be done on the socket at the user's discretion. A `None` return |
269 | /// value from the callback function will signal an unrecoverable error to |
270 | /// libcurl and it will return `is_couldnt_connect` from the function that |
271 | /// triggered this callback. |
272 | /// |
273 | /// By default this function opens a standard socket and |
274 | /// corresponds to `CURLOPT_OPENSOCKETFUNCTION `. |
275 | fn open_socket( |
276 | &mut self, |
277 | family: c_int, |
278 | socktype: c_int, |
279 | protocol: c_int, |
280 | ) -> Option<curl_sys::curl_socket_t> { |
281 | // Note that we override this to calling a function in `socket2` to |
282 | // ensure that we open all sockets with CLOEXEC. Otherwise if we rely on |
283 | // libcurl to open sockets it won't use CLOEXEC. |
284 | return Socket::new(family.into(), socktype.into(), Some(protocol.into())) |
285 | .ok() |
286 | .map(cvt); |
287 | |
288 | #[cfg (unix)] |
289 | fn cvt(socket: Socket) -> curl_sys::curl_socket_t { |
290 | use std::os::unix::prelude::*; |
291 | socket.into_raw_fd() |
292 | } |
293 | |
294 | #[cfg (windows)] |
295 | fn cvt(socket: Socket) -> curl_sys::curl_socket_t { |
296 | use std::os::windows::prelude::*; |
297 | socket.into_raw_socket() |
298 | } |
299 | } |
300 | } |
301 | |
302 | pub fn debug(kind: InfoType, data: &[u8]) { |
303 | let out: Stderr = io::stderr(); |
304 | let prefix: &str = match kind { |
305 | InfoType::Text => "*" , |
306 | InfoType::HeaderIn => "<" , |
307 | InfoType::HeaderOut => ">" , |
308 | InfoType::DataIn | InfoType::SslDataIn => "{" , |
309 | InfoType::DataOut | InfoType::SslDataOut => "}" , |
310 | }; |
311 | let mut out: StderrLock<'_> = out.lock(); |
312 | drop(write!(out, " {} " , prefix)); |
313 | match str::from_utf8(data) { |
314 | Ok(s: &str) => drop(out.write_all(buf:s.as_bytes())), |
315 | Err(_) => drop(writeln!(out, "( {} bytes of data)" , data.len())), |
316 | } |
317 | } |
318 | |
319 | pub fn ssl_ctx(cx: *mut c_void) -> Result<(), Error> { |
320 | windows::add_certs_to_context(cx); |
321 | Ok(()) |
322 | } |
323 | |
324 | /// Raw bindings to a libcurl "easy session". |
325 | /// |
326 | /// This type corresponds to the `CURL` type in libcurl, and is probably what |
327 | /// you want for just sending off a simple HTTP request and fetching a response. |
328 | /// Each easy handle can be thought of as a large builder before calling the |
329 | /// final `perform` function. |
330 | /// |
331 | /// There are many many configuration options for each `Easy2` handle, and they |
332 | /// should all have their own documentation indicating what it affects and how |
333 | /// it interacts with other options. Some implementations of libcurl can use |
334 | /// this handle to interact with many different protocols, although by default |
335 | /// this crate only guarantees the HTTP/HTTPS protocols working. |
336 | /// |
337 | /// Note that almost all methods on this structure which configure various |
338 | /// properties return a `Result`. This is largely used to detect whether the |
339 | /// underlying implementation of libcurl actually implements the option being |
340 | /// requested. If you're linked to a version of libcurl which doesn't support |
341 | /// the option, then an error will be returned. Some options also perform some |
342 | /// validation when they're set, and the error is returned through this vector. |
343 | /// |
344 | /// Note that historically this library contained an `Easy` handle so this one's |
345 | /// called `Easy2`. The major difference between the `Easy` type is that an |
346 | /// `Easy2` structure uses a trait instead of closures for all of the callbacks |
347 | /// that curl can invoke. The `Easy` type is actually built on top of this |
348 | /// `Easy` type, and this `Easy2` type can be more flexible in some situations |
349 | /// due to the generic parameter. |
350 | /// |
351 | /// There's not necessarily a right answer for which type is correct to use, but |
352 | /// as a general rule of thumb `Easy` is typically a reasonable choice for |
353 | /// synchronous I/O and `Easy2` is a good choice for asynchronous I/O. |
354 | /// |
355 | /// # Examples |
356 | /// |
357 | /// ``` |
358 | /// use curl::easy::{Easy2, Handler, WriteError}; |
359 | /// |
360 | /// struct Collector(Vec<u8>); |
361 | /// |
362 | /// impl Handler for Collector { |
363 | /// fn write(&mut self, data: &[u8]) -> Result<usize, WriteError> { |
364 | /// self.0.extend_from_slice(data); |
365 | /// Ok(data.len()) |
366 | /// } |
367 | /// } |
368 | /// |
369 | /// let mut easy = Easy2::new(Collector(Vec::new())); |
370 | /// easy.get(true).unwrap(); |
371 | /// easy.url("https://www.rust-lang.org/" ).unwrap(); |
372 | /// easy.perform().unwrap(); |
373 | /// |
374 | /// assert_eq!(easy.response_code().unwrap(), 200); |
375 | /// let contents = easy.get_ref(); |
376 | /// println!("{}" , String::from_utf8_lossy(&contents.0)); |
377 | /// ``` |
378 | pub struct Easy2<H> { |
379 | inner: Box<Inner<H>>, |
380 | } |
381 | |
382 | struct Inner<H> { |
383 | handle: *mut curl_sys::CURL, |
384 | header_list: Option<List>, |
385 | resolve_list: Option<List>, |
386 | connect_to_list: Option<List>, |
387 | form: Option<Form>, |
388 | error_buf: RefCell<Vec<u8>>, |
389 | handler: H, |
390 | } |
391 | |
392 | unsafe impl<H: Send> Send for Inner<H> {} |
393 | |
394 | /// Possible proxy types that libcurl currently understands. |
395 | #[non_exhaustive ] |
396 | #[allow (missing_docs)] |
397 | #[derive (Debug, Clone, Copy)] |
398 | pub enum ProxyType { |
399 | Http = curl_sys::CURLPROXY_HTTP as isize, |
400 | Http1 = curl_sys::CURLPROXY_HTTP_1_0 as isize, |
401 | Socks4 = curl_sys::CURLPROXY_SOCKS4 as isize, |
402 | Socks5 = curl_sys::CURLPROXY_SOCKS5 as isize, |
403 | Socks4a = curl_sys::CURLPROXY_SOCKS4A as isize, |
404 | Socks5Hostname = curl_sys::CURLPROXY_SOCKS5_HOSTNAME as isize, |
405 | } |
406 | |
407 | /// Possible conditions for the `time_condition` method. |
408 | #[non_exhaustive ] |
409 | #[allow (missing_docs)] |
410 | #[derive (Debug, Clone, Copy)] |
411 | pub enum TimeCondition { |
412 | None = curl_sys::CURL_TIMECOND_NONE as isize, |
413 | IfModifiedSince = curl_sys::CURL_TIMECOND_IFMODSINCE as isize, |
414 | IfUnmodifiedSince = curl_sys::CURL_TIMECOND_IFUNMODSINCE as isize, |
415 | LastModified = curl_sys::CURL_TIMECOND_LASTMOD as isize, |
416 | } |
417 | |
418 | /// Possible values to pass to the `ip_resolve` method. |
419 | #[non_exhaustive ] |
420 | #[allow (missing_docs)] |
421 | #[derive (Debug, Clone, Copy)] |
422 | pub enum IpResolve { |
423 | V4 = curl_sys::CURL_IPRESOLVE_V4 as isize, |
424 | V6 = curl_sys::CURL_IPRESOLVE_V6 as isize, |
425 | Any = curl_sys::CURL_IPRESOLVE_WHATEVER as isize, |
426 | } |
427 | |
428 | /// Possible values to pass to the `http_version` method. |
429 | #[non_exhaustive ] |
430 | #[derive (Debug, Clone, Copy)] |
431 | pub enum HttpVersion { |
432 | /// We don't care what http version to use, and we'd like the library to |
433 | /// choose the best possible for us. |
434 | Any = curl_sys::CURL_HTTP_VERSION_NONE as isize, |
435 | |
436 | /// Please use HTTP 1.0 in the request |
437 | V10 = curl_sys::CURL_HTTP_VERSION_1_0 as isize, |
438 | |
439 | /// Please use HTTP 1.1 in the request |
440 | V11 = curl_sys::CURL_HTTP_VERSION_1_1 as isize, |
441 | |
442 | /// Please use HTTP 2 in the request |
443 | /// (Added in CURL 7.33.0) |
444 | V2 = curl_sys::CURL_HTTP_VERSION_2_0 as isize, |
445 | |
446 | /// Use version 2 for HTTPS, version 1.1 for HTTP |
447 | /// (Added in CURL 7.47.0) |
448 | V2TLS = curl_sys::CURL_HTTP_VERSION_2TLS as isize, |
449 | |
450 | /// Please use HTTP 2 without HTTP/1.1 Upgrade |
451 | /// (Added in CURL 7.49.0) |
452 | V2PriorKnowledge = curl_sys::CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE as isize, |
453 | |
454 | /// Setting this value will make libcurl attempt to use HTTP/3 directly to |
455 | /// server given in the URL. Note that this cannot gracefully downgrade to |
456 | /// earlier HTTP version if the server doesn't support HTTP/3. |
457 | /// |
458 | /// For more reliably upgrading to HTTP/3, set the preferred version to |
459 | /// something lower and let the server announce its HTTP/3 support via |
460 | /// Alt-Svc:. |
461 | /// |
462 | /// (Added in CURL 7.66.0) |
463 | V3 = curl_sys::CURL_HTTP_VERSION_3 as isize, |
464 | } |
465 | |
466 | /// Possible values to pass to the `ssl_version` and `ssl_min_max_version` method. |
467 | #[non_exhaustive ] |
468 | #[allow (missing_docs)] |
469 | #[derive (Debug, Clone, Copy)] |
470 | pub enum SslVersion { |
471 | Default = curl_sys::CURL_SSLVERSION_DEFAULT as isize, |
472 | Tlsv1 = curl_sys::CURL_SSLVERSION_TLSv1 as isize, |
473 | Sslv2 = curl_sys::CURL_SSLVERSION_SSLv2 as isize, |
474 | Sslv3 = curl_sys::CURL_SSLVERSION_SSLv3 as isize, |
475 | Tlsv10 = curl_sys::CURL_SSLVERSION_TLSv1_0 as isize, |
476 | Tlsv11 = curl_sys::CURL_SSLVERSION_TLSv1_1 as isize, |
477 | Tlsv12 = curl_sys::CURL_SSLVERSION_TLSv1_2 as isize, |
478 | Tlsv13 = curl_sys::CURL_SSLVERSION_TLSv1_3 as isize, |
479 | } |
480 | |
481 | /// Possible return values from the `seek_function` callback. |
482 | #[non_exhaustive ] |
483 | #[derive (Debug, Clone, Copy)] |
484 | pub enum SeekResult { |
485 | /// Indicates that the seek operation was a success |
486 | Ok = curl_sys::CURL_SEEKFUNC_OK as isize, |
487 | |
488 | /// Indicates that the seek operation failed, and the entire request should |
489 | /// fail as a result. |
490 | Fail = curl_sys::CURL_SEEKFUNC_FAIL as isize, |
491 | |
492 | /// Indicates that although the seek failed libcurl should attempt to keep |
493 | /// working if possible (for example "seek" through reading). |
494 | CantSeek = curl_sys::CURL_SEEKFUNC_CANTSEEK as isize, |
495 | } |
496 | |
497 | /// Possible data chunks that can be witnessed as part of the `debug_function` |
498 | /// callback. |
499 | #[non_exhaustive ] |
500 | #[derive (Debug, Clone, Copy)] |
501 | pub enum InfoType { |
502 | /// The data is informational text. |
503 | Text, |
504 | |
505 | /// The data is header (or header-like) data received from the peer. |
506 | HeaderIn, |
507 | |
508 | /// The data is header (or header-like) data sent to the peer. |
509 | HeaderOut, |
510 | |
511 | /// The data is protocol data received from the peer. |
512 | DataIn, |
513 | |
514 | /// The data is protocol data sent to the peer. |
515 | DataOut, |
516 | |
517 | /// The data is SSL/TLS (binary) data received from the peer. |
518 | SslDataIn, |
519 | |
520 | /// The data is SSL/TLS (binary) data sent to the peer. |
521 | SslDataOut, |
522 | } |
523 | |
524 | /// Possible error codes that can be returned from the `read_function` callback. |
525 | #[non_exhaustive ] |
526 | #[derive (Debug)] |
527 | pub enum ReadError { |
528 | /// Indicates that the connection should be aborted immediately |
529 | Abort, |
530 | |
531 | /// Indicates that reading should be paused until `unpause` is called. |
532 | Pause, |
533 | } |
534 | |
535 | /// Possible error codes that can be returned from the `write_function` callback. |
536 | #[non_exhaustive ] |
537 | #[derive (Debug)] |
538 | pub enum WriteError { |
539 | /// Indicates that reading should be paused until `unpause` is called. |
540 | Pause, |
541 | } |
542 | |
543 | /// Options for `.netrc` parsing. |
544 | #[derive (Debug, Clone, Copy)] |
545 | pub enum NetRc { |
546 | /// Ignoring `.netrc` file and use information from url |
547 | /// |
548 | /// This option is default |
549 | Ignored = curl_sys::CURL_NETRC_IGNORED as isize, |
550 | |
551 | /// The use of your `~/.netrc` file is optional, and information in the URL is to be |
552 | /// preferred. The file will be scanned for the host and user name (to find the password only) |
553 | /// or for the host only, to find the first user name and password after that machine, which |
554 | /// ever information is not specified in the URL. |
555 | Optional = curl_sys::CURL_NETRC_OPTIONAL as isize, |
556 | |
557 | /// This value tells the library that use of the file is required, to ignore the information in |
558 | /// the URL, and to search the file for the host only. |
559 | Required = curl_sys::CURL_NETRC_REQUIRED as isize, |
560 | } |
561 | |
562 | /// Structure which stores possible authentication methods to get passed to |
563 | /// `http_auth` and `proxy_auth`. |
564 | #[derive (Clone)] |
565 | pub struct Auth { |
566 | bits: c_long, |
567 | } |
568 | |
569 | /// Structure which stores possible ssl options to pass to `ssl_options`. |
570 | #[derive (Clone)] |
571 | pub struct SslOpt { |
572 | bits: c_long, |
573 | } |
574 | |
575 | impl<H: Handler> Easy2<H> { |
576 | /// Creates a new "easy" handle which is the core of almost all operations |
577 | /// in libcurl. |
578 | /// |
579 | /// To use a handle, applications typically configure a number of options |
580 | /// followed by a call to `perform`. Options are preserved across calls to |
581 | /// `perform` and need to be reset manually (or via the `reset` method) if |
582 | /// this is not desired. |
583 | pub fn new(handler: H) -> Easy2<H> { |
584 | crate::init(); |
585 | unsafe { |
586 | let handle = curl_sys::curl_easy_init(); |
587 | assert!(!handle.is_null()); |
588 | let mut ret = Easy2 { |
589 | inner: Box::new(Inner { |
590 | handle, |
591 | header_list: None, |
592 | resolve_list: None, |
593 | connect_to_list: None, |
594 | form: None, |
595 | error_buf: RefCell::new(vec![0; curl_sys::CURL_ERROR_SIZE]), |
596 | handler, |
597 | }), |
598 | }; |
599 | ret.default_configure(); |
600 | ret |
601 | } |
602 | } |
603 | |
604 | /// Re-initializes this handle to the default values. |
605 | /// |
606 | /// This puts the handle to the same state as it was in when it was just |
607 | /// created. This does, however, keep live connections, the session id |
608 | /// cache, the dns cache, and cookies. |
609 | pub fn reset(&mut self) { |
610 | unsafe { |
611 | curl_sys::curl_easy_reset(self.inner.handle); |
612 | } |
613 | self.default_configure(); |
614 | } |
615 | |
616 | fn default_configure(&mut self) { |
617 | self.setopt_ptr( |
618 | curl_sys::CURLOPT_ERRORBUFFER, |
619 | self.inner.error_buf.borrow().as_ptr() as *const _, |
620 | ) |
621 | .expect("failed to set error buffer" ); |
622 | let _ = self.signal(false); |
623 | self.ssl_configure(); |
624 | |
625 | let ptr = &*self.inner as *const _ as *const _; |
626 | |
627 | let cb: extern "C" fn(*mut c_char, size_t, size_t, *mut c_void) -> size_t = header_cb::<H>; |
628 | self.setopt_ptr(curl_sys::CURLOPT_HEADERFUNCTION, cb as *const _) |
629 | .expect("failed to set header callback" ); |
630 | self.setopt_ptr(curl_sys::CURLOPT_HEADERDATA, ptr) |
631 | .expect("failed to set header callback" ); |
632 | |
633 | let cb: curl_sys::curl_write_callback = write_cb::<H>; |
634 | self.setopt_ptr(curl_sys::CURLOPT_WRITEFUNCTION, cb as *const _) |
635 | .expect("failed to set write callback" ); |
636 | self.setopt_ptr(curl_sys::CURLOPT_WRITEDATA, ptr) |
637 | .expect("failed to set write callback" ); |
638 | |
639 | let cb: curl_sys::curl_read_callback = read_cb::<H>; |
640 | self.setopt_ptr(curl_sys::CURLOPT_READFUNCTION, cb as *const _) |
641 | .expect("failed to set read callback" ); |
642 | self.setopt_ptr(curl_sys::CURLOPT_READDATA, ptr) |
643 | .expect("failed to set read callback" ); |
644 | |
645 | let cb: curl_sys::curl_seek_callback = seek_cb::<H>; |
646 | self.setopt_ptr(curl_sys::CURLOPT_SEEKFUNCTION, cb as *const _) |
647 | .expect("failed to set seek callback" ); |
648 | self.setopt_ptr(curl_sys::CURLOPT_SEEKDATA, ptr) |
649 | .expect("failed to set seek callback" ); |
650 | |
651 | let cb: curl_sys::curl_progress_callback = progress_cb::<H>; |
652 | self.setopt_ptr(curl_sys::CURLOPT_PROGRESSFUNCTION, cb as *const _) |
653 | .expect("failed to set progress callback" ); |
654 | self.setopt_ptr(curl_sys::CURLOPT_PROGRESSDATA, ptr) |
655 | .expect("failed to set progress callback" ); |
656 | |
657 | let cb: curl_sys::curl_debug_callback = debug_cb::<H>; |
658 | self.setopt_ptr(curl_sys::CURLOPT_DEBUGFUNCTION, cb as *const _) |
659 | .expect("failed to set debug callback" ); |
660 | self.setopt_ptr(curl_sys::CURLOPT_DEBUGDATA, ptr) |
661 | .expect("failed to set debug callback" ); |
662 | |
663 | let cb: curl_sys::curl_ssl_ctx_callback = ssl_ctx_cb::<H>; |
664 | drop(self.setopt_ptr(curl_sys::CURLOPT_SSL_CTX_FUNCTION, cb as *const _)); |
665 | drop(self.setopt_ptr(curl_sys::CURLOPT_SSL_CTX_DATA, ptr)); |
666 | |
667 | let cb: curl_sys::curl_opensocket_callback = opensocket_cb::<H>; |
668 | self.setopt_ptr(curl_sys::CURLOPT_OPENSOCKETFUNCTION, cb as *const _) |
669 | .expect("failed to set open socket callback" ); |
670 | self.setopt_ptr(curl_sys::CURLOPT_OPENSOCKETDATA, ptr) |
671 | .expect("failed to set open socket callback" ); |
672 | } |
673 | |
674 | #[cfg (need_openssl_probe)] |
675 | fn ssl_configure(&mut self) { |
676 | use std::sync::Once; |
677 | |
678 | static mut PROBE: Option<::openssl_probe::ProbeResult> = None; |
679 | static INIT: Once = Once::new(); |
680 | |
681 | // Probe for certificate stores the first time an easy handle is created, |
682 | // and re-use the results for subsequent handles. |
683 | INIT.call_once(|| unsafe { |
684 | PROBE = Some(::openssl_probe::probe()); |
685 | }); |
686 | let probe = unsafe { PROBE.as_ref().unwrap() }; |
687 | |
688 | if let Some(ref path) = probe.cert_file { |
689 | let _ = self.cainfo(path); |
690 | } |
691 | if let Some(ref path) = probe.cert_dir { |
692 | let _ = self.capath(path); |
693 | } |
694 | } |
695 | |
696 | #[cfg (not(need_openssl_probe))] |
697 | fn ssl_configure(&mut self) {} |
698 | } |
699 | |
700 | impl<H> Easy2<H> { |
701 | // ========================================================================= |
702 | // Behavior options |
703 | |
704 | /// Configures this handle to have verbose output to help debug protocol |
705 | /// information. |
706 | /// |
707 | /// By default output goes to stderr, but the `stderr` function on this type |
708 | /// can configure that. You can also use the `debug_function` method to get |
709 | /// all protocol data sent and received. |
710 | /// |
711 | /// By default, this option is `false`. |
712 | pub fn verbose(&mut self, verbose: bool) -> Result<(), Error> { |
713 | self.setopt_long(curl_sys::CURLOPT_VERBOSE, verbose as c_long) |
714 | } |
715 | |
716 | /// Indicates whether header information is streamed to the output body of |
717 | /// this request. |
718 | /// |
719 | /// This option is only relevant for protocols which have header metadata |
720 | /// (like http or ftp). It's not generally possible to extract headers |
721 | /// from the body if using this method, that use case should be intended for |
722 | /// the `header_function` method. |
723 | /// |
724 | /// To set HTTP headers, use the `http_header` method. |
725 | /// |
726 | /// By default, this option is `false` and corresponds to |
727 | /// `CURLOPT_HEADER`. |
728 | pub fn show_header(&mut self, show: bool) -> Result<(), Error> { |
729 | self.setopt_long(curl_sys::CURLOPT_HEADER, show as c_long) |
730 | } |
731 | |
732 | /// Indicates whether a progress meter will be shown for requests done with |
733 | /// this handle. |
734 | /// |
735 | /// This will also prevent the `progress_function` from being called. |
736 | /// |
737 | /// By default this option is `false` and corresponds to |
738 | /// `CURLOPT_NOPROGRESS`. |
739 | pub fn progress(&mut self, progress: bool) -> Result<(), Error> { |
740 | self.setopt_long(curl_sys::CURLOPT_NOPROGRESS, (!progress) as c_long) |
741 | } |
742 | |
743 | /// Inform libcurl whether or not it should install signal handlers or |
744 | /// attempt to use signals to perform library functions. |
745 | /// |
746 | /// If this option is disabled then timeouts during name resolution will not |
747 | /// work unless libcurl is built against c-ares. Note that enabling this |
748 | /// option, however, may not cause libcurl to work with multiple threads. |
749 | /// |
750 | /// By default this option is `false` and corresponds to `CURLOPT_NOSIGNAL`. |
751 | /// Note that this default is **different than libcurl** as it is intended |
752 | /// that this library is threadsafe by default. See the [libcurl docs] for |
753 | /// some more information. |
754 | /// |
755 | /// [libcurl docs]: https://curl.haxx.se/libcurl/c/threadsafe.html |
756 | pub fn signal(&mut self, signal: bool) -> Result<(), Error> { |
757 | self.setopt_long(curl_sys::CURLOPT_NOSIGNAL, (!signal) as c_long) |
758 | } |
759 | |
760 | /// Indicates whether multiple files will be transferred based on the file |
761 | /// name pattern. |
762 | /// |
763 | /// The last part of a filename uses fnmatch-like pattern matching. |
764 | /// |
765 | /// By default this option is `false` and corresponds to |
766 | /// `CURLOPT_WILDCARDMATCH`. |
767 | pub fn wildcard_match(&mut self, m: bool) -> Result<(), Error> { |
768 | self.setopt_long(curl_sys::CURLOPT_WILDCARDMATCH, m as c_long) |
769 | } |
770 | |
771 | /// Provides the Unix domain socket which this handle will work with. |
772 | /// |
773 | /// The string provided must be a path to a Unix domain socket encoded with |
774 | /// the format: |
775 | /// |
776 | /// ```text |
777 | /// /path/file.sock |
778 | /// ``` |
779 | /// |
780 | /// By default this option is not set and corresponds to |
781 | /// [`CURLOPT_UNIX_SOCKET_PATH`](https://curl.haxx.se/libcurl/c/CURLOPT_UNIX_SOCKET_PATH.html). |
782 | pub fn unix_socket(&mut self, unix_domain_socket: &str) -> Result<(), Error> { |
783 | let socket = CString::new(unix_domain_socket)?; |
784 | self.setopt_str(curl_sys::CURLOPT_UNIX_SOCKET_PATH, &socket) |
785 | } |
786 | |
787 | /// Provides the Unix domain socket which this handle will work with. |
788 | /// |
789 | /// The string provided must be a path to a Unix domain socket encoded with |
790 | /// the format: |
791 | /// |
792 | /// ```text |
793 | /// /path/file.sock |
794 | /// ``` |
795 | /// |
796 | /// This function is an alternative to [`Easy2::unix_socket`] that supports |
797 | /// non-UTF-8 paths and also supports disabling Unix sockets by setting the |
798 | /// option to `None`. |
799 | /// |
800 | /// By default this option is not set and corresponds to |
801 | /// [`CURLOPT_UNIX_SOCKET_PATH`](https://curl.haxx.se/libcurl/c/CURLOPT_UNIX_SOCKET_PATH.html). |
802 | pub fn unix_socket_path<P: AsRef<Path>>(&mut self, path: Option<P>) -> Result<(), Error> { |
803 | if let Some(path) = path { |
804 | self.setopt_path(curl_sys::CURLOPT_UNIX_SOCKET_PATH, path.as_ref()) |
805 | } else { |
806 | self.setopt_ptr(curl_sys::CURLOPT_UNIX_SOCKET_PATH, 0 as _) |
807 | } |
808 | } |
809 | |
810 | // ========================================================================= |
811 | // Internal accessors |
812 | |
813 | /// Acquires a reference to the underlying handler for events. |
814 | pub fn get_ref(&self) -> &H { |
815 | &self.inner.handler |
816 | } |
817 | |
818 | /// Acquires a reference to the underlying handler for events. |
819 | pub fn get_mut(&mut self) -> &mut H { |
820 | &mut self.inner.handler |
821 | } |
822 | |
823 | // ========================================================================= |
824 | // Error options |
825 | |
826 | // TODO: error buffer and stderr |
827 | |
828 | /// Indicates whether this library will fail on HTTP response codes >= 400. |
829 | /// |
830 | /// This method is not fail-safe especially when authentication is involved. |
831 | /// |
832 | /// By default this option is `false` and corresponds to |
833 | /// `CURLOPT_FAILONERROR`. |
834 | pub fn fail_on_error(&mut self, fail: bool) -> Result<(), Error> { |
835 | self.setopt_long(curl_sys::CURLOPT_FAILONERROR, fail as c_long) |
836 | } |
837 | |
838 | // ========================================================================= |
839 | // Network options |
840 | |
841 | /// Provides the URL which this handle will work with. |
842 | /// |
843 | /// The string provided must be URL-encoded with the format: |
844 | /// |
845 | /// ```text |
846 | /// scheme://host:port/path |
847 | /// ``` |
848 | /// |
849 | /// The syntax is not validated as part of this function and that is |
850 | /// deferred until later. |
851 | /// |
852 | /// By default this option is not set and `perform` will not work until it |
853 | /// is set. This option corresponds to `CURLOPT_URL`. |
854 | pub fn url(&mut self, url: &str) -> Result<(), Error> { |
855 | let url = CString::new(url)?; |
856 | self.setopt_str(curl_sys::CURLOPT_URL, &url) |
857 | } |
858 | |
859 | /// Configures the port number to connect to, instead of the one specified |
860 | /// in the URL or the default of the protocol. |
861 | pub fn port(&mut self, port: u16) -> Result<(), Error> { |
862 | self.setopt_long(curl_sys::CURLOPT_PORT, port as c_long) |
863 | } |
864 | |
865 | /// Connect to a specific host and port. |
866 | /// |
867 | /// Each single string should be written using the format |
868 | /// `HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT` where `HOST` is the host of |
869 | /// the request, `PORT` is the port of the request, `CONNECT-TO-HOST` is the |
870 | /// host name to connect to, and `CONNECT-TO-PORT` is the port to connect |
871 | /// to. |
872 | /// |
873 | /// The first string that matches the request's host and port is used. |
874 | /// |
875 | /// By default, this option is empty and corresponds to |
876 | /// [`CURLOPT_CONNECT_TO`](https://curl.haxx.se/libcurl/c/CURLOPT_CONNECT_TO.html). |
877 | pub fn connect_to(&mut self, list: List) -> Result<(), Error> { |
878 | let ptr = list::raw(&list); |
879 | self.inner.connect_to_list = Some(list); |
880 | self.setopt_ptr(curl_sys::CURLOPT_CONNECT_TO, ptr as *const _) |
881 | } |
882 | |
883 | /// Indicates whether sequences of `/../` and `/./` will be squashed or not. |
884 | /// |
885 | /// By default this option is `false` and corresponds to |
886 | /// `CURLOPT_PATH_AS_IS`. |
887 | pub fn path_as_is(&mut self, as_is: bool) -> Result<(), Error> { |
888 | self.setopt_long(curl_sys::CURLOPT_PATH_AS_IS, as_is as c_long) |
889 | } |
890 | |
891 | /// Provide the URL of a proxy to use. |
892 | /// |
893 | /// By default this option is not set and corresponds to `CURLOPT_PROXY`. |
894 | pub fn proxy(&mut self, url: &str) -> Result<(), Error> { |
895 | let url = CString::new(url)?; |
896 | self.setopt_str(curl_sys::CURLOPT_PROXY, &url) |
897 | } |
898 | |
899 | /// Provide port number the proxy is listening on. |
900 | /// |
901 | /// By default this option is not set (the default port for the proxy |
902 | /// protocol is used) and corresponds to `CURLOPT_PROXYPORT`. |
903 | pub fn proxy_port(&mut self, port: u16) -> Result<(), Error> { |
904 | self.setopt_long(curl_sys::CURLOPT_PROXYPORT, port as c_long) |
905 | } |
906 | |
907 | /// Set CA certificate to verify peer against for proxy. |
908 | /// |
909 | /// By default this value is not set and corresponds to |
910 | /// `CURLOPT_PROXY_CAINFO`. |
911 | pub fn proxy_cainfo(&mut self, cainfo: &str) -> Result<(), Error> { |
912 | let cainfo = CString::new(cainfo)?; |
913 | self.setopt_str(curl_sys::CURLOPT_PROXY_CAINFO, &cainfo) |
914 | } |
915 | |
916 | /// Specify a directory holding CA certificates for proxy. |
917 | /// |
918 | /// The specified directory should hold multiple CA certificates to verify |
919 | /// the HTTPS proxy with. If libcurl is built against OpenSSL, the |
920 | /// certificate directory must be prepared using the OpenSSL `c_rehash` |
921 | /// utility. |
922 | /// |
923 | /// By default this value is not set and corresponds to |
924 | /// `CURLOPT_PROXY_CAPATH`. |
925 | pub fn proxy_capath<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> { |
926 | self.setopt_path(curl_sys::CURLOPT_PROXY_CAPATH, path.as_ref()) |
927 | } |
928 | |
929 | /// Set client certificate for proxy. |
930 | /// |
931 | /// By default this value is not set and corresponds to |
932 | /// `CURLOPT_PROXY_SSLCERT`. |
933 | pub fn proxy_sslcert(&mut self, sslcert: &str) -> Result<(), Error> { |
934 | let sslcert = CString::new(sslcert)?; |
935 | self.setopt_str(curl_sys::CURLOPT_PROXY_SSLCERT, &sslcert) |
936 | } |
937 | |
938 | /// Specify type of the client SSL certificate for HTTPS proxy. |
939 | /// |
940 | /// The string should be the format of your certificate. Supported formats |
941 | /// are "PEM" and "DER", except with Secure Transport. OpenSSL (versions |
942 | /// 0.9.3 and later) and Secure Transport (on iOS 5 or later, or OS X 10.7 |
943 | /// or later) also support "P12" for PKCS#12-encoded files. |
944 | /// |
945 | /// By default this option is "PEM" and corresponds to |
946 | /// `CURLOPT_PROXY_SSLCERTTYPE`. |
947 | pub fn proxy_sslcert_type(&mut self, kind: &str) -> Result<(), Error> { |
948 | let kind = CString::new(kind)?; |
949 | self.setopt_str(curl_sys::CURLOPT_PROXY_SSLCERTTYPE, &kind) |
950 | } |
951 | |
952 | /// Set the client certificate for the proxy using an in-memory blob. |
953 | /// |
954 | /// The specified byte buffer should contain the binary content of the |
955 | /// certificate, which will be copied into the handle. |
956 | /// |
957 | /// By default this option is not set and corresponds to |
958 | /// `CURLOPT_PROXY_SSLCERT_BLOB`. |
959 | pub fn proxy_sslcert_blob(&mut self, blob: &[u8]) -> Result<(), Error> { |
960 | self.setopt_blob(curl_sys::CURLOPT_PROXY_SSLCERT_BLOB, blob) |
961 | } |
962 | |
963 | /// Set private key for HTTPS proxy. |
964 | /// |
965 | /// By default this value is not set and corresponds to |
966 | /// `CURLOPT_PROXY_SSLKEY`. |
967 | pub fn proxy_sslkey(&mut self, sslkey: &str) -> Result<(), Error> { |
968 | let sslkey = CString::new(sslkey)?; |
969 | self.setopt_str(curl_sys::CURLOPT_PROXY_SSLKEY, &sslkey) |
970 | } |
971 | |
972 | /// Set type of the private key file for HTTPS proxy. |
973 | /// |
974 | /// The string should be the format of your private key. Supported formats |
975 | /// are "PEM", "DER" and "ENG". |
976 | /// |
977 | /// The format "ENG" enables you to load the private key from a crypto |
978 | /// engine. In this case `ssl_key` is used as an identifier passed to |
979 | /// the engine. You have to set the crypto engine with `ssl_engine`. |
980 | /// "DER" format key file currently does not work because of a bug in |
981 | /// OpenSSL. |
982 | /// |
983 | /// By default this option is "PEM" and corresponds to |
984 | /// `CURLOPT_PROXY_SSLKEYTYPE`. |
985 | pub fn proxy_sslkey_type(&mut self, kind: &str) -> Result<(), Error> { |
986 | let kind = CString::new(kind)?; |
987 | self.setopt_str(curl_sys::CURLOPT_PROXY_SSLKEYTYPE, &kind) |
988 | } |
989 | |
990 | /// Set the private key for the proxy using an in-memory blob. |
991 | /// |
992 | /// The specified byte buffer should contain the binary content of the |
993 | /// private key, which will be copied into the handle. |
994 | /// |
995 | /// By default this option is not set and corresponds to |
996 | /// `CURLOPT_PROXY_SSLKEY_BLOB`. |
997 | pub fn proxy_sslkey_blob(&mut self, blob: &[u8]) -> Result<(), Error> { |
998 | self.setopt_blob(curl_sys::CURLOPT_PROXY_SSLKEY_BLOB, blob) |
999 | } |
1000 | |
1001 | /// Set passphrase to private key for HTTPS proxy. |
1002 | /// |
1003 | /// This will be used as the password required to use the `ssl_key`. |
1004 | /// You never needed a pass phrase to load a certificate but you need one to |
1005 | /// load your private key. |
1006 | /// |
1007 | /// By default this option is not set and corresponds to |
1008 | /// `CURLOPT_PROXY_KEYPASSWD`. |
1009 | pub fn proxy_key_password(&mut self, password: &str) -> Result<(), Error> { |
1010 | let password = CString::new(password)?; |
1011 | self.setopt_str(curl_sys::CURLOPT_PROXY_KEYPASSWD, &password) |
1012 | } |
1013 | |
1014 | /// Indicates the type of proxy being used. |
1015 | /// |
1016 | /// By default this option is `ProxyType::Http` and corresponds to |
1017 | /// `CURLOPT_PROXYTYPE`. |
1018 | pub fn proxy_type(&mut self, kind: ProxyType) -> Result<(), Error> { |
1019 | self.setopt_long(curl_sys::CURLOPT_PROXYTYPE, kind as c_long) |
1020 | } |
1021 | |
1022 | /// Provide a list of hosts that should not be proxied to. |
1023 | /// |
1024 | /// This string is a comma-separated list of hosts which should not use the |
1025 | /// proxy specified for connections. A single `*` character is also accepted |
1026 | /// as a wildcard for all hosts. |
1027 | /// |
1028 | /// By default this option is not set and corresponds to |
1029 | /// `CURLOPT_NOPROXY`. |
1030 | pub fn noproxy(&mut self, skip: &str) -> Result<(), Error> { |
1031 | let skip = CString::new(skip)?; |
1032 | self.setopt_str(curl_sys::CURLOPT_NOPROXY, &skip) |
1033 | } |
1034 | |
1035 | /// Inform curl whether it should tunnel all operations through the proxy. |
1036 | /// |
1037 | /// This essentially means that a `CONNECT` is sent to the proxy for all |
1038 | /// outbound requests. |
1039 | /// |
1040 | /// By default this option is `false` and corresponds to |
1041 | /// `CURLOPT_HTTPPROXYTUNNEL`. |
1042 | pub fn http_proxy_tunnel(&mut self, tunnel: bool) -> Result<(), Error> { |
1043 | self.setopt_long(curl_sys::CURLOPT_HTTPPROXYTUNNEL, tunnel as c_long) |
1044 | } |
1045 | |
1046 | /// Tell curl which interface to bind to for an outgoing network interface. |
1047 | /// |
1048 | /// The interface name, IP address, or host name can be specified here. |
1049 | /// |
1050 | /// By default this option is not set and corresponds to |
1051 | /// `CURLOPT_INTERFACE`. |
1052 | pub fn interface(&mut self, interface: &str) -> Result<(), Error> { |
1053 | let s = CString::new(interface)?; |
1054 | self.setopt_str(curl_sys::CURLOPT_INTERFACE, &s) |
1055 | } |
1056 | |
1057 | /// Indicate which port should be bound to locally for this connection. |
1058 | /// |
1059 | /// By default this option is 0 (any port) and corresponds to |
1060 | /// `CURLOPT_LOCALPORT`. |
1061 | pub fn set_local_port(&mut self, port: u16) -> Result<(), Error> { |
1062 | self.setopt_long(curl_sys::CURLOPT_LOCALPORT, port as c_long) |
1063 | } |
1064 | |
1065 | /// Indicates the number of attempts libcurl will perform to find a working |
1066 | /// port number. |
1067 | /// |
1068 | /// By default this option is 1 and corresponds to |
1069 | /// `CURLOPT_LOCALPORTRANGE`. |
1070 | pub fn local_port_range(&mut self, range: u16) -> Result<(), Error> { |
1071 | self.setopt_long(curl_sys::CURLOPT_LOCALPORTRANGE, range as c_long) |
1072 | } |
1073 | |
1074 | /// Sets the DNS servers that wil be used. |
1075 | /// |
1076 | /// Provide a comma separated list, for example: `8.8.8.8,8.8.4.4`. |
1077 | /// |
1078 | /// By default this option is not set and the OS's DNS resolver is used. |
1079 | /// This option can only be used if libcurl is linked against |
1080 | /// [c-ares](https://c-ares.haxx.se), otherwise setting it will return |
1081 | /// an error. |
1082 | pub fn dns_servers(&mut self, servers: &str) -> Result<(), Error> { |
1083 | let s = CString::new(servers)?; |
1084 | self.setopt_str(curl_sys::CURLOPT_DNS_SERVERS, &s) |
1085 | } |
1086 | |
1087 | /// Sets the timeout of how long name resolves will be kept in memory. |
1088 | /// |
1089 | /// This is distinct from DNS TTL options and is entirely speculative. |
1090 | /// |
1091 | /// By default this option is 60s and corresponds to |
1092 | /// `CURLOPT_DNS_CACHE_TIMEOUT`. |
1093 | pub fn dns_cache_timeout(&mut self, dur: Duration) -> Result<(), Error> { |
1094 | self.setopt_long(curl_sys::CURLOPT_DNS_CACHE_TIMEOUT, dur.as_secs() as c_long) |
1095 | } |
1096 | |
1097 | /// Provide the DNS-over-HTTPS URL. |
1098 | /// |
1099 | /// The parameter must be URL-encoded in the following format: |
1100 | /// `https://host:port/path`. It **must** specify a HTTPS URL. |
1101 | /// |
1102 | /// libcurl does not validate the syntax or use this variable until the |
1103 | /// transfer is issued. Even if you set a crazy value here, this method will |
1104 | /// still return [`Ok`]. |
1105 | /// |
1106 | /// curl sends `POST` requests to the given DNS-over-HTTPS URL. |
1107 | /// |
1108 | /// To find the DoH server itself, which might be specified using a name, |
1109 | /// libcurl will use the default name lookup function. You can bootstrap |
1110 | /// that by providing the address for the DoH server with |
1111 | /// [`Easy2::resolve`]. |
1112 | /// |
1113 | /// Disable DoH use again by setting this option to [`None`]. |
1114 | /// |
1115 | /// By default this option is not set and corresponds to `CURLOPT_DOH_URL`. |
1116 | pub fn doh_url(&mut self, url: Option<&str>) -> Result<(), Error> { |
1117 | if let Some(url) = url { |
1118 | let url = CString::new(url)?; |
1119 | self.setopt_str(curl_sys::CURLOPT_DOH_URL, &url) |
1120 | } else { |
1121 | self.setopt_ptr(curl_sys::CURLOPT_DOH_URL, ptr::null()) |
1122 | } |
1123 | } |
1124 | |
1125 | /// This option tells curl to verify the authenticity of the DoH |
1126 | /// (DNS-over-HTTPS) server's certificate. A value of `true` means curl |
1127 | /// verifies; `false` means it does not. |
1128 | /// |
1129 | /// This option is the DoH equivalent of [`Easy2::ssl_verify_peer`] and only |
1130 | /// affects requests to the DoH server. |
1131 | /// |
1132 | /// When negotiating a TLS or SSL connection, the server sends a certificate |
1133 | /// indicating its identity. Curl verifies whether the certificate is |
1134 | /// authentic, i.e. that you can trust that the server is who the |
1135 | /// certificate says it is. This trust is based on a chain of digital |
1136 | /// signatures, rooted in certification authority (CA) certificates you |
1137 | /// supply. curl uses a default bundle of CA certificates (the path for that |
1138 | /// is determined at build time) and you can specify alternate certificates |
1139 | /// with the [`Easy2::cainfo`] option or the [`Easy2::capath`] option. |
1140 | /// |
1141 | /// When `doh_ssl_verify_peer` is enabled, and the verification fails to |
1142 | /// prove that the certificate is authentic, the connection fails. When the |
1143 | /// option is zero, the peer certificate verification succeeds regardless. |
1144 | /// |
1145 | /// Authenticating the certificate is not enough to be sure about the |
1146 | /// server. You typically also want to ensure that the server is the server |
1147 | /// you mean to be talking to. Use [`Easy2::doh_ssl_verify_host`] for that. |
1148 | /// The check that the host name in the certificate is valid for the host |
1149 | /// name you are connecting to is done independently of the |
1150 | /// `doh_ssl_verify_peer` option. |
1151 | /// |
1152 | /// **WARNING:** disabling verification of the certificate allows bad guys |
1153 | /// to man-in-the-middle the communication without you knowing it. Disabling |
1154 | /// verification makes the communication insecure. Just having encryption on |
1155 | /// a transfer is not enough as you cannot be sure that you are |
1156 | /// communicating with the correct end-point. |
1157 | /// |
1158 | /// By default this option is set to `true` and corresponds to |
1159 | /// `CURLOPT_DOH_SSL_VERIFYPEER`. |
1160 | pub fn doh_ssl_verify_peer(&mut self, verify: bool) -> Result<(), Error> { |
1161 | self.setopt_long(curl_sys::CURLOPT_DOH_SSL_VERIFYPEER, verify.into()) |
1162 | } |
1163 | |
1164 | /// Tells curl to verify the DoH (DNS-over-HTTPS) server's certificate name |
1165 | /// fields against the host name. |
1166 | /// |
1167 | /// This option is the DoH equivalent of [`Easy2::ssl_verify_host`] and only |
1168 | /// affects requests to the DoH server. |
1169 | /// |
1170 | /// When `doh_ssl_verify_host` is `true`, the SSL certificate provided by |
1171 | /// the DoH server must indicate that the server name is the same as the |
1172 | /// server name to which you meant to connect to, or the connection fails. |
1173 | /// |
1174 | /// Curl considers the DoH server the intended one when the Common Name |
1175 | /// field or a Subject Alternate Name field in the certificate matches the |
1176 | /// host name in the DoH URL to which you told Curl to connect. |
1177 | /// |
1178 | /// When the verify value is set to `false`, the connection succeeds |
1179 | /// regardless of the names used in the certificate. Use that ability with |
1180 | /// caution! |
1181 | /// |
1182 | /// See also [`Easy2::doh_ssl_verify_peer`] to verify the digital signature |
1183 | /// of the DoH server certificate. If libcurl is built against NSS and |
1184 | /// [`Easy2::doh_ssl_verify_peer`] is `false`, `doh_ssl_verify_host` is also |
1185 | /// set to `false` and cannot be overridden. |
1186 | /// |
1187 | /// By default this option is set to `true` and corresponds to |
1188 | /// `CURLOPT_DOH_SSL_VERIFYHOST`. |
1189 | pub fn doh_ssl_verify_host(&mut self, verify: bool) -> Result<(), Error> { |
1190 | self.setopt_long( |
1191 | curl_sys::CURLOPT_DOH_SSL_VERIFYHOST, |
1192 | if verify { 2 } else { 0 }, |
1193 | ) |
1194 | } |
1195 | |
1196 | /// Pass a long as parameter set to 1 to enable or 0 to disable. |
1197 | /// |
1198 | /// This option determines whether libcurl verifies the status of the DoH |
1199 | /// (DNS-over-HTTPS) server cert using the "Certificate Status Request" TLS |
1200 | /// extension (aka. OCSP stapling). |
1201 | /// |
1202 | /// This option is the DoH equivalent of CURLOPT_SSL_VERIFYSTATUS and only |
1203 | /// affects requests to the DoH server. |
1204 | /// |
1205 | /// Note that if this option is enabled but the server does not support the |
1206 | /// TLS extension, the verification will fail. |
1207 | /// |
1208 | /// By default this option is set to `false` and corresponds to |
1209 | /// `CURLOPT_DOH_SSL_VERIFYSTATUS`. |
1210 | pub fn doh_ssl_verify_status(&mut self, verify: bool) -> Result<(), Error> { |
1211 | self.setopt_long(curl_sys::CURLOPT_DOH_SSL_VERIFYSTATUS, verify.into()) |
1212 | } |
1213 | |
1214 | /// Specify the preferred receive buffer size, in bytes. |
1215 | /// |
1216 | /// This is treated as a request, not an order, and the main point of this |
1217 | /// is that the write callback may get called more often with smaller |
1218 | /// chunks. |
1219 | /// |
1220 | /// By default this option is the maximum write size and corresopnds to |
1221 | /// `CURLOPT_BUFFERSIZE`. |
1222 | pub fn buffer_size(&mut self, size: usize) -> Result<(), Error> { |
1223 | self.setopt_long(curl_sys::CURLOPT_BUFFERSIZE, size as c_long) |
1224 | } |
1225 | |
1226 | /// Specify the preferred send buffer size, in bytes. |
1227 | /// |
1228 | /// This is treated as a request, not an order, and the main point of this |
1229 | /// is that the read callback may get called more often with smaller |
1230 | /// chunks. |
1231 | /// |
1232 | /// The upload buffer size is by default 64 kilobytes. |
1233 | pub fn upload_buffer_size(&mut self, size: usize) -> Result<(), Error> { |
1234 | self.setopt_long(curl_sys::CURLOPT_UPLOAD_BUFFERSIZE, size as c_long) |
1235 | } |
1236 | |
1237 | // /// Enable or disable TCP Fast Open |
1238 | // /// |
1239 | // /// By default this options defaults to `false` and corresponds to |
1240 | // /// `CURLOPT_TCP_FASTOPEN` |
1241 | // pub fn fast_open(&mut self, enable: bool) -> Result<(), Error> { |
1242 | // } |
1243 | |
1244 | /// Configures whether the TCP_NODELAY option is set, or Nagle's algorithm |
1245 | /// is disabled. |
1246 | /// |
1247 | /// The purpose of Nagle's algorithm is to minimize the number of small |
1248 | /// packet's on the network, and disabling this may be less efficient in |
1249 | /// some situations. |
1250 | /// |
1251 | /// By default this option is `false` and corresponds to |
1252 | /// `CURLOPT_TCP_NODELAY`. |
1253 | pub fn tcp_nodelay(&mut self, enable: bool) -> Result<(), Error> { |
1254 | self.setopt_long(curl_sys::CURLOPT_TCP_NODELAY, enable as c_long) |
1255 | } |
1256 | |
1257 | /// Configures whether TCP keepalive probes will be sent. |
1258 | /// |
1259 | /// The delay and frequency of these probes is controlled by `tcp_keepidle` |
1260 | /// and `tcp_keepintvl`. |
1261 | /// |
1262 | /// By default this option is `false` and corresponds to |
1263 | /// `CURLOPT_TCP_KEEPALIVE`. |
1264 | pub fn tcp_keepalive(&mut self, enable: bool) -> Result<(), Error> { |
1265 | self.setopt_long(curl_sys::CURLOPT_TCP_KEEPALIVE, enable as c_long) |
1266 | } |
1267 | |
1268 | /// Configures the TCP keepalive idle time wait. |
1269 | /// |
1270 | /// This is the delay, after which the connection is idle, keepalive probes |
1271 | /// will be sent. Not all operating systems support this. |
1272 | /// |
1273 | /// By default this corresponds to `CURLOPT_TCP_KEEPIDLE`. |
1274 | pub fn tcp_keepidle(&mut self, amt: Duration) -> Result<(), Error> { |
1275 | self.setopt_long(curl_sys::CURLOPT_TCP_KEEPIDLE, amt.as_secs() as c_long) |
1276 | } |
1277 | |
1278 | /// Configures the delay between keepalive probes. |
1279 | /// |
1280 | /// By default this corresponds to `CURLOPT_TCP_KEEPINTVL`. |
1281 | pub fn tcp_keepintvl(&mut self, amt: Duration) -> Result<(), Error> { |
1282 | self.setopt_long(curl_sys::CURLOPT_TCP_KEEPINTVL, amt.as_secs() as c_long) |
1283 | } |
1284 | |
1285 | /// Configures the scope for local IPv6 addresses. |
1286 | /// |
1287 | /// Sets the scope_id value to use when connecting to IPv6 or link-local |
1288 | /// addresses. |
1289 | /// |
1290 | /// By default this value is 0 and corresponds to `CURLOPT_ADDRESS_SCOPE` |
1291 | pub fn address_scope(&mut self, scope: u32) -> Result<(), Error> { |
1292 | self.setopt_long(curl_sys::CURLOPT_ADDRESS_SCOPE, scope as c_long) |
1293 | } |
1294 | |
1295 | // ========================================================================= |
1296 | // Names and passwords |
1297 | |
1298 | /// Configures the username to pass as authentication for this connection. |
1299 | /// |
1300 | /// By default this value is not set and corresponds to `CURLOPT_USERNAME`. |
1301 | pub fn username(&mut self, user: &str) -> Result<(), Error> { |
1302 | let user = CString::new(user)?; |
1303 | self.setopt_str(curl_sys::CURLOPT_USERNAME, &user) |
1304 | } |
1305 | |
1306 | /// Configures the password to pass as authentication for this connection. |
1307 | /// |
1308 | /// By default this value is not set and corresponds to `CURLOPT_PASSWORD`. |
1309 | pub fn password(&mut self, pass: &str) -> Result<(), Error> { |
1310 | let pass = CString::new(pass)?; |
1311 | self.setopt_str(curl_sys::CURLOPT_PASSWORD, &pass) |
1312 | } |
1313 | |
1314 | /// Set HTTP server authentication methods to try |
1315 | /// |
1316 | /// If more than one method is set, libcurl will first query the site to see |
1317 | /// which authentication methods it supports and then pick the best one you |
1318 | /// allow it to use. For some methods, this will induce an extra network |
1319 | /// round-trip. Set the actual name and password with the `password` and |
1320 | /// `username` methods. |
1321 | /// |
1322 | /// For authentication with a proxy, see `proxy_auth`. |
1323 | /// |
1324 | /// By default this value is basic and corresponds to `CURLOPT_HTTPAUTH`. |
1325 | pub fn http_auth(&mut self, auth: &Auth) -> Result<(), Error> { |
1326 | self.setopt_long(curl_sys::CURLOPT_HTTPAUTH, auth.bits) |
1327 | } |
1328 | |
1329 | /// Provides AWS V4 signature authentication on HTTP(S) header. |
1330 | /// |
1331 | /// `param` is used to create outgoing authentication headers. |
1332 | /// Its format is `provider1[:provider2[:region[:service]]]`. |
1333 | /// `provider1,\ provider2"` are used for generating auth parameters |
1334 | /// such as "Algorithm", "date", "request type" and "signed headers". |
1335 | /// `region` is the geographic area of a resources collection. It is |
1336 | /// extracted from the host name specified in the URL if omitted. |
1337 | /// `service` is a function provided by a cloud. It is extracted |
1338 | /// from the host name specified in the URL if omitted. |
1339 | /// |
1340 | /// Example with "Test:Try", when curl will do the algorithm, it will |
1341 | /// generate "TEST-HMAC-SHA256" for "Algorithm", "x-try-date" and |
1342 | /// "X-Try-Date" for "date", "test4_request" for "request type", and |
1343 | /// "SignedHeaders=content-type;host;x-try-date" for "signed headers". |
1344 | /// If you use just "test", instead of "test:try", test will be use |
1345 | /// for every strings generated. |
1346 | /// |
1347 | /// This is a special auth type that can't be combined with the others. |
1348 | /// It will override the other auth types you might have set. |
1349 | /// |
1350 | /// By default this is not set and corresponds to `CURLOPT_AWS_SIGV4`. |
1351 | pub fn aws_sigv4(&mut self, param: &str) -> Result<(), Error> { |
1352 | let param = CString::new(param)?; |
1353 | self.setopt_str(curl_sys::CURLOPT_AWS_SIGV4, ¶m) |
1354 | } |
1355 | |
1356 | /// Configures the proxy username to pass as authentication for this |
1357 | /// connection. |
1358 | /// |
1359 | /// By default this value is not set and corresponds to |
1360 | /// `CURLOPT_PROXYUSERNAME`. |
1361 | pub fn proxy_username(&mut self, user: &str) -> Result<(), Error> { |
1362 | let user = CString::new(user)?; |
1363 | self.setopt_str(curl_sys::CURLOPT_PROXYUSERNAME, &user) |
1364 | } |
1365 | |
1366 | /// Configures the proxy password to pass as authentication for this |
1367 | /// connection. |
1368 | /// |
1369 | /// By default this value is not set and corresponds to |
1370 | /// `CURLOPT_PROXYPASSWORD`. |
1371 | pub fn proxy_password(&mut self, pass: &str) -> Result<(), Error> { |
1372 | let pass = CString::new(pass)?; |
1373 | self.setopt_str(curl_sys::CURLOPT_PROXYPASSWORD, &pass) |
1374 | } |
1375 | |
1376 | /// Set HTTP proxy authentication methods to try |
1377 | /// |
1378 | /// If more than one method is set, libcurl will first query the site to see |
1379 | /// which authentication methods it supports and then pick the best one you |
1380 | /// allow it to use. For some methods, this will induce an extra network |
1381 | /// round-trip. Set the actual name and password with the `proxy_password` |
1382 | /// and `proxy_username` methods. |
1383 | /// |
1384 | /// By default this value is basic and corresponds to `CURLOPT_PROXYAUTH`. |
1385 | pub fn proxy_auth(&mut self, auth: &Auth) -> Result<(), Error> { |
1386 | self.setopt_long(curl_sys::CURLOPT_PROXYAUTH, auth.bits) |
1387 | } |
1388 | |
1389 | /// Enable .netrc parsing |
1390 | /// |
1391 | /// By default the .netrc file is ignored and corresponds to `CURL_NETRC_IGNORED`. |
1392 | pub fn netrc(&mut self, netrc: NetRc) -> Result<(), Error> { |
1393 | self.setopt_long(curl_sys::CURLOPT_NETRC, netrc as c_long) |
1394 | } |
1395 | |
1396 | // ========================================================================= |
1397 | // HTTP Options |
1398 | |
1399 | /// Indicates whether the referer header is automatically updated |
1400 | /// |
1401 | /// By default this option is `false` and corresponds to |
1402 | /// `CURLOPT_AUTOREFERER`. |
1403 | pub fn autoreferer(&mut self, enable: bool) -> Result<(), Error> { |
1404 | self.setopt_long(curl_sys::CURLOPT_AUTOREFERER, enable as c_long) |
1405 | } |
1406 | |
1407 | /// Enables automatic decompression of HTTP downloads. |
1408 | /// |
1409 | /// Sets the contents of the Accept-Encoding header sent in an HTTP request. |
1410 | /// This enables decoding of a response with Content-Encoding. |
1411 | /// |
1412 | /// Currently supported encoding are `identity`, `zlib`, and `gzip`. A |
1413 | /// zero-length string passed in will send all accepted encodings. |
1414 | /// |
1415 | /// By default this option is not set and corresponds to |
1416 | /// `CURLOPT_ACCEPT_ENCODING`. |
1417 | pub fn accept_encoding(&mut self, encoding: &str) -> Result<(), Error> { |
1418 | let encoding = CString::new(encoding)?; |
1419 | self.setopt_str(curl_sys::CURLOPT_ACCEPT_ENCODING, &encoding) |
1420 | } |
1421 | |
1422 | /// Request the HTTP Transfer Encoding. |
1423 | /// |
1424 | /// By default this option is `false` and corresponds to |
1425 | /// `CURLOPT_TRANSFER_ENCODING`. |
1426 | pub fn transfer_encoding(&mut self, enable: bool) -> Result<(), Error> { |
1427 | self.setopt_long(curl_sys::CURLOPT_TRANSFER_ENCODING, enable as c_long) |
1428 | } |
1429 | |
1430 | /// Follow HTTP 3xx redirects. |
1431 | /// |
1432 | /// Indicates whether any `Location` headers in the response should get |
1433 | /// followed. |
1434 | /// |
1435 | /// By default this option is `false` and corresponds to |
1436 | /// `CURLOPT_FOLLOWLOCATION`. |
1437 | pub fn follow_location(&mut self, enable: bool) -> Result<(), Error> { |
1438 | self.setopt_long(curl_sys::CURLOPT_FOLLOWLOCATION, enable as c_long) |
1439 | } |
1440 | |
1441 | /// Send credentials to hosts other than the first as well. |
1442 | /// |
1443 | /// Sends username/password credentials even when the host changes as part |
1444 | /// of a redirect. |
1445 | /// |
1446 | /// By default this option is `false` and corresponds to |
1447 | /// `CURLOPT_UNRESTRICTED_AUTH`. |
1448 | pub fn unrestricted_auth(&mut self, enable: bool) -> Result<(), Error> { |
1449 | self.setopt_long(curl_sys::CURLOPT_UNRESTRICTED_AUTH, enable as c_long) |
1450 | } |
1451 | |
1452 | /// Set the maximum number of redirects allowed. |
1453 | /// |
1454 | /// A value of 0 will refuse any redirect. |
1455 | /// |
1456 | /// By default this option is `-1` (unlimited) and corresponds to |
1457 | /// `CURLOPT_MAXREDIRS`. |
1458 | pub fn max_redirections(&mut self, max: u32) -> Result<(), Error> { |
1459 | self.setopt_long(curl_sys::CURLOPT_MAXREDIRS, max as c_long) |
1460 | } |
1461 | |
1462 | // TODO: post_redirections |
1463 | |
1464 | /// Make an HTTP PUT request. |
1465 | /// |
1466 | /// By default this option is `false` and corresponds to `CURLOPT_PUT`. |
1467 | pub fn put(&mut self, enable: bool) -> Result<(), Error> { |
1468 | self.setopt_long(curl_sys::CURLOPT_PUT, enable as c_long) |
1469 | } |
1470 | |
1471 | /// Make an HTTP POST request. |
1472 | /// |
1473 | /// This will also make the library use the |
1474 | /// `Content-Type: application/x-www-form-urlencoded` header. |
1475 | /// |
1476 | /// POST data can be specified through `post_fields` or by specifying a read |
1477 | /// function. |
1478 | /// |
1479 | /// By default this option is `false` and corresponds to `CURLOPT_POST`. |
1480 | pub fn post(&mut self, enable: bool) -> Result<(), Error> { |
1481 | self.setopt_long(curl_sys::CURLOPT_POST, enable as c_long) |
1482 | } |
1483 | |
1484 | /// Configures the data that will be uploaded as part of a POST. |
1485 | /// |
1486 | /// Note that the data is copied into this handle and if that's not desired |
1487 | /// then the read callbacks can be used instead. |
1488 | /// |
1489 | /// By default this option is not set and corresponds to |
1490 | /// `CURLOPT_COPYPOSTFIELDS`. |
1491 | pub fn post_fields_copy(&mut self, data: &[u8]) -> Result<(), Error> { |
1492 | // Set the length before the pointer so libcurl knows how much to read |
1493 | self.post_field_size(data.len() as u64)?; |
1494 | self.setopt_ptr(curl_sys::CURLOPT_COPYPOSTFIELDS, data.as_ptr() as *const _) |
1495 | } |
1496 | |
1497 | /// Configures the size of data that's going to be uploaded as part of a |
1498 | /// POST operation. |
1499 | /// |
1500 | /// This is called automatically as part of `post_fields` and should only |
1501 | /// be called if data is being provided in a read callback (and even then |
1502 | /// it's optional). |
1503 | /// |
1504 | /// By default this option is not set and corresponds to |
1505 | /// `CURLOPT_POSTFIELDSIZE_LARGE`. |
1506 | pub fn post_field_size(&mut self, size: u64) -> Result<(), Error> { |
1507 | // Clear anything previous to ensure we don't read past a buffer |
1508 | self.setopt_ptr(curl_sys::CURLOPT_POSTFIELDS, ptr::null())?; |
1509 | self.setopt_off_t( |
1510 | curl_sys::CURLOPT_POSTFIELDSIZE_LARGE, |
1511 | size as curl_sys::curl_off_t, |
1512 | ) |
1513 | } |
1514 | |
1515 | /// Tells libcurl you want a multipart/formdata HTTP POST to be made and you |
1516 | /// instruct what data to pass on to the server in the `form` argument. |
1517 | /// |
1518 | /// By default this option is set to null and corresponds to |
1519 | /// `CURLOPT_HTTPPOST`. |
1520 | pub fn httppost(&mut self, form: Form) -> Result<(), Error> { |
1521 | self.setopt_ptr(curl_sys::CURLOPT_HTTPPOST, form::raw(&form) as *const _)?; |
1522 | self.inner.form = Some(form); |
1523 | Ok(()) |
1524 | } |
1525 | |
1526 | /// Sets the HTTP referer header |
1527 | /// |
1528 | /// By default this option is not set and corresponds to `CURLOPT_REFERER`. |
1529 | pub fn referer(&mut self, referer: &str) -> Result<(), Error> { |
1530 | let referer = CString::new(referer)?; |
1531 | self.setopt_str(curl_sys::CURLOPT_REFERER, &referer) |
1532 | } |
1533 | |
1534 | /// Sets the HTTP user-agent header |
1535 | /// |
1536 | /// By default this option is not set and corresponds to |
1537 | /// `CURLOPT_USERAGENT`. |
1538 | pub fn useragent(&mut self, useragent: &str) -> Result<(), Error> { |
1539 | let useragent = CString::new(useragent)?; |
1540 | self.setopt_str(curl_sys::CURLOPT_USERAGENT, &useragent) |
1541 | } |
1542 | |
1543 | /// Add some headers to this HTTP request. |
1544 | /// |
1545 | /// If you add a header that is otherwise used internally, the value here |
1546 | /// takes precedence. If a header is added with no content (like `Accept:`) |
1547 | /// the internally the header will get disabled. To add a header with no |
1548 | /// content, use the form `MyHeader;` (not the trailing semicolon). |
1549 | /// |
1550 | /// Headers must not be CRLF terminated. Many replaced headers have common |
1551 | /// shortcuts which should be prefered. |
1552 | /// |
1553 | /// By default this option is not set and corresponds to |
1554 | /// `CURLOPT_HTTPHEADER` |
1555 | /// |
1556 | /// # Examples |
1557 | /// |
1558 | /// ``` |
1559 | /// use curl::easy::{Easy, List}; |
1560 | /// |
1561 | /// let mut list = List::new(); |
1562 | /// list.append("Foo: bar" ).unwrap(); |
1563 | /// list.append("Bar: baz" ).unwrap(); |
1564 | /// |
1565 | /// let mut handle = Easy::new(); |
1566 | /// handle.url("https://www.rust-lang.org/" ).unwrap(); |
1567 | /// handle.http_headers(list).unwrap(); |
1568 | /// handle.perform().unwrap(); |
1569 | /// ``` |
1570 | pub fn http_headers(&mut self, list: List) -> Result<(), Error> { |
1571 | let ptr = list::raw(&list); |
1572 | self.inner.header_list = Some(list); |
1573 | self.setopt_ptr(curl_sys::CURLOPT_HTTPHEADER, ptr as *const _) |
1574 | } |
1575 | |
1576 | // /// Add some headers to send to the HTTP proxy. |
1577 | // /// |
1578 | // /// This function is essentially the same as `http_headers`. |
1579 | // /// |
1580 | // /// By default this option is not set and corresponds to |
1581 | // /// `CURLOPT_PROXYHEADER` |
1582 | // pub fn proxy_headers(&mut self, list: &'a List) -> Result<(), Error> { |
1583 | // self.setopt_ptr(curl_sys::CURLOPT_PROXYHEADER, list.raw as *const _) |
1584 | // } |
1585 | |
1586 | /// Set the contents of the HTTP Cookie header. |
1587 | /// |
1588 | /// Pass a string of the form `name=contents` for one cookie value or |
1589 | /// `name1=val1; name2=val2` for multiple values. |
1590 | /// |
1591 | /// Using this option multiple times will only make the latest string |
1592 | /// override the previous ones. This option will not enable the cookie |
1593 | /// engine, use `cookie_file` or `cookie_jar` to do that. |
1594 | /// |
1595 | /// By default this option is not set and corresponds to `CURLOPT_COOKIE`. |
1596 | pub fn cookie(&mut self, cookie: &str) -> Result<(), Error> { |
1597 | let cookie = CString::new(cookie)?; |
1598 | self.setopt_str(curl_sys::CURLOPT_COOKIE, &cookie) |
1599 | } |
1600 | |
1601 | /// Set the file name to read cookies from. |
1602 | /// |
1603 | /// The cookie data can be in either the old Netscape / Mozilla cookie data |
1604 | /// format or just regular HTTP headers (Set-Cookie style) dumped to a file. |
1605 | /// |
1606 | /// This also enables the cookie engine, making libcurl parse and send |
1607 | /// cookies on subsequent requests with this handle. |
1608 | /// |
1609 | /// Given an empty or non-existing file or by passing the empty string ("") |
1610 | /// to this option, you can enable the cookie engine without reading any |
1611 | /// initial cookies. |
1612 | /// |
1613 | /// If you use this option multiple times, you just add more files to read. |
1614 | /// Subsequent files will add more cookies. |
1615 | /// |
1616 | /// By default this option is not set and corresponds to |
1617 | /// `CURLOPT_COOKIEFILE`. |
1618 | pub fn cookie_file<P: AsRef<Path>>(&mut self, file: P) -> Result<(), Error> { |
1619 | self.setopt_path(curl_sys::CURLOPT_COOKIEFILE, file.as_ref()) |
1620 | } |
1621 | |
1622 | /// Set the file name to store cookies to. |
1623 | /// |
1624 | /// This will make libcurl write all internally known cookies to the file |
1625 | /// when this handle is dropped. If no cookies are known, no file will be |
1626 | /// created. Specify "-" as filename to instead have the cookies written to |
1627 | /// stdout. Using this option also enables cookies for this session, so if |
1628 | /// you for example follow a location it will make matching cookies get sent |
1629 | /// accordingly. |
1630 | /// |
1631 | /// Note that libcurl doesn't read any cookies from the cookie jar. If you |
1632 | /// want to read cookies from a file, use `cookie_file`. |
1633 | /// |
1634 | /// By default this option is not set and corresponds to |
1635 | /// `CURLOPT_COOKIEJAR`. |
1636 | pub fn cookie_jar<P: AsRef<Path>>(&mut self, file: P) -> Result<(), Error> { |
1637 | self.setopt_path(curl_sys::CURLOPT_COOKIEJAR, file.as_ref()) |
1638 | } |
1639 | |
1640 | /// Start a new cookie session |
1641 | /// |
1642 | /// Marks this as a new cookie "session". It will force libcurl to ignore |
1643 | /// all cookies it is about to load that are "session cookies" from the |
1644 | /// previous session. By default, libcurl always stores and loads all |
1645 | /// cookies, independent if they are session cookies or not. Session cookies |
1646 | /// are cookies without expiry date and they are meant to be alive and |
1647 | /// existing for this "session" only. |
1648 | /// |
1649 | /// By default this option is `false` and corresponds to |
1650 | /// `CURLOPT_COOKIESESSION`. |
1651 | pub fn cookie_session(&mut self, session: bool) -> Result<(), Error> { |
1652 | self.setopt_long(curl_sys::CURLOPT_COOKIESESSION, session as c_long) |
1653 | } |
1654 | |
1655 | /// Add to or manipulate cookies held in memory. |
1656 | /// |
1657 | /// Such a cookie can be either a single line in Netscape / Mozilla format |
1658 | /// or just regular HTTP-style header (Set-Cookie: ...) format. This will |
1659 | /// also enable the cookie engine. This adds that single cookie to the |
1660 | /// internal cookie store. |
1661 | /// |
1662 | /// Exercise caution if you are using this option and multiple transfers may |
1663 | /// occur. If you use the Set-Cookie format and don't specify a domain then |
1664 | /// the cookie is sent for any domain (even after redirects are followed) |
1665 | /// and cannot be modified by a server-set cookie. If a server sets a cookie |
1666 | /// of the same name (or maybe you've imported one) then both will be sent |
1667 | /// on a future transfer to that server, likely not what you intended. |
1668 | /// address these issues set a domain in Set-Cookie or use the Netscape |
1669 | /// format. |
1670 | /// |
1671 | /// Additionally, there are commands available that perform actions if you |
1672 | /// pass in these exact strings: |
1673 | /// |
1674 | /// * "ALL" - erases all cookies held in memory |
1675 | /// * "SESS" - erases all session cookies held in memory |
1676 | /// * "FLUSH" - write all known cookies to the specified cookie jar |
1677 | /// * "RELOAD" - reread all cookies from the cookie file |
1678 | /// |
1679 | /// By default this options corresponds to `CURLOPT_COOKIELIST` |
1680 | pub fn cookie_list(&mut self, cookie: &str) -> Result<(), Error> { |
1681 | let cookie = CString::new(cookie)?; |
1682 | self.setopt_str(curl_sys::CURLOPT_COOKIELIST, &cookie) |
1683 | } |
1684 | |
1685 | /// Ask for a HTTP GET request. |
1686 | /// |
1687 | /// By default this option is `false` and corresponds to `CURLOPT_HTTPGET`. |
1688 | pub fn get(&mut self, enable: bool) -> Result<(), Error> { |
1689 | self.setopt_long(curl_sys::CURLOPT_HTTPGET, enable as c_long) |
1690 | } |
1691 | |
1692 | // /// Ask for a HTTP GET request. |
1693 | // /// |
1694 | // /// By default this option is `false` and corresponds to `CURLOPT_HTTPGET`. |
1695 | // pub fn http_version(&mut self, vers: &str) -> Result<(), Error> { |
1696 | // self.setopt_long(curl_sys::CURLOPT_HTTPGET, enable as c_long) |
1697 | // } |
1698 | |
1699 | /// Ignore the content-length header. |
1700 | /// |
1701 | /// By default this option is `false` and corresponds to |
1702 | /// `CURLOPT_IGNORE_CONTENT_LENGTH`. |
1703 | pub fn ignore_content_length(&mut self, ignore: bool) -> Result<(), Error> { |
1704 | self.setopt_long(curl_sys::CURLOPT_IGNORE_CONTENT_LENGTH, ignore as c_long) |
1705 | } |
1706 | |
1707 | /// Enable or disable HTTP content decoding. |
1708 | /// |
1709 | /// By default this option is `true` and corresponds to |
1710 | /// `CURLOPT_HTTP_CONTENT_DECODING`. |
1711 | pub fn http_content_decoding(&mut self, enable: bool) -> Result<(), Error> { |
1712 | self.setopt_long(curl_sys::CURLOPT_HTTP_CONTENT_DECODING, enable as c_long) |
1713 | } |
1714 | |
1715 | /// Enable or disable HTTP transfer decoding. |
1716 | /// |
1717 | /// By default this option is `true` and corresponds to |
1718 | /// `CURLOPT_HTTP_TRANSFER_DECODING`. |
1719 | pub fn http_transfer_decoding(&mut self, enable: bool) -> Result<(), Error> { |
1720 | self.setopt_long(curl_sys::CURLOPT_HTTP_TRANSFER_DECODING, enable as c_long) |
1721 | } |
1722 | |
1723 | // /// Timeout for the Expect: 100-continue response |
1724 | // /// |
1725 | // /// By default this option is 1s and corresponds to |
1726 | // /// `CURLOPT_EXPECT_100_TIMEOUT_MS`. |
1727 | // pub fn expect_100_timeout(&mut self, enable: bool) -> Result<(), Error> { |
1728 | // self.setopt_long(curl_sys::CURLOPT_HTTP_TRANSFER_DECODING, |
1729 | // enable as c_long) |
1730 | // } |
1731 | |
1732 | // /// Wait for pipelining/multiplexing. |
1733 | // /// |
1734 | // /// Tells libcurl to prefer to wait for a connection to confirm or deny that |
1735 | // /// it can do pipelining or multiplexing before continuing. |
1736 | // /// |
1737 | // /// When about to perform a new transfer that allows pipelining or |
1738 | // /// multiplexing, libcurl will check for existing connections to re-use and |
1739 | // /// pipeline on. If no such connection exists it will immediately continue |
1740 | // /// and create a fresh new connection to use. |
1741 | // /// |
1742 | // /// By setting this option to `true` - having `pipeline` enabled for the |
1743 | // /// multi handle this transfer is associated with - libcurl will instead |
1744 | // /// wait for the connection to reveal if it is possible to |
1745 | // /// pipeline/multiplex on before it continues. This enables libcurl to much |
1746 | // /// better keep the number of connections to a minimum when using pipelining |
1747 | // /// or multiplexing protocols. |
1748 | // /// |
1749 | // /// The effect thus becomes that with this option set, libcurl prefers to |
1750 | // /// wait and re-use an existing connection for pipelining rather than the |
1751 | // /// opposite: prefer to open a new connection rather than waiting. |
1752 | // /// |
1753 | // /// The waiting time is as long as it takes for the connection to get up and |
1754 | // /// for libcurl to get the necessary response back that informs it about its |
1755 | // /// protocol and support level. |
1756 | // pub fn http_pipewait(&mut self, enable: bool) -> Result<(), Error> { |
1757 | // } |
1758 | |
1759 | // ========================================================================= |
1760 | // Protocol Options |
1761 | |
1762 | /// Indicates the range that this request should retrieve. |
1763 | /// |
1764 | /// The string provided should be of the form `N-M` where either `N` or `M` |
1765 | /// can be left out. For HTTP transfers multiple ranges separated by commas |
1766 | /// are also accepted. |
1767 | /// |
1768 | /// By default this option is not set and corresponds to `CURLOPT_RANGE`. |
1769 | pub fn range(&mut self, range: &str) -> Result<(), Error> { |
1770 | let range = CString::new(range)?; |
1771 | self.setopt_str(curl_sys::CURLOPT_RANGE, &range) |
1772 | } |
1773 | |
1774 | /// Set a point to resume transfer from |
1775 | /// |
1776 | /// Specify the offset in bytes you want the transfer to start from. |
1777 | /// |
1778 | /// By default this option is 0 and corresponds to |
1779 | /// `CURLOPT_RESUME_FROM_LARGE`. |
1780 | pub fn resume_from(&mut self, from: u64) -> Result<(), Error> { |
1781 | self.setopt_off_t( |
1782 | curl_sys::CURLOPT_RESUME_FROM_LARGE, |
1783 | from as curl_sys::curl_off_t, |
1784 | ) |
1785 | } |
1786 | |
1787 | /// Set a custom request string |
1788 | /// |
1789 | /// Specifies that a custom request will be made (e.g. a custom HTTP |
1790 | /// method). This does not change how libcurl performs internally, just |
1791 | /// changes the string sent to the server. |
1792 | /// |
1793 | /// By default this option is not set and corresponds to |
1794 | /// `CURLOPT_CUSTOMREQUEST`. |
1795 | pub fn custom_request(&mut self, request: &str) -> Result<(), Error> { |
1796 | let request = CString::new(request)?; |
1797 | self.setopt_str(curl_sys::CURLOPT_CUSTOMREQUEST, &request) |
1798 | } |
1799 | |
1800 | /// Get the modification time of the remote resource |
1801 | /// |
1802 | /// If true, libcurl will attempt to get the modification time of the |
1803 | /// remote document in this operation. This requires that the remote server |
1804 | /// sends the time or replies to a time querying command. The `filetime` |
1805 | /// function can be used after a transfer to extract the received time (if |
1806 | /// any). |
1807 | /// |
1808 | /// By default this option is `false` and corresponds to `CURLOPT_FILETIME` |
1809 | pub fn fetch_filetime(&mut self, fetch: bool) -> Result<(), Error> { |
1810 | self.setopt_long(curl_sys::CURLOPT_FILETIME, fetch as c_long) |
1811 | } |
1812 | |
1813 | /// Indicate whether to download the request without getting the body |
1814 | /// |
1815 | /// This is useful, for example, for doing a HEAD request. |
1816 | /// |
1817 | /// By default this option is `false` and corresponds to `CURLOPT_NOBODY`. |
1818 | pub fn nobody(&mut self, enable: bool) -> Result<(), Error> { |
1819 | self.setopt_long(curl_sys::CURLOPT_NOBODY, enable as c_long) |
1820 | } |
1821 | |
1822 | /// Set the size of the input file to send off. |
1823 | /// |
1824 | /// By default this option is not set and corresponds to |
1825 | /// `CURLOPT_INFILESIZE_LARGE`. |
1826 | pub fn in_filesize(&mut self, size: u64) -> Result<(), Error> { |
1827 | self.setopt_off_t( |
1828 | curl_sys::CURLOPT_INFILESIZE_LARGE, |
1829 | size as curl_sys::curl_off_t, |
1830 | ) |
1831 | } |
1832 | |
1833 | /// Enable or disable data upload. |
1834 | /// |
1835 | /// This means that a PUT request will be made for HTTP and probably wants |
1836 | /// to be combined with the read callback as well as the `in_filesize` |
1837 | /// method. |
1838 | /// |
1839 | /// By default this option is `false` and corresponds to `CURLOPT_UPLOAD`. |
1840 | pub fn upload(&mut self, enable: bool) -> Result<(), Error> { |
1841 | self.setopt_long(curl_sys::CURLOPT_UPLOAD, enable as c_long) |
1842 | } |
1843 | |
1844 | /// Configure the maximum file size to download. |
1845 | /// |
1846 | /// By default this option is not set and corresponds to |
1847 | /// `CURLOPT_MAXFILESIZE_LARGE`. |
1848 | pub fn max_filesize(&mut self, size: u64) -> Result<(), Error> { |
1849 | self.setopt_off_t( |
1850 | curl_sys::CURLOPT_MAXFILESIZE_LARGE, |
1851 | size as curl_sys::curl_off_t, |
1852 | ) |
1853 | } |
1854 | |
1855 | /// Selects a condition for a time request. |
1856 | /// |
1857 | /// This value indicates how the `time_value` option is interpreted. |
1858 | /// |
1859 | /// By default this option is not set and corresponds to |
1860 | /// `CURLOPT_TIMECONDITION`. |
1861 | pub fn time_condition(&mut self, cond: TimeCondition) -> Result<(), Error> { |
1862 | self.setopt_long(curl_sys::CURLOPT_TIMECONDITION, cond as c_long) |
1863 | } |
1864 | |
1865 | /// Sets the time value for a conditional request. |
1866 | /// |
1867 | /// The value here should be the number of seconds elapsed since January 1, |
1868 | /// 1970. To pass how to interpret this value, use `time_condition`. |
1869 | /// |
1870 | /// By default this option is not set and corresponds to |
1871 | /// `CURLOPT_TIMEVALUE`. |
1872 | pub fn time_value(&mut self, val: i64) -> Result<(), Error> { |
1873 | self.setopt_long(curl_sys::CURLOPT_TIMEVALUE, val as c_long) |
1874 | } |
1875 | |
1876 | // ========================================================================= |
1877 | // Connection Options |
1878 | |
1879 | /// Set maximum time the request is allowed to take. |
1880 | /// |
1881 | /// Normally, name lookups can take a considerable time and limiting |
1882 | /// operations to less than a few minutes risk aborting perfectly normal |
1883 | /// operations. |
1884 | /// |
1885 | /// If libcurl is built to use the standard system name resolver, that |
1886 | /// portion of the transfer will still use full-second resolution for |
1887 | /// timeouts with a minimum timeout allowed of one second. |
1888 | /// |
1889 | /// In unix-like systems, this might cause signals to be used unless |
1890 | /// `nosignal` is set. |
1891 | /// |
1892 | /// Since this puts a hard limit for how long a request is allowed to |
1893 | /// take, it has limited use in dynamic use cases with varying transfer |
1894 | /// times. You are then advised to explore `low_speed_limit`, |
1895 | /// `low_speed_time` or using `progress_function` to implement your own |
1896 | /// timeout logic. |
1897 | /// |
1898 | /// By default this option is not set and corresponds to |
1899 | /// `CURLOPT_TIMEOUT_MS`. |
1900 | pub fn timeout(&mut self, timeout: Duration) -> Result<(), Error> { |
1901 | // TODO: checked arithmetic and casts |
1902 | // TODO: use CURLOPT_TIMEOUT if the timeout is too great |
1903 | let ms = timeout.as_secs() * 1000 + timeout.subsec_millis() as u64; |
1904 | self.setopt_long(curl_sys::CURLOPT_TIMEOUT_MS, ms as c_long) |
1905 | } |
1906 | |
1907 | /// Set the low speed limit in bytes per second. |
1908 | /// |
1909 | /// This specifies the average transfer speed in bytes per second that the |
1910 | /// transfer should be below during `low_speed_time` for libcurl to consider |
1911 | /// it to be too slow and abort. |
1912 | /// |
1913 | /// By default this option is not set and corresponds to |
1914 | /// `CURLOPT_LOW_SPEED_LIMIT`. |
1915 | pub fn low_speed_limit(&mut self, limit: u32) -> Result<(), Error> { |
1916 | self.setopt_long(curl_sys::CURLOPT_LOW_SPEED_LIMIT, limit as c_long) |
1917 | } |
1918 | |
1919 | /// Set the low speed time period. |
1920 | /// |
1921 | /// Specifies the window of time for which if the transfer rate is below |
1922 | /// `low_speed_limit` the request will be aborted. |
1923 | /// |
1924 | /// By default this option is not set and corresponds to |
1925 | /// `CURLOPT_LOW_SPEED_TIME`. |
1926 | pub fn low_speed_time(&mut self, dur: Duration) -> Result<(), Error> { |
1927 | self.setopt_long(curl_sys::CURLOPT_LOW_SPEED_TIME, dur.as_secs() as c_long) |
1928 | } |
1929 | |
1930 | /// Rate limit data upload speed |
1931 | /// |
1932 | /// If an upload exceeds this speed (counted in bytes per second) on |
1933 | /// cumulative average during the transfer, the transfer will pause to keep |
1934 | /// the average rate less than or equal to the parameter value. |
1935 | /// |
1936 | /// By default this option is not set (unlimited speed) and corresponds to |
1937 | /// `CURLOPT_MAX_SEND_SPEED_LARGE`. |
1938 | pub fn max_send_speed(&mut self, speed: u64) -> Result<(), Error> { |
1939 | self.setopt_off_t( |
1940 | curl_sys::CURLOPT_MAX_SEND_SPEED_LARGE, |
1941 | speed as curl_sys::curl_off_t, |
1942 | ) |
1943 | } |
1944 | |
1945 | /// Rate limit data download speed |
1946 | /// |
1947 | /// If a download exceeds this speed (counted in bytes per second) on |
1948 | /// cumulative average during the transfer, the transfer will pause to keep |
1949 | /// the average rate less than or equal to the parameter value. |
1950 | /// |
1951 | /// By default this option is not set (unlimited speed) and corresponds to |
1952 | /// `CURLOPT_MAX_RECV_SPEED_LARGE`. |
1953 | pub fn max_recv_speed(&mut self, speed: u64) -> Result<(), Error> { |
1954 | self.setopt_off_t( |
1955 | curl_sys::CURLOPT_MAX_RECV_SPEED_LARGE, |
1956 | speed as curl_sys::curl_off_t, |
1957 | ) |
1958 | } |
1959 | |
1960 | /// Set the maximum connection cache size. |
1961 | /// |
1962 | /// The set amount will be the maximum number of simultaneously open |
1963 | /// persistent connections that libcurl may cache in the pool associated |
1964 | /// with this handle. The default is 5, and there isn't much point in |
1965 | /// changing this value unless you are perfectly aware of how this works and |
1966 | /// changes libcurl's behaviour. This concerns connections using any of the |
1967 | /// protocols that support persistent connections. |
1968 | /// |
1969 | /// When reaching the maximum limit, curl closes the oldest one in the cache |
1970 | /// to prevent increasing the number of open connections. |
1971 | /// |
1972 | /// By default this option is set to 5 and corresponds to |
1973 | /// `CURLOPT_MAXCONNECTS` |
1974 | pub fn max_connects(&mut self, max: u32) -> Result<(), Error> { |
1975 | self.setopt_long(curl_sys::CURLOPT_MAXCONNECTS, max as c_long) |
1976 | } |
1977 | |
1978 | /// Set the maximum idle time allowed for a connection. |
1979 | /// |
1980 | /// This configuration sets the maximum time that a connection inside of the connection cache |
1981 | /// can be reused. Any connection older than this value will be considered stale and will |
1982 | /// be closed. |
1983 | /// |
1984 | /// By default, a value of 118 seconds is used. |
1985 | pub fn maxage_conn(&mut self, max_age: Duration) -> Result<(), Error> { |
1986 | self.setopt_long(curl_sys::CURLOPT_MAXAGE_CONN, max_age.as_secs() as c_long) |
1987 | } |
1988 | |
1989 | /// Force a new connection to be used. |
1990 | /// |
1991 | /// Makes the next transfer use a new (fresh) connection by force instead of |
1992 | /// trying to re-use an existing one. This option should be used with |
1993 | /// caution and only if you understand what it does as it may seriously |
1994 | /// impact performance. |
1995 | /// |
1996 | /// By default this option is `false` and corresponds to |
1997 | /// `CURLOPT_FRESH_CONNECT`. |
1998 | pub fn fresh_connect(&mut self, enable: bool) -> Result<(), Error> { |
1999 | self.setopt_long(curl_sys::CURLOPT_FRESH_CONNECT, enable as c_long) |
2000 | } |
2001 | |
2002 | /// Make connection get closed at once after use. |
2003 | /// |
2004 | /// Makes libcurl explicitly close the connection when done with the |
2005 | /// transfer. Normally, libcurl keeps all connections alive when done with |
2006 | /// one transfer in case a succeeding one follows that can re-use them. |
2007 | /// This option should be used with caution and only if you understand what |
2008 | /// it does as it can seriously impact performance. |
2009 | /// |
2010 | /// By default this option is `false` and corresponds to |
2011 | /// `CURLOPT_FORBID_REUSE`. |
2012 | pub fn forbid_reuse(&mut self, enable: bool) -> Result<(), Error> { |
2013 | self.setopt_long(curl_sys::CURLOPT_FORBID_REUSE, enable as c_long) |
2014 | } |
2015 | |
2016 | /// Timeout for the connect phase |
2017 | /// |
2018 | /// This is the maximum time that you allow the connection phase to the |
2019 | /// server to take. This only limits the connection phase, it has no impact |
2020 | /// once it has connected. |
2021 | /// |
2022 | /// By default this value is 300 seconds and corresponds to |
2023 | /// `CURLOPT_CONNECTTIMEOUT_MS`. |
2024 | pub fn connect_timeout(&mut self, timeout: Duration) -> Result<(), Error> { |
2025 | let ms = timeout.as_secs() * 1000 + timeout.subsec_millis() as u64; |
2026 | self.setopt_long(curl_sys::CURLOPT_CONNECTTIMEOUT_MS, ms as c_long) |
2027 | } |
2028 | |
2029 | /// Specify which IP protocol version to use |
2030 | /// |
2031 | /// Allows an application to select what kind of IP addresses to use when |
2032 | /// resolving host names. This is only interesting when using host names |
2033 | /// that resolve addresses using more than one version of IP. |
2034 | /// |
2035 | /// By default this value is "any" and corresponds to `CURLOPT_IPRESOLVE`. |
2036 | pub fn ip_resolve(&mut self, resolve: IpResolve) -> Result<(), Error> { |
2037 | self.setopt_long(curl_sys::CURLOPT_IPRESOLVE, resolve as c_long) |
2038 | } |
2039 | |
2040 | /// Specify custom host name to IP address resolves. |
2041 | /// |
2042 | /// Allows specifying hostname to IP mappins to use before trying the |
2043 | /// system resolver. |
2044 | /// |
2045 | /// # Examples |
2046 | /// |
2047 | /// ```no_run |
2048 | /// use curl::easy::{Easy, List}; |
2049 | /// |
2050 | /// let mut list = List::new(); |
2051 | /// list.append("www.rust-lang.org:443:185.199.108.153" ).unwrap(); |
2052 | /// |
2053 | /// let mut handle = Easy::new(); |
2054 | /// handle.url("https://www.rust-lang.org/" ).unwrap(); |
2055 | /// handle.resolve(list).unwrap(); |
2056 | /// handle.perform().unwrap(); |
2057 | /// ``` |
2058 | pub fn resolve(&mut self, list: List) -> Result<(), Error> { |
2059 | let ptr = list::raw(&list); |
2060 | self.inner.resolve_list = Some(list); |
2061 | self.setopt_ptr(curl_sys::CURLOPT_RESOLVE, ptr as *const _) |
2062 | } |
2063 | |
2064 | /// Configure whether to stop when connected to target server |
2065 | /// |
2066 | /// When enabled it tells the library to perform all the required proxy |
2067 | /// authentication and connection setup, but no data transfer, and then |
2068 | /// return. |
2069 | /// |
2070 | /// The option can be used to simply test a connection to a server. |
2071 | /// |
2072 | /// By default this value is `false` and corresponds to |
2073 | /// `CURLOPT_CONNECT_ONLY`. |
2074 | pub fn connect_only(&mut self, enable: bool) -> Result<(), Error> { |
2075 | self.setopt_long(curl_sys::CURLOPT_CONNECT_ONLY, enable as c_long) |
2076 | } |
2077 | |
2078 | // /// Set interface to speak DNS over. |
2079 | // /// |
2080 | // /// Set the name of the network interface that the DNS resolver should bind |
2081 | // /// to. This must be an interface name (not an address). |
2082 | // /// |
2083 | // /// By default this option is not set and corresponds to |
2084 | // /// `CURLOPT_DNS_INTERFACE`. |
2085 | // pub fn dns_interface(&mut self, interface: &str) -> Result<(), Error> { |
2086 | // let interface = CString::new(interface)?; |
2087 | // self.setopt_str(curl_sys::CURLOPT_DNS_INTERFACE, &interface) |
2088 | // } |
2089 | // |
2090 | // /// IPv4 address to bind DNS resolves to |
2091 | // /// |
2092 | // /// Set the local IPv4 address that the resolver should bind to. The |
2093 | // /// argument should be of type char * and contain a single numerical IPv4 |
2094 | // /// address as a string. |
2095 | // /// |
2096 | // /// By default this option is not set and corresponds to |
2097 | // /// `CURLOPT_DNS_LOCAL_IP4`. |
2098 | // pub fn dns_local_ip4(&mut self, ip: &str) -> Result<(), Error> { |
2099 | // let ip = CString::new(ip)?; |
2100 | // self.setopt_str(curl_sys::CURLOPT_DNS_LOCAL_IP4, &ip) |
2101 | // } |
2102 | // |
2103 | // /// IPv6 address to bind DNS resolves to |
2104 | // /// |
2105 | // /// Set the local IPv6 address that the resolver should bind to. The |
2106 | // /// argument should be of type char * and contain a single numerical IPv6 |
2107 | // /// address as a string. |
2108 | // /// |
2109 | // /// By default this option is not set and corresponds to |
2110 | // /// `CURLOPT_DNS_LOCAL_IP6`. |
2111 | // pub fn dns_local_ip6(&mut self, ip: &str) -> Result<(), Error> { |
2112 | // let ip = CString::new(ip)?; |
2113 | // self.setopt_str(curl_sys::CURLOPT_DNS_LOCAL_IP6, &ip) |
2114 | // } |
2115 | // |
2116 | // /// Set preferred DNS servers. |
2117 | // /// |
2118 | // /// Provides a list of DNS servers to be used instead of the system default. |
2119 | // /// The format of the dns servers option is: |
2120 | // /// |
2121 | // /// ```text |
2122 | // /// host[:port],[host[:port]]... |
2123 | // /// ``` |
2124 | // /// |
2125 | // /// By default this option is not set and corresponds to |
2126 | // /// `CURLOPT_DNS_SERVERS`. |
2127 | // pub fn dns_servers(&mut self, servers: &str) -> Result<(), Error> { |
2128 | // let servers = CString::new(servers)?; |
2129 | // self.setopt_str(curl_sys::CURLOPT_DNS_SERVERS, &servers) |
2130 | // } |
2131 | |
2132 | // ========================================================================= |
2133 | // SSL/Security Options |
2134 | |
2135 | /// Sets the SSL client certificate. |
2136 | /// |
2137 | /// The string should be the file name of your client certificate. The |
2138 | /// default format is "P12" on Secure Transport and "PEM" on other engines, |
2139 | /// and can be changed with `ssl_cert_type`. |
2140 | /// |
2141 | /// With NSS or Secure Transport, this can also be the nickname of the |
2142 | /// certificate you wish to authenticate with as it is named in the security |
2143 | /// database. If you want to use a file from the current directory, please |
2144 | /// precede it with "./" prefix, in order to avoid confusion with a |
2145 | /// nickname. |
2146 | /// |
2147 | /// When using a client certificate, you most likely also need to provide a |
2148 | /// private key with `ssl_key`. |
2149 | /// |
2150 | /// By default this option is not set and corresponds to `CURLOPT_SSLCERT`. |
2151 | pub fn ssl_cert<P: AsRef<Path>>(&mut self, cert: P) -> Result<(), Error> { |
2152 | self.setopt_path(curl_sys::CURLOPT_SSLCERT, cert.as_ref()) |
2153 | } |
2154 | |
2155 | /// Set the SSL client certificate using an in-memory blob. |
2156 | /// |
2157 | /// The specified byte buffer should contain the binary content of your |
2158 | /// client certificate, which will be copied into the handle. The format of |
2159 | /// the certificate can be specified with `ssl_cert_type`. |
2160 | /// |
2161 | /// By default this option is not set and corresponds to |
2162 | /// `CURLOPT_SSLCERT_BLOB`. |
2163 | pub fn ssl_cert_blob(&mut self, blob: &[u8]) -> Result<(), Error> { |
2164 | self.setopt_blob(curl_sys::CURLOPT_SSLCERT_BLOB, blob) |
2165 | } |
2166 | |
2167 | /// Specify type of the client SSL certificate. |
2168 | /// |
2169 | /// The string should be the format of your certificate. Supported formats |
2170 | /// are "PEM" and "DER", except with Secure Transport. OpenSSL (versions |
2171 | /// 0.9.3 and later) and Secure Transport (on iOS 5 or later, or OS X 10.7 |
2172 | /// or later) also support "P12" for PKCS#12-encoded files. |
2173 | /// |
2174 | /// By default this option is "PEM" and corresponds to |
2175 | /// `CURLOPT_SSLCERTTYPE`. |
2176 | pub fn ssl_cert_type(&mut self, kind: &str) -> Result<(), Error> { |
2177 | let kind = CString::new(kind)?; |
2178 | self.setopt_str(curl_sys::CURLOPT_SSLCERTTYPE, &kind) |
2179 | } |
2180 | |
2181 | /// Specify private keyfile for TLS and SSL client cert. |
2182 | /// |
2183 | /// The string should be the file name of your private key. The default |
2184 | /// format is "PEM" and can be changed with `ssl_key_type`. |
2185 | /// |
2186 | /// (iOS and Mac OS X only) This option is ignored if curl was built against |
2187 | /// Secure Transport. Secure Transport expects the private key to be already |
2188 | /// present in the keychain or PKCS#12 file containing the certificate. |
2189 | /// |
2190 | /// By default this option is not set and corresponds to `CURLOPT_SSLKEY`. |
2191 | pub fn ssl_key<P: AsRef<Path>>(&mut self, key: P) -> Result<(), Error> { |
2192 | self.setopt_path(curl_sys::CURLOPT_SSLKEY, key.as_ref()) |
2193 | } |
2194 | |
2195 | /// Specify an SSL private key using an in-memory blob. |
2196 | /// |
2197 | /// The specified byte buffer should contain the binary content of your |
2198 | /// private key, which will be copied into the handle. The format of |
2199 | /// the private key can be specified with `ssl_key_type`. |
2200 | /// |
2201 | /// By default this option is not set and corresponds to |
2202 | /// `CURLOPT_SSLKEY_BLOB`. |
2203 | pub fn ssl_key_blob(&mut self, blob: &[u8]) -> Result<(), Error> { |
2204 | self.setopt_blob(curl_sys::CURLOPT_SSLKEY_BLOB, blob) |
2205 | } |
2206 | |
2207 | /// Set type of the private key file. |
2208 | /// |
2209 | /// The string should be the format of your private key. Supported formats |
2210 | /// are "PEM", "DER" and "ENG". |
2211 | /// |
2212 | /// The format "ENG" enables you to load the private key from a crypto |
2213 | /// engine. In this case `ssl_key` is used as an identifier passed to |
2214 | /// the engine. You have to set the crypto engine with `ssl_engine`. |
2215 | /// "DER" format key file currently does not work because of a bug in |
2216 | /// OpenSSL. |
2217 | /// |
2218 | /// By default this option is "PEM" and corresponds to |
2219 | /// `CURLOPT_SSLKEYTYPE`. |
2220 | pub fn ssl_key_type(&mut self, kind: &str) -> Result<(), Error> { |
2221 | let kind = CString::new(kind)?; |
2222 | self.setopt_str(curl_sys::CURLOPT_SSLKEYTYPE, &kind) |
2223 | } |
2224 | |
2225 | /// Set passphrase to private key. |
2226 | /// |
2227 | /// This will be used as the password required to use the `ssl_key`. |
2228 | /// You never needed a pass phrase to load a certificate but you need one to |
2229 | /// load your private key. |
2230 | /// |
2231 | /// By default this option is not set and corresponds to |
2232 | /// `CURLOPT_KEYPASSWD`. |
2233 | pub fn key_password(&mut self, password: &str) -> Result<(), Error> { |
2234 | let password = CString::new(password)?; |
2235 | self.setopt_str(curl_sys::CURLOPT_KEYPASSWD, &password) |
2236 | } |
2237 | |
2238 | /// Set the SSL Certificate Authorities using an in-memory blob. |
2239 | /// |
2240 | /// The specified byte buffer should contain the binary content of one |
2241 | /// or more PEM-encoded CA certificates, which will be copied into |
2242 | /// the handle. |
2243 | /// |
2244 | /// By default this option is not set and corresponds to |
2245 | /// `CURLOPT_CAINFO_BLOB`. |
2246 | pub fn ssl_cainfo_blob(&mut self, blob: &[u8]) -> Result<(), Error> { |
2247 | self.setopt_blob(curl_sys::CURLOPT_CAINFO_BLOB, blob) |
2248 | } |
2249 | |
2250 | /// Set the SSL Certificate Authorities for HTTPS proxies using an in-memory |
2251 | /// blob. |
2252 | /// |
2253 | /// The specified byte buffer should contain the binary content of one |
2254 | /// or more PEM-encoded CA certificates, which will be copied into |
2255 | /// the handle. |
2256 | /// |
2257 | /// By default this option is not set and corresponds to |
2258 | /// `CURLOPT_PROXY_CAINFO_BLOB`. |
2259 | pub fn proxy_ssl_cainfo_blob(&mut self, blob: &[u8]) -> Result<(), Error> { |
2260 | self.setopt_blob(curl_sys::CURLOPT_PROXY_CAINFO_BLOB, blob) |
2261 | } |
2262 | |
2263 | /// Set the SSL engine identifier. |
2264 | /// |
2265 | /// This will be used as the identifier for the crypto engine you want to |
2266 | /// use for your private key. |
2267 | /// |
2268 | /// By default this option is not set and corresponds to |
2269 | /// `CURLOPT_SSLENGINE`. |
2270 | pub fn ssl_engine(&mut self, engine: &str) -> Result<(), Error> { |
2271 | let engine = CString::new(engine)?; |
2272 | self.setopt_str(curl_sys::CURLOPT_SSLENGINE, &engine) |
2273 | } |
2274 | |
2275 | /// Make this handle's SSL engine the default. |
2276 | /// |
2277 | /// By default this option is not set and corresponds to |
2278 | /// `CURLOPT_SSLENGINE_DEFAULT`. |
2279 | pub fn ssl_engine_default(&mut self, enable: bool) -> Result<(), Error> { |
2280 | self.setopt_long(curl_sys::CURLOPT_SSLENGINE_DEFAULT, enable as c_long) |
2281 | } |
2282 | |
2283 | // /// Enable TLS false start. |
2284 | // /// |
2285 | // /// This option determines whether libcurl should use false start during the |
2286 | // /// TLS handshake. False start is a mode where a TLS client will start |
2287 | // /// sending application data before verifying the server's Finished message, |
2288 | // /// thus saving a round trip when performing a full handshake. |
2289 | // /// |
2290 | // /// By default this option is not set and corresponds to |
2291 | // /// `CURLOPT_SSL_FALSESTARTE`. |
2292 | // pub fn ssl_false_start(&mut self, enable: bool) -> Result<(), Error> { |
2293 | // self.setopt_long(curl_sys::CURLOPT_SSLENGINE_DEFAULT, enable as c_long) |
2294 | // } |
2295 | |
2296 | /// Set preferred HTTP version. |
2297 | /// |
2298 | /// By default this option is not set and corresponds to |
2299 | /// `CURLOPT_HTTP_VERSION`. |
2300 | pub fn http_version(&mut self, version: HttpVersion) -> Result<(), Error> { |
2301 | self.setopt_long(curl_sys::CURLOPT_HTTP_VERSION, version as c_long) |
2302 | } |
2303 | |
2304 | /// Set preferred TLS/SSL version. |
2305 | /// |
2306 | /// By default this option is not set and corresponds to |
2307 | /// `CURLOPT_SSLVERSION`. |
2308 | pub fn ssl_version(&mut self, version: SslVersion) -> Result<(), Error> { |
2309 | self.setopt_long(curl_sys::CURLOPT_SSLVERSION, version as c_long) |
2310 | } |
2311 | |
2312 | /// Set preferred TLS/SSL version when connecting to an HTTPS proxy. |
2313 | /// |
2314 | /// By default this option is not set and corresponds to |
2315 | /// `CURLOPT_PROXY_SSLVERSION`. |
2316 | pub fn proxy_ssl_version(&mut self, version: SslVersion) -> Result<(), Error> { |
2317 | self.setopt_long(curl_sys::CURLOPT_PROXY_SSLVERSION, version as c_long) |
2318 | } |
2319 | |
2320 | /// Set preferred TLS/SSL version with minimum version and maximum version. |
2321 | /// |
2322 | /// By default this option is not set and corresponds to |
2323 | /// `CURLOPT_SSLVERSION`. |
2324 | pub fn ssl_min_max_version( |
2325 | &mut self, |
2326 | min_version: SslVersion, |
2327 | max_version: SslVersion, |
2328 | ) -> Result<(), Error> { |
2329 | let version = (min_version as c_long) | ((max_version as c_long) << 16); |
2330 | self.setopt_long(curl_sys::CURLOPT_SSLVERSION, version) |
2331 | } |
2332 | |
2333 | /// Set preferred TLS/SSL version with minimum version and maximum version |
2334 | /// when connecting to an HTTPS proxy. |
2335 | /// |
2336 | /// By default this option is not set and corresponds to |
2337 | /// `CURLOPT_PROXY_SSLVERSION`. |
2338 | pub fn proxy_ssl_min_max_version( |
2339 | &mut self, |
2340 | min_version: SslVersion, |
2341 | max_version: SslVersion, |
2342 | ) -> Result<(), Error> { |
2343 | let version = (min_version as c_long) | ((max_version as c_long) << 16); |
2344 | self.setopt_long(curl_sys::CURLOPT_PROXY_SSLVERSION, version) |
2345 | } |
2346 | |
2347 | /// Verify the certificate's name against host. |
2348 | /// |
2349 | /// This should be disabled with great caution! It basically disables the |
2350 | /// security features of SSL if it is disabled. |
2351 | /// |
2352 | /// By default this option is set to `true` and corresponds to |
2353 | /// `CURLOPT_SSL_VERIFYHOST`. |
2354 | pub fn ssl_verify_host(&mut self, verify: bool) -> Result<(), Error> { |
2355 | let val = if verify { 2 } else { 0 }; |
2356 | self.setopt_long(curl_sys::CURLOPT_SSL_VERIFYHOST, val) |
2357 | } |
2358 | |
2359 | /// Verify the certificate's name against host for HTTPS proxy. |
2360 | /// |
2361 | /// This should be disabled with great caution! It basically disables the |
2362 | /// security features of SSL if it is disabled. |
2363 | /// |
2364 | /// By default this option is set to `true` and corresponds to |
2365 | /// `CURLOPT_PROXY_SSL_VERIFYHOST`. |
2366 | pub fn proxy_ssl_verify_host(&mut self, verify: bool) -> Result<(), Error> { |
2367 | let val = if verify { 2 } else { 0 }; |
2368 | self.setopt_long(curl_sys::CURLOPT_PROXY_SSL_VERIFYHOST, val) |
2369 | } |
2370 | |
2371 | /// Verify the peer's SSL certificate. |
2372 | /// |
2373 | /// This should be disabled with great caution! It basically disables the |
2374 | /// security features of SSL if it is disabled. |
2375 | /// |
2376 | /// By default this option is set to `true` and corresponds to |
2377 | /// `CURLOPT_SSL_VERIFYPEER`. |
2378 | pub fn ssl_verify_peer(&mut self, verify: bool) -> Result<(), Error> { |
2379 | self.setopt_long(curl_sys::CURLOPT_SSL_VERIFYPEER, verify as c_long) |
2380 | } |
2381 | |
2382 | /// Verify the peer's SSL certificate for HTTPS proxy. |
2383 | /// |
2384 | /// This should be disabled with great caution! It basically disables the |
2385 | /// security features of SSL if it is disabled. |
2386 | /// |
2387 | /// By default this option is set to `true` and corresponds to |
2388 | /// `CURLOPT_PROXY_SSL_VERIFYPEER`. |
2389 | pub fn proxy_ssl_verify_peer(&mut self, verify: bool) -> Result<(), Error> { |
2390 | self.setopt_long(curl_sys::CURLOPT_PROXY_SSL_VERIFYPEER, verify as c_long) |
2391 | } |
2392 | |
2393 | // /// Verify the certificate's status. |
2394 | // /// |
2395 | // /// This option determines whether libcurl verifies the status of the server |
2396 | // /// cert using the "Certificate Status Request" TLS extension (aka. OCSP |
2397 | // /// stapling). |
2398 | // /// |
2399 | // /// By default this option is set to `false` and corresponds to |
2400 | // /// `CURLOPT_SSL_VERIFYSTATUS`. |
2401 | // pub fn ssl_verify_status(&mut self, verify: bool) -> Result<(), Error> { |
2402 | // self.setopt_long(curl_sys::CURLOPT_SSL_VERIFYSTATUS, verify as c_long) |
2403 | // } |
2404 | |
2405 | /// Specify the path to Certificate Authority (CA) bundle |
2406 | /// |
2407 | /// The file referenced should hold one or more certificates to verify the |
2408 | /// peer with. |
2409 | /// |
2410 | /// This option is by default set to the system path where libcurl's cacert |
2411 | /// bundle is assumed to be stored, as established at build time. |
2412 | /// |
2413 | /// If curl is built against the NSS SSL library, the NSS PEM PKCS#11 module |
2414 | /// (libnsspem.so) needs to be available for this option to work properly. |
2415 | /// |
2416 | /// By default this option is the system defaults, and corresponds to |
2417 | /// `CURLOPT_CAINFO`. |
2418 | pub fn cainfo<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> { |
2419 | self.setopt_path(curl_sys::CURLOPT_CAINFO, path.as_ref()) |
2420 | } |
2421 | |
2422 | /// Set the issuer SSL certificate filename |
2423 | /// |
2424 | /// Specifies a file holding a CA certificate in PEM format. If the option |
2425 | /// is set, an additional check against the peer certificate is performed to |
2426 | /// verify the issuer is indeed the one associated with the certificate |
2427 | /// provided by the option. This additional check is useful in multi-level |
2428 | /// PKI where one needs to enforce that the peer certificate is from a |
2429 | /// specific branch of the tree. |
2430 | /// |
2431 | /// This option makes sense only when used in combination with the |
2432 | /// [`Easy2::ssl_verify_peer`] option. Otherwise, the result of the check is |
2433 | /// not considered as failure. |
2434 | /// |
2435 | /// By default this option is not set and corresponds to |
2436 | /// `CURLOPT_ISSUERCERT`. |
2437 | pub fn issuer_cert<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> { |
2438 | self.setopt_path(curl_sys::CURLOPT_ISSUERCERT, path.as_ref()) |
2439 | } |
2440 | |
2441 | /// Set the issuer SSL certificate filename for HTTPS proxies |
2442 | /// |
2443 | /// Specifies a file holding a CA certificate in PEM format. If the option |
2444 | /// is set, an additional check against the peer certificate is performed to |
2445 | /// verify the issuer is indeed the one associated with the certificate |
2446 | /// provided by the option. This additional check is useful in multi-level |
2447 | /// PKI where one needs to enforce that the peer certificate is from a |
2448 | /// specific branch of the tree. |
2449 | /// |
2450 | /// This option makes sense only when used in combination with the |
2451 | /// [`Easy2::proxy_ssl_verify_peer`] option. Otherwise, the result of the |
2452 | /// check is not considered as failure. |
2453 | /// |
2454 | /// By default this option is not set and corresponds to |
2455 | /// `CURLOPT_PROXY_ISSUERCERT`. |
2456 | pub fn proxy_issuer_cert<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> { |
2457 | self.setopt_path(curl_sys::CURLOPT_PROXY_ISSUERCERT, path.as_ref()) |
2458 | } |
2459 | |
2460 | /// Set the issuer SSL certificate using an in-memory blob. |
2461 | /// |
2462 | /// The specified byte buffer should contain the binary content of a CA |
2463 | /// certificate in the PEM format. The certificate will be copied into the |
2464 | /// handle. |
2465 | /// |
2466 | /// By default this option is not set and corresponds to |
2467 | /// `CURLOPT_ISSUERCERT_BLOB`. |
2468 | pub fn issuer_cert_blob(&mut self, blob: &[u8]) -> Result<(), Error> { |
2469 | self.setopt_blob(curl_sys::CURLOPT_ISSUERCERT_BLOB, blob) |
2470 | } |
2471 | |
2472 | /// Set the issuer SSL certificate for HTTPS proxies using an in-memory blob. |
2473 | /// |
2474 | /// The specified byte buffer should contain the binary content of a CA |
2475 | /// certificate in the PEM format. The certificate will be copied into the |
2476 | /// handle. |
2477 | /// |
2478 | /// By default this option is not set and corresponds to |
2479 | /// `CURLOPT_PROXY_ISSUERCERT_BLOB`. |
2480 | pub fn proxy_issuer_cert_blob(&mut self, blob: &[u8]) -> Result<(), Error> { |
2481 | self.setopt_blob(curl_sys::CURLOPT_PROXY_ISSUERCERT_BLOB, blob) |
2482 | } |
2483 | |
2484 | /// Specify directory holding CA certificates |
2485 | /// |
2486 | /// Names a directory holding multiple CA certificates to verify the peer |
2487 | /// with. If libcurl is built against OpenSSL, the certificate directory |
2488 | /// must be prepared using the openssl c_rehash utility. This makes sense |
2489 | /// only when used in combination with the `ssl_verify_peer` option. |
2490 | /// |
2491 | /// By default this option is not set and corresponds to `CURLOPT_CAPATH`. |
2492 | pub fn capath<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> { |
2493 | self.setopt_path(curl_sys::CURLOPT_CAPATH, path.as_ref()) |
2494 | } |
2495 | |
2496 | /// Specify a Certificate Revocation List file |
2497 | /// |
2498 | /// Names a file with the concatenation of CRL (in PEM format) to use in the |
2499 | /// certificate validation that occurs during the SSL exchange. |
2500 | /// |
2501 | /// When curl is built to use NSS or GnuTLS, there is no way to influence |
2502 | /// the use of CRL passed to help in the verification process. When libcurl |
2503 | /// is built with OpenSSL support, X509_V_FLAG_CRL_CHECK and |
2504 | /// X509_V_FLAG_CRL_CHECK_ALL are both set, requiring CRL check against all |
2505 | /// the elements of the certificate chain if a CRL file is passed. |
2506 | /// |
2507 | /// This option makes sense only when used in combination with the |
2508 | /// [`Easy2::ssl_verify_peer`] option. |
2509 | /// |
2510 | /// A specific error code (`is_ssl_crl_badfile`) is defined with the |
2511 | /// option. It is returned when the SSL exchange fails because the CRL file |
2512 | /// cannot be loaded. A failure in certificate verification due to a |
2513 | /// revocation information found in the CRL does not trigger this specific |
2514 | /// error. |
2515 | /// |
2516 | /// By default this option is not set and corresponds to `CURLOPT_CRLFILE`. |
2517 | pub fn crlfile<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> { |
2518 | self.setopt_path(curl_sys::CURLOPT_CRLFILE, path.as_ref()) |
2519 | } |
2520 | |
2521 | /// Specify a Certificate Revocation List file to use when connecting to an |
2522 | /// HTTPS proxy. |
2523 | /// |
2524 | /// Names a file with the concatenation of CRL (in PEM format) to use in the |
2525 | /// certificate validation that occurs during the SSL exchange. |
2526 | /// |
2527 | /// When curl is built to use NSS or GnuTLS, there is no way to influence |
2528 | /// the use of CRL passed to help in the verification process. When libcurl |
2529 | /// is built with OpenSSL support, X509_V_FLAG_CRL_CHECK and |
2530 | /// X509_V_FLAG_CRL_CHECK_ALL are both set, requiring CRL check against all |
2531 | /// the elements of the certificate chain if a CRL file is passed. |
2532 | /// |
2533 | /// This option makes sense only when used in combination with the |
2534 | /// [`Easy2::proxy_ssl_verify_peer`] option. |
2535 | /// |
2536 | /// By default this option is not set and corresponds to |
2537 | /// `CURLOPT_PROXY_CRLFILE`. |
2538 | pub fn proxy_crlfile<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> { |
2539 | self.setopt_path(curl_sys::CURLOPT_PROXY_CRLFILE, path.as_ref()) |
2540 | } |
2541 | |
2542 | /// Request SSL certificate information |
2543 | /// |
2544 | /// Enable libcurl's certificate chain info gatherer. With this enabled, |
2545 | /// libcurl will extract lots of information and data about the certificates |
2546 | /// in the certificate chain used in the SSL connection. |
2547 | /// |
2548 | /// By default this option is `false` and corresponds to |
2549 | /// `CURLOPT_CERTINFO`. |
2550 | pub fn certinfo(&mut self, enable: bool) -> Result<(), Error> { |
2551 | self.setopt_long(curl_sys::CURLOPT_CERTINFO, enable as c_long) |
2552 | } |
2553 | |
2554 | /// Set pinned public key. |
2555 | /// |
2556 | /// Pass a pointer to a zero terminated string as parameter. The string can |
2557 | /// be the file name of your pinned public key. The file format expected is |
2558 | /// "PEM" or "DER". The string can also be any number of base64 encoded |
2559 | /// sha256 hashes preceded by "sha256//" and separated by ";" |
2560 | /// |
2561 | /// When negotiating a TLS or SSL connection, the server sends a certificate |
2562 | /// indicating its identity. A public key is extracted from this certificate |
2563 | /// and if it does not exactly match the public key provided to this option, |
2564 | /// curl will abort the connection before sending or receiving any data. |
2565 | /// |
2566 | /// By default this option is not set and corresponds to |
2567 | /// `CURLOPT_PINNEDPUBLICKEY`. |
2568 | pub fn pinned_public_key(&mut self, pubkey: &str) -> Result<(), Error> { |
2569 | let key = CString::new(pubkey)?; |
2570 | self.setopt_str(curl_sys::CURLOPT_PINNEDPUBLICKEY, &key) |
2571 | } |
2572 | |
2573 | /// Specify a source for random data |
2574 | /// |
2575 | /// The file will be used to read from to seed the random engine for SSL and |
2576 | /// more. |
2577 | /// |
2578 | /// By default this option is not set and corresponds to |
2579 | /// `CURLOPT_RANDOM_FILE`. |
2580 | pub fn random_file<P: AsRef<Path>>(&mut self, p: P) -> Result<(), Error> { |
2581 | self.setopt_path(curl_sys::CURLOPT_RANDOM_FILE, p.as_ref()) |
2582 | } |
2583 | |
2584 | /// Specify EGD socket path. |
2585 | /// |
2586 | /// Indicates the path name to the Entropy Gathering Daemon socket. It will |
2587 | /// be used to seed the random engine for SSL. |
2588 | /// |
2589 | /// By default this option is not set and corresponds to |
2590 | /// `CURLOPT_EGDSOCKET`. |
2591 | pub fn egd_socket<P: AsRef<Path>>(&mut self, p: P) -> Result<(), Error> { |
2592 | self.setopt_path(curl_sys::CURLOPT_EGDSOCKET, p.as_ref()) |
2593 | } |
2594 | |
2595 | /// Specify ciphers to use for TLS. |
2596 | /// |
2597 | /// Holds the list of ciphers to use for the SSL connection. The list must |
2598 | /// be syntactically correct, it consists of one or more cipher strings |
2599 | /// separated by colons. Commas or spaces are also acceptable separators |
2600 | /// but colons are normally used, !, - and + can be used as operators. |
2601 | /// |
2602 | /// For OpenSSL and GnuTLS valid examples of cipher lists include 'RC4-SHA', |
2603 | /// ´SHA1+DES´, 'TLSv1' and 'DEFAULT'. The default list is normally set when |
2604 | /// you compile OpenSSL. |
2605 | /// |
2606 | /// You'll find more details about cipher lists on this URL: |
2607 | /// |
2608 | /// https://www.openssl.org/docs/apps/ciphers.html |
2609 | /// |
2610 | /// For NSS, valid examples of cipher lists include 'rsa_rc4_128_md5', |
2611 | /// ´rsa_aes_128_sha´, etc. With NSS you don't add/remove ciphers. If one |
2612 | /// uses this option then all known ciphers are disabled and only those |
2613 | /// passed in are enabled. |
2614 | /// |
2615 | /// You'll find more details about the NSS cipher lists on this URL: |
2616 | /// |
2617 | /// http://git.fedorahosted.org/cgit/mod_nss.git/plain/docs/mod_nss.html#Directives |
2618 | /// |
2619 | /// By default this option is not set and corresponds to |
2620 | /// `CURLOPT_SSL_CIPHER_LIST`. |
2621 | pub fn ssl_cipher_list(&mut self, ciphers: &str) -> Result<(), Error> { |
2622 | let ciphers = CString::new(ciphers)?; |
2623 | self.setopt_str(curl_sys::CURLOPT_SSL_CIPHER_LIST, &ciphers) |
2624 | } |
2625 | |
2626 | /// Specify ciphers to use for TLS for an HTTPS proxy. |
2627 | /// |
2628 | /// Holds the list of ciphers to use for the SSL connection. The list must |
2629 | /// be syntactically correct, it consists of one or more cipher strings |
2630 | /// separated by colons. Commas or spaces are also acceptable separators |
2631 | /// but colons are normally used, !, - and + can be used as operators. |
2632 | /// |
2633 | /// For OpenSSL and GnuTLS valid examples of cipher lists include 'RC4-SHA', |
2634 | /// ´SHA1+DES´, 'TLSv1' and 'DEFAULT'. The default list is normally set when |
2635 | /// you compile OpenSSL. |
2636 | /// |
2637 | /// You'll find more details about cipher lists on this URL: |
2638 | /// |
2639 | /// https://www.openssl.org/docs/apps/ciphers.html |
2640 | /// |
2641 | /// For NSS, valid examples of cipher lists include 'rsa_rc4_128_md5', |
2642 | /// ´rsa_aes_128_sha´, etc. With NSS you don't add/remove ciphers. If one |
2643 | /// uses this option then all known ciphers are disabled and only those |
2644 | /// passed in are enabled. |
2645 | /// |
2646 | /// You'll find more details about the NSS cipher lists on this URL: |
2647 | /// |
2648 | /// http://git.fedorahosted.org/cgit/mod_nss.git/plain/docs/mod_nss.html#Directives |
2649 | /// |
2650 | /// By default this option is not set and corresponds to |
2651 | /// `CURLOPT_PROXY_SSL_CIPHER_LIST`. |
2652 | pub fn proxy_ssl_cipher_list(&mut self, ciphers: &str) -> Result<(), Error> { |
2653 | let ciphers = CString::new(ciphers)?; |
2654 | self.setopt_str(curl_sys::CURLOPT_PROXY_SSL_CIPHER_LIST, &ciphers) |
2655 | } |
2656 | |
2657 | /// Enable or disable use of the SSL session-ID cache |
2658 | /// |
2659 | /// By default all transfers are done using the cache enabled. While nothing |
2660 | /// ever should get hurt by attempting to reuse SSL session-IDs, there seem |
2661 | /// to be or have been broken SSL implementations in the wild that may |
2662 | /// require you to disable this in order for you to succeed. |
2663 | /// |
2664 | /// This corresponds to the `CURLOPT_SSL_SESSIONID_CACHE` option. |
2665 | pub fn ssl_sessionid_cache(&mut self, enable: bool) -> Result<(), Error> { |
2666 | self.setopt_long(curl_sys::CURLOPT_SSL_SESSIONID_CACHE, enable as c_long) |
2667 | } |
2668 | |
2669 | /// Set SSL behavior options |
2670 | /// |
2671 | /// Inform libcurl about SSL specific behaviors. |
2672 | /// |
2673 | /// This corresponds to the `CURLOPT_SSL_OPTIONS` option. |
2674 | pub fn ssl_options(&mut self, bits: &SslOpt) -> Result<(), Error> { |
2675 | self.setopt_long(curl_sys::CURLOPT_SSL_OPTIONS, bits.bits) |
2676 | } |
2677 | |
2678 | /// Set SSL behavior options for proxies |
2679 | /// |
2680 | /// Inform libcurl about SSL specific behaviors. |
2681 | /// |
2682 | /// This corresponds to the `CURLOPT_PROXY_SSL_OPTIONS` option. |
2683 | pub fn proxy_ssl_options(&mut self, bits: &SslOpt) -> Result<(), Error> { |
2684 | self.setopt_long(curl_sys::CURLOPT_PROXY_SSL_OPTIONS, bits.bits) |
2685 | } |
2686 | |
2687 | // /// Stores a private pointer-sized piece of data. |
2688 | // /// |
2689 | // /// This can be retrieved through the `private` function and otherwise |
2690 | // /// libcurl does not tamper with this value. This corresponds to |
2691 | // /// `CURLOPT_PRIVATE` and defaults to 0. |
2692 | // pub fn set_private(&mut self, private: usize) -> Result<(), Error> { |
2693 | // self.setopt_ptr(curl_sys::CURLOPT_PRIVATE, private as *const _) |
2694 | // } |
2695 | // |
2696 | // /// Fetches this handle's private pointer-sized piece of data. |
2697 | // /// |
2698 | // /// This corresponds to `CURLINFO_PRIVATE` and defaults to 0. |
2699 | // pub fn private(&mut self) -> Result<usize, Error> { |
2700 | // self.getopt_ptr(curl_sys::CURLINFO_PRIVATE).map(|p| p as usize) |
2701 | // } |
2702 | |
2703 | // ========================================================================= |
2704 | // getters |
2705 | |
2706 | /// Set maximum time to wait for Expect 100 request before sending body. |
2707 | /// |
2708 | /// `curl` has internal heuristics that trigger the use of a `Expect` |
2709 | /// header for large enough request bodies where the client first sends the |
2710 | /// request header along with an `Expect: 100-continue` header. The server |
2711 | /// is supposed to validate the headers and respond with a `100` response |
2712 | /// status code after which `curl` will send the actual request body. |
2713 | /// |
2714 | /// However, if the server does not respond to the initial request |
2715 | /// within `CURLOPT_EXPECT_100_TIMEOUT_MS` then `curl` will send the |
2716 | /// request body anyways. |
2717 | /// |
2718 | /// The best-case scenario is where the request is invalid and the server |
2719 | /// replies with a `417 Expectation Failed` without having to wait for or process |
2720 | /// the request body at all. However, this behaviour can also lead to higher |
2721 | /// total latency since in the best case, an additional server roundtrip is required |
2722 | /// and in the worst case, the request is delayed by `CURLOPT_EXPECT_100_TIMEOUT_MS`. |
2723 | /// |
2724 | /// More info: https://curl.se/libcurl/c/CURLOPT_EXPECT_100_TIMEOUT_MS.html |
2725 | /// |
2726 | /// By default this option is not set and corresponds to |
2727 | /// `CURLOPT_EXPECT_100_TIMEOUT_MS`. |
2728 | pub fn expect_100_timeout(&mut self, timeout: Duration) -> Result<(), Error> { |
2729 | let ms = timeout.as_secs() * 1000 + timeout.subsec_millis() as u64; |
2730 | self.setopt_long(curl_sys::CURLOPT_EXPECT_100_TIMEOUT_MS, ms as c_long) |
2731 | } |
2732 | |
2733 | /// Get info on unmet time conditional |
2734 | /// |
2735 | /// Returns if the condition provided in the previous request didn't match |
2736 | /// |
2737 | //// This corresponds to `CURLINFO_CONDITION_UNMET` and may return an error if the |
2738 | /// option is not supported |
2739 | pub fn time_condition_unmet(&mut self) -> Result<bool, Error> { |
2740 | self.getopt_long(curl_sys::CURLINFO_CONDITION_UNMET) |
2741 | .map(|r| r != 0) |
2742 | } |
2743 | |
2744 | /// Get the last used URL |
2745 | /// |
2746 | /// In cases when you've asked libcurl to follow redirects, it may |
2747 | /// not be the same value you set with `url`. |
2748 | /// |
2749 | /// This methods corresponds to the `CURLINFO_EFFECTIVE_URL` option. |
2750 | /// |
2751 | /// Returns `Ok(None)` if no effective url is listed or `Err` if an error |
2752 | /// happens or the underlying bytes aren't valid utf-8. |
2753 | pub fn effective_url(&mut self) -> Result<Option<&str>, Error> { |
2754 | self.getopt_str(curl_sys::CURLINFO_EFFECTIVE_URL) |
2755 | } |
2756 | |
2757 | /// Get the last used URL, in bytes |
2758 | /// |
2759 | /// In cases when you've asked libcurl to follow redirects, it may |
2760 | /// not be the same value you set with `url`. |
2761 | /// |
2762 | /// This methods corresponds to the `CURLINFO_EFFECTIVE_URL` option. |
2763 | /// |
2764 | /// Returns `Ok(None)` if no effective url is listed or `Err` if an error |
2765 | /// happens or the underlying bytes aren't valid utf-8. |
2766 | pub fn effective_url_bytes(&mut self) -> Result<Option<&[u8]>, Error> { |
2767 | self.getopt_bytes(curl_sys::CURLINFO_EFFECTIVE_URL) |
2768 | } |
2769 | |
2770 | /// Get the last response code |
2771 | /// |
2772 | /// The stored value will be zero if no server response code has been |
2773 | /// received. Note that a proxy's CONNECT response should be read with |
2774 | /// `http_connectcode` and not this. |
2775 | /// |
2776 | /// Corresponds to `CURLINFO_RESPONSE_CODE` and returns an error if this |
2777 | /// option is not supported. |
2778 | pub fn response_code(&mut self) -> Result<u32, Error> { |
2779 | self.getopt_long(curl_sys::CURLINFO_RESPONSE_CODE) |
2780 | .map(|c| c as u32) |
2781 | } |
2782 | |
2783 | /// Get the CONNECT response code |
2784 | /// |
2785 | /// Returns the last received HTTP proxy response code to a CONNECT request. |
2786 | /// The returned value will be zero if no such response code was available. |
2787 | /// |
2788 | /// Corresponds to `CURLINFO_HTTP_CONNECTCODE` and returns an error if this |
2789 | /// option is not supported. |
2790 | pub fn http_connectcode(&mut self) -> Result<u32, Error> { |
2791 | self.getopt_long(curl_sys::CURLINFO_HTTP_CONNECTCODE) |
2792 | .map(|c| c as u32) |
2793 | } |
2794 | |
2795 | /// Get the remote time of the retrieved document |
2796 | /// |
2797 | /// Returns the remote time of the retrieved document (in number of seconds |
2798 | /// since 1 Jan 1970 in the GMT/UTC time zone). If you get `None`, it can be |
2799 | /// because of many reasons (it might be unknown, the server might hide it |
2800 | /// or the server doesn't support the command that tells document time etc) |
2801 | /// and the time of the document is unknown. |
2802 | /// |
2803 | /// Note that you must tell the server to collect this information before |
2804 | /// the transfer is made, by using the `filetime` method to |
2805 | /// or you will unconditionally get a `None` back. |
2806 | /// |
2807 | /// This corresponds to `CURLINFO_FILETIME` and may return an error if the |
2808 | /// option is not supported |
2809 | pub fn filetime(&mut self) -> Result<Option<i64>, Error> { |
2810 | self.getopt_long(curl_sys::CURLINFO_FILETIME).map(|r| { |
2811 | if r == -1 { |
2812 | None |
2813 | } else { |
2814 | Some(r as i64) |
2815 | } |
2816 | }) |
2817 | } |
2818 | |
2819 | /// Get the number of downloaded bytes |
2820 | /// |
2821 | /// Returns the total amount of bytes that were downloaded. |
2822 | /// The amount is only for the latest transfer and will be reset again for each new transfer. |
2823 | /// This counts actual payload data, what's also commonly called body. |
2824 | /// All meta and header data are excluded and will not be counted in this number. |
2825 | /// |
2826 | /// This corresponds to `CURLINFO_SIZE_DOWNLOAD` and may return an error if the |
2827 | /// option is not supported |
2828 | pub fn download_size(&mut self) -> Result<f64, Error> { |
2829 | self.getopt_double(curl_sys::CURLINFO_SIZE_DOWNLOAD) |
2830 | .map(|r| r as f64) |
2831 | } |
2832 | |
2833 | /// Get the number of uploaded bytes |
2834 | /// |
2835 | /// Returns the total amount of bytes that were uploaded. |
2836 | /// |
2837 | /// This corresponds to `CURLINFO_SIZE_UPLOAD` and may return an error if the |
2838 | /// option is not supported |
2839 | pub fn upload_size(&mut self) -> Result<f64, Error> { |
2840 | self.getopt_double(curl_sys::CURLINFO_SIZE_UPLOAD) |
2841 | .map(|r| r as f64) |
2842 | } |
2843 | |
2844 | /// Get the content-length of the download |
2845 | /// |
2846 | /// Returns the content-length of the download. |
2847 | /// This is the value read from the Content-Length: field |
2848 | /// |
2849 | /// This corresponds to `CURLINFO_CONTENT_LENGTH_DOWNLOAD` and may return an error if the |
2850 | /// option is not supported |
2851 | pub fn content_length_download(&mut self) -> Result<f64, Error> { |
2852 | self.getopt_double(curl_sys::CURLINFO_CONTENT_LENGTH_DOWNLOAD) |
2853 | .map(|r| r as f64) |
2854 | } |
2855 | |
2856 | /// Get total time of previous transfer |
2857 | /// |
2858 | /// Returns the total time for the previous transfer, |
2859 | /// including name resolving, TCP connect etc. |
2860 | /// |
2861 | /// Corresponds to `CURLINFO_TOTAL_TIME` and may return an error if the |
2862 | /// option isn't supported. |
2863 | pub fn total_time(&mut self) -> Result<Duration, Error> { |
2864 | self.getopt_double(curl_sys::CURLINFO_TOTAL_TIME) |
2865 | .map(double_seconds_to_duration) |
2866 | } |
2867 | |
2868 | /// Get the name lookup time |
2869 | /// |
2870 | /// Returns the total time from the start |
2871 | /// until the name resolving was completed. |
2872 | /// |
2873 | /// Corresponds to `CURLINFO_NAMELOOKUP_TIME` and may return an error if the |
2874 | /// option isn't supported. |
2875 | pub fn namelookup_time(&mut self) -> Result<Duration, Error> { |
2876 | self.getopt_double(curl_sys::CURLINFO_NAMELOOKUP_TIME) |
2877 | .map(double_seconds_to_duration) |
2878 | } |
2879 | |
2880 | /// Get the time until connect |
2881 | /// |
2882 | /// Returns the total time from the start |
2883 | /// until the connection to the remote host (or proxy) was completed. |
2884 | /// |
2885 | /// Corresponds to `CURLINFO_CONNECT_TIME` and may return an error if the |
2886 | /// option isn't supported. |
2887 | pub fn connect_time(&mut self) -> Result<Duration, Error> { |
2888 | self.getopt_double(curl_sys::CURLINFO_CONNECT_TIME) |
2889 | .map(double_seconds_to_duration) |
2890 | } |
2891 | |
2892 | /// Get the time until the SSL/SSH handshake is completed |
2893 | /// |
2894 | /// Returns the total time it took from the start until the SSL/SSH |
2895 | /// connect/handshake to the remote host was completed. This time is most often |
2896 | /// very near to the `pretransfer_time` time, except for cases such as |
2897 | /// HTTP pipelining where the pretransfer time can be delayed due to waits in |
2898 | /// line for the pipeline and more. |
2899 | /// |
2900 | /// Corresponds to `CURLINFO_APPCONNECT_TIME` and may return an error if the |
2901 | /// option isn't supported. |
2902 | pub fn appconnect_time(&mut self) -> Result<Duration, Error> { |
2903 | self.getopt_double(curl_sys::CURLINFO_APPCONNECT_TIME) |
2904 | .map(double_seconds_to_duration) |
2905 | } |
2906 | |
2907 | /// Get the time until the file transfer start |
2908 | /// |
2909 | /// Returns the total time it took from the start until the file |
2910 | /// transfer is just about to begin. This includes all pre-transfer commands |
2911 | /// and negotiations that are specific to the particular protocol(s) involved. |
2912 | /// It does not involve the sending of the protocol- specific request that |
2913 | /// triggers a transfer. |
2914 | /// |
2915 | /// Corresponds to `CURLINFO_PRETRANSFER_TIME` and may return an error if the |
2916 | /// option isn't supported. |
2917 | pub fn pretransfer_time(&mut self) -> Result<Duration, Error> { |
2918 | self.getopt_double(curl_sys::CURLINFO_PRETRANSFER_TIME) |
2919 | .map(double_seconds_to_duration) |
2920 | } |
2921 | |
2922 | /// Get the time until the first byte is received |
2923 | /// |
2924 | /// Returns the total time it took from the start until the first |
2925 | /// byte is received by libcurl. This includes `pretransfer_time` and |
2926 | /// also the time the server needs to calculate the result. |
2927 | /// |
2928 | /// Corresponds to `CURLINFO_STARTTRANSFER_TIME` and may return an error if the |
2929 | /// option isn't supported. |
2930 | pub fn starttransfer_time(&mut self) -> Result<Duration, Error> { |
2931 | self.getopt_double(curl_sys::CURLINFO_STARTTRANSFER_TIME) |
2932 | .map(double_seconds_to_duration) |
2933 | } |
2934 | |
2935 | /// Get the time for all redirection steps |
2936 | /// |
2937 | /// Returns the total time it took for all redirection steps |
2938 | /// include name lookup, connect, pretransfer and transfer before final |
2939 | /// transaction was started. `redirect_time` contains the complete |
2940 | /// execution time for multiple redirections. |
2941 | /// |
2942 | /// Corresponds to `CURLINFO_REDIRECT_TIME` and may return an error if the |
2943 | /// option isn't supported. |
2944 | pub fn redirect_time(&mut self) -> Result<Duration, Error> { |
2945 | self.getopt_double(curl_sys::CURLINFO_REDIRECT_TIME) |
2946 | .map(double_seconds_to_duration) |
2947 | } |
2948 | |
2949 | /// Get the number of redirects |
2950 | /// |
2951 | /// Corresponds to `CURLINFO_REDIRECT_COUNT` and may return an error if the |
2952 | /// option isn't supported. |
2953 | pub fn redirect_count(&mut self) -> Result<u32, Error> { |
2954 | self.getopt_long(curl_sys::CURLINFO_REDIRECT_COUNT) |
2955 | .map(|c| c as u32) |
2956 | } |
2957 | |
2958 | /// Get the URL a redirect would go to |
2959 | /// |
2960 | /// Returns the URL a redirect would take you to if you would enable |
2961 | /// `follow_location`. This can come very handy if you think using the |
2962 | /// built-in libcurl redirect logic isn't good enough for you but you would |
2963 | /// still prefer to avoid implementing all the magic of figuring out the new |
2964 | /// URL. |
2965 | /// |
2966 | /// Corresponds to `CURLINFO_REDIRECT_URL` and may return an error if the |
2967 | /// url isn't valid utf-8 or an error happens. |
2968 | pub fn redirect_url(&mut self) -> Result<Option<&str>, Error> { |
2969 | self.getopt_str(curl_sys::CURLINFO_REDIRECT_URL) |
2970 | } |
2971 | |
2972 | /// Get the URL a redirect would go to, in bytes |
2973 | /// |
2974 | /// Returns the URL a redirect would take you to if you would enable |
2975 | /// `follow_location`. This can come very handy if you think using the |
2976 | /// built-in libcurl redirect logic isn't good enough for you but you would |
2977 | /// still prefer to avoid implementing all the magic of figuring out the new |
2978 | /// URL. |
2979 | /// |
2980 | /// Corresponds to `CURLINFO_REDIRECT_URL` and may return an error. |
2981 | pub fn redirect_url_bytes(&mut self) -> Result<Option<&[u8]>, Error> { |
2982 | self.getopt_bytes(curl_sys::CURLINFO_REDIRECT_URL) |
2983 | } |
2984 | |
2985 | /// Get size of retrieved headers |
2986 | /// |
2987 | /// Corresponds to `CURLINFO_HEADER_SIZE` and may return an error if the |
2988 | /// option isn't supported. |
2989 | pub fn header_size(&mut self) -> Result<u64, Error> { |
2990 | self.getopt_long(curl_sys::CURLINFO_HEADER_SIZE) |
2991 | .map(|c| c as u64) |
2992 | } |
2993 | |
2994 | /// Get size of sent request. |
2995 | /// |
2996 | /// Corresponds to `CURLINFO_REQUEST_SIZE` and may return an error if the |
2997 | /// option isn't supported. |
2998 | pub fn request_size(&mut self) -> Result<u64, Error> { |
2999 | self.getopt_long(curl_sys::CURLINFO_REQUEST_SIZE) |
3000 | .map(|c| c as u64) |
3001 | } |
3002 | |
3003 | /// Get Content-Type |
3004 | /// |
3005 | /// Returns the content-type of the downloaded object. This is the value |
3006 | /// read from the Content-Type: field. If you get `None`, it means that the |
3007 | /// server didn't send a valid Content-Type header or that the protocol |
3008 | /// used doesn't support this. |
3009 | /// |
3010 | /// Corresponds to `CURLINFO_CONTENT_TYPE` and may return an error if the |
3011 | /// option isn't supported. |
3012 | pub fn content_type(&mut self) -> Result<Option<&str>, Error> { |
3013 | self.getopt_str(curl_sys::CURLINFO_CONTENT_TYPE) |
3014 | } |
3015 | |
3016 | /// Get Content-Type, in bytes |
3017 | /// |
3018 | /// Returns the content-type of the downloaded object. This is the value |
3019 | /// read from the Content-Type: field. If you get `None`, it means that the |
3020 | /// server didn't send a valid Content-Type header or that the protocol |
3021 | /// used doesn't support this. |
3022 | /// |
3023 | /// Corresponds to `CURLINFO_CONTENT_TYPE` and may return an error if the |
3024 | /// option isn't supported. |
3025 | pub fn content_type_bytes(&mut self) -> Result<Option<&[u8]>, Error> { |
3026 | self.getopt_bytes(curl_sys::CURLINFO_CONTENT_TYPE) |
3027 | } |
3028 | |
3029 | /// Get errno number from last connect failure. |
3030 | /// |
3031 | /// Note that the value is only set on failure, it is not reset upon a |
3032 | /// successful operation. The number is OS and system specific. |
3033 | /// |
3034 | /// Corresponds to `CURLINFO_OS_ERRNO` and may return an error if the |
3035 | /// option isn't supported. |
3036 | pub fn os_errno(&mut self) -> Result<i32, Error> { |
3037 | self.getopt_long(curl_sys::CURLINFO_OS_ERRNO) |
3038 | .map(|c| c as i32) |
3039 | } |
3040 | |
3041 | /// Get IP address of last connection. |
3042 | /// |
3043 | /// Returns a string holding the IP address of the most recent connection |
3044 | /// done with this curl handle. This string may be IPv6 when that is |
3045 | /// enabled. |
3046 | /// |
3047 | /// Corresponds to `CURLINFO_PRIMARY_IP` and may return an error if the |
3048 | /// option isn't supported. |
3049 | pub fn primary_ip(&mut self) -> Result<Option<&str>, Error> { |
3050 | self.getopt_str(curl_sys::CURLINFO_PRIMARY_IP) |
3051 | } |
3052 | |
3053 | /// Get the latest destination port number |
3054 | /// |
3055 | /// Corresponds to `CURLINFO_PRIMARY_PORT` and may return an error if the |
3056 | /// option isn't supported. |
3057 | pub fn primary_port(&mut self) -> Result<u16, Error> { |
3058 | self.getopt_long(curl_sys::CURLINFO_PRIMARY_PORT) |
3059 | .map(|c| c as u16) |
3060 | } |
3061 | |
3062 | /// Get local IP address of last connection |
3063 | /// |
3064 | /// Returns a string holding the IP address of the local end of most recent |
3065 | /// connection done with this curl handle. This string may be IPv6 when that |
3066 | /// is enabled. |
3067 | /// |
3068 | /// Corresponds to `CURLINFO_LOCAL_IP` and may return an error if the |
3069 | /// option isn't supported. |
3070 | pub fn local_ip(&mut self) -> Result<Option<&str>, Error> { |
3071 | self.getopt_str(curl_sys::CURLINFO_LOCAL_IP) |
3072 | } |
3073 | |
3074 | /// Get the latest local port number |
3075 | /// |
3076 | /// Corresponds to `CURLINFO_LOCAL_PORT` and may return an error if the |
3077 | /// option isn't supported. |
3078 | pub fn local_port(&mut self) -> Result<u16, Error> { |
3079 | self.getopt_long(curl_sys::CURLINFO_LOCAL_PORT) |
3080 | .map(|c| c as u16) |
3081 | } |
3082 | |
3083 | /// Get all known cookies |
3084 | /// |
3085 | /// Returns a linked-list of all cookies cURL knows (expired ones, too). |
3086 | /// |
3087 | /// Corresponds to the `CURLINFO_COOKIELIST` option and may return an error |
3088 | /// if the option isn't supported. |
3089 | pub fn cookies(&mut self) -> Result<List, Error> { |
3090 | unsafe { |
3091 | let mut list = ptr::null_mut(); |
3092 | let rc = curl_sys::curl_easy_getinfo( |
3093 | self.inner.handle, |
3094 | curl_sys::CURLINFO_COOKIELIST, |
3095 | &mut list, |
3096 | ); |
3097 | self.cvt(rc)?; |
3098 | Ok(list::from_raw(list)) |
3099 | } |
3100 | } |
3101 | |
3102 | /// Wait for pipelining/multiplexing |
3103 | /// |
3104 | /// Set wait to `true` to tell libcurl to prefer to wait for a connection to |
3105 | /// confirm or deny that it can do pipelining or multiplexing before |
3106 | /// continuing. |
3107 | /// |
3108 | /// When about to perform a new transfer that allows pipelining or |
3109 | /// multiplexing, libcurl will check for existing connections to re-use and |
3110 | /// pipeline on. If no such connection exists it will immediately continue |
3111 | /// and create a fresh new connection to use. |
3112 | /// |
3113 | /// By setting this option to `true` - and having `pipelining(true, true)` |
3114 | /// enabled for the multi handle this transfer is associated with - libcurl |
3115 | /// will instead wait for the connection to reveal if it is possible to |
3116 | /// pipeline/multiplex on before it continues. This enables libcurl to much |
3117 | /// better keep the number of connections to a minimum when using pipelining |
3118 | /// or multiplexing protocols. |
3119 | /// |
3120 | /// The effect thus becomes that with this option set, libcurl prefers to |
3121 | /// wait and re-use an existing connection for pipelining rather than the |
3122 | /// opposite: prefer to open a new connection rather than waiting. |
3123 | /// |
3124 | /// The waiting time is as long as it takes for the connection to get up and |
3125 | /// for libcurl to get the necessary response back that informs it about its |
3126 | /// protocol and support level. |
3127 | /// |
3128 | /// This corresponds to the `CURLOPT_PIPEWAIT` option. |
3129 | pub fn pipewait(&mut self, wait: bool) -> Result<(), Error> { |
3130 | self.setopt_long(curl_sys::CURLOPT_PIPEWAIT, wait as c_long) |
3131 | } |
3132 | |
3133 | /// Allow HTTP/0.9 compliant responses |
3134 | /// |
3135 | /// Set allow to `true` to tell libcurl to allow HTTP/0.9 responses. A HTTP/0.9 |
3136 | /// response is a server response entirely without headers and only a body. |
3137 | /// |
3138 | /// By default this option is not set and corresponds to |
3139 | /// `CURLOPT_HTTP09_ALLOWED`. |
3140 | pub fn http_09_allowed(&mut self, allow: bool) -> Result<(), Error> { |
3141 | self.setopt_long(curl_sys::CURLOPT_HTTP09_ALLOWED, allow as c_long) |
3142 | } |
3143 | |
3144 | // ========================================================================= |
3145 | // Other methods |
3146 | |
3147 | /// After options have been set, this will perform the transfer described by |
3148 | /// the options. |
3149 | /// |
3150 | /// This performs the request in a synchronous fashion. This can be used |
3151 | /// multiple times for one easy handle and libcurl will attempt to re-use |
3152 | /// the same connection for all transfers. |
3153 | /// |
3154 | /// This method will preserve all options configured in this handle for the |
3155 | /// next request, and if that is not desired then the options can be |
3156 | /// manually reset or the `reset` method can be called. |
3157 | /// |
3158 | /// Note that this method takes `&self`, which is quite important! This |
3159 | /// allows applications to close over the handle in various callbacks to |
3160 | /// call methods like `unpause_write` and `unpause_read` while a transfer is |
3161 | /// in progress. |
3162 | pub fn perform(&self) -> Result<(), Error> { |
3163 | let ret = unsafe { self.cvt(curl_sys::curl_easy_perform(self.inner.handle)) }; |
3164 | panic::propagate(); |
3165 | ret |
3166 | } |
3167 | |
3168 | /// Some protocols have "connection upkeep" mechanisms. These mechanisms |
3169 | /// usually send some traffic on existing connections in order to keep them |
3170 | /// alive; this can prevent connections from being closed due to overzealous |
3171 | /// firewalls, for example. |
3172 | /// |
3173 | /// Currently the only protocol with a connection upkeep mechanism is |
3174 | /// HTTP/2: when the connection upkeep interval is exceeded and upkeep() is |
3175 | /// called, an HTTP/2 PING frame is sent on the connection. |
3176 | #[cfg (feature = "upkeep_7_62_0" )] |
3177 | pub fn upkeep(&self) -> Result<(), Error> { |
3178 | let ret = unsafe { self.cvt(curl_sys::curl_easy_upkeep(self.inner.handle)) }; |
3179 | panic::propagate(); |
3180 | return ret; |
3181 | } |
3182 | |
3183 | /// Unpause reading on a connection. |
3184 | /// |
3185 | /// Using this function, you can explicitly unpause a connection that was |
3186 | /// previously paused. |
3187 | /// |
3188 | /// A connection can be paused by letting the read or the write callbacks |
3189 | /// return `ReadError::Pause` or `WriteError::Pause`. |
3190 | /// |
3191 | /// To unpause, you may for example call this from the progress callback |
3192 | /// which gets called at least once per second, even if the connection is |
3193 | /// paused. |
3194 | /// |
3195 | /// The chance is high that you will get your write callback called before |
3196 | /// this function returns. |
3197 | pub fn unpause_read(&self) -> Result<(), Error> { |
3198 | unsafe { |
3199 | let rc = curl_sys::curl_easy_pause(self.inner.handle, curl_sys::CURLPAUSE_RECV_CONT); |
3200 | self.cvt(rc) |
3201 | } |
3202 | } |
3203 | |
3204 | /// Unpause writing on a connection. |
3205 | /// |
3206 | /// Using this function, you can explicitly unpause a connection that was |
3207 | /// previously paused. |
3208 | /// |
3209 | /// A connection can be paused by letting the read or the write callbacks |
3210 | /// return `ReadError::Pause` or `WriteError::Pause`. A write callback that |
3211 | /// returns pause signals to the library that it couldn't take care of any |
3212 | /// data at all, and that data will then be delivered again to the callback |
3213 | /// when the writing is later unpaused. |
3214 | /// |
3215 | /// To unpause, you may for example call this from the progress callback |
3216 | /// which gets called at least once per second, even if the connection is |
3217 | /// paused. |
3218 | pub fn unpause_write(&self) -> Result<(), Error> { |
3219 | unsafe { |
3220 | let rc = curl_sys::curl_easy_pause(self.inner.handle, curl_sys::CURLPAUSE_SEND_CONT); |
3221 | self.cvt(rc) |
3222 | } |
3223 | } |
3224 | |
3225 | /// URL encodes a string `s` |
3226 | pub fn url_encode(&mut self, s: &[u8]) -> String { |
3227 | if s.is_empty() { |
3228 | return String::new(); |
3229 | } |
3230 | unsafe { |
3231 | let p = curl_sys::curl_easy_escape( |
3232 | self.inner.handle, |
3233 | s.as_ptr() as *const _, |
3234 | s.len() as c_int, |
3235 | ); |
3236 | assert!(!p.is_null()); |
3237 | let ret = str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap(); |
3238 | let ret = String::from(ret); |
3239 | curl_sys::curl_free(p as *mut _); |
3240 | ret |
3241 | } |
3242 | } |
3243 | |
3244 | /// URL decodes a string `s`, returning `None` if it fails |
3245 | pub fn url_decode(&mut self, s: &str) -> Vec<u8> { |
3246 | if s.is_empty() { |
3247 | return Vec::new(); |
3248 | } |
3249 | |
3250 | // Work around https://curl.haxx.se/docs/adv_20130622.html, a bug where |
3251 | // if the last few characters are a bad escape then curl will have a |
3252 | // buffer overrun. |
3253 | let mut iter = s.chars().rev(); |
3254 | let orig_len = s.len(); |
3255 | let mut data; |
3256 | let mut s = s; |
3257 | if iter.next() == Some('%' ) || iter.next() == Some('%' ) || iter.next() == Some('%' ) { |
3258 | data = s.to_string(); |
3259 | data.push(0u8 as char); |
3260 | s = &data[..]; |
3261 | } |
3262 | unsafe { |
3263 | let mut len = 0; |
3264 | let p = curl_sys::curl_easy_unescape( |
3265 | self.inner.handle, |
3266 | s.as_ptr() as *const _, |
3267 | orig_len as c_int, |
3268 | &mut len, |
3269 | ); |
3270 | assert!(!p.is_null()); |
3271 | let slice = slice::from_raw_parts(p as *const u8, len as usize); |
3272 | let ret = slice.to_vec(); |
3273 | curl_sys::curl_free(p as *mut _); |
3274 | ret |
3275 | } |
3276 | } |
3277 | |
3278 | // TODO: I don't think this is safe, you can drop this which has all the |
3279 | // callback data and then the next is use-after-free |
3280 | // |
3281 | // /// Attempts to clone this handle, returning a new session handle with the |
3282 | // /// same options set for this handle. |
3283 | // /// |
3284 | // /// Internal state info and things like persistent connections ccannot be |
3285 | // /// transferred. |
3286 | // /// |
3287 | // /// # Errors |
3288 | // /// |
3289 | // /// If a new handle could not be allocated or another error happens, `None` |
3290 | // /// is returned. |
3291 | // pub fn try_clone<'b>(&mut self) -> Option<Easy<'b>> { |
3292 | // unsafe { |
3293 | // let handle = curl_sys::curl_easy_duphandle(self.handle); |
3294 | // if handle.is_null() { |
3295 | // None |
3296 | // } else { |
3297 | // Some(Easy { |
3298 | // handle: handle, |
3299 | // data: blank_data(), |
3300 | // _marker: marker::PhantomData, |
3301 | // }) |
3302 | // } |
3303 | // } |
3304 | // } |
3305 | |
3306 | /// Receives data from a connected socket. |
3307 | /// |
3308 | /// Only useful after a successful `perform` with the `connect_only` option |
3309 | /// set as well. |
3310 | pub fn recv(&mut self, data: &mut [u8]) -> Result<usize, Error> { |
3311 | unsafe { |
3312 | let mut n = 0; |
3313 | let r = curl_sys::curl_easy_recv( |
3314 | self.inner.handle, |
3315 | data.as_mut_ptr() as *mut _, |
3316 | data.len(), |
3317 | &mut n, |
3318 | ); |
3319 | if r == curl_sys::CURLE_OK { |
3320 | Ok(n) |
3321 | } else { |
3322 | Err(Error::new(r)) |
3323 | } |
3324 | } |
3325 | } |
3326 | |
3327 | /// Sends data over the connected socket. |
3328 | /// |
3329 | /// Only useful after a successful `perform` with the `connect_only` option |
3330 | /// set as well. |
3331 | pub fn send(&mut self, data: &[u8]) -> Result<usize, Error> { |
3332 | unsafe { |
3333 | let mut n = 0; |
3334 | let rc = curl_sys::curl_easy_send( |
3335 | self.inner.handle, |
3336 | data.as_ptr() as *const _, |
3337 | data.len(), |
3338 | &mut n, |
3339 | ); |
3340 | self.cvt(rc)?; |
3341 | Ok(n) |
3342 | } |
3343 | } |
3344 | |
3345 | /// Get a pointer to the raw underlying CURL handle. |
3346 | pub fn raw(&self) -> *mut curl_sys::CURL { |
3347 | self.inner.handle |
3348 | } |
3349 | |
3350 | #[cfg (unix)] |
3351 | fn setopt_path(&mut self, opt: curl_sys::CURLoption, val: &Path) -> Result<(), Error> { |
3352 | use std::os::unix::prelude::*; |
3353 | let s = CString::new(val.as_os_str().as_bytes())?; |
3354 | self.setopt_str(opt, &s) |
3355 | } |
3356 | |
3357 | #[cfg (windows)] |
3358 | fn setopt_path(&mut self, opt: curl_sys::CURLoption, val: &Path) -> Result<(), Error> { |
3359 | match val.to_str() { |
3360 | Some(s) => self.setopt_str(opt, &CString::new(s)?), |
3361 | None => Err(Error::new(curl_sys::CURLE_CONV_FAILED)), |
3362 | } |
3363 | } |
3364 | |
3365 | fn setopt_long(&mut self, opt: curl_sys::CURLoption, val: c_long) -> Result<(), Error> { |
3366 | unsafe { self.cvt(curl_sys::curl_easy_setopt(self.inner.handle, opt, val)) } |
3367 | } |
3368 | |
3369 | fn setopt_str(&mut self, opt: curl_sys::CURLoption, val: &CStr) -> Result<(), Error> { |
3370 | self.setopt_ptr(opt, val.as_ptr()) |
3371 | } |
3372 | |
3373 | fn setopt_ptr(&self, opt: curl_sys::CURLoption, val: *const c_char) -> Result<(), Error> { |
3374 | unsafe { self.cvt(curl_sys::curl_easy_setopt(self.inner.handle, opt, val)) } |
3375 | } |
3376 | |
3377 | fn setopt_off_t( |
3378 | &mut self, |
3379 | opt: curl_sys::CURLoption, |
3380 | val: curl_sys::curl_off_t, |
3381 | ) -> Result<(), Error> { |
3382 | unsafe { |
3383 | let rc = curl_sys::curl_easy_setopt(self.inner.handle, opt, val); |
3384 | self.cvt(rc) |
3385 | } |
3386 | } |
3387 | |
3388 | fn setopt_blob(&mut self, opt: curl_sys::CURLoption, val: &[u8]) -> Result<(), Error> { |
3389 | let blob = curl_sys::curl_blob { |
3390 | data: val.as_ptr() as *const c_void as *mut c_void, |
3391 | len: val.len(), |
3392 | flags: curl_sys::CURL_BLOB_COPY, |
3393 | }; |
3394 | let blob_ptr = &blob as *const curl_sys::curl_blob; |
3395 | unsafe { self.cvt(curl_sys::curl_easy_setopt(self.inner.handle, opt, blob_ptr)) } |
3396 | } |
3397 | |
3398 | fn getopt_bytes(&mut self, opt: curl_sys::CURLINFO) -> Result<Option<&[u8]>, Error> { |
3399 | unsafe { |
3400 | let p = self.getopt_ptr(opt)?; |
3401 | if p.is_null() { |
3402 | Ok(None) |
3403 | } else { |
3404 | Ok(Some(CStr::from_ptr(p).to_bytes())) |
3405 | } |
3406 | } |
3407 | } |
3408 | |
3409 | fn getopt_ptr(&mut self, opt: curl_sys::CURLINFO) -> Result<*const c_char, Error> { |
3410 | unsafe { |
3411 | let mut p = ptr::null(); |
3412 | let rc = curl_sys::curl_easy_getinfo(self.inner.handle, opt, &mut p); |
3413 | self.cvt(rc)?; |
3414 | Ok(p) |
3415 | } |
3416 | } |
3417 | |
3418 | fn getopt_str(&mut self, opt: curl_sys::CURLINFO) -> Result<Option<&str>, Error> { |
3419 | match self.getopt_bytes(opt) { |
3420 | Ok(None) => Ok(None), |
3421 | Err(e) => Err(e), |
3422 | Ok(Some(bytes)) => match str::from_utf8(bytes) { |
3423 | Ok(s) => Ok(Some(s)), |
3424 | Err(_) => Err(Error::new(curl_sys::CURLE_CONV_FAILED)), |
3425 | }, |
3426 | } |
3427 | } |
3428 | |
3429 | fn getopt_long(&mut self, opt: curl_sys::CURLINFO) -> Result<c_long, Error> { |
3430 | unsafe { |
3431 | let mut p = 0; |
3432 | let rc = curl_sys::curl_easy_getinfo(self.inner.handle, opt, &mut p); |
3433 | self.cvt(rc)?; |
3434 | Ok(p) |
3435 | } |
3436 | } |
3437 | |
3438 | fn getopt_double(&mut self, opt: curl_sys::CURLINFO) -> Result<c_double, Error> { |
3439 | unsafe { |
3440 | let mut p = 0 as c_double; |
3441 | let rc = curl_sys::curl_easy_getinfo(self.inner.handle, opt, &mut p); |
3442 | self.cvt(rc)?; |
3443 | Ok(p) |
3444 | } |
3445 | } |
3446 | |
3447 | /// Returns the contents of the internal error buffer, if available. |
3448 | /// |
3449 | /// When an easy handle is created it configured the `CURLOPT_ERRORBUFFER` |
3450 | /// parameter and instructs libcurl to store more error information into a |
3451 | /// buffer for better error messages and better debugging. The contents of |
3452 | /// that buffer are automatically coupled with all errors for methods on |
3453 | /// this type, but if manually invoking APIs the contents will need to be |
3454 | /// extracted with this method. |
3455 | /// |
3456 | /// Put another way, you probably don't need this, you're probably already |
3457 | /// getting nice error messages! |
3458 | /// |
3459 | /// This function will clear the internal buffer, so this is an operation |
3460 | /// that mutates the handle internally. |
3461 | pub fn take_error_buf(&self) -> Option<String> { |
3462 | let mut buf = self.inner.error_buf.borrow_mut(); |
3463 | if buf[0] == 0 { |
3464 | return None; |
3465 | } |
3466 | let pos = buf.iter().position(|i| *i == 0).unwrap_or(buf.len()); |
3467 | let msg = String::from_utf8_lossy(&buf[..pos]).into_owned(); |
3468 | buf[0] = 0; |
3469 | Some(msg) |
3470 | } |
3471 | |
3472 | fn cvt(&self, rc: curl_sys::CURLcode) -> Result<(), Error> { |
3473 | if rc == curl_sys::CURLE_OK { |
3474 | return Ok(()); |
3475 | } |
3476 | let mut err = Error::new(rc); |
3477 | if let Some(msg) = self.take_error_buf() { |
3478 | err.set_extra(msg); |
3479 | } |
3480 | Err(err) |
3481 | } |
3482 | } |
3483 | |
3484 | impl<H: fmt::Debug> fmt::Debug for Easy2<H> { |
3485 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
3486 | f&mut DebugStruct<'_, '_>.debug_struct("Easy" ) |
3487 | .field("handle" , &self.inner.handle) |
3488 | .field(name:"handler" , &self.inner.handler) |
3489 | .finish() |
3490 | } |
3491 | } |
3492 | |
3493 | impl<H> Drop for Easy2<H> { |
3494 | fn drop(&mut self) { |
3495 | unsafe { |
3496 | curl_sys::curl_easy_cleanup(self.inner.handle); |
3497 | } |
3498 | } |
3499 | } |
3500 | |
3501 | extern "C" fn header_cb<H: Handler>( |
3502 | buffer: *mut c_char, |
3503 | size: size_t, |
3504 | nitems: size_t, |
3505 | userptr: *mut c_void, |
3506 | ) -> size_t { |
3507 | let keep_going: bool = panic::catch(|| unsafe { |
3508 | let data = slice::from_raw_parts(buffer as *const u8, size * nitems); |
3509 | (*(userptr as *mut Inner<H>)).handler.header(data) |
3510 | }) |
3511 | .unwrap_or(default:false); |
3512 | if keep_going { |
3513 | size * nitems |
3514 | } else { |
3515 | !0 |
3516 | } |
3517 | } |
3518 | |
3519 | extern "C" fn write_cb<H: Handler>( |
3520 | ptr: *mut c_char, |
3521 | size: size_t, |
3522 | nmemb: size_t, |
3523 | data: *mut c_void, |
3524 | ) -> size_t { |
3525 | panic::catch(|| unsafe { |
3526 | let input = slice::from_raw_parts(ptr as *const u8, size * nmemb); |
3527 | match (*(data as *mut Inner<H>)).handler.write(input) { |
3528 | Ok(s) => s, |
3529 | Err(WriteError::Pause) => curl_sys::CURL_WRITEFUNC_PAUSE, |
3530 | } |
3531 | }) |
3532 | .unwrap_or(!0) |
3533 | } |
3534 | |
3535 | extern "C" fn read_cb<H: Handler>( |
3536 | ptr: *mut c_char, |
3537 | size: size_t, |
3538 | nmemb: size_t, |
3539 | data: *mut c_void, |
3540 | ) -> size_t { |
3541 | panic::catch(|| unsafe { |
3542 | let input = slice::from_raw_parts_mut(ptr as *mut u8, size * nmemb); |
3543 | match (*(data as *mut Inner<H>)).handler.read(input) { |
3544 | Ok(s) => s, |
3545 | Err(ReadError::Pause) => curl_sys::CURL_READFUNC_PAUSE, |
3546 | Err(ReadError::Abort) => curl_sys::CURL_READFUNC_ABORT, |
3547 | } |
3548 | }) |
3549 | .unwrap_or(!0) |
3550 | } |
3551 | |
3552 | extern "C" fn seek_cb<H: Handler>( |
3553 | data: *mut c_void, |
3554 | offset: curl_sys::curl_off_t, |
3555 | origin: c_int, |
3556 | ) -> c_int { |
3557 | panic::catch(|| unsafe { |
3558 | let from = if origin == libc::SEEK_SET { |
3559 | SeekFrom::Start(offset as u64) |
3560 | } else { |
3561 | panic!("unknown origin from libcurl: {}" , origin); |
3562 | }; |
3563 | (*(data as *mut Inner<H>)).handler.seek(from) as c_int |
3564 | }) |
3565 | .unwrap_or(!0) |
3566 | } |
3567 | |
3568 | extern "C" fn progress_cb<H: Handler>( |
3569 | data: *mut c_void, |
3570 | dltotal: c_double, |
3571 | dlnow: c_double, |
3572 | ultotal: c_double, |
3573 | ulnow: c_double, |
3574 | ) -> c_int { |
3575 | let keep_going: bool = panic::catch(|| unsafe { |
3576 | (*(data as *mut Inner<H>)) |
3577 | .handler |
3578 | .progress(dltotal, dlnow, ultotal, ulnow) |
3579 | }) |
3580 | .unwrap_or(default:false); |
3581 | if keep_going { |
3582 | 0 |
3583 | } else { |
3584 | 1 |
3585 | } |
3586 | } |
3587 | |
3588 | // TODO: expose `handle`? is that safe? |
3589 | extern "C" fn debug_cb<H: Handler>( |
3590 | _handle: *mut curl_sys::CURL, |
3591 | kind: curl_sys::curl_infotype, |
3592 | data: *mut c_char, |
3593 | size: size_t, |
3594 | userptr: *mut c_void, |
3595 | ) -> c_int { |
3596 | panic::catch(|| unsafe { |
3597 | let data: &[u8] = slice::from_raw_parts(data as *const u8, len:size); |
3598 | let kind: InfoType = match kind { |
3599 | curl_sys::CURLINFO_TEXT => InfoType::Text, |
3600 | curl_sys::CURLINFO_HEADER_IN => InfoType::HeaderIn, |
3601 | curl_sys::CURLINFO_HEADER_OUT => InfoType::HeaderOut, |
3602 | curl_sys::CURLINFO_DATA_IN => InfoType::DataIn, |
3603 | curl_sys::CURLINFO_DATA_OUT => InfoType::DataOut, |
3604 | curl_sys::CURLINFO_SSL_DATA_IN => InfoType::SslDataIn, |
3605 | curl_sys::CURLINFO_SSL_DATA_OUT => InfoType::SslDataOut, |
3606 | _ => return, |
3607 | }; |
3608 | (*(userptr as *mut Inner<H>)).handler.debug(kind, data) |
3609 | }); |
3610 | 0 |
3611 | } |
3612 | |
3613 | extern "C" fn ssl_ctx_cb<H: Handler>( |
3614 | _handle: *mut curl_sys::CURL, |
3615 | ssl_ctx: *mut c_void, |
3616 | data: *mut c_void, |
3617 | ) -> curl_sys::CURLcode { |
3618 | let res: Option = panic::catch(|| unsafe { |
3619 | match (*(data as *mut Inner<H>)).handler.ssl_ctx(cx:ssl_ctx) { |
3620 | Ok(()) => curl_sys::CURLE_OK, |
3621 | Err(e: Error) => e.code(), |
3622 | } |
3623 | }); |
3624 | // Default to a generic SSL error in case of panic. This |
3625 | // shouldn't really matter since the error should be |
3626 | // propagated later on but better safe than sorry... |
3627 | res.unwrap_or(default:curl_sys::CURLE_SSL_CONNECT_ERROR) |
3628 | } |
3629 | |
3630 | // TODO: expose `purpose` and `sockaddr` inside of `address` |
3631 | extern "C" fn opensocket_cb<H: Handler>( |
3632 | data: *mut c_void, |
3633 | _purpose: curl_sys::curlsocktype, |
3634 | address: *mut curl_sys::curl_sockaddr, |
3635 | ) -> curl_sys::curl_socket_t { |
3636 | let res: Option = panic::catch(|| unsafe { |
3637 | (*(data as *mut Inner<H>)) |
3638 | .handler |
3639 | .open_socket((*address).family, (*address).socktype, (*address).protocol) |
3640 | .unwrap_or(default:curl_sys::CURL_SOCKET_BAD) |
3641 | }); |
3642 | res.unwrap_or(default:curl_sys::CURL_SOCKET_BAD) |
3643 | } |
3644 | |
3645 | fn double_seconds_to_duration(seconds: f64) -> Duration { |
3646 | let whole_seconds: u64 = seconds.trunc() as u64; |
3647 | let nanos: f64 = seconds.fract() * 1_000_000_000f64; |
3648 | Duration::new(secs:whole_seconds, nanos as u32) |
3649 | } |
3650 | |
3651 | #[test ] |
3652 | fn double_seconds_to_duration_whole_second() { |
3653 | let dur: Duration = double_seconds_to_duration(seconds:1.0); |
3654 | assert_eq!(dur.as_secs(), 1); |
3655 | assert_eq!(dur.subsec_nanos(), 0); |
3656 | } |
3657 | |
3658 | #[test ] |
3659 | fn double_seconds_to_duration_sub_second1() { |
3660 | let dur: Duration = double_seconds_to_duration(seconds:0.0); |
3661 | assert_eq!(dur.as_secs(), 0); |
3662 | assert_eq!(dur.subsec_nanos(), 0); |
3663 | } |
3664 | |
3665 | #[test ] |
3666 | fn double_seconds_to_duration_sub_second2() { |
3667 | let dur: Duration = double_seconds_to_duration(seconds:0.5); |
3668 | assert_eq!(dur.as_secs(), 0); |
3669 | assert_eq!(dur.subsec_nanos(), 500_000_000); |
3670 | } |
3671 | |
3672 | impl Auth { |
3673 | /// Creates a new set of authentications with no members. |
3674 | /// |
3675 | /// An `Auth` structure is used to configure which forms of authentication |
3676 | /// are attempted when negotiating connections with servers. |
3677 | pub fn new() -> Auth { |
3678 | Auth { bits: 0 } |
3679 | } |
3680 | |
3681 | /// HTTP Basic authentication. |
3682 | /// |
3683 | /// This is the default choice, and the only method that is in wide-spread |
3684 | /// use and supported virtually everywhere. This sends the user name and |
3685 | /// password over the network in plain text, easily captured by others. |
3686 | pub fn basic(&mut self, on: bool) -> &mut Auth { |
3687 | self.flag(curl_sys::CURLAUTH_BASIC, on) |
3688 | } |
3689 | |
3690 | /// HTTP Digest authentication. |
3691 | /// |
3692 | /// Digest authentication is defined in RFC 2617 and is a more secure way to |
3693 | /// do authentication over public networks than the regular old-fashioned |
3694 | /// Basic method. |
3695 | pub fn digest(&mut self, on: bool) -> &mut Auth { |
3696 | self.flag(curl_sys::CURLAUTH_DIGEST, on) |
3697 | } |
3698 | |
3699 | /// HTTP Digest authentication with an IE flavor. |
3700 | /// |
3701 | /// Digest authentication is defined in RFC 2617 and is a more secure way to |
3702 | /// do authentication over public networks than the regular old-fashioned |
3703 | /// Basic method. The IE flavor is simply that libcurl will use a special |
3704 | /// "quirk" that IE is known to have used before version 7 and that some |
3705 | /// servers require the client to use. |
3706 | pub fn digest_ie(&mut self, on: bool) -> &mut Auth { |
3707 | self.flag(curl_sys::CURLAUTH_DIGEST_IE, on) |
3708 | } |
3709 | |
3710 | /// HTTP Negotiate (SPNEGO) authentication. |
3711 | /// |
3712 | /// Negotiate authentication is defined in RFC 4559 and is the most secure |
3713 | /// way to perform authentication over HTTP. |
3714 | /// |
3715 | /// You need to build libcurl with a suitable GSS-API library or SSPI on |
3716 | /// Windows for this to work. |
3717 | pub fn gssnegotiate(&mut self, on: bool) -> &mut Auth { |
3718 | self.flag(curl_sys::CURLAUTH_GSSNEGOTIATE, on) |
3719 | } |
3720 | |
3721 | /// HTTP NTLM authentication. |
3722 | /// |
3723 | /// A proprietary protocol invented and used by Microsoft. It uses a |
3724 | /// challenge-response and hash concept similar to Digest, to prevent the |
3725 | /// password from being eavesdropped. |
3726 | /// |
3727 | /// You need to build libcurl with either OpenSSL, GnuTLS or NSS support for |
3728 | /// this option to work, or build libcurl on Windows with SSPI support. |
3729 | pub fn ntlm(&mut self, on: bool) -> &mut Auth { |
3730 | self.flag(curl_sys::CURLAUTH_NTLM, on) |
3731 | } |
3732 | |
3733 | /// NTLM delegating to winbind helper. |
3734 | /// |
3735 | /// Authentication is performed by a separate binary application that is |
3736 | /// executed when needed. The name of the application is specified at |
3737 | /// compile time but is typically /usr/bin/ntlm_auth |
3738 | /// |
3739 | /// Note that libcurl will fork when necessary to run the winbind |
3740 | /// application and kill it when complete, calling waitpid() to await its |
3741 | /// exit when done. On POSIX operating systems, killing the process will |
3742 | /// cause a SIGCHLD signal to be raised (regardless of whether |
3743 | /// CURLOPT_NOSIGNAL is set), which must be handled intelligently by the |
3744 | /// application. In particular, the application must not unconditionally |
3745 | /// call wait() in its SIGCHLD signal handler to avoid being subject to a |
3746 | /// race condition. This behavior is subject to change in future versions of |
3747 | /// libcurl. |
3748 | /// |
3749 | /// A proprietary protocol invented and used by Microsoft. It uses a |
3750 | /// challenge-response and hash concept similar to Digest, to prevent the |
3751 | /// password from being eavesdropped. |
3752 | pub fn ntlm_wb(&mut self, on: bool) -> &mut Auth { |
3753 | self.flag(curl_sys::CURLAUTH_NTLM_WB, on) |
3754 | } |
3755 | |
3756 | /// HTTP AWS V4 signature authentication. |
3757 | /// |
3758 | /// This is a special auth type that can't be combined with the others. |
3759 | /// It will override the other auth types you might have set. |
3760 | /// |
3761 | /// Enabling this auth type is the same as using "aws:amz" as param in |
3762 | /// [`Easy2::aws_sigv4`](struct.Easy2.html#method.aws_sigv4) method. |
3763 | pub fn aws_sigv4(&mut self, on: bool) -> &mut Auth { |
3764 | self.flag(curl_sys::CURLAUTH_AWS_SIGV4, on) |
3765 | } |
3766 | |
3767 | fn flag(&mut self, bit: c_ulong, on: bool) -> &mut Auth { |
3768 | if on { |
3769 | self.bits |= bit as c_long; |
3770 | } else { |
3771 | self.bits &= !bit as c_long; |
3772 | } |
3773 | self |
3774 | } |
3775 | } |
3776 | |
3777 | impl fmt::Debug for Auth { |
3778 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
3779 | let bits: u64 = self.bits as c_ulong; |
3780 | f&mut DebugStruct<'_, '_>.debug_struct("Auth" ) |
3781 | .field("basic" , &(bits & curl_sys::CURLAUTH_BASIC != 0)) |
3782 | .field("digest" , &(bits & curl_sys::CURLAUTH_DIGEST != 0)) |
3783 | .field("digest_ie" , &(bits & curl_sys::CURLAUTH_DIGEST_IE != 0)) |
3784 | .field( |
3785 | "gssnegotiate" , |
3786 | &(bits & curl_sys::CURLAUTH_GSSNEGOTIATE != 0), |
3787 | ) |
3788 | .field("ntlm" , &(bits & curl_sys::CURLAUTH_NTLM != 0)) |
3789 | .field("ntlm_wb" , &(bits & curl_sys::CURLAUTH_NTLM_WB != 0)) |
3790 | .field(name:"aws_sigv4" , &(bits & curl_sys::CURLAUTH_AWS_SIGV4 != 0)) |
3791 | .finish() |
3792 | } |
3793 | } |
3794 | |
3795 | impl SslOpt { |
3796 | /// Creates a new set of SSL options. |
3797 | pub fn new() -> SslOpt { |
3798 | SslOpt { bits: 0 } |
3799 | } |
3800 | |
3801 | /// Tells libcurl to disable certificate revocation checks for those SSL |
3802 | /// backends where such behavior is present. |
3803 | /// |
3804 | /// Currently this option is only supported for WinSSL (the native Windows |
3805 | /// SSL library), with an exception in the case of Windows' Untrusted |
3806 | /// Publishers blacklist which it seems can't be bypassed. This option may |
3807 | /// have broader support to accommodate other SSL backends in the future. |
3808 | /// https://curl.haxx.se/docs/ssl-compared.html |
3809 | pub fn no_revoke(&mut self, on: bool) -> &mut SslOpt { |
3810 | self.flag(curl_sys::CURLSSLOPT_NO_REVOKE, on) |
3811 | } |
3812 | |
3813 | /// Tells libcurl to not attempt to use any workarounds for a security flaw |
3814 | /// in the SSL3 and TLS1.0 protocols. |
3815 | /// |
3816 | /// If this option isn't used or this bit is set to 0, the SSL layer libcurl |
3817 | /// uses may use a work-around for this flaw although it might cause |
3818 | /// interoperability problems with some (older) SSL implementations. |
3819 | /// |
3820 | /// > WARNING: avoiding this work-around lessens the security, and by |
3821 | /// > setting this option to 1 you ask for exactly that. This option is only |
3822 | /// > supported for DarwinSSL, NSS and OpenSSL. |
3823 | pub fn allow_beast(&mut self, on: bool) -> &mut SslOpt { |
3824 | self.flag(curl_sys::CURLSSLOPT_ALLOW_BEAST, on) |
3825 | } |
3826 | |
3827 | fn flag(&mut self, bit: c_long, on: bool) -> &mut SslOpt { |
3828 | if on { |
3829 | self.bits |= bit as c_long; |
3830 | } else { |
3831 | self.bits &= !bit as c_long; |
3832 | } |
3833 | self |
3834 | } |
3835 | } |
3836 | |
3837 | impl fmt::Debug for SslOpt { |
3838 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
3839 | f&mut DebugStruct<'_, '_>.debug_struct("SslOpt" ) |
3840 | .field( |
3841 | "no_revoke" , |
3842 | &(self.bits & curl_sys::CURLSSLOPT_NO_REVOKE != 0), |
3843 | ) |
3844 | .field( |
3845 | name:"allow_beast" , |
3846 | &(self.bits & curl_sys::CURLSSLOPT_ALLOW_BEAST != 0), |
3847 | ) |
3848 | .finish() |
3849 | } |
3850 | } |
3851 | |