Client

Struct Client 

Source
pub struct Client { /* private fields */ }
Expand description

A flexible HTTP client.

Use the client if you wanna have controll over mio yourself. You should look at the documentation of the individual methods for more info on what exactly they do.

In general, you pass the client a handle to your Poll when you send a request. Inside you mio event loop, when you get an event, you then call the Client::pump function, which drives the request to completion.

§Example

This is more or less a full blown example on what it takes to correctly send a request.


let io = mio::Poll::new()?;
let mut client = rtv::Client::new(mio::Token(0));

let request = Request::get().host("example.com").https();
let _id = client.send(&io, mio::Token(2), request)?;
//  ^^^ the returned id can be used to check which response belongs to which request
//      although we are just sending one request here so this isn't needed

// we have to store the body ourselfes
let mut response_body = Vec::new();

'ev: loop {
     
    // see note below on how to handle timeouts
    io.poll(&mut events, client.timeout())?;
     
    // loop over all the responses we may have gotten
    // you don't need to handle events generated by rtv in any other way
    for resp in client.pump(&io, &events)? {
        match resp.state {
            rtv::ResponseState::Head(head) => {
                // the head contains headers etc.
                pritnln!("Content-Length: {}", head.content_length);
                pritnln!("Some header: {}", head.headers[0]);
            },
            rtv::ResponseState::Data(some_data) => {
                // you will receive data in small chunks as it comes in
                response_body.extend(some_data);
            },
            rtv::ResponseState::Done => {
                break 'ev;
            },
            // maybe a timeout or I/O error
            other => panic!("Error: {}", other),
        };
    };
     
    events.clear();

}

let body_str = str::from_utf8(&response_body)?;
println!("{}", body_str);

§Timeouts

Rtv supports a timeout for every individual request. It will even be applied to dns resolution.

You have to specify this timeout in two places. First, when creating your Request and then once again when waiting for events with mio.

The timeout used with mio always has to match the smallest time left for any request currently in progress, so that the Client can terminate the request if the timeout is reached.

You could do this manually but you should probably use Client::timeout which does the calculation for you.

Implementations§

Source§

impl Client

Source

pub fn new(token: Token) -> Self

Creates a new client.

The token you pass in will be used for dns resolution as this requires (only) one socket.

Source

pub fn with_tls_config(token: Token, tls_config: Arc<ClientConfig>) -> Self

Creates a new client with a custom ClientConfig.

The token you pass in will be used for dns resolution as this requires (only) one socket.

Source

pub fn send( &mut self, io: &Poll, token: Token, input: impl Into<RawRequest>, ) -> Result<ReqId>

Send a request.

The token you pass in will be used for this request’s TCP connection. It will be available again once the request completed.

This function will return a ReqId that can be used to check which response belongs to which request later.

For more information on how to create a request see [Request] and RequestBuilder. If you wanna set a timeout, you can do so when creating a request. This function can take anything that implements Into<Request> so you can pass it a Request or a RequestBuilder, both will work.

§Example
let request = Request::get().host("example.com");
client.send(&io, mio::Token(1), request)?; // io is the mio::Poll
Source

pub fn pump(&mut self, io: &Poll, events: &Events) -> Result<Vec<Response>>

Drive all sent requests to completion and get the responses.

The pump function must be executed everytime an event is generated which belongs to this Client. You don’t need to match against the event token yourself though as this is done internally. All events not belonging to this Client will be ignored.

This function will return a Vec of responses, that contain the ReqId of the request that belongs to the response. The returned Vec may be empty, for example if the event belonged to dns resolution.

In general a request will go through following stages:

  1. Dns resolution, which will generate one or more events.
  2. Receiving the head, with information about the response such as the content length. (ResponseState::Head)
  3. Receiving the body, which will generate multiple events. (ResponseState::Data)
  4. In the end either ResponseState::Done or [ResponseState::Error].
§Example
let events = ...; // wait for new events using mio
let resps = client.pump(&io, &events)?;
if resps.is_empty() { println!("Got an event but no response yet!") }
for resp in resps {
    println!("Got a response: {:?}", resp.state);
}
§Note

The maximum response header count is currently 4096, but this will be user-controllable in the future.

Source

pub fn timeout(&self) -> Option<Duration>

Returns the smallest timeout for any of the current requests.

Use this function to always correctly set the timeout when waiting for events with mio.

§Example
client.send(&io, req1); // imagine 750ms timeout set on this request
client.send(&io, req2); // imagine 3s timeout set on this other one
io.poll(&mut events, client.timeout())?; // poll with smallest time left (here ~750ms)
§Note

This function comes with a very small runtime cost sinc it has to loop over all current requests.

Auto Trait Implementations§

§

impl !Freeze for Client

§

impl !RefUnwindSafe for Client

§

impl Send for Client

§

impl Sync for Client

§

impl Unpin for Client

§

impl !UnwindSafe for Client

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.