Expand description
Client implementation of the HTTP/2.0 protocol.
Getting started
Running an HTTP/2.0 client requires the caller to establish the underlying connection as well as get the connection to a state that is ready to begin the HTTP/2.0 handshake. See here for more details.
This could be as basic as using Tokio’s TcpStream
to connect to a remote
host, but usually it means using either ALPN or HTTP/1.1 protocol upgrades.
Once a connection is obtained, it is passed to handshake
, which will
begin the HTTP/2.0 handshake. This returns a future that completes once
the handshake process is performed and HTTP/2.0 streams may be initialized.
handshake
uses default configuration values. There are a number of
settings that can be changed by using Builder
instead.
Once the handshake future completes, the caller is provided with a
Connection
instance and a SendRequest
instance. The Connection
instance is used to drive the connection (see Managing the connection).
The SendRequest
instance is used to initialize new streams (see Making
requests).
Making requests
Requests are made using the SendRequest
handle provided by the handshake
future. Once a request is submitted, an HTTP/2.0 stream is initialized and
the request is sent to the server.
A request body and request trailers are sent using SendRequest
and the
server’s response is returned once the ResponseFuture
future completes.
Both the SendStream
and ResponseFuture
instances are returned by
SendRequest::send_request
and are tied to the HTTP/2.0 stream
initialized by the sent request.
The SendRequest::poll_ready
function returns Ready
when a new HTTP/2.0
stream can be created, i.e. as long as the current number of active streams
is below MAX_CONCURRENT_STREAMS
. If a new stream cannot be created, the
caller will be notified once an existing stream closes, freeing capacity for
the caller. The caller should use SendRequest::poll_ready
to check for
capacity before sending a request to the server.
SendRequest
enforces the MAX_CONCURRENT_STREAMS
setting. The user
must not send a request if poll_ready
does not return Ready
. Attempting
to do so will result in an Error
being returned.
Managing the connection
The Connection
instance is used to manage connection state. The caller
is required to call Connection::poll
in order to advance state.
SendRequest::send_request
and other functions have no effect unless
Connection::poll
is called.
The Connection
instance should only be dropped once Connection::poll
returns Ready
. At this point, the underlying socket has been closed and no
further work needs to be done.
The easiest way to ensure that the Connection
instance gets polled is to
submit the Connection
instance to an executor. The executor will then
manage polling the connection until the connection is complete.
Alternatively, the caller can call poll
manually.
Example
extern crate futures;
extern crate h2;
extern crate http;
extern crate tokio;
use h2::client;
use futures::*;
use http::*;
use tokio::net::TcpStream;
pub fn main() {
let addr = "127.0.0.1:5928".parse().unwrap();
tokio::run(
// Establish TCP connection to the server.
TcpStream::connect(&addr)
.map_err(|_| {
panic!("failed to establish TCP connection")
})
.and_then(|tcp| client::handshake(tcp))
.and_then(|(h2, connection)| {
let connection = connection
.map_err(|_| panic!("HTTP/2.0 connection failed"));
// Spawn a new task to drive the connection state
tokio::spawn(connection);
// Wait until the `SendRequest` handle has available
// capacity.
h2.ready()
})
.and_then(|mut h2| {
// Prepare the HTTP request to send to the server.
let request = Request::builder()
.method(Method::GET)
.uri("https://www.example.com/")
.body(())
.unwrap();
// Send the request. The second tuple item allows the caller
// to stream a request body.
let (response, _) = h2.send_request(request, true).unwrap();
response.and_then(|response| {
let (head, mut body) = response.into_parts();
println!("Received response: {:?}", head);
// The `release_capacity` handle allows the caller to manage
// flow control.
//
// Whenever data is received, the caller is responsible for
// releasing capacity back to the server once it has freed
// the data from memory.
let mut release_capacity = body.release_capacity().clone();
body.for_each(move |chunk| {
println!("RX: {:?}", chunk);
// Let the server send more data.
let _ = release_capacity.release_capacity(chunk.len());
Ok(())
})
})
})
.map_err(|e| panic!("failed to perform HTTP/2.0 request: {:?}", e))
)
}
Structs
Builds client connections with custom configuration values.
Manages all state associated with an HTTP/2.0 client connection.
Performs the HTTP/2.0 connection handshake.
A pushed response and corresponding request headers
A stream of pushed responses and corresponding promised requests
A future of a pushed HTTP response.
Returns a SendRequest
instance once it is ready to send at least one
request.
A future of an HTTP response.
Initializes new HTTP/2.0 streams on a connection by sending a request.
Functions
Creates a new configured HTTP/2.0 client with default configuration
values backed by io
.