Files
h2/examples/client.rs
Carl Lerche c4fc2928fe API cleanup (#155)
* Change send_reset to take &mut self.

While calling this function is the last thing that should be done with
the instance, the intent of the h2 library is not to be used directly by
users, but to be used as an implementation detail by other libraries.

Requiring `self` on `send_reset` is pretty annoying when calling the
function from inside a `Future` implementation. Also, all the other fns
on the type take `&mut self`.

* Remove the P: Peer generic from internals

* Split out `Respond` from `server::Stream`

This new type is used to send HTTP responses to the client as well as
reserve streams for push promises.

* Remove unused `Send` helper.

This could be brought back later when the API becomes stable.

* Unite `client` and `server` types

* Remove `B` generic from internal proto structs

This is a first step in removing the `B` generic from public API types
that do not strictly require it.

Currently, all public API types must be generic over `B` even if they do
not actually interact with the send data frame type. The first step in
removing this is to remove `B` as a generic on all internal types.

* Remove `Buffer<B>` from inner stream state

This is the next step in removing the `B` generic from all public API
types. The send buffer is the only type that requires `B`. It has now
been extracted from the rest of the stream state.

The strategy used in this PR requires an additional `Arc` and `Mutex`,
but this is not a fundamental requirement. The additional overhead can
be avoided with a little bit of unsafe code. However, this optimization
should not be made until it is proven that it is required.

* Remove `B` generic from `Body` + `ReleaseCapacity`

This commit actually removes the generic from these two public API
types. Also note, that removing the generic requires that `B: 'static`.
This is because there is no more generic on `Body` and `ReleaseCapacity`
and the compiler must be able to ensure that `B` outlives all `Body` and
`ReleaseCapacity` handles.

In practice, in an async world, passing a non 'static `B` is never going
to happen.

* Remove generic from `ResponseFuture`

This change also makes generic free types `Send`. The original strategy
of using a trait object meant that those handles could not be `Send`.
The solution was to avoid using the send buffer when canceling a stream.
This is done by transitioning the stream state to `Canceled`, a new
`Cause` variant.

* Simplify Send::send_reset

Now that implicit cancelation goes through a separate path, the
send_reset function can be simplified.

* Export types common to client & server at root

* Rename Stream -> SendStream, Body -> RecvStream

* Implement send_reset on server::Respond
2017-10-19 20:02:08 -07:00

99 lines
2.5 KiB
Rust

extern crate env_logger;
extern crate futures;
extern crate h2;
extern crate http;
extern crate io_dump;
extern crate tokio_core;
use h2::client::{Client};
use h2::RecvStream;
use futures::*;
use http::*;
use tokio_core::net::TcpStream;
use tokio_core::reactor;
struct Process {
body: RecvStream,
trailers: bool,
}
impl Future for Process {
type Item = ();
type Error = h2::Error;
fn poll(&mut self) -> Poll<(), h2::Error> {
loop {
if self.trailers {
let trailers = try_ready!(self.body.poll_trailers());
println!("GOT TRAILERS: {:?}", trailers);
return Ok(().into());
} else {
match try_ready!(self.body.poll()) {
Some(chunk) => {
println!("GOT CHUNK = {:?}", chunk);
},
None => {
self.trailers = true;
},
}
}
}
}
}
pub fn main() {
let _ = env_logger::init();
let mut core = reactor::Core::new().unwrap();
let handle = core.handle();
let tcp = TcpStream::connect(&"127.0.0.1:5928".parse().unwrap(), &handle);
let tcp = tcp.then(|res| {
let tcp = io_dump::Dump::to_stdout(res.unwrap());
Client::handshake(tcp)
}).then(|res| {
let (mut client, h2) = res.unwrap();
println!("sending request");
let request = Request::builder()
.uri("https://http2.akamai.com/")
.body(())
.unwrap();
let mut trailers = HeaderMap::new();
trailers.insert("zomg", "hello".parse().unwrap());
let (response, mut stream) = client.send_request(request, false).unwrap();
// send trailers
stream.send_trailers(trailers).unwrap();
// Spawn a task to run the conn...
handle.spawn(h2.map_err(|e| println!("GOT ERR={:?}", e)));
response
.and_then(|response| {
println!("GOT RESPONSE: {:?}", response);
// Get the body
let (_, body) = response.into_parts();
Process {
body,
trailers: false,
}
})
.map_err(|e| {
println!("GOT ERR={:?}", e);
})
});
core.run(tcp).unwrap();
}