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
impl Client
Sourcepub fn new(token: Token) -> Self
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.
Sourcepub fn with_tls_config(token: Token, tls_config: Arc<ClientConfig>) -> Self
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.
Sourcepub fn send(
&mut self,
io: &Poll,
token: Token,
input: impl Into<RawRequest>,
) -> Result<ReqId>
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::PollSourcepub fn pump(&mut self, io: &Poll, events: &Events) -> Result<Vec<Response>>
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:
- Dns resolution, which will generate one or more events.
- Receiving the head, with information about the response such as the content length.
(
ResponseState::Head) - Receiving the body, which will generate multiple events.
(
ResponseState::Data) - In the end either
ResponseState::Doneor [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.
Sourcepub fn timeout(&self) -> Option<Duration>
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.