1 //! Multi - initiating multiple requests simultaneously
6 use std
::time
::Duration
;
9 use libc
::{c_char, c_int, c_long, c_short, c_void}
;
12 use libc
::{pollfd, POLLIN, POLLOUT, POLLPRI}
;
14 use easy
::{Easy, Easy2, List}
;
16 use {Error, MultiError}
;
18 /// A multi handle for initiating multiple connections simultaneously.
20 /// This structure corresponds to `CURLM` in libcurl and provides the ability to
21 /// have multiple transfers in flight simultaneously. This handle is then used
22 /// to manage each transfer. The main purpose of a `CURLM` is for the
23 /// *application* to drive the I/O rather than libcurl itself doing all the
24 /// blocking. Methods like `action` allow the application to inform libcurl of
25 /// when events have happened.
27 /// Lots more documentation can be found on the libcurl [multi tutorial] where
28 /// the APIs correspond pretty closely with this crate.
30 /// [multi tutorial]: https://curl.haxx.se/libcurl/c/libcurl-multi.html
32 raw
: *mut curl_sys
::CURLM
,
37 socket
: Box
<dyn FnMut(Socket
, SocketEvents
, usize) + Send
>,
38 timer
: Box
<dyn FnMut(Option
<Duration
>) -> bool
+ Send
>,
41 /// Message from the `messages` function of a multi handle.
43 /// Currently only indicates whether a transfer is done.
44 pub struct Message
<'multi
> {
45 ptr
: *mut curl_sys
::CURLMsg
,
46 _multi
: &'multi Multi
,
49 /// Wrapper around an easy handle while it's owned by a multi handle.
51 /// Once an easy handle has been added to a multi handle then it can no longer
52 /// be used via `perform`. This handle is also used to remove the easy handle
53 /// from the multi handle when desired.
54 pub struct EasyHandle
{
56 // This is now effectively bound to a `Multi`, so it is no longer sendable.
57 _marker
: marker
::PhantomData
<&'
static Multi
>,
60 /// Wrapper around an easy handle while it's owned by a multi handle.
62 /// Once an easy handle has been added to a multi handle then it can no longer
63 /// be used via `perform`. This handle is also used to remove the easy handle
64 /// from the multi handle when desired.
65 pub struct Easy2Handle
<H
> {
67 // This is now effectively bound to a `Multi`, so it is no longer sendable.
68 _marker
: marker
::PhantomData
<&'
static Multi
>,
71 /// Notification of the events that have happened on a socket.
73 /// This type is passed as an argument to the `action` method on a multi handle
74 /// to indicate what events have occurred on a socket.
79 /// Notification of events that are requested on a socket.
81 /// This type is yielded to the `socket_function` callback to indicate what
82 /// events are requested on a socket.
83 pub struct SocketEvents
{
87 /// Raw underlying socket type that the multi handles use
88 pub type Socket
= curl_sys
::curl_socket_t
;
90 /// File descriptor to wait on for use with the `wait` method on a multi handle.
92 inner
: curl_sys
::curl_waitfd
,
96 /// Creates a new multi session through which multiple HTTP transfers can be
98 pub fn new() -> Multi
{
101 let ptr
= curl_sys
::curl_multi_init();
102 assert
!(!ptr
.is_null());
105 data
: Box
::new(MultiData
{
106 socket
: Box
::new(|_
, _
, _
| ()),
107 timer
: Box
::new(|_
| true),
113 /// Set the callback informed about what to wait for
115 /// When the `action` function runs, it informs the application about
116 /// updates in the socket (file descriptor) status by doing none, one, or
117 /// multiple calls to the socket callback. The callback gets status updates
118 /// with changes since the previous time the callback was called. See
119 /// `action` for more details on how the callback is used and should work.
121 /// The `SocketEvents` parameter informs the callback on the status of the
122 /// given socket, and the methods on that type can be used to learn about
123 /// what's going on with the socket.
125 /// The third `usize` parameter is a custom value set by the `assign` method
127 pub fn socket_function
<F
>(&mut self, f
: F
) -> Result
<(), MultiError
>
129 F
: FnMut(Socket
, SocketEvents
, usize) + Send
+ '
static,
131 self._socket_function(Box
::new(f
))
136 f
: Box
<dyn FnMut(Socket
, SocketEvents
, usize) + Send
>,
137 ) -> Result
<(), MultiError
> {
138 self.data
.socket
= f
;
139 let cb
: curl_sys
::curl_socket_callback
= cb
;
141 curl_sys
::CURLMOPT_SOCKETFUNCTION
,
142 cb
as usize as *const c_char
,
144 let ptr
= &*self.data
as *const _
;
145 self.setopt_ptr(curl_sys
::CURLMOPT_SOCKETDATA
, ptr
as *const c_char
)?
;
148 // TODO: figure out how to expose `_easy`
150 _easy
: *mut curl_sys
::CURL
,
151 socket
: curl_sys
::curl_socket_t
,
153 userptr
: *mut c_void
,
154 socketp
: *mut c_void
,
156 panic
::catch(|| unsafe {
157 let f
= &mut (*(userptr
as *mut MultiData
)).socket
;
158 f(socket
, SocketEvents { bits: what }
, socketp
as usize)
164 /// Set data to associate with an internal socket
166 /// This function creates an association in the multi handle between the
167 /// given socket and a private token of the application. This is designed
168 /// for `action` uses.
170 /// When set, the token will be passed to all future socket callbacks for
171 /// the specified socket.
173 /// If the given socket isn't already in use by libcurl, this function will
176 /// libcurl only keeps one single token associated with a socket, so
177 /// calling this function several times for the same socket will make the
178 /// last set token get used.
180 /// The idea here being that this association (socket to token) is something
181 /// that just about every application that uses this API will need and then
182 /// libcurl can just as well do it since it already has an internal hash
183 /// table lookup for this.
187 /// In a typical application you allocate a struct or at least use some kind
188 /// of semi-dynamic data for each socket that we must wait for action on
189 /// when using the `action` approach.
191 /// When our socket-callback gets called by libcurl and we get to know about
192 /// yet another socket to wait for, we can use `assign` to point out the
193 /// particular data so that when we get updates about this same socket
194 /// again, we don't have to find the struct associated with this socket by
196 pub fn assign(&self, socket
: Socket
, token
: usize) -> Result
<(), MultiError
> {
198 cvt(curl_sys
::curl_multi_assign(
207 /// Set callback to receive timeout values
209 /// Certain features, such as timeouts and retries, require you to call
210 /// libcurl even when there is no activity on the file descriptors.
212 /// Your callback function should install a non-repeating timer with the
213 /// interval specified. Each time that timer fires, call either `action` or
214 /// `perform`, depending on which interface you use.
216 /// A timeout value of `None` means you should delete your timer.
218 /// A timeout value of 0 means you should call `action` or `perform` (once)
219 /// as soon as possible.
221 /// This callback will only be called when the timeout changes.
223 /// The timer callback should return `true` on success, and `false` on
224 /// error. This callback can be used instead of, or in addition to,
226 pub fn timer_function
<F
>(&mut self, f
: F
) -> Result
<(), MultiError
>
228 F
: FnMut(Option
<Duration
>) -> bool
+ Send
+ '
static,
230 self._timer_function(Box
::new(f
))
235 f
: Box
<dyn FnMut(Option
<Duration
>) -> bool
+ Send
>,
236 ) -> Result
<(), MultiError
> {
238 let cb
: curl_sys
::curl_multi_timer_callback
= cb
;
240 curl_sys
::CURLMOPT_TIMERFUNCTION
,
241 cb
as usize as *const c_char
,
243 let ptr
= &*self.data
as *const _
;
244 self.setopt_ptr(curl_sys
::CURLMOPT_TIMERDATA
, ptr
as *const c_char
)?
;
247 // TODO: figure out how to expose `_multi`
249 _multi
: *mut curl_sys
::CURLM
,
253 let keep_going
= panic
::catch(|| unsafe {
254 let f
= &mut (*(user
as *mut MultiData
)).timer
;
255 if timeout_ms
== -1 {
258 f(Some(Duration
::from_millis(timeout_ms
as u64)))
270 /// Enable or disable HTTP pipelining and multiplexing.
272 /// When http_1 is true, enable HTTP/1.1 pipelining, which means that if
273 /// you add a second request that can use an already existing connection,
274 /// the second request will be "piped" on the same connection rather than
275 /// being executed in parallel.
277 /// When multiplex is true, enable HTTP/2 multiplexing, which means that
278 /// follow-up requests can re-use an existing connection and send the new
279 /// request multiplexed over that at the same time as other transfers are
280 /// already using that single connection.
281 pub fn pipelining(&mut self, http_1
: bool
, multiplex
: bool
) -> Result
<(), MultiError
> {
282 let bitmask
= if http_1 { curl_sys::CURLPIPE_HTTP1 }
else { 0 }
284 curl_sys
::CURLPIPE_MULTIPLEX
288 self.setopt_long(curl_sys
::CURLMOPT_PIPELINING
, bitmask
)
291 /// Sets the max number of connections to a single host.
293 /// Pass a long to indicate the max number of simultaneously open connections
294 /// to a single host (a host being the same as a host name + port number pair).
295 /// For each new session to a host, libcurl will open up a new connection up to the
296 /// limit set by the provided value. When the limit is reached, the sessions will
297 /// be pending until a connection becomes available. If pipelining is enabled,
298 /// libcurl will try to pipeline if the host is capable of it.
299 pub fn set_max_host_connections(&mut self, val
: usize) -> Result
<(), MultiError
> {
300 self.setopt_long(curl_sys
::CURLMOPT_MAX_HOST_CONNECTIONS
, val
as c_long
)
303 /// Sets the max simultaneously open connections.
305 /// The set number will be used as the maximum number of simultaneously open
306 /// connections in total using this multi handle. For each new session,
307 /// libcurl will open a new connection up to the limit set by the provided
308 /// value. When the limit is reached, the sessions will be pending until
309 /// there are available connections. If pipelining is enabled, libcurl will
310 /// try to pipeline or use multiplexing if the host is capable of it.
311 pub fn set_max_total_connections(&mut self, val
: usize) -> Result
<(), MultiError
> {
312 self.setopt_long(curl_sys
::CURLMOPT_MAX_TOTAL_CONNECTIONS
, val
as c_long
)
315 /// Set size of connection cache.
317 /// The set number will be used as the maximum amount of simultaneously open
318 /// connections that libcurl may keep in its connection cache after
319 /// completed use. By default libcurl will enlarge the size for each added
320 /// easy handle to make it fit 4 times the number of added easy handles.
322 /// By setting this option, you can prevent the cache size from growing
323 /// beyond the limit set by you.
325 /// When the cache is full, curl closes the oldest one in the cache to
326 /// prevent the number of open connections from increasing.
328 /// See [`set_max_total_connections`](#method.set_max_total_connections) for
329 /// limiting the number of active connections.
330 pub fn set_max_connects(&mut self, val
: usize) -> Result
<(), MultiError
> {
331 self.setopt_long(curl_sys
::CURLMOPT_MAXCONNECTS
, val
as c_long
)
334 /// Sets the pipeline length.
336 /// This sets the max number that will be used as the maximum amount of
337 /// outstanding requests in an HTTP/1.1 pipelined connection. This option
338 /// is only used for HTTP/1.1 pipelining, and not HTTP/2 multiplexing.
339 pub fn set_pipeline_length(&mut self, val
: usize) -> Result
<(), MultiError
> {
340 self.setopt_long(curl_sys
::CURLMOPT_MAX_PIPELINE_LENGTH
, val
as c_long
)
343 fn setopt_long(&mut self, opt
: curl_sys
::CURLMoption
, val
: c_long
) -> Result
<(), MultiError
> {
344 unsafe { cvt(curl_sys::curl_multi_setopt(self.raw, opt, val)) }
349 opt
: curl_sys
::CURLMoption
,
351 ) -> Result
<(), MultiError
> {
352 unsafe { cvt(curl_sys::curl_multi_setopt(self.raw, opt, val)) }
355 /// Add an easy handle to a multi session
357 /// Adds a standard easy handle to the multi stack. This function call will
358 /// make this multi handle control the specified easy handle.
360 /// When an easy interface is added to a multi handle, it will use a shared
361 /// connection cache owned by the multi handle. Removing and adding new easy
362 /// handles will not affect the pool of connections or the ability to do
363 /// connection re-use.
365 /// If you have `timer_function` set in the multi handle (and you really
366 /// should if you're working event-based with `action` and friends), that
367 /// callback will be called from within this function to ask for an updated
368 /// timer so that your main event loop will get the activity on this handle
371 /// The easy handle will remain added to the multi handle until you remove
372 /// it again with `remove` on the returned handle - even when a transfer
373 /// with that specific easy handle is completed.
374 pub fn add(&self, mut easy
: Easy
) -> Result
<EasyHandle
, MultiError
> {
375 // Clear any configuration set by previous transfers because we're
376 // moving this into a `Send+'static` situation now basically.
380 cvt(curl_sys
::curl_multi_add_handle(self.raw
, easy
.raw()))?
;
384 _marker
: marker
::PhantomData
,
388 /// Same as `add`, but works with the `Easy2` type.
389 pub fn add2
<H
>(&self, easy
: Easy2
<H
>) -> Result
<Easy2Handle
<H
>, MultiError
> {
391 cvt(curl_sys
::curl_multi_add_handle(self.raw
, easy
.raw()))?
;
395 _marker
: marker
::PhantomData
,
399 /// Remove an easy handle from this multi session
401 /// Removes the easy handle from this multi handle. This will make the
402 /// returned easy handle be removed from this multi handle's control.
404 /// When the easy handle has been removed from a multi stack, it is again
405 /// perfectly legal to invoke `perform` on it.
407 /// Removing an easy handle while being used is perfectly legal and will
408 /// effectively halt the transfer in progress involving that easy handle.
409 /// All other easy handles and transfers will remain unaffected.
410 pub fn remove(&self, easy
: EasyHandle
) -> Result
<Easy
, MultiError
> {
412 cvt(curl_sys
::curl_multi_remove_handle(
420 /// Same as `remove`, but for `Easy2Handle`.
421 pub fn remove2
<H
>(&self, easy
: Easy2Handle
<H
>) -> Result
<Easy2
<H
>, MultiError
> {
423 cvt(curl_sys
::curl_multi_remove_handle(
431 /// Read multi stack informationals
433 /// Ask the multi handle if there are any messages/informationals from the
434 /// individual transfers. Messages may include informationals such as an
435 /// error code from the transfer or just the fact that a transfer is
436 /// completed. More details on these should be written down as well.
437 pub fn messages
<F
>(&self, mut f
: F
)
441 self._messages(&mut f
)
444 fn _messages(&self, f
: &mut dyn FnMut(Message
)) {
448 let ptr
= curl_sys
::curl_multi_info_read(self.raw
, &mut queue
);
452 f(Message { ptr, _multi: self }
)
457 /// Inform of reads/writes available data given an action
459 /// When the application has detected action on a socket handled by libcurl,
460 /// it should call this function with the sockfd argument set to
461 /// the socket with the action. When the events on a socket are known, they
462 /// can be passed `events`. When the events on a socket are unknown, pass
463 /// `Events::new()` instead, and libcurl will test the descriptor
466 /// The returned integer will contain the number of running easy handles
467 /// within the multi handle. When this number reaches zero, all transfers
468 /// are complete/done. When you call `action` on a specific socket and the
469 /// counter decreases by one, it DOES NOT necessarily mean that this exact
470 /// socket/transfer is the one that completed. Use `messages` to figure out
471 /// which easy handle that completed.
473 /// The `action` function informs the application about updates in the
474 /// socket (file descriptor) status by doing none, one, or multiple calls to
475 /// the socket callback function set with the `socket_function` method. They
476 /// update the status with changes since the previous time the callback was
478 pub fn action(&self, socket
: Socket
, events
: &Events
) -> Result
<u32, MultiError
> {
479 let mut remaining
= 0;
481 cvt(curl_sys
::curl_multi_socket_action(
491 /// Inform libcurl that a timeout has expired and sockets should be tested.
493 /// The returned integer will contain the number of running easy handles
494 /// within the multi handle. When this number reaches zero, all transfers
495 /// are complete/done. When you call `action` on a specific socket and the
496 /// counter decreases by one, it DOES NOT necessarily mean that this exact
497 /// socket/transfer is the one that completed. Use `messages` to figure out
498 /// which easy handle that completed.
500 /// Get the timeout time by calling the `timer_function` method. Your
501 /// application will then get called with information on how long to wait
502 /// for socket actions at most before doing the timeout action: call the
503 /// `timeout` method. You can also use the `get_timeout` function to
504 /// poll the value at any given time, but for an event-based system using
505 /// the callback is far better than relying on polling the timeout value.
506 pub fn timeout(&self) -> Result
<u32, MultiError
> {
507 let mut remaining
= 0;
509 cvt(curl_sys
::curl_multi_socket_action(
511 curl_sys
::CURL_SOCKET_BAD
,
519 /// Get how long to wait for action before proceeding
521 /// An application using the libcurl multi interface should call
522 /// `get_timeout` to figure out how long it should wait for socket actions -
523 /// at most - before proceeding.
525 /// Proceeding means either doing the socket-style timeout action: call the
526 /// `timeout` function, or call `perform` if you're using the simpler and
527 /// older multi interface approach.
529 /// The timeout value returned is the duration at this very moment. If 0, it
530 /// means you should proceed immediately without waiting for anything. If it
531 /// returns `None`, there's no timeout at all set.
533 /// Note: if libcurl returns a `None` timeout here, it just means that
534 /// libcurl currently has no stored timeout value. You must not wait too
535 /// long (more than a few seconds perhaps) before you call `perform` again.
536 pub fn get_timeout(&self) -> Result
<Option
<Duration
>, MultiError
> {
539 cvt(curl_sys
::curl_multi_timeout(self.raw
, &mut ms
))?
;
543 Ok(Some(Duration
::from_millis(ms
as u64)))
548 /// Block until activity is detected or a timeout passes.
550 /// The timeout is used in millisecond-precision. Large durations are
551 /// clamped at the maximum value curl accepts.
553 /// The returned integer will contain the number of internal file
554 /// descriptors on which interesting events occured.
556 /// This function is a simpler alternative to using `fdset()` and `select()`
557 /// and does not suffer from file descriptor limits.
562 /// use curl::multi::Multi;
563 /// use std::time::Duration;
565 /// let m = Multi::new();
567 /// // Add some Easy handles...
569 /// while m.perform().unwrap() > 0 {
570 /// m.wait(&mut [], Duration::from_secs(1)).unwrap();
573 pub fn wait(&self, waitfds
: &mut [WaitFd
], timeout
: Duration
) -> Result
<u32, MultiError
> {
575 let secs
= timeout
.as_secs();
576 if secs
> (i32::max_value() / 1000) as u64 {
577 // Duration too large, clamp at maximum value.
580 secs
as i32 * 1000 + timeout
.subsec_nanos() as i32 / 1_000_000
585 cvt(curl_sys
::curl_multi_wait(
587 waitfds
.as_mut_ptr() as *mut _
,
588 waitfds
.len() as u32,
596 /// Reads/writes available data from each easy handle.
598 /// This function handles transfers on all the added handles that need
599 /// attention in an non-blocking fashion.
601 /// When an application has found out there's data available for this handle
602 /// or a timeout has elapsed, the application should call this function to
603 /// read/write whatever there is to read or write right now etc. This
604 /// method returns as soon as the reads/writes are done. This function does
605 /// not require that there actually is any data available for reading or
606 /// that data can be written, it can be called just in case. It will return
607 /// the number of handles that still transfer data.
609 /// If the amount of running handles is changed from the previous call (or
610 /// is less than the amount of easy handles you've added to the multi
611 /// handle), you know that there is one or more transfers less "running".
612 /// You can then call `info` to get information about each individual
613 /// completed transfer, and that returned info includes `Error` and more.
614 /// If an added handle fails very quickly, it may never be counted as a
617 /// When running_handles is set to zero (0) on the return of this function,
618 /// there is no longer any transfers in progress.
622 /// Before libcurl version 7.20.0: If you receive `is_call_perform`, this
623 /// basically means that you should call `perform` again, before you select
624 /// on more actions. You don't have to do it immediately, but the return
625 /// code means that libcurl may have more data available to return or that
626 /// there may be more data to send off before it is "satisfied". Do note
627 /// that `perform` will return `is_call_perform` only when it wants to be
628 /// called again immediately. When things are fine and there is nothing
629 /// immediate it wants done, it'll return `Ok` and you need to wait for
630 /// "action" and then call this function again.
632 /// This function only returns errors etc regarding the whole multi stack.
633 /// Problems still might have occurred on individual transfers even when
634 /// this function returns `Ok`. Use `info` to figure out how individual
636 pub fn perform(&self) -> Result
<u32, MultiError
> {
639 cvt(curl_sys
::curl_multi_perform(self.raw
, &mut ret
))?
;
644 /// Extracts file descriptor information from a multi handle
646 /// This function extracts file descriptor information from a given
647 /// handle, and libcurl returns its `fd_set` sets. The application can use
648 /// these to `select()` on, but be sure to `FD_ZERO` them before calling
649 /// this function as curl_multi_fdset only adds its own descriptors, it
650 /// doesn't zero or otherwise remove any others. The curl_multi_perform
651 /// function should be called as soon as one of them is ready to be read
652 /// from or written to.
654 /// If no file descriptors are set by libcurl, this function will return
655 /// `Ok(None)`. Otherwise `Ok(Some(n))` will be returned where `n` the
656 /// highest descriptor number libcurl set. When `Ok(None)` is returned it
657 /// is because libcurl currently does something that isn't possible for
658 /// your application to monitor with a socket and unfortunately you can
659 /// then not know exactly when the current action is completed using
660 /// `select()`. You then need to wait a while before you proceed and call
661 /// `perform` anyway.
663 /// When doing `select()`, you should use `get_timeout` to figure out
664 /// how long to wait for action. Call `perform` even if no activity has
665 /// been seen on the `fd_set`s after the timeout expires as otherwise
666 /// internal retries and timeouts may not work as you'd think and want.
668 /// If one of the sockets used by libcurl happens to be larger than what
669 /// can be set in an `fd_set`, which on POSIX systems means that the file
670 /// descriptor is larger than `FD_SETSIZE`, then libcurl will try to not
671 /// set it. Setting a too large file descriptor in an `fd_set` implies an out
672 /// of bounds write which can cause crashes, or worse. The effect of NOT
673 /// storing it will possibly save you from the crash, but will make your
674 /// program NOT wait for sockets it should wait for...
677 read
: Option
<&mut curl_sys
::fd_set
>,
678 write
: Option
<&mut curl_sys
::fd_set
>,
679 except
: Option
<&mut curl_sys
::fd_set
>,
680 ) -> Result
<Option
<i32>, MultiError
> {
683 let read
= read
.map(|r
| r
as *mut _
).unwrap_or(ptr
::null_mut());
684 let write
= write
.map(|r
| r
as *mut _
).unwrap_or(ptr
::null_mut());
685 let except
= except
.map(|r
| r
as *mut _
).unwrap_or(ptr
::null_mut());
686 cvt(curl_sys
::curl_multi_fdset(
687 self.raw
, read
, write
, except
, &mut ret
,
697 /// Does nothing and returns `Ok(())`. This method remains for backwards
700 /// This method will be changed to take `self` in a future release.
704 note
= "cannot close safely without consuming self; \
705 will be changed or removed in a future release"
707 pub fn close(&self) -> Result
<(), MultiError
> {
711 /// Get a pointer to the raw underlying CURLM handle.
712 pub fn raw(&self) -> *mut curl_sys
::CURLM
{
716 unsafe fn close_impl(&self) -> Result
<(), MultiError
> {
717 cvt(curl_sys
::curl_multi_cleanup(self.raw
))
721 fn cvt(code
: curl_sys
::CURLMcode
) -> Result
<(), MultiError
> {
722 if code
== curl_sys
::CURLM_OK
{
725 Err(MultiError
::new(code
))
729 impl fmt
::Debug
for Multi
{
730 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
731 f
.debug_struct("Multi").field("raw", &self.raw
).finish()
735 impl Drop
for Multi
{
737 let _
= unsafe { self.close_impl() }
;
741 macro_rules
! impl_easy_getters
{
744 time_condition_unmet
-> bool
,
745 effective_url
-> Option
<&str>,
746 effective_url_bytes
-> Option
<&[u8]>,
747 response_code
-> u32,
748 http_connectcode
-> u32,
749 filetime
-> Option
<i64>,
750 download_size
-> f64,
751 content_length_download
-> f64,
752 total_time
-> Duration
,
753 namelookup_time
-> Duration
,
754 connect_time
-> Duration
,
755 appconnect_time
-> Duration
,
756 pretransfer_time
-> Duration
,
757 starttransfer_time
-> Duration
,
758 redirect_time
-> Duration
,
759 redirect_count
-> u32,
760 redirect_url
-> Option
<&str>,
761 redirect_url_bytes
-> Option
<&[u8]>,
764 content_type
-> Option
<&str>,
765 content_type_bytes
-> Option
<&[u8]>,
767 primary_ip
-> Option
<&str>,
769 local_ip
-> Option
<&str>,
775 ($
($name
:ident
-> $ret
:ty
,)*) => {
777 impl_easy_getters
!($name
, $ret
, concat
!(
780 "`](../easy/struct.Easy2.html#method.",
787 ($name
:ident
, $ret
:ty
, $doc
:expr
) => {
789 pub fn $
name(&mut self) -> Result
<$ret
, Error
> {
796 /// Sets an internal private token for this `EasyHandle`.
798 /// This function will set the `CURLOPT_PRIVATE` field on the underlying
800 pub fn set_token(&mut self, token
: usize) -> Result
<(), Error
> {
802 ::cvt(curl_sys
::curl_easy_setopt(
804 curl_sys
::CURLOPT_PRIVATE
,
810 impl_easy_getters
!();
812 /// Unpause reading on a connection.
814 /// Using this function, you can explicitly unpause a connection that was
815 /// previously paused.
817 /// A connection can be paused by letting the read or the write callbacks
818 /// return `ReadError::Pause` or `WriteError::Pause`.
820 /// The chance is high that you will get your write callback called before
821 /// this function returns.
822 pub fn unpause_read(&self) -> Result
<(), Error
> {
823 self.easy
.unpause_read()
826 /// Unpause writing on a connection.
828 /// Using this function, you can explicitly unpause a connection that was
829 /// previously paused.
831 /// A connection can be paused by letting the read or the write callbacks
832 /// return `ReadError::Pause` or `WriteError::Pause`. A write callback that
833 /// returns pause signals to the library that it couldn't take care of any
834 /// data at all, and that data will then be delivered again to the callback
835 /// when the writing is later unpaused.
836 pub fn unpause_write(&self) -> Result
<(), Error
> {
837 self.easy
.unpause_write()
840 /// Get a pointer to the raw underlying CURL handle.
841 pub fn raw(&self) -> *mut curl_sys
::CURL
{
846 impl fmt
::Debug
for EasyHandle
{
847 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
852 impl<H
> Easy2Handle
<H
> {
853 /// Acquires a reference to the underlying handler for events.
854 pub fn get_ref(&self) -> &H
{
858 /// Acquires a reference to the underlying handler for events.
859 pub fn get_mut(&mut self) -> &mut H
{
863 /// Same as `EasyHandle::set_token`
864 pub fn set_token(&mut self, token
: usize) -> Result
<(), Error
> {
866 ::cvt(curl_sys
::curl_easy_setopt(
868 curl_sys
::CURLOPT_PRIVATE
,
874 impl_easy_getters
!();
876 /// Unpause reading on a connection.
878 /// Using this function, you can explicitly unpause a connection that was
879 /// previously paused.
881 /// A connection can be paused by letting the read or the write callbacks
882 /// return `ReadError::Pause` or `WriteError::Pause`.
884 /// The chance is high that you will get your write callback called before
885 /// this function returns.
886 pub fn unpause_read(&self) -> Result
<(), Error
> {
887 self.easy
.unpause_read()
890 /// Unpause writing on a connection.
892 /// Using this function, you can explicitly unpause a connection that was
893 /// previously paused.
895 /// A connection can be paused by letting the read or the write callbacks
896 /// return `ReadError::Pause` or `WriteError::Pause`. A write callback that
897 /// returns pause signals to the library that it couldn't take care of any
898 /// data at all, and that data will then be delivered again to the callback
899 /// when the writing is later unpaused.
900 pub fn unpause_write(&self) -> Result
<(), Error
> {
901 self.easy
.unpause_write()
904 /// Get a pointer to the raw underlying CURL handle.
905 pub fn raw(&self) -> *mut curl_sys
::CURL
{
910 impl<H
: fmt
::Debug
> fmt
::Debug
for Easy2Handle
<H
> {
911 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
916 impl<'multi
> Message
<'multi
> {
917 /// If this message indicates that a transfer has finished, returns the
918 /// result of the transfer in `Some`.
920 /// If the message doesn't indicate that a transfer has finished, then
921 /// `None` is returned.
923 /// Note that the `result*_for` methods below should be preferred as they
924 /// provide better error messages as the associated error data on the
925 /// handle can be associated with the error type.
926 pub fn result(&self) -> Option
<Result
<(), Error
>> {
928 if (*self.ptr
).msg
== curl_sys
::CURLMSG_DONE
{
929 Some(::cvt((*self.ptr
).data
as curl_sys
::CURLcode
))
936 /// Same as `result`, except only returns `Some` for the specified handle.
938 /// Note that this function produces better error messages than `result` as
939 /// it uses `take_error_buf` to associate error information with the
941 pub fn result_for(&self, handle
: &EasyHandle
) -> Option
<Result
<(), Error
>> {
942 if !self.is_for(handle
) {
945 let mut err
= self.result();
946 if let Some(Err(e
)) = &mut err
{
947 if let Some(s
) = handle
.easy
.take_error_buf() {
954 /// Same as `result`, except only returns `Some` for the specified handle.
956 /// Note that this function produces better error messages than `result` as
957 /// it uses `take_error_buf` to associate error information with the
959 pub fn result_for2
<H
>(&self, handle
: &Easy2Handle
<H
>) -> Option
<Result
<(), Error
>> {
960 if !self.is_for2(handle
) {
963 let mut err
= self.result();
964 if let Some(Err(e
)) = &mut err
{
965 if let Some(s
) = handle
.easy
.take_error_buf() {
972 /// Returns whether this easy message was for the specified easy handle or
974 pub fn is_for(&self, handle
: &EasyHandle
) -> bool
{
975 unsafe { (*self.ptr).easy_handle == handle.easy.raw() }
978 /// Same as `is_for`, but for `Easy2Handle`.
979 pub fn is_for2
<H
>(&self, handle
: &Easy2Handle
<H
>) -> bool
{
980 unsafe { (*self.ptr).easy_handle == handle.easy.raw() }
983 /// Returns the token associated with the easy handle that this message
984 /// represents a completion for.
986 /// This function will return the token assigned with
987 /// `EasyHandle::set_token`. This reads the `CURLINFO_PRIVATE` field of the
988 /// underlying `*mut CURL`.
989 pub fn token(&self) -> Result
<usize, Error
> {
992 ::cvt(curl_sys
::curl_easy_getinfo(
993 (*self.ptr
).easy_handle
,
994 curl_sys
::CURLINFO_PRIVATE
,
1002 impl<'a
> fmt
::Debug
for Message
<'a
> {
1003 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1004 f
.debug_struct("Message").field("ptr", &self.ptr
).finish()
1009 /// Creates a new blank event bit mask.
1010 pub fn new() -> Events
{
1014 /// Set or unset the whether these events indicate that input is ready.
1015 pub fn input(&mut self, val
: bool
) -> &mut Events
{
1016 self.flag(curl_sys
::CURL_CSELECT_IN
, val
)
1019 /// Set or unset the whether these events indicate that output is ready.
1020 pub fn output(&mut self, val
: bool
) -> &mut Events
{
1021 self.flag(curl_sys
::CURL_CSELECT_OUT
, val
)
1024 /// Set or unset the whether these events indicate that an error has
1026 pub fn error(&mut self, val
: bool
) -> &mut Events
{
1027 self.flag(curl_sys
::CURL_CSELECT_ERR
, val
)
1030 fn flag(&mut self, flag
: c_int
, val
: bool
) -> &mut Events
{
1040 impl fmt
::Debug
for Events
{
1041 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1042 f
.debug_struct("Events")
1043 .field("input", &(self.bits
& curl_sys
::CURL_CSELECT_IN
!= 0))
1044 .field("output", &(self.bits
& curl_sys
::CURL_CSELECT_OUT
!= 0))
1045 .field("error", &(self.bits
& curl_sys
::CURL_CSELECT_ERR
!= 0))
1051 /// Wait for incoming data. For the socket to become readable.
1052 pub fn input(&self) -> bool
{
1053 self.bits
& curl_sys
::CURL_POLL_IN
== curl_sys
::CURL_POLL_IN
1056 /// Wait for outgoing data. For the socket to become writable.
1057 pub fn output(&self) -> bool
{
1058 self.bits
& curl_sys
::CURL_POLL_OUT
== curl_sys
::CURL_POLL_OUT
1061 /// Wait for incoming and outgoing data. For the socket to become readable
1063 pub fn input_and_output(&self) -> bool
{
1064 self.bits
& curl_sys
::CURL_POLL_INOUT
== curl_sys
::CURL_POLL_INOUT
1067 /// The specified socket/file descriptor is no longer used by libcurl.
1068 pub fn remove(&self) -> bool
{
1069 self.bits
& curl_sys
::CURL_POLL_REMOVE
== curl_sys
::CURL_POLL_REMOVE
1073 impl fmt
::Debug
for SocketEvents
{
1074 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1075 f
.debug_struct("Events")
1076 .field("input", &self.input())
1077 .field("output", &self.output())
1078 .field("remove", &self.remove())
1084 /// Constructs an empty (invalid) WaitFd.
1085 pub fn new() -> WaitFd
{
1087 inner
: curl_sys
::curl_waitfd
{
1095 /// Set the file descriptor to wait for.
1096 pub fn set_fd(&mut self, fd
: Socket
) {
1100 /// Indicate that the socket should poll on read events such as new data
1103 /// Corresponds to `CURL_WAIT_POLLIN`.
1104 pub fn poll_on_read(&mut self, val
: bool
) -> &mut WaitFd
{
1105 self.flag(curl_sys
::CURL_WAIT_POLLIN
, val
)
1108 /// Indicate that the socket should poll on high priority read events such
1109 /// as out of band data.
1111 /// Corresponds to `CURL_WAIT_POLLPRI`.
1112 pub fn poll_on_priority_read(&mut self, val
: bool
) -> &mut WaitFd
{
1113 self.flag(curl_sys
::CURL_WAIT_POLLPRI
, val
)
1116 /// Indicate that the socket should poll on write events such as the socket
1117 /// being clear to write without blocking.
1119 /// Corresponds to `CURL_WAIT_POLLOUT`.
1120 pub fn poll_on_write(&mut self, val
: bool
) -> &mut WaitFd
{
1121 self.flag(curl_sys
::CURL_WAIT_POLLOUT
, val
)
1124 fn flag(&mut self, flag
: c_short
, val
: bool
) -> &mut WaitFd
{
1126 self.inner
.events
|= flag
;
1128 self.inner
.events
&= !flag
;
1133 /// After a call to `wait`, returns `true` if `poll_on_read` was set and a
1134 /// read event occured.
1135 pub fn received_read(&self) -> bool
{
1136 self.inner
.revents
& curl_sys
::CURL_WAIT_POLLIN
== curl_sys
::CURL_WAIT_POLLIN
1139 /// After a call to `wait`, returns `true` if `poll_on_priority_read` was set and a
1140 /// priority read event occured.
1141 pub fn received_priority_read(&self) -> bool
{
1142 self.inner
.revents
& curl_sys
::CURL_WAIT_POLLPRI
== curl_sys
::CURL_WAIT_POLLPRI
1145 /// After a call to `wait`, returns `true` if `poll_on_write` was set and a
1146 /// write event occured.
1147 pub fn received_write(&self) -> bool
{
1148 self.inner
.revents
& curl_sys
::CURL_WAIT_POLLOUT
== curl_sys
::CURL_WAIT_POLLOUT
1153 impl From
<pollfd
> for WaitFd
{
1154 fn from(pfd
: pollfd
) -> WaitFd
{
1156 if pfd
.events
& POLLIN
== POLLIN
{
1157 events
|= curl_sys
::CURL_WAIT_POLLIN
;
1159 if pfd
.events
& POLLPRI
== POLLPRI
{
1160 events
|= curl_sys
::CURL_WAIT_POLLPRI
;
1162 if pfd
.events
& POLLOUT
== POLLOUT
{
1163 events
|= curl_sys
::CURL_WAIT_POLLOUT
;
1166 inner
: curl_sys
::curl_waitfd
{
1175 impl fmt
::Debug
for WaitFd
{
1176 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1177 f
.debug_struct("WaitFd")
1178 .field("fd", &self.inner
.fd
)
1179 .field("events", &self.inner
.fd
)
1180 .field("revents", &self.inner
.fd
)