Merge pull request #12 from carllerche/stream-api

Restructure API using a handle per stream
This commit is contained in:
Carl Lerche
2017-08-08 15:42:24 -07:00
committed by GitHub
29 changed files with 1933 additions and 823 deletions

View File

@@ -8,7 +8,7 @@ futures = "0.1"
tokio-io = "0.1"
tokio-timer = "0.1"
bytes = "0.4"
http = { git = "https://github.com/carllerche/http" }
http = { git = "https://github.com/carllerche/http", branch = "uri-try-from-parts" }
byteorder = "1.0"
log = "0.3.8"
fnv = "1.0.5"

View File

@@ -8,23 +8,29 @@ extern crate openssl;
extern crate io_dump;
extern crate env_logger;
use h2::client;
use http::request;
use h2::client::Client;
use http::{method, Request};
use futures::*;
use tokio_core::reactor;
use tokio_core::net::TcpStream;
use std::net::ToSocketAddrs;
pub fn main() {
let _ = env_logger::init();
let mut core = reactor::Core::new().unwrap();;
// Sync DNS resolution.
let addr = "http2.akamai.com:443".to_socket_addrs()
.unwrap().next().unwrap();
let tcp = TcpStream::connect(
&"23.39.23.98:443".parse().unwrap(),
&core.handle());
println!("ADDR: {:?}", addr);
let mut core = reactor::Core::new().unwrap();;
let handle = core.handle();
let tcp = TcpStream::connect(&addr, &handle);
let tcp = tcp.then(|res| {
use openssl::ssl::{SslMethod, SslConnectorBuilder};
@@ -46,24 +52,29 @@ pub fn main() {
// Dump output to stdout
let tls = io_dump::Dump::to_stdout(tls);
client::handshake(tls)
println!("Starting client handshake");
Client::handshake(tls)
})
.then(|res| {
let conn = res.unwrap();
let mut h2 = res.unwrap();
let mut request = request::Head::default();
request.uri = "https://http2.akamai.com/".parse().unwrap();
// request.version = version::H2;
let request = Request::builder()
.method(method::GET)
.uri("https://http2.akamai.com/")
.body(()).unwrap();
conn.send_request(1.into(), request, true)
})
.then(|res| {
let conn = res.unwrap();
// Get the next message
conn.for_each(|frame| {
println!("RX: {:?}", frame);
Ok(())
})
let stream = h2.request(request, true).unwrap();
let stream = stream.and_then(|response| {
let (_, body) = response.into_parts();
body.for_each(|chunk| {
println!("RX: {:?}", chunk);
Ok(())
})
});
h2.join(stream)
})
});

View File

@@ -1,3 +1,4 @@
/*
extern crate h2;
extern crate http;
extern crate futures;
@@ -59,3 +60,6 @@ pub fn main() {
core.run(tcp).unwrap();
}
*/
pub fn main() {}

View File

@@ -1,3 +1,4 @@
/*
extern crate h2;
extern crate http;
extern crate futures;
@@ -72,3 +73,6 @@ pub fn main() {
core.run(server).unwrap();
}
*/
pub fn main() {}

View File

@@ -1,7 +1,9 @@
use {frame, proto, Peer, ConnectionError, StreamId};
use {frame, ConnectionError, StreamId};
use proto::{self, Connection};
use error::Reason::*;
use http;
use futures::{Future, Poll, Sink, AsyncSink};
use http::{self, Request, Response};
use futures::{self, Future, Poll, Sink, AsyncSink};
use tokio_io::{AsyncRead, AsyncWrite};
use bytes::{Bytes, IntoBuf};
@@ -10,57 +12,201 @@ use std::fmt;
/// In progress H2 connection binding
pub struct Handshake<T, B: IntoBuf = Bytes> {
// TODO: unbox
inner: Box<Future<Item = Connection<T, B>, Error = ConnectionError>>,
inner: Box<Future<Item = Client<T, B>, Error = ConnectionError>>,
}
#[derive(Debug)]
pub(crate) struct Peer;
/// Marker type indicating a client peer
#[derive(Debug)]
pub struct Client;
pub type Connection<T, B = Bytes> = super::Connection<T, Client, B>;
pub fn handshake<T>(io: T) -> Handshake<T, Bytes>
where T: AsyncRead + AsyncWrite + 'static,
{
handshake2(io)
pub struct Client<T, B: IntoBuf> {
connection: Connection<T, Peer, B>,
}
/// Bind an H2 client connection.
///
/// Returns a future which resolves to the connection value once the H2
/// handshake has been completed.
pub fn handshake2<T, B>(io: T) -> Handshake<T, B>
#[derive(Debug)]
pub struct Stream<B: IntoBuf> {
inner: proto::StreamRef<Peer, B::Buf>,
}
#[derive(Debug)]
pub struct Body<B: IntoBuf> {
inner: proto::StreamRef<Peer, B::Buf>,
}
#[derive(Debug)]
pub struct Chunk<B: IntoBuf> {
inner: proto::Chunk<Peer, B::Buf>,
}
impl<T> Client<T, Bytes>
where T: AsyncRead + AsyncWrite + 'static,
{
pub fn handshake(io: T) -> Handshake<T, Bytes> {
Client::handshake2(io)
}
}
impl<T, B> Client<T, B>
// TODO: Get rid of 'static
where T: AsyncRead + AsyncWrite + 'static,
B: IntoBuf + 'static,
{
use tokio_io::io;
/// Bind an H2 client connection.
///
/// Returns a future which resolves to the connection value once the H2
/// handshake has been completed.
pub fn handshake2(io: T) -> Handshake<T, B> {
use tokio_io::io;
debug!("binding client connection");
debug!("binding client connection");
let handshake = io::write_all(io, b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")
.map_err(ConnectionError::from)
.and_then(|(io, _)| {
debug!("client connection bound");
let handshake = io::write_all(io, b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")
.map_err(ConnectionError::from)
.and_then(|(io, _)| {
debug!("client connection bound");
let mut framed_write = proto::framed_write(io);
let settings = frame::Settings::default();
let mut framed_write = proto::framed_write(io);
let settings = frame::Settings::default();
// Send initial settings frame
match framed_write.start_send(settings.into()) {
Ok(AsyncSink::Ready) => {
Ok(proto::from_framed_write(framed_write))
// Send initial settings frame
match framed_write.start_send(settings.into()) {
Ok(AsyncSink::Ready) => {
let conn = proto::from_framed_write(framed_write);
Ok(Client { connection: conn })
}
Ok(_) => unreachable!(),
Err(e) => Err(ConnectionError::from(e)),
}
Ok(_) => unreachable!(),
Err(e) => Err(ConnectionError::from(e)),
}
});
});
Handshake { inner: Box::new(handshake) }
Handshake { inner: Box::new(handshake) }
}
/// Returns `Ready` when the connection can initialize a new HTTP 2.0
/// stream.
pub fn poll_ready(&mut self) -> Poll<(), ConnectionError> {
unimplemented!();
}
/// Send a request on a new HTTP 2.0 stream
pub fn request(&mut self, request: Request<()>, end_of_stream: bool)
-> Result<Stream<B>, ConnectionError>
{
self.connection.send_request(request, end_of_stream)
.map(|stream| Stream {
inner: stream,
})
}
}
impl Peer for Client {
type Send = http::request::Head;
type Poll = http::response::Head;
impl<T, B> Future for Client<T, B>
// TODO: Get rid of 'static
where T: AsyncRead + AsyncWrite + 'static,
B: IntoBuf + 'static,
{
type Item = ();
type Error = ConnectionError;
fn poll(&mut self) -> Poll<(), ConnectionError> {
self.connection.poll()
}
}
impl<T, B> fmt::Debug for Client<T, B>
where T: fmt::Debug,
B: fmt::Debug + IntoBuf,
B::Buf: fmt::Debug + IntoBuf,
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Client")
.field("connection", &self.connection)
.finish()
}
}
// ===== impl Handshake =====
impl<T, B: IntoBuf> Future for Handshake<T, B> {
type Item = Client<T, B>;
type Error = ConnectionError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
self.inner.poll()
}
}
impl<T, B> fmt::Debug for Handshake<T, B>
where T: fmt::Debug,
B: fmt::Debug + IntoBuf,
B::Buf: fmt::Debug + IntoBuf,
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "client::Handshake")
}
}
// ===== impl Stream =====
impl<B: IntoBuf> Stream<B> {
/// Receive the HTTP/2.0 response, if it is ready.
pub fn poll_response(&mut self) -> Poll<Response<Body<B>>, ConnectionError> {
let (parts, _) = try_ready!(self.inner.poll_response()).into_parts();
let body = Body { inner: self.inner.clone() };
Ok(Response::from_parts(parts, body).into())
}
/// Send data
pub fn send_data(&mut self, data: B, end_of_stream: bool)
-> Result<(), ConnectionError>
{
self.inner.send_data(data.into_buf(), end_of_stream)
}
/// Send trailers
pub fn send_trailers(&mut self, trailers: ())
-> Result<(), ConnectionError>
{
unimplemented!();
}
}
impl<B: IntoBuf> Future for Stream<B> {
type Item = Response<Body<B>>;
type Error = ConnectionError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
self.poll_response()
}
}
// ===== impl Body =====
impl<B: IntoBuf> futures::Stream for Body<B> {
type Item = Chunk<B>;
type Error = ConnectionError;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
let chunk = try_ready!(self.inner.poll_data())
.map(|inner| Chunk { inner });
Ok(chunk.into())
}
}
// ===== impl Chunk =====
impl<B: IntoBuf> Chunk<B> {
pub fn pop_bytes(&mut self) -> Option<Bytes> {
self.inner.pop_bytes()
}
}
// ===== impl Peer =====
impl proto::Peer for Peer {
type Send = Request<()>;
type Poll = Response<()>;
fn is_server() -> bool {
false
@@ -68,15 +214,12 @@ impl Peer for Client {
fn convert_send_message(
id: StreamId,
headers: Self::Send,
request: Self::Send,
end_of_stream: bool) -> frame::Headers
{
use http::request::Head;
use http::request::Parts;
// Extract the components of the HTTP request
let Head { method, uri, headers, .. } = headers;
// TODO: Ensure that the version is set to H2
let (Parts { method, uri, headers, .. }, _) = request.into_parts();
// Build the set pseudo header set. All requests will include `method`
// and `path`.
@@ -92,25 +235,9 @@ impl Peer for Client {
frame
}
fn convert_poll_message(headers: frame::Headers) -> Self::Poll {
fn convert_poll_message(headers: frame::Headers) -> Result<Self::Poll, ConnectionError> {
headers.into_response()
}
}
impl<T, B: IntoBuf> Future for Handshake<T, B> {
type Item = Connection<T, B>;
type Error = ConnectionError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
self.inner.poll()
}
}
impl<T, B> fmt::Debug for Handshake<T, B>
where T: fmt::Debug,
B: fmt::Debug + IntoBuf,
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "client::Handshake")
// TODO: Is this always a protocol error?
.map_err(|_| ProtocolError.into())
}
}

View File

@@ -3,7 +3,8 @@ use hpack;
use frame::{self, Frame, Head, Kind, Error};
use HeaderMap;
use http::{request, response, version, uri, Method, StatusCode, Uri};
use http::{self, request, response, version, uri, Method, StatusCode, Uri};
use http::{Request, Response};
use http::header::{self, HeaderName, HeaderValue};
use bytes::{BytesMut, Bytes};
@@ -46,11 +47,11 @@ pub struct PushPromise {
promised_id: StreamId,
/// The associated flags
flags: HeadersFlag,
flags: PushPromiseFlag,
}
impl PushPromise {
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct PushPromiseFlag(u8);
#[derive(Debug)]
pub struct Continuation {
@@ -199,31 +200,28 @@ impl Headers {
self.flags.set_end_stream()
}
pub fn into_response(self) -> response::Head {
let mut response = response::Head::default();
pub fn into_response(self) -> http::Result<Response<()>> {
let mut b = Response::builder();
if let Some(status) = self.pseudo.status {
response.status = status;
} else {
unimplemented!();
b.status(status);
}
response.headers = self.fields;
response
let mut response = try!(b.body(()));
*response.headers_mut() = self.fields;
Ok(response)
}
pub fn into_request(self) -> request::Head {
let mut request = request::Head::default();
pub fn into_request(self) -> http::Result<Request<()>> {
let mut b = Request::builder();
// TODO: should we distinguish between HTTP_2 and HTTP_2C?
// carllerche/http#42
request.version = version::HTTP_2;
b.version(version::HTTP_2);
if let Some(method) = self.pseudo.method {
request.method = method;
} else {
// TODO: invalid request
unimplemented!();
b.method(method);
}
// Convert the URI
@@ -244,12 +242,12 @@ impl Headers {
parts.origin_form = Some(uri::OriginForm::try_from_shared(path.into_inner()).unwrap());
}
request.uri = parts.into();
b.uri(parts);
// Set the header fields
request.headers = self.fields;
let mut request = try!(b.body(()));
*request.headers_mut() = self.fields;
request
Ok(request)
}
pub fn into_fields(self) -> HeaderMap {
@@ -298,12 +296,46 @@ impl Headers {
}
}
impl From<Headers> for Frame {
fn from(src: Headers) -> Frame {
impl<T> From<Headers> for Frame<T> {
fn from(src: Headers) -> Self {
Frame::Headers(src)
}
}
// ===== impl PushPromise =====
impl PushPromise {
pub fn load(head: Head, payload: &[u8])
-> Result<Self, Error>
{
let flags = PushPromiseFlag(head.flag());
// TODO: Handle padding
let promised_id = StreamId::parse(&payload[..4]);
Ok(PushPromise {
stream_id: head.stream_id(),
promised_id: promised_id,
flags: flags,
})
}
pub fn stream_id(&self) -> StreamId {
self.stream_id
}
pub fn promised_id(&self) -> StreamId {
self.promised_id
}
}
impl<T> From<PushPromise> for Frame<T> {
fn from(src: PushPromise) -> Self {
Frame::PushPromise(src)
}
}
// ===== impl Pseudo =====
impl Pseudo {

View File

@@ -67,6 +67,15 @@ pub enum Frame<T = Bytes> {
}
impl<T> Frame<T> {
/// Returns true if the frame is a DATA frame.
pub fn is_data(&self) -> bool {
use self::Frame::*;
match *self {
Data(..) => true,
_ => false,
}
}
}
impl<T> fmt::Debug for Frame<T> {

View File

@@ -39,6 +39,10 @@ impl StreamId {
pub fn is_zero(&self) -> bool {
self.0 == 0
}
pub fn increment(&mut self) {
self.0 += 2;
}
}
impl From<u32> for StreamId {

View File

@@ -495,29 +495,29 @@ impl From<Utf8Error> for DecoderError {
}
}
impl From<header::InvalidValueError> for DecoderError {
fn from(_: header::InvalidValueError) -> DecoderError {
impl From<header::InvalidHeaderValue> for DecoderError {
fn from(_: header::InvalidHeaderValue) -> DecoderError {
// TODO: Better error?
DecoderError::InvalidUtf8
}
}
impl From<method::FromBytesError> for DecoderError {
fn from(_: method::FromBytesError) -> DecoderError {
impl From<header::InvalidHeaderName> for DecoderError {
fn from(_: header::InvalidHeaderName) -> DecoderError {
// TODO: Better error
DecoderError::InvalidUtf8
}
}
impl From<header::FromBytesError> for DecoderError {
fn from(_: header::FromBytesError) -> DecoderError {
impl From<method::InvalidMethod> for DecoderError {
fn from(_: method::InvalidMethod) -> DecoderError {
// TODO: Better error
DecoderError::InvalidUtf8
}
}
impl From<status::FromStrError> for DecoderError {
fn from(_: status::FromStrError) -> DecoderError {
impl From<status::InvalidStatusCode> for DecoderError {
fn from(_: status::InvalidStatusCode) -> DecoderError {
// TODO: Better error
DecoderError::InvalidUtf8
}

View File

@@ -251,7 +251,6 @@ fn gen_header_name(g: &mut StdRng) -> HeaderName {
header::ACCEPT_CHARSET,
header::ACCEPT_ENCODING,
header::ACCEPT_LANGUAGE,
header::ACCEPT_PATCH,
header::ACCEPT_RANGES,
header::ACCESS_CONTROL_ALLOW_CREDENTIALS,
header::ACCESS_CONTROL_ALLOW_HEADERS,
@@ -272,7 +271,6 @@ fn gen_header_name(g: &mut StdRng) -> HeaderName {
header::CONTENT_LANGUAGE,
header::CONTENT_LENGTH,
header::CONTENT_LOCATION,
header::CONTENT_MD5,
header::CONTENT_RANGE,
header::CONTENT_SECURITY_POLICY,
header::CONTENT_SECURITY_POLICY_REPORT_ONLY,
@@ -292,7 +290,6 @@ fn gen_header_name(g: &mut StdRng) -> HeaderName {
header::IF_RANGE,
header::IF_UNMODIFIED_SINCE,
header::LAST_MODIFIED,
header::KEEP_ALIVE,
header::LINK,
header::LOCATION,
header::MAX_FORWARDS,
@@ -311,10 +308,8 @@ fn gen_header_name(g: &mut StdRng) -> HeaderName {
header::SET_COOKIE,
header::STRICT_TRANSPORT_SECURITY,
header::TE,
header::TK,
header::TRAILER,
header::TRANSFER_ENCODING,
header::TSV,
header::USER_AGENT,
header::UPGRADE,
header::UPGRADE_INSECURE_REQUESTS,

View File

@@ -1,5 +1,5 @@
// #![allow(warnings)]
#![deny(missing_debug_implementations)]
#![allow(warnings)]
// #![deny(missing_debug_implementations)]
#[macro_use]
extern crate futures;
@@ -20,6 +20,8 @@ extern crate fnv;
extern crate byteorder;
extern crate slab;
#[macro_use]
extern crate log;
@@ -30,11 +32,10 @@ pub mod error;
mod hpack;
mod proto;
mod frame;
pub mod server;
// pub mod server;
pub use error::{ConnectionError, Reason};
pub use frame::StreamId;
pub use proto::Connection;
use bytes::Bytes;
@@ -68,23 +69,3 @@ pub enum Frame<T, B = Bytes> {
error: Reason,
},
}
/// Either a Client or a Server
pub trait Peer {
/// Message type sent into the transport
type Send;
/// Message type polled from the transport
type Poll;
fn is_server() -> bool;
#[doc(hidden)]
fn convert_send_message(
id: StreamId,
headers: Self::Send,
end_of_stream: bool) -> frame::Headers;
#[doc(hidden)]
fn convert_poll_message(headers: frame::Headers) -> Self::Poll;
}

View File

@@ -1,12 +1,10 @@
use {ConnectionError, Frame, Peer};
use {client, ConnectionError, Frame};
use HeaderMap;
use frame::{self, StreamId};
use client::Client;
use server::Server;
use proto::*;
use http::{request, response};
use http::{Request, Response};
use bytes::{Bytes, IntoBuf};
use tokio_io::{AsyncRead, AsyncWrite};
@@ -21,39 +19,34 @@ pub struct Connection<T, P, B: IntoBuf = Bytes> {
// TODO: Remove <B>
ping_pong: PingPong<B::Buf>,
settings: Settings,
streams: Streams<P>,
streams: Streams<P, B::Buf>,
_phantom: PhantomData<P>,
}
pub fn new<T, P, B>(codec: Codec<T, B::Buf>)
-> Connection<T, P, B>
where T: AsyncRead + AsyncWrite,
P: Peer,
B: IntoBuf,
{
// TODO: Actually configure
let streams = Streams::new(streams::Config {
max_remote_initiated: None,
init_remote_window_sz: DEFAULT_INITIAL_WINDOW_SIZE,
max_local_initiated: None,
init_local_window_sz: DEFAULT_INITIAL_WINDOW_SIZE,
});
Connection {
codec: codec,
ping_pong: PingPong::new(),
settings: Settings::new(),
streams: streams,
_phantom: PhantomData,
}
}
impl<T, P, B> Connection<T, P, B>
where T: AsyncRead + AsyncWrite,
P: Peer,
B: IntoBuf,
{
pub fn new(codec: Codec<T, B::Buf>) -> Connection<T, P, B> {
// TODO: Actually configure
let streams = Streams::new(streams::Config {
max_remote_initiated: None,
init_remote_window_sz: DEFAULT_INITIAL_WINDOW_SIZE,
max_local_initiated: None,
init_local_window_sz: DEFAULT_INITIAL_WINDOW_SIZE,
});
Connection {
codec: codec,
ping_pong: PingPong::new(),
settings: Settings::new(),
streams: streams,
_phantom: PhantomData,
}
}
/// Polls for the next update to a remote flow control window.
pub fn poll_window_update(&mut self) -> Poll<WindowUpdate, ConnectionError> {
self.streams.poll_window_update()
@@ -87,6 +80,7 @@ impl<T, P, B> Connection<T, P, B>
unimplemented!();
}
/// Returns `Ready` when the connection is ready to receive a frame.
pub fn poll_ready(&mut self) -> Poll<(), ConnectionError> {
try_ready!(self.poll_send_ready());
@@ -96,6 +90,94 @@ impl<T, P, B> Connection<T, P, B>
Ok(().into())
}
/// Advances the internal state of the connection.
pub fn poll(&mut self) -> Poll<(), ConnectionError> {
match self.poll2() {
Err(e) => {
self.streams.recv_err(&e);
Err(e)
}
ret => ret,
}
}
fn poll2(&mut self) -> Poll<(), ConnectionError> {
use frame::Frame::*;
loop {
// First, ensure that the `Connection` is able to receive a frame
try_ready!(self.poll_recv_ready());
trace!("polling codec");
let frame = match try!(self.codec.poll()) {
Async::Ready(frame) => frame,
Async::NotReady => {
// Flush any pending writes
let _ = try!(self.poll_complete());
return Ok(Async::NotReady);
}
};
match frame {
Some(Headers(frame)) => {
trace!("recv HEADERS; frame={:?}", frame);
if let Some(frame) = try!(self.streams.recv_headers(frame)) {
unimplemented!();
}
/*
// Update stream state while ensuring that the headers frame
// can be received.
if let Some(frame) = try!(self.streams.recv_headers(frame)) {
let frame = Self::convert_poll_message(frame)?;
return Ok(Some(frame).into());
}
*/
}
Some(Data(frame)) => {
trace!("recv DATA; frame={:?}", frame);
try!(self.streams.recv_data(frame));
}
Some(Reset(frame)) => {
trace!("recv RST_STREAM; frame={:?}", frame);
try!(self.streams.recv_reset(frame));
}
Some(PushPromise(frame)) => {
trace!("recv PUSH_PROMISE; frame={:?}", frame);
self.streams.recv_push_promise(frame)?;
}
Some(Settings(frame)) => {
trace!("recv SETTINGS; frame={:?}", frame);
self.settings.recv_settings(frame);
// TODO: ACK must be sent THEN settings applied.
}
Some(Ping(frame)) => {
unimplemented!();
/*
trace!("recv PING; frame={:?}", frame);
self.ping_pong.recv_ping(frame);
*/
}
Some(WindowUpdate(frame)) => {
unimplemented!();
/*
trace!("recv WINDOW_UPDATE; frame={:?}", frame);
try!(self.streams.recv_window_update(frame));
*/
}
None => {
// TODO: Is this correct?
trace!("codec closed");
return Ok(Async::Ready(()));
}
}
}
}
/*
pub fn send_data(self,
id: StreamId,
data: B,
@@ -119,10 +201,7 @@ impl<T, P, B> Connection<T, P, B>
headers,
})
}
pub fn start_ping(&mut self, _body: PingPayload) -> StartSend<PingPayload, ConnectionError> {
unimplemented!();
}
*/
// ===== Private =====
@@ -146,110 +225,51 @@ impl<T, P, B> Connection<T, P, B>
/// This function is currently used by poll_complete, but at some point it
/// will probably not be required.
fn poll_send_ready(&mut self) -> Poll<(), ConnectionError> {
// TODO: Is this function needed?
try_ready!(self.poll_recv_ready());
// Ensure all window updates have been sent.
try_ready!(self.streams.send_pending_window_updates(&mut self.codec));
Ok(().into())
}
/// Try to receive the next frame
fn recv_frame(&mut self) -> Poll<Option<Frame<P::Poll>>, ConnectionError> {
use frame::Frame::*;
fn poll_complete(&mut self) -> Poll<(), ConnectionError> {
try_ready!(self.poll_send_ready());
loop {
// First, ensure that the `Connection` is able to receive a frame
try_ready!(self.poll_recv_ready());
// Ensure all window updates have been sent.
try_ready!(self.streams.poll_complete(&mut self.codec));
try_ready!(self.codec.poll_complete());
trace!("polling codec");
let frame = match try!(self.codec.poll()) {
Async::Ready(frame) => frame,
Async::NotReady => {
// Receiving new frames may depend on ensuring that the write buffer
// is clear (e.g. if window updates need to be sent), so `poll_complete`
// is called here.
let _ = try!(self.poll_complete());
return Ok(Async::NotReady);
}
};
match frame {
Some(Headers(frame)) => {
trace!("recv HEADERS; frame={:?}", frame);
// Update stream state while ensuring that the headers frame
// can be received.
if let Some(frame) = try!(self.streams.recv_headers(frame)) {
let frame = Self::convert_poll_message(frame);
return Ok(Some(frame).into());
}
}
Some(Data(frame)) => {
trace!("recv DATA; frame={:?}", frame);
try!(self.streams.recv_data(&frame));
let frame = Frame::Data {
id: frame.stream_id(),
end_of_stream: frame.is_end_stream(),
data: frame.into_payload(),
};
return Ok(Some(frame).into());
}
Some(Reset(frame)) => {
trace!("recv RST_STREAM; frame={:?}", frame);
try!(self.streams.recv_reset(&frame));
let frame = Frame::Reset {
id: frame.stream_id(),
error: frame.reason(),
};
return Ok(Some(frame).into());
}
Some(PushPromise(frame)) => {
trace!("recv PUSH_PROMISE; frame={:?}", frame);
try!(self.streams.recv_push_promise(frame));
}
Some(Settings(frame)) => {
trace!("recv SETTINGS; frame={:?}", frame);
self.settings.recv_settings(frame);
// TODO: ACK must be sent THEN settings applied.
}
Some(Ping(frame)) => {
trace!("recv PING; frame={:?}", frame);
self.ping_pong.recv_ping(frame);
}
Some(WindowUpdate(frame)) => {
trace!("recv WINDOW_UPDATE; frame={:?}", frame);
try!(self.streams.recv_window_update(frame));
}
None => {
trace!("codec closed");
return Ok(Async::Ready(None));
}
}
}
Ok(().into())
}
fn convert_poll_message(frame: frame::Headers) -> Frame<P::Poll> {
fn convert_poll_message(frame: frame::Headers) -> Result<Frame<P::Poll>, ConnectionError> {
if frame.is_trailers() {
Frame::Trailers {
Ok(Frame::Trailers {
id: frame.stream_id(),
headers: frame.into_fields()
}
})
} else {
Frame::Headers {
Ok(Frame::Headers {
id: frame.stream_id(),
end_of_stream: frame.is_end_stream(),
headers: P::convert_poll_message(frame),
}
headers: P::convert_poll_message(frame)?,
})
}
}
}
impl<T, B> Connection<T, client::Peer, B>
where T: AsyncRead + AsyncWrite,
B: IntoBuf,
{
/// Initialize a new HTTP/2.0 stream and send the message.
pub fn send_request(&mut self, request: Request<()>, end_of_stream: bool)
-> Result<StreamRef<client::Peer, B::Buf>, ConnectionError>
{
self.streams.send_request(request, end_of_stream)
}
}
/*
impl<T, B> Connection<T, Client, B>
where T: AsyncRead + AsyncWrite,
B: IntoBuf,
@@ -296,21 +316,9 @@ impl<T, B> Connection<T, Server, B>
})
}
}
*/
impl<T, P, B> Stream for Connection<T, P, B>
where T: AsyncRead + AsyncWrite,
P: Peer,
B: IntoBuf,
{
type Item = Frame<P::Poll>;
type Error = ConnectionError;
fn poll(&mut self) -> Poll<Option<Self::Item>, ConnectionError> {
// TODO: intercept errors and flag the connection
self.recv_frame()
}
}
/*
impl<T, P, B> Sink for Connection<T, P, B>
where T: AsyncRead + AsyncWrite,
P: Peer,
@@ -384,11 +392,5 @@ impl<T, P, B> Sink for Connection<T, P, B>
// Return success
Ok(AsyncSink::Ready)
}
fn poll_complete(&mut self) -> Poll<(), ConnectionError> {
try_ready!(self.poll_send_ready());
try_ready!(self.codec.poll_complete());
Ok(().into())
}
}
*/

View File

@@ -92,7 +92,9 @@ impl<T> FramedRead<T> {
let _todo = try!(frame::GoAway::load(&bytes[frame::HEADER_LEN..]));
unimplemented!();
}
Kind::PushPromise |
Kind::PushPromise => {
frame::PushPromise::load(head, &bytes[frame::HEADER_LEN..])?.into()
}
Kind::Priority |
Kind::Continuation |
Kind::Unknown => {
@@ -117,7 +119,7 @@ impl<T: ApplySettings> ApplySettings for FramedRead<T> {
}
*/
impl<T> Stream for FramedRead<T>
impl<T> futures::Stream for FramedRead<T>
where T: AsyncRead,
{
type Item = Frame;

View File

@@ -6,22 +6,42 @@ mod settings;
mod streams;
pub use self::connection::Connection;
pub use self::streams::{Streams, StreamRef, Chunk};
use self::framed_read::FramedRead;
use self::framed_write::FramedWrite;
use self::ping_pong::PingPong;
use self::settings::Settings;
use self::streams::Streams;
use {StreamId, Peer};
use {StreamId, ConnectionError};
use error::Reason;
use frame::Frame;
use frame::{self, Frame};
use futures::*;
use futures::{self, task, Poll, Async, AsyncSink, Sink, Stream as Stream2};
use bytes::{Buf, IntoBuf};
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::codec::length_delimited;
/// Either a Client or a Server
pub trait Peer {
/// Message type sent into the transport
type Send;
/// Message type polled from the transport
type Poll;
fn is_server() -> bool;
#[doc(hidden)]
fn convert_send_message(
id: StreamId,
headers: Self::Send,
end_of_stream: bool) -> frame::Headers;
#[doc(hidden)]
fn convert_poll_message(headers: frame::Headers) -> Result<Self::Poll, ConnectionError>;
}
pub type PingPayload = [u8; 8];
pub type WindowSize = u32;
@@ -69,7 +89,7 @@ pub fn from_framed_write<T, P, B>(framed_write: FramedWrite<T, B::Buf>)
let codec = FramedRead::new(framed);
connection::new(codec)
Connection::new(codec)
}
impl WindowUpdate {

140
src/proto/streams/buffer.rs Normal file
View File

@@ -0,0 +1,140 @@
use frame::{self, Frame};
use slab::Slab;
use std::marker::PhantomData;
/// Buffers frames for multiple streams.
#[derive(Debug)]
pub struct Buffer<B> {
slab: Slab<Slot<B>>,
}
/// A sequence of frames in a `Buffer`
#[derive(Debug)]
pub struct Deque<B> {
indices: Option<Indices>,
_p: PhantomData<B>,
}
/// Tracks the head & tail for a sequence of frames in a `Buffer`.
#[derive(Debug, Default, Copy, Clone)]
struct Indices {
head: usize,
tail: usize,
}
#[derive(Debug)]
struct Slot<B> {
frame: Frame<B>,
next: Option<usize>,
}
impl<B> Buffer<B> {
pub fn new() -> Self {
Buffer {
slab: Slab::new(),
}
}
}
impl<B> Deque<B> {
pub fn new() -> Self {
Deque {
indices: None,
_p: PhantomData,
}
}
pub fn is_empty(&self) -> bool {
self.indices.is_none()
}
pub fn push_back(&mut self, buf: &mut Buffer<B>, frame: Frame<B>) {
let key = buf.slab.insert(Slot {
frame,
next: None,
});
match self.indices {
Some(ref mut idxs) => {
buf.slab[idxs.tail].next = Some(key);
idxs.tail = key;
}
None => {
self.indices = Some(Indices {
head: key,
tail: key,
});
}
}
}
pub fn pop_front(&mut self, buf: &mut Buffer<B>) -> Option<Frame<B>> {
match self.indices {
Some(mut idxs) => {
let mut slot = buf.slab.remove(idxs.head);
if idxs.head == idxs.tail {
assert!(slot.next.is_none());
self.indices = None;
} else {
idxs.head = slot.next.take().unwrap();
self.indices = Some(idxs);
}
return Some(slot.frame);
}
None => None,
}
}
pub fn take_while<F>(&mut self, buf: &mut Buffer<B>, mut f: F) -> Self
where F: FnMut(&Frame<B>) -> bool
{
match self.indices {
Some(mut idxs) => {
if !f(&buf.slab[idxs.head].frame) {
return Deque::new();
}
let head = idxs.head;
let mut tail = idxs.head;
loop {
let next = match buf.slab[tail].next {
Some(next) => next,
None => {
self.indices = None;
return Deque {
indices: Some(idxs),
_p: PhantomData,
};
}
};
if !f(&buf.slab[next].frame) {
// Split the linked list
buf.slab[tail].next = None;
self.indices = Some(Indices {
head: next,
tail: idxs.tail,
});
return Deque {
indices: Some(Indices {
head: head,
tail: tail,
}),
_p: PhantomData,
}
}
tail = next;
}
}
None => Deque::new(),
}
}
}

View File

@@ -1,43 +1,31 @@
mod buffer;
mod flow_control;
mod prioritize;
mod recv;
mod send;
mod state;
mod store;
mod stream;
mod streams;
pub use self::streams::{Streams, StreamRef, Chunk};
use self::buffer::Buffer;
use self::flow_control::FlowControl;
use self::prioritize::Prioritize;
use self::recv::Recv;
use self::send::Send;
use self::state::State;
use self::store::{Store, Entry};
use self::stream::Stream;
use {frame, Peer, StreamId, ConnectionError};
use {frame, StreamId, ConnectionError};
use proto::*;
use error::Reason::*;
use error::User::*;
// TODO: All the VecDeques should become linked lists using the State
// values.
#[derive(Debug)]
pub struct Streams<P> {
/// State related to managing the set of streams.
inner: Inner<P>,
/// Streams
streams: Store,
}
/// Fields needed to manage state related to managing the set of streams. This
/// is mostly split out to make ownership happy.
///
/// TODO: better name
#[derive(Debug)]
struct Inner<P> {
/// Manages state transitions initiated by receiving frames
recv: Recv<P>,
/// Manages state transitions initiated by sending frames
send: Send<P>,
}
use http::{Request, Response};
use bytes::Bytes;
#[derive(Debug)]
pub struct Config {
@@ -53,218 +41,3 @@ pub struct Config {
/// Initial window size of locally initiated streams
pub init_local_window_sz: WindowSize,
}
impl<P: Peer> Streams<P> {
pub fn new(config: Config) -> Self {
Streams {
inner: Inner {
recv: Recv::new(&config),
send: Send::new(&config),
},
streams: Store::new(),
}
}
pub fn recv_headers(&mut self, frame: frame::Headers)
-> Result<Option<frame::Headers>, ConnectionError>
{
let id = frame.stream_id();
let state = match self.streams.entry(id) {
Entry::Occupied(e) => e.into_mut(),
Entry::Vacant(e) => {
// Trailers cannot open a stream. Trailers are header frames
// that do not contain pseudo headers. Requests MUST contain a
// method and responses MUST contain a status. If they do not,t
// hey are considered to be malformed.
if frame.is_trailers() {
return Err(ProtocolError.into());
}
match try!(self.inner.recv.open(id)) {
Some(state) => e.insert(state),
None => return Ok(None),
}
}
};
if frame.is_trailers() {
if !frame.is_end_stream() {
// TODO: What error should this return?
unimplemented!();
}
try!(self.inner.recv.recv_eos(state));
} else {
try!(self.inner.recv.recv_headers(state, frame.is_end_stream()));
}
if state.is_closed() {
self.inner.dec_num_streams(id);
}
Ok(Some(frame))
}
pub fn recv_data(&mut self, frame: &frame::Data)
-> Result<(), ConnectionError>
{
let id = frame.stream_id();
let state = match self.streams.get_mut(&id) {
Some(state) => state,
None => return Err(ProtocolError.into()),
};
// Ensure there's enough capacity on the connection before acting on the
// stream.
try!(self.inner.recv.recv_data(frame, state));
if state.is_closed() {
self.inner.dec_num_streams(id);
}
Ok(())
}
pub fn recv_reset(&mut self, _frame: &frame::Reset)
-> Result<(), ConnectionError>
{
unimplemented!();
}
pub fn recv_window_update(&mut self, frame: frame::WindowUpdate)
-> Result<(), ConnectionError> {
let id = frame.stream_id();
if id.is_zero() {
try!(self.inner.send.recv_connection_window_update(frame));
} else {
// The remote may send window updates for streams that the local now
// considers closed. It's ok...
if let Some(state) = self.streams.get_mut(&id) {
try!(self.inner.send.recv_stream_window_update(frame, state));
}
}
Ok(())
}
pub fn recv_push_promise(&mut self, _frame: frame::PushPromise)
-> Result<(), ConnectionError>
{
unimplemented!();
}
pub fn send_headers(&mut self, frame: &frame::Headers)
-> Result<(), ConnectionError>
{
let id = frame.stream_id();
trace!("send_headers; id={:?}", id);
let state = match self.streams.entry(id) {
Entry::Occupied(e) => e.into_mut(),
Entry::Vacant(e) => {
// Trailers cannot open a stream. Trailers are header frames
// that do not contain pseudo headers. Requests MUST contain a
// method and responses MUST contain a status. If they do not,t
// hey are considered to be malformed.
if frame.is_trailers() {
// TODO: Should this be a different error?
return Err(UnexpectedFrameType.into());
}
let state = try!(self.inner.send.open(id));
e.insert(state)
}
};
if frame.is_trailers() {
try!(self.inner.send.send_eos(state));
} else {
try!(self.inner.send.send_headers(state, frame.is_end_stream()));
}
if state.is_closed() {
self.inner.dec_num_streams(id);
}
Ok(())
}
pub fn send_data<B: Buf>(&mut self, frame: &frame::Data<B>)
-> Result<(), ConnectionError>
{
let id = frame.stream_id();
let state = match self.streams.get_mut(&id) {
Some(state) => state,
None => return Err(UnexpectedFrameType.into()),
};
// Ensure there's enough capacity on the connection before acting on the
// stream.
try!(self.inner.send.send_data(frame, state));
if state.is_closed() {
self.inner.dec_num_streams(id);
}
Ok(())
}
pub fn poll_window_update(&mut self)
-> Poll<WindowUpdate, ConnectionError>
{
self.inner.send.poll_window_update(&mut self.streams)
}
pub fn expand_window(&mut self, id: StreamId, sz: WindowSize)
-> Result<(), ConnectionError>
{
if id.is_zero() {
try!(self.inner.recv.expand_connection_window(sz));
} else {
if let Some(state) = self.streams.get_mut(&id) {
try!(self.inner.recv.expand_stream_window(id, sz, state));
}
}
Ok(())
}
pub fn send_pending_refusal<T, B>(&mut self, dst: &mut Codec<T, B>)
-> Poll<(), ConnectionError>
where T: AsyncWrite,
B: Buf,
{
self.inner.recv.send_pending_refusal(dst)
}
pub fn send_pending_window_updates<T, B>(&mut self, dst: &mut Codec<T, B>)
-> Poll<(), ConnectionError>
where T: AsyncWrite,
B: Buf,
{
try_ready!(self.inner.recv.send_connection_window_update(dst));
try_ready!(self.inner.recv.send_stream_window_update(&mut self.streams, dst));
Ok(().into())
}
}
impl<P: Peer> Inner<P> {
fn dec_num_streams(&mut self, id: StreamId) {
if self.is_local_init(id) {
self.send.dec_num_streams();
} else {
self.recv.dec_num_streams();
}
}
fn is_local_init(&self, id: StreamId) -> bool {
assert!(!id.is_zero());
P::is_server() == id.is_server_initiated()
}
}

View File

@@ -0,0 +1,97 @@
use super::*;
#[derive(Debug)]
pub(super) struct Prioritize<B> {
pending_send: store::List<B>,
/// Holds frames that are waiting to be written to the socket
buffer: Buffer<B>,
}
impl<B> Prioritize<B>
where B: Buf,
{
pub fn new() -> Prioritize<B> {
Prioritize {
pending_send: store::List::new(),
buffer: Buffer::new(),
}
}
pub fn queue_frame(&mut self,
frame: Frame<B>,
stream: &mut store::Ptr<B>)
{
// queue the frame in the buffer
stream.pending_send.push_back(&mut self.buffer, frame);
if stream.is_pending_send {
debug_assert!(!self.pending_send.is_empty());
// Already queued to have frame processed.
return;
}
// Queue the stream
self.push_sender(stream);
}
pub fn poll_complete<T>(&mut self,
store: &mut Store<B>,
dst: &mut Codec<T, B>)
-> Poll<(), ConnectionError>
where T: AsyncWrite,
{
loop {
// Ensure codec is ready
try_ready!(dst.poll_ready());
match self.pop_frame(store) {
Some(frame) => {
// TODO: data frames should be handled specially...
let res = dst.start_send(frame)?;
// We already verified that `dst` is ready to accept the
// write
assert!(res.is_ready());
}
None => break,
}
}
Ok(().into())
}
fn pop_frame(&mut self, store: &mut Store<B>) -> Option<Frame<B>> {
match self.pop_sender(store) {
Some(mut stream) => {
let frame = stream.pending_send.pop_front(&mut self.buffer).unwrap();
if !stream.pending_send.is_empty() {
self.push_sender(&mut stream);
}
Some(frame)
}
None => None,
}
}
fn push_sender(&mut self, stream: &mut store::Ptr<B>) {
debug_assert!(!stream.is_pending_send);
self.pending_send.push(stream);
stream.is_pending_send = true;
}
fn pop_sender<'a>(&mut self, store: &'a mut Store<B>) -> Option<store::Ptr<'a, B>> {
match self.pending_send.pop(store) {
Some(mut stream) => {
stream.is_pending_send = false;
Some(stream)
}
None => None,
}
}
}

View File

@@ -1,4 +1,4 @@
use {frame, Peer, ConnectionError};
use {client, frame, ConnectionError};
use proto::*;
use super::*;
@@ -8,7 +8,7 @@ use std::collections::VecDeque;
use std::marker::PhantomData;
#[derive(Debug)]
pub struct Recv<P> {
pub(super) struct Recv<P, B> {
/// Maximum number of remote initiated streams
max_streams: Option<usize>,
@@ -21,15 +21,35 @@ pub struct Recv<P> {
/// Connection level flow control governing received data
flow_control: FlowControl,
/// Streams that have pending window updates
/// TODO: don't use a VecDeque
pending_window_updates: VecDeque<StreamId>,
/// Holds frames that are waiting to be read
buffer: Buffer<Bytes>,
/// Refused StreamId, this represents a frame that must be sent out.
refused: Option<StreamId>,
_p: PhantomData<P>,
_p: PhantomData<(P, B)>,
}
impl<P: Peer> Recv<P> {
#[derive(Debug)]
pub(super) struct Chunk {
/// Data frames pending receival
pub pending_recv: buffer::Deque<Bytes>,
}
#[derive(Debug, Clone, Copy)]
struct Indices {
head: store::Key,
tail: store::Key,
}
impl<P, B> Recv<P, B>
where P: Peer,
B: Buf,
{
pub fn new(config: &Config) -> Self {
Recv {
max_streams: config.max_remote_initiated,
@@ -37,6 +57,7 @@ impl<P: Peer> Recv<P> {
init_window_sz: config.init_remote_window_sz,
flow_control: FlowControl::new(config.init_remote_window_sz),
pending_window_updates: VecDeque::new(),
buffer: Buffer::new(),
refused: None,
_p: PhantomData,
}
@@ -45,40 +66,58 @@ impl<P: Peer> Recv<P> {
/// Update state reflecting a new, remotely opened stream
///
/// Returns the stream state if successful. `None` if refused
pub fn open(&mut self, id: StreamId) -> Result<Option<State>, ConnectionError> {
pub fn open(&mut self, id: StreamId) -> Result<Option<Stream<B>>, ConnectionError> {
assert!(self.refused.is_none());
try!(self.ensure_can_open(id));
if let Some(max) = self.max_streams {
if max <= self.num_streams {
self.refused = Some(id);
return Ok(None);
}
if !self.can_inc_num_streams() {
self.refused = Some(id);
return Ok(None);
}
// Increment the number of remote initiated streams
self.num_streams += 1;
Ok(Some(State::default()))
Ok(Some(Stream::new(id)))
}
/// Transition the stream state based on receiving headers
pub fn recv_headers(&mut self, state: &mut State, eos: bool)
-> Result<(), ConnectionError>
pub fn recv_headers(&mut self,
frame: frame::Headers,
stream: &mut store::Ptr<B>)
-> Result<Option<frame::Headers>, ConnectionError>
{
state.recv_open(self.init_window_sz, eos)
let is_initial = stream.state.recv_open(self.init_window_sz, frame.is_end_stream())?;
if is_initial {
if !self.can_inc_num_streams() {
unimplemented!();
}
// Increment the number of concurrent streams
self.inc_num_streams();
}
// Only servers can receive a headers frame that initiates the stream.
// This is verified in `Streams` before calling this function.
if P::is_server() {
Ok(Some(frame))
} else {
// Push the frame onto the recv buffer
stream.pending_recv.push_back(&mut self.buffer, frame.into());
stream.notify_recv();
Ok(None)
}
}
pub fn recv_eos(&mut self, state: &mut State)
pub fn recv_eos(&mut self, stream: &mut Stream<B>)
-> Result<(), ConnectionError>
{
state.recv_close()
stream.state.recv_close()
}
pub fn recv_data(&mut self,
frame: &frame::Data,
state: &mut State)
frame: frame::Data,
stream: &mut store::Ptr<B>)
-> Result<(), ConnectionError>
{
let sz = frame.payload().len();
@@ -89,7 +128,7 @@ impl<P: Peer> Recv<P> {
let sz = sz as WindowSize;
match state.recv_flow_control() {
match stream.recv_flow_control() {
Some(flow) => {
// Ensure there's enough capacity on the connection before
// acting on the stream.
@@ -106,12 +145,97 @@ impl<P: Peer> Recv<P> {
}
if frame.is_end_stream() {
try!(state.recv_close());
try!(stream.state.recv_close());
}
// Push the frame onto the recv buffer
stream.pending_recv.push_back(&mut self.buffer, frame.into());
stream.notify_recv();
Ok(())
}
pub fn recv_push_promise(&mut self, frame: frame::PushPromise, stream: &mut store::Ptr<B>)
-> Result<(), ConnectionError>
{
// First, make sure that the values are legit
self.ensure_can_reserve(frame.promised_id())?;
// Make sure that the stream state is valid
stream.state.ensure_recv_open()?;
// TODO: Streams in the reserved states do not count towards the concurrency
// limit. However, it seems like there should be a cap otherwise this
// could grow in memory indefinitely.
/*
if !self.inc_num_streams() {
self.refused = Some(frame.promised_id());
return Ok(());
}
*/
// TODO: All earlier stream IDs should be implicitly closed.
// Now, create a new entry for the stream
let mut new_stream = Stream::new(frame.promised_id());
new_stream.state.reserve_remote();
let mut ppp = stream.pending_push_promises.take();
{
// Store the stream
let mut new_stream = stream.store()
.insert(frame.promised_id(), new_stream);
ppp.push(&mut new_stream);
}
stream.pending_push_promises = ppp;
stream.notify_recv();
Ok(())
}
pub fn recv_reset(&mut self, frame: frame::Reset, stream: &mut Stream<B>)
-> Result<(), ConnectionError>
{
let err = ConnectionError::Proto(frame.reason());
// Notify the stream
stream.state.recv_err(&err);
stream.notify_recv();
Ok(())
}
pub fn recv_err(&mut self, err: &ConnectionError, stream: &mut Stream<B>) {
// Receive an error
stream.state.recv_err(err);
// If a receiver is waiting, notify it
stream.notify_recv();
}
/// Returns true if the current stream concurrency can be incremetned
fn can_inc_num_streams(&self) -> bool {
if let Some(max) = self.max_streams {
max > self.num_streams
} else {
true
}
}
/// Increments the number of concurrenty streams. Panics on failure as this
/// should have been validated before hand.
fn inc_num_streams(&mut self) {
if !self.can_inc_num_streams() {
panic!();
}
// Increment the number of remote initiated streams
self.num_streams += 1;
}
pub fn dec_num_streams(&mut self) {
self.num_streams -= 1;
}
@@ -132,11 +256,25 @@ impl<P: Peer> Recv<P> {
Ok(())
}
/// Returns true if the remote peer can reserve a stream with the given ID.
fn ensure_can_reserve(&self, promised_id: StreamId) -> Result<(), ConnectionError> {
// TODO: Are there other rules?
if P::is_server() {
// The remote is a client and cannot reserve
return Err(ProtocolError.into());
}
if !promised_id.is_server_initiated() {
return Err(ProtocolError.into());
}
Ok(())
}
/// Send any pending refusals.
pub fn send_pending_refusal<T, B>(&mut self, dst: &mut Codec<T, B>)
pub fn send_pending_refusal<T>(&mut self, dst: &mut Codec<T, B>)
-> Poll<(), ConnectionError>
where T: AsyncWrite,
B: Buf,
{
if let Some(stream_id) = self.refused.take() {
let frame = frame::Reset::new(stream_id, RefusedStream);
@@ -168,11 +306,11 @@ impl<P: Peer> Recv<P> {
pub fn expand_stream_window(&mut self,
id: StreamId,
sz: WindowSize,
state: &mut State)
stream: &mut store::Ptr<B>)
-> Result<(), ConnectionError>
{
// TODO: handle overflow
if let Some(flow) = state.recv_flow_control() {
if let Some(flow) = stream.recv_flow_control() {
flow.expand_window(sz);
self.pending_window_updates.push_back(id);
}
@@ -181,10 +319,9 @@ impl<P: Peer> Recv<P> {
}
/// Send connection level window update
pub fn send_connection_window_update<T, B>(&mut self, dst: &mut Codec<T, B>)
pub fn send_connection_window_update<T>(&mut self, dst: &mut Codec<T, B>)
-> Poll<(), ConnectionError>
where T: AsyncWrite,
B: Buf,
{
if let Some(incr) = self.flow_control.peek_window_update() {
let frame = frame::WindowUpdate::new(StreamId::zero(), incr);
@@ -199,17 +336,47 @@ impl<P: Peer> Recv<P> {
Ok(().into())
}
pub fn poll_chunk(&mut self, stream: &mut Stream<B>)
-> Poll<Option<Chunk>, ConnectionError>
{
let frames = stream.pending_recv
.take_while(&mut self.buffer, |frame| frame.is_data());
if frames.is_empty() {
if stream.state.is_recv_closed() {
Ok(None.into())
} else {
stream.recv_task = Some(task::current());
Ok(Async::NotReady)
}
} else {
Ok(Some(Chunk {
pending_recv: frames,
}).into())
}
}
pub fn pop_bytes(&mut self, chunk: &mut Chunk) -> Option<Bytes> {
match chunk.pending_recv.pop_front(&mut self.buffer) {
Some(Frame::Data(frame)) => {
Some(frame.into_payload())
}
None => None,
_ => panic!("unexpected frame type"),
}
}
/// Send stream level window update
pub fn send_stream_window_update<T, B>(&mut self,
streams: &mut Store,
dst: &mut Codec<T, B>)
pub fn send_stream_window_update<T>(&mut self,
streams: &mut Store<B>,
dst: &mut Codec<T, B>)
-> Poll<(), ConnectionError>
where T: AsyncWrite,
B: Buf,
{
while let Some(id) = self.pending_window_updates.pop_front() {
let flow = streams.get_mut(&id)
.and_then(|state| state.recv_flow_control());
let flow = streams.find_mut(&id)
.and_then(|stream| stream.into_mut().recv_flow_control());
if let Some(flow) = flow {
@@ -233,3 +400,27 @@ impl<P: Peer> Recv<P> {
unimplemented!();
}
}
impl<B> Recv<client::Peer, B>
where B: Buf,
{
pub fn poll_response(&mut self, stream: &mut store::Ptr<B>)
-> Poll<Response<()>, ConnectionError> {
// If the buffer is not empty, then the first frame must be a HEADERS
// frame or the user violated the contract.
match stream.pending_recv.pop_front(&mut self.buffer) {
Some(Frame::Headers(v)) => {
// TODO: This error should probably be caught on receipt of the
// frame vs. now.
Ok(client::Peer::convert_poll_message(v)?.into())
}
Some(frame) => unimplemented!(),
None => {
stream.state.ensure_recv_open()?;
stream.recv_task = Some(task::current());
Ok(Async::NotReady)
}
}
}
}

View File

@@ -1,4 +1,4 @@
use {frame, Peer, ConnectionError};
use {frame, ConnectionError};
use proto::*;
use super::*;
@@ -10,13 +10,16 @@ use std::collections::VecDeque;
use std::marker::PhantomData;
#[derive(Debug)]
pub struct Send<P> {
pub(super) struct Send<P, B> {
/// Maximum number of locally initiated streams
max_streams: Option<usize>,
/// Current number of locally initiated streams
num_streams: usize,
/// Stream identifier to use for next initialized stream.
next_stream_id: StreamId,
/// Initial window size of locally initiated streams
init_window_sz: WindowSize,
@@ -27,6 +30,8 @@ pub struct Send<P> {
// XXX It would be cool if this didn't exist.
pending_window_updates: VecDeque<StreamId>,
prioritize: Prioritize<B>,
/// When `poll_window_update` is not ready, then the calling task is saved to
/// be notified later. Access to poll_window_update must not be shared across tasks,
/// as we only track a single task (and *not* i.e. a task per stream id).
@@ -35,13 +40,24 @@ pub struct Send<P> {
_p: PhantomData<P>,
}
impl<P: Peer> Send<P> {
impl<P, B> Send<P, B>
where P: Peer,
B: Buf,
{
pub fn new(config: &Config) -> Self {
let next_stream_id = if P::is_server() {
2
} else {
1
};
Send {
max_streams: config.max_local_initiated,
num_streams: 0,
next_stream_id: next_stream_id.into(),
init_window_sz: config.init_local_window_sz,
flow_control: FlowControl::new(config.init_local_window_sz),
prioritize: Prioritize::new(),
pending_window_updates: VecDeque::new(),
blocked: None,
_p: PhantomData,
@@ -51,8 +67,8 @@ impl<P: Peer> Send<P> {
/// Update state reflecting a new, locally opened stream
///
/// Returns the stream state if successful. `None` if refused
pub fn open(&mut self, id: StreamId) -> Result<State, ConnectionError> {
try!(self.ensure_can_open(id));
pub fn open(&mut self) -> Result<Stream<B>, ConnectionError> {
try!(self.ensure_can_open());
if let Some(max) = self.max_streams {
if max <= self.num_streams {
@@ -60,27 +76,38 @@ impl<P: Peer> Send<P> {
}
}
let ret = Stream::new(self.next_stream_id);
// Increment the number of locally initiated streams
self.num_streams += 1;
self.next_stream_id.increment();
Ok(State::default())
Ok(ret)
}
pub fn send_headers(&mut self, state: &mut State, eos: bool)
pub fn send_headers(&mut self,
frame: frame::Headers,
stream: &mut store::Ptr<B>)
-> Result<(), ConnectionError>
{
state.send_open(self.init_window_sz, eos)
// Update the state
stream.state.send_open(self.init_window_sz, frame.is_end_stream())?;
// Queue the frame for sending
self.prioritize.queue_frame(frame.into(), stream);
Ok(())
}
pub fn send_eos(&mut self, state: &mut State)
pub fn send_eos(&mut self, stream: &mut Stream<B>)
-> Result<(), ConnectionError>
{
state.send_close()
stream.state.send_close()
}
pub fn send_data<B: Buf>(&mut self,
frame: &frame::Data<B>,
state: &mut State)
pub fn send_data(&mut self,
frame: frame::Data<B>,
stream: &mut store::Ptr<B>)
-> Result<(), ConnectionError>
{
let sz = frame.payload().remaining();
@@ -94,7 +121,7 @@ impl<P: Peer> Send<P> {
// Make borrow checker happy
loop {
match state.send_flow_control() {
match stream.send_flow_control() {
Some(flow) => {
try!(self.flow_control.ensure_window(sz, FlowControlViolation));
@@ -110,7 +137,7 @@ impl<P: Peer> Send<P> {
None => {}
}
if state.is_closed() {
if stream.state.is_closed() {
return Err(InactiveStreamId.into())
} else {
return Err(UnexpectedFrameType.into())
@@ -118,14 +145,25 @@ impl<P: Peer> Send<P> {
}
if frame.is_end_stream() {
try!(state.send_close());
try!(stream.state.send_close());
}
self.prioritize.queue_frame(frame.into(), stream);
Ok(())
}
pub fn poll_complete<T>(&mut self,
store: &mut Store<B>,
dst: &mut Codec<T, B>)
-> Poll<(), ConnectionError>
where T: AsyncWrite,
{
self.prioritize.poll_complete(store, dst)
}
/// Get pending window updates
pub fn poll_window_update(&mut self, streams: &mut Store)
pub fn poll_window_update(&mut self, streams: &mut Store<B>)
-> Poll<WindowUpdate, ConnectionError>
{
// This biases connection window updates, which probably makes sense.
@@ -138,8 +176,8 @@ impl<P: Peer> Send<P> {
// TODO this should probably account for stream priority?
let update = self.pending_window_updates.pop_front()
.and_then(|id| {
streams.get_mut(&id)
.and_then(|state| state.send_flow_control())
streams.find_mut(&id)
.and_then(|stream| stream.into_mut().send_flow_control())
.and_then(|flow| flow.apply_window_update())
.map(|incr| WindowUpdate::new(id, incr))
});
@@ -171,10 +209,10 @@ impl<P: Peer> Send<P> {
pub fn recv_stream_window_update(&mut self,
frame: frame::WindowUpdate,
state: &mut State)
stream: &mut store::Ptr<B>)
-> Result<(), ConnectionError>
{
if let Some(flow) = state.send_flow_control() {
if let Some(flow) = stream.send_flow_control() {
// TODO: Handle invalid increment
flow.expand_window(frame.size_increment());
}
@@ -191,15 +229,13 @@ impl<P: Peer> Send<P> {
}
/// Returns true if the local actor can initiate a stream with the given ID.
fn ensure_can_open(&self, id: StreamId) -> Result<(), ConnectionError> {
fn ensure_can_open(&self) -> Result<(), ConnectionError> {
if P::is_server() {
// Servers cannot open streams. PushPromise must first be reserved.
return Err(UnexpectedFrameType.into());
}
if !id.is_client_initiated() {
return Err(InvalidStreamId.into());
}
// TODO: Handle StreamId overflow
Ok(())
}

View File

@@ -58,7 +58,7 @@ enum Inner {
Idle,
// TODO: these states shouldn't count against concurrency limits:
//ReservedLocal,
//ReservedRemote,
ReservedRemote,
Open {
local: Peer,
remote: Peer,
@@ -66,7 +66,7 @@ enum Inner {
HalfClosedLocal(Peer), // TODO: explicitly name this value
HalfClosedRemote(Peer),
// When reset, a reason is provided
Closed(Option<Reason>),
Closed(Option<Cause>),
}
#[derive(Debug, Copy, Clone)]
@@ -76,6 +76,12 @@ enum Peer {
Streaming(FlowControl),
}
#[derive(Debug, Copy, Clone)]
enum Cause {
Proto(Reason),
Io,
}
impl State {
/// Opens the send-half of a stream if it is not already open.
pub fn send_open(&mut self, sz: WindowSize, eos: bool) -> Result<(), ConnectionError> {
@@ -120,11 +126,16 @@ impl State {
/// Open the receive have of the stream, this action is taken when a HEADERS
/// frame is received.
pub fn recv_open(&mut self, sz: WindowSize, eos: bool) -> Result<(), ConnectionError> {
///
/// Returns true if this transitions the state to Open
pub fn recv_open(&mut self, sz: WindowSize, eos: bool) -> Result<bool, ConnectionError> {
let remote = Peer::streaming(sz);
let mut initial = false;
self.inner = match self.inner {
Idle => {
initial = true;
if eos {
HalfClosedRemote(AwaitingHeaders)
} else {
@@ -134,6 +145,18 @@ impl State {
}
}
}
ReservedRemote => {
initial = true;
if eos {
Closed(None)
} else {
Open {
local: AwaitingHeaders,
remote,
}
}
}
Open { local, remote: AwaitingHeaders } => {
if eos {
HalfClosedRemote(local)
@@ -157,7 +180,18 @@ impl State {
}
};
return Ok(());
return Ok(initial);
}
/// Transition from Idle -> ReservedRemote
pub fn reserve_remote(&mut self) -> Result<(), ConnectionError> {
match self.inner {
Idle => {
self.inner = ReservedRemote;
Ok(())
}
_ => Err(ProtocolError.into()),
}
}
/// Indicates that the remote side will not send more data to the local.
@@ -178,6 +212,19 @@ impl State {
}
}
pub fn recv_err(&mut self, err: &ConnectionError) {
match self.inner {
Closed(..) => {}
_ => {
self.inner = Closed(match *err {
ConnectionError::Proto(reason) => Some(Cause::Proto(reason)),
ConnectionError::Io(..) => Some(Cause::Io),
_ => panic!("cannot terminate stream with user error"),
});
}
}
}
/// Indicates that the local side will not send more data to the local.
pub fn send_close(&mut self) -> Result<(), ConnectionError> {
match self.inner {
@@ -196,6 +243,17 @@ impl State {
}
}
/// Returns true if a stream with the current state counts against the
/// concurrency limit.
pub fn is_counted(&self) -> bool {
match self.inner {
Open { .. } => true,
HalfClosedLocal(..) => true,
HalfClosedRemote(..) => true,
_ => false,
}
}
pub fn is_closed(&self) -> bool {
match self.inner {
Closed(_) => true,
@@ -203,6 +261,13 @@ impl State {
}
}
pub fn is_recv_closed(&self) -> bool {
match self.inner {
Closed(..) | HalfClosedRemote(..) => true,
_ => false,
}
}
pub fn recv_flow_control(&mut self) -> Option<&mut FlowControl> {
match self.inner {
Open { ref mut remote, .. } |
@@ -218,6 +283,21 @@ impl State {
_ => None,
}
}
pub fn ensure_recv_open(&self) -> Result<(), ConnectionError> {
use std::io;
// TODO: Is this correct?
match self.inner {
Closed(Some(Cause::Proto(reason))) => {
Err(ConnectionError::Proto(reason))
}
Closed(Some(Cause::Io)) => {
Err(ConnectionError::Io(io::ErrorKind::BrokenPipe.into()))
}
_ => Ok(()),
}
}
}
impl Default for State {

View File

@@ -1,32 +1,59 @@
extern crate slab;
use super::*;
use slab;
use std::ops;
use std::collections::{HashMap, hash_map};
use std::marker::PhantomData;
/// Storage for streams
#[derive(Debug)]
pub struct Store {
slab: slab::Slab<State>,
pub(super) struct Store<B> {
slab: slab::Slab<Stream<B>>,
ids: HashMap<StreamId, usize>,
}
pub enum Entry<'a> {
Occupied(OccupiedEntry<'a>),
Vacant(VacantEntry<'a>),
/// "Pointer" to an entry in the store
pub(super) struct Ptr<'a, B: 'a> {
key: Key,
store: &'a mut Store<B>,
}
pub struct OccupiedEntry<'a> {
/// References an entry in the store.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) struct Key(usize);
#[derive(Debug)]
pub(super) struct List<B> {
indices: Option<store::Indices>,
_p: PhantomData<B>,
}
/// A linked list
#[derive(Debug, Clone, Copy)]
struct Indices {
pub head: Key,
pub tail: Key,
}
pub(super) enum Entry<'a, B: 'a> {
Occupied(OccupiedEntry<'a, B>),
Vacant(VacantEntry<'a, B>),
}
pub(super) struct OccupiedEntry<'a, B: 'a> {
ids: hash_map::OccupiedEntry<'a, StreamId, usize>,
slab: &'a mut slab::Slab<State>,
slab: &'a mut slab::Slab<Stream<B>>,
}
pub struct VacantEntry<'a> {
pub(super) struct VacantEntry<'a, B: 'a> {
ids: hash_map::VacantEntry<'a, StreamId, usize>,
slab: &'a mut slab::Slab<State>,
slab: &'a mut slab::Slab<Stream<B>>,
}
impl Store {
// ===== impl Store =====
impl<B> Store<B> {
pub fn new() -> Self {
Store {
slab: slab::Slab::new(),
@@ -34,15 +61,35 @@ impl Store {
}
}
pub fn get_mut(&mut self, id: &StreamId) -> Option<&mut State> {
if let Some(handle) = self.ids.get(id) {
Some(&mut self.slab[*handle])
pub fn resolve(&mut self, key: Key) -> Ptr<B> {
Ptr {
key: key,
store: self,
}
}
pub fn find_mut(&mut self, id: &StreamId) -> Option<Ptr<B>> {
if let Some(&key) = self.ids.get(id) {
Some(Ptr {
key: Key(key),
store: self,
})
} else {
None
}
}
pub fn entry(&mut self, id: StreamId) -> Entry {
pub fn insert(&mut self, id: StreamId, val: Stream<B>) -> Ptr<B> {
let key = self.slab.insert(val);
assert!(self.ids.insert(id, key).is_none());
Ptr {
key: Key(key),
store: self,
}
}
pub fn find_entry(&mut self, id: StreamId) -> Entry<B> {
use self::hash_map::Entry::*;
match self.ids.entry(id) {
@@ -60,22 +107,145 @@ impl Store {
}
}
}
pub fn for_each<F>(&mut self, mut f: F)
where F: FnMut(&mut Stream<B>)
{
for &id in self.ids.values() {
f(&mut self.slab[id])
}
}
}
impl<'a> OccupiedEntry<'a> {
pub fn into_mut(self) -> &'a mut State {
// ===== impl List =====
impl<B> List<B> {
pub fn new() -> Self {
List {
indices: None,
_p: PhantomData,
}
}
pub fn is_empty(&self) -> bool {
self.indices.is_none()
}
pub fn take(&mut self) -> Self {
List {
indices: self.indices.take(),
_p: PhantomData,
}
}
pub fn push(&mut self, stream: &mut store::Ptr<B>) {
// The next pointer shouldn't be set
debug_assert!(stream.next.is_none());
// Queue the stream
match self.indices {
Some(ref mut idxs) => {
// Update the current tail node to point to `stream`
stream.resolve(idxs.tail).next = Some(stream.key());
// Update the tail pointer
idxs.tail = stream.key();
}
None => {
self.indices = Some(store::Indices {
head: stream.key(),
tail: stream.key(),
});
}
}
}
pub fn pop<'a>(&mut self, store: &'a mut Store<B>) -> Option<store::Ptr<'a, B>> {
if let Some(mut idxs) = self.indices {
let mut stream = store.resolve(idxs.head);
if idxs.head == idxs.tail {
assert!(stream.next.is_none());
self.indices = None;
} else {
idxs.head = stream.next.take().unwrap();
self.indices = Some(idxs);
}
return Some(stream);
}
None
}
}
// ===== impl Ptr =====
impl<'a, B: 'a> Ptr<'a, B> {
pub fn key(&self) -> Key {
self.key
}
pub fn store(&mut self) -> &mut Store<B> {
&mut self.store
}
pub fn resolve(&mut self, key: Key) -> Ptr<B> {
Ptr {
key: key,
store: self.store,
}
}
pub fn into_mut(self) -> &'a mut Stream<B> {
&mut self.store.slab[self.key.0]
}
}
impl<'a, B: 'a> ops::Deref for Ptr<'a, B> {
type Target = Stream<B>;
fn deref(&self) -> &Stream<B> {
&self.store.slab[self.key.0]
}
}
impl<'a, B: 'a> ops::DerefMut for Ptr<'a, B> {
fn deref_mut(&mut self) -> &mut Stream<B> {
&mut self.store.slab[self.key.0]
}
}
// ===== impl OccupiedEntry =====
impl<'a, B> OccupiedEntry<'a, B> {
pub fn key(&self) -> Key {
Key(*self.ids.get())
}
pub fn get(&self) -> &Stream<B> {
&self.slab[*self.ids.get()]
}
pub fn get_mut(&mut self) -> &mut Stream<B> {
&mut self.slab[*self.ids.get()]
}
pub fn into_mut(self) -> &'a mut Stream<B> {
&mut self.slab[*self.ids.get()]
}
}
impl<'a> VacantEntry<'a> {
pub fn insert(self, value: State) -> &'a mut State {
// ===== impl VacantEntry =====
impl<'a, B> VacantEntry<'a, B> {
pub fn insert(self, value: Stream<B>) -> Key {
// Insert the value in the slab
let handle = self.slab.insert(value);
let key = self.slab.insert(value);
// Insert the handle in the ID map
self.ids.insert(handle);
self.ids.insert(key);
&mut self.slab[handle]
Key(key)
}
}

View File

@@ -0,0 +1,60 @@
use super::*;
#[derive(Debug)]
pub(super) struct Stream<B> {
/// The h2 stream identifier
pub id: StreamId,
/// Current state of the stream
pub state: State,
/// Frames pending for this stream to read
pub pending_recv: buffer::Deque<Bytes>,
/// Task tracking receiving frames
pub recv_task: Option<task::Task>,
/// Frames pending for this stream being sent to the socket
pub pending_send: buffer::Deque<B>,
/// Next node in the `Stream` linked list.
///
/// This field is used in different linked lists depending on the stream
/// state.
pub next: Option<store::Key>,
/// The stream's pending push promises
pub pending_push_promises: store::List<B>,
/// True if the stream is currently pending send
pub is_pending_send: bool,
}
impl<B> Stream<B> {
pub fn new(id: StreamId) -> Stream<B> {
Stream {
id,
state: State::default(),
pending_recv: buffer::Deque::new(),
recv_task: None,
pending_send: buffer::Deque::new(),
next: None,
pending_push_promises: store::List::new(),
is_pending_send: false,
}
}
pub fn send_flow_control(&mut self) -> Option<&mut FlowControl> {
self.state.send_flow_control()
}
pub fn recv_flow_control(&mut self) -> Option<&mut FlowControl> {
self.state.recv_flow_control()
}
pub fn notify_recv(&mut self) {
if let Some(ref mut task) = self.recv_task {
task.notify();
}
}
}

View File

@@ -0,0 +1,446 @@
use client;
use proto::*;
use super::*;
use std::sync::{Arc, Mutex};
// TODO: All the VecDeques should become linked lists using the State
// values.
#[derive(Debug)]
pub struct Streams<P, B> {
inner: Arc<Mutex<Inner<P, B>>>,
}
/// Reference to the stream state
#[derive(Debug)]
pub struct StreamRef<P, B> {
inner: Arc<Mutex<Inner<P, B>>>,
key: store::Key,
}
#[derive(Debug)]
pub struct Chunk<P, B>
where P: Peer,
B: Buf,
{
inner: Arc<Mutex<Inner<P, B>>>,
recv: recv::Chunk,
}
/// Fields needed to manage state related to managing the set of streams. This
/// is mostly split out to make ownership happy.
///
/// TODO: better name
#[derive(Debug)]
struct Inner<P, B> {
actions: Actions<P, B>,
store: Store<B>,
}
#[derive(Debug)]
struct Actions<P, B> {
/// Manages state transitions initiated by receiving frames
recv: Recv<P, B>,
/// Manages state transitions initiated by sending frames
send: Send<P, B>,
}
impl<P, B> Streams<P, B>
where P: Peer,
B: Buf,
{
pub fn new(config: Config) -> Self {
Streams {
inner: Arc::new(Mutex::new(Inner {
actions: Actions {
recv: Recv::new(&config),
send: Send::new(&config),
},
store: Store::new(),
})),
}
}
/// Process inbound headers
pub fn recv_headers(&mut self, frame: frame::Headers)
-> Result<Option<frame::Headers>, ConnectionError>
{
let id = frame.stream_id();
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
let key = match me.store.find_entry(id) {
Entry::Occupied(e) => e.key(),
Entry::Vacant(e) => {
// Trailers cannot open a stream. Trailers are header frames
// that do not contain pseudo headers. Requests MUST contain a
// method and responses MUST contain a status. If they do not,t
// hey are considered to be malformed.
if frame.is_trailers() {
return Err(ProtocolError.into());
}
match try!(me.actions.recv.open(id)) {
Some(stream) => e.insert(stream),
None => return Ok(None),
}
}
};
let stream = me.store.resolve(key);
me.actions.transition(stream, |actions, stream| {
if frame.is_trailers() {
unimplemented!();
/*
if !frame.is_end_stream() {
// TODO: What error should this return?
unimplemented!();
}
try!(me.actions.recv.recv_eos(stream));
*/
} else {
actions.recv.recv_headers(frame, stream)
}
})
}
pub fn recv_data(&mut self, frame: frame::Data)
-> Result<(), ConnectionError>
{
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
let id = frame.stream_id();
let stream = match me.store.find_mut(&id) {
Some(stream) => stream,
None => return Err(ProtocolError.into()),
};
me.actions.transition(stream, |actions, stream| {
actions.recv.recv_data(frame, stream)
})
}
pub fn recv_reset(&mut self, frame: frame::Reset)
-> Result<(), ConnectionError>
{
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
let id = frame.stream_id();
let mut stream = match me.store.find_mut(&id) {
Some(stream) => stream,
// TODO: should this be an error?
None => return Ok(()),
};
me.actions.transition(stream, |actions, stream| {
actions.recv.recv_reset(frame, stream)?;
assert!(stream.state.is_closed());
Ok(())
})
}
pub fn recv_err(&mut self, err: &ConnectionError) {
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
let actions = &mut me.actions;
me.store.for_each(|stream| actions.recv.recv_err(err, stream));
}
pub fn recv_window_update(&mut self, frame: frame::WindowUpdate)
-> Result<(), ConnectionError> {
let id = frame.stream_id();
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
if id.is_zero() {
try!(me.actions.send.recv_connection_window_update(frame));
} else {
// The remote may send window updates for streams that the local now
// considers closed. It's ok...
if let Some(mut stream) = me.store.find_mut(&id) {
try!(me.actions.send.recv_stream_window_update(frame, &mut stream));
}
}
Ok(())
}
pub fn recv_push_promise(&mut self, frame: frame::PushPromise)
-> Result<(), ConnectionError>
{
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
let id = frame.stream_id();
let mut stream = match me.store.find_mut(&id) {
Some(stream) => stream,
None => return Err(ProtocolError.into()),
};
me.actions.recv.recv_push_promise(frame, &mut stream)
}
pub fn send_headers(&mut self, headers: frame::Headers)
-> Result<(), ConnectionError>
{
unimplemented!();
/*
let id = frame.stream_id();
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
// let (id, state) = me.actions.send.open());
let state = match me.store.entry(id) {
Entry::Occupied(e) => e.into_mut(),
Entry::Vacant(e) => {
let (id, state) = try!(me.actions.send.open());
e.insert(state)
}
};
if frame.is_trailers() {
try!(me.actions.send.send_eos(state));
} else {
try!(me.actions.send.send_headers(state, frame.is_end_stream()));
}
if state.is_closed() {
me.actions.dec_num_streams(id);
}
Ok(())
*/
}
pub fn poll_window_update(&mut self)
-> Poll<WindowUpdate, ConnectionError>
{
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
me.actions.send.poll_window_update(&mut me.store)
}
pub fn expand_window(&mut self, id: StreamId, sz: WindowSize)
-> Result<(), ConnectionError>
{
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
if id.is_zero() {
try!(me.actions.recv.expand_connection_window(sz));
} else {
if let Some(mut stream) = me.store.find_mut(&id) {
try!(me.actions.recv.expand_stream_window(id, sz, &mut stream));
}
}
Ok(())
}
pub fn send_pending_refusal<T>(&mut self, dst: &mut Codec<T, B>)
-> Poll<(), ConnectionError>
where T: AsyncWrite,
{
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
me.actions.recv.send_pending_refusal(dst)
}
pub fn poll_complete<T>(&mut self, dst: &mut Codec<T, B>)
-> Poll<(), ConnectionError>
where T: AsyncWrite,
{
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
// TODO: sending window updates should be part of Prioritize
/*
try_ready!(me.actions.recv.send_connection_window_update(dst));
try_ready!(me.actions.recv.send_stream_window_update(&mut me.store, dst));
*/
me.actions.send.poll_complete(&mut me.store, dst)
}
}
impl<B> Streams<client::Peer, B>
where B: Buf,
{
pub fn send_request(&mut self, request: Request<()>, end_of_stream: bool)
-> Result<StreamRef<client::Peer, B>, ConnectionError>
{
// TODO: There is a hazard with assigning a stream ID before the
// prioritize layer. If prioritization reorders new streams, this
// implicitly closes the earlier stream IDs.
//
// See: carllerche/h2#11
let key = {
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
// Initialize a new stream. This fails if the connection is at capacity.
let mut stream = me.actions.send.open()?;
// Convert the message
let headers = client::Peer::convert_send_message(
stream.id, request, end_of_stream);
let mut stream = me.store.insert(stream.id, stream);
me.actions.send.send_headers(headers, &mut stream)?;
// Given that the stream has been initialized, it should not be in the
// closed state.
debug_assert!(!stream.state.is_closed());
stream.key()
};
Ok(StreamRef {
inner: self.inner.clone(),
key: key,
})
}
}
// ===== impl StreamRef =====
impl<P, B> StreamRef<P, B>
where P: Peer,
B: Buf,
{
pub fn send_data(&mut self, data: B, end_of_stream: bool)
-> Result<(), ConnectionError>
{
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
let stream = me.store.resolve(self.key);
// Create the data frame
let frame = frame::Data::from_buf(stream.id, data, end_of_stream);
me.actions.transition(stream, |actions, stream| {
// Send the data frame
actions.send.send_data(frame, stream)
})
}
pub fn poll_data(&mut self) -> Poll<Option<Chunk<P, B>>, ConnectionError> {
let recv = {
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
let mut stream = me.store.resolve(self.key);
try_ready!(me.actions.recv.poll_chunk(&mut stream))
};
// Convert to a chunk
let chunk = recv.map(|recv| {
Chunk {
inner: self.inner.clone(),
recv: recv,
}
});
Ok(chunk.into())
}
}
impl<B> StreamRef<client::Peer, B>
where B: Buf,
{
pub fn poll_response(&mut self) -> Poll<Response<()>, ConnectionError> {
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
let mut stream = me.store.resolve(self.key);
me.actions.recv.poll_response(&mut stream)
}
}
impl<P, B> Clone for StreamRef<P, B> {
fn clone(&self) -> Self {
StreamRef {
inner: self.inner.clone(),
key: self.key.clone(),
}
}
}
// ===== impl Chunk =====
impl<P, B> Chunk<P, B>
where P: Peer,
B: Buf,
{
// TODO: Come up w/ a better API
pub fn pop_bytes(&mut self) -> Option<Bytes> {
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
me.actions.recv.pop_bytes(&mut self.recv)
}
}
impl<P, B> Drop for Chunk<P, B>
where P: Peer,
B: Buf,
{
fn drop(&mut self) {
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
while let Some(_) = me.actions.recv.pop_bytes(&mut self.recv) {
}
}
}
// ===== impl Actions =====
impl<P, B> Actions<P, B>
where P: Peer,
B: Buf,
{
fn dec_num_streams(&mut self, id: StreamId) {
if self.is_local_init(id) {
self.send.dec_num_streams();
} else {
self.recv.dec_num_streams();
}
}
fn is_local_init(&self, id: StreamId) -> bool {
assert!(!id.is_zero());
P::is_server() == id.is_server_initiated()
}
fn transition<F, U>(&mut self, mut stream: store::Ptr<B>, f: F) -> U
where F: FnOnce(&mut Self, &mut store::Ptr<B>) -> U,
{
let is_counted = stream.state.is_counted();
let ret = f(self, &mut stream);
if is_counted && stream.state.is_closed() {
self.dec_num_streams(stream.id);
}
ret
}
}

View File

@@ -14,78 +14,13 @@ fn handshake() {
.write(SETTINGS_ACK)
.build();
let h2 = client::handshake(mock)
let h2 = Client::handshake(mock)
.wait().unwrap();
trace!("hands have been shook");
// At this point, the connection should be closed
assert!(Stream::wait(h2).next().is_none());
}
#[test]
fn send_request_with_zero_stream_id() {
let mock = mock_io::Builder::new()
.handshake()
.build();
let h2 = client::handshake(mock)
.wait().unwrap();
// Send the request
let mut request = request::Head::default();
request.uri = "https://http2.akamai.com/".parse().unwrap();
let err = h2.send_request(0.into(), request, true).wait().unwrap_err();
assert_user_err!(err, InvalidStreamId);
}
#[test]
fn send_request_with_server_stream_id() {
let mock = mock_io::Builder::new()
.handshake()
.build();
let h2 = client::handshake(mock)
.wait().unwrap();
// Send the request
let mut request = request::Head::default();
request.uri = "https://http2.akamai.com/".parse().unwrap();
let err = h2.send_request(2.into(), request, true).wait().unwrap_err();
assert_user_err!(err, InvalidStreamId);
}
#[test]
#[ignore]
fn request_without_scheme() {
}
#[test]
#[ignore]
fn request_with_h1_version() {
}
#[test]
fn send_invalid_client_stream_id() {
let _ = ::env_logger::init();
for &id in &[0, 2] {
let mock = mock_io::Builder::new()
.handshake()
.build();
let h2 = client::handshake(mock)
.wait().unwrap();
// Send the request
let mut request = request::Head::default();
request.uri = "https://http2.akamai.com/".parse().unwrap();
let err = h2.send_request(id.into(), request, true).wait().unwrap_err();
assert_user_err!(err, InvalidStreamId);
}
h2.wait().unwrap();
}
#[test]
@@ -104,17 +39,38 @@ fn recv_invalid_server_stream_id() {
.read(&[0, 0, 1, 1, 5, 0, 0, 0, 2, 137])
.build();
let h2 = client::handshake(mock)
let mut h2 = Client::handshake(mock)
.wait().unwrap();
// Send the request
let mut request = request::Head::default();
request.uri = "https://http2.akamai.com/".parse().unwrap();
let h2 = h2.send_request(1.into(), request, true).wait().unwrap();
let request = Request::builder()
.uri("https://http2.akamai.com/")
.body(()).unwrap();
// Get the response
let (err, _) = h2.into_future().wait().unwrap_err();
assert_proto_err!(err, ProtocolError);
info!("sending request");
let mut stream = h2.request(request, true).unwrap();
// The connection errors
assert_proto_err!(h2.wait().unwrap_err(), ProtocolError);
// The stream errors
assert_proto_err!(stream.wait().unwrap_err(), ProtocolError);
}
#[test]
#[ignore]
fn request_without_scheme() {
}
#[test]
#[ignore]
fn request_with_h1_version() {
}
#[test]
#[ignore]
fn sending_request_on_closed_soket() {
}
const SETTINGS: &'static [u8] = &[0, 0, 0, 4, 0, 0, 0, 0, 0];

View File

@@ -31,10 +31,10 @@ fn recv_single_ping() {
*/
.build();
/*
let h2 = client::handshake(mock)
.wait().unwrap();
/*
// Send the request
let mut request = request::Head::default();
request.method = method::POST;

View File

@@ -29,6 +29,7 @@ fn single_stream_send_large_body() {
])
.build();
/*
let h2 = client::handshake(mock)
.wait().unwrap();
@@ -65,4 +66,5 @@ fn single_stream_send_large_body() {
}
assert!(Stream::wait(h2).next().is_none());;
*/
}

View File

@@ -4,7 +4,7 @@ extern crate futures;
extern crate mock_io;
extern crate env_logger;
use h2::server;
// use h2::server;
use futures::*;
@@ -13,6 +13,7 @@ const SETTINGS_ACK: &'static [u8] = &[0, 0, 0, 4, 1, 0, 0, 0, 0];
#[test]
fn read_preface_in_multiple_frames() {
/*
let _ = ::env_logger::init().unwrap();
let mock = mock_io::Builder::new()
@@ -28,4 +29,5 @@ fn read_preface_in_multiple_frames() {
.wait().unwrap();
assert!(Stream::wait(h2).next().is_none());
*/
}

View File

@@ -5,8 +5,6 @@ extern crate log;
pub mod support;
use support::*;
use h2::Frame;
#[test]
fn send_recv_headers_only() {
let _ = env_logger::init();
@@ -23,31 +21,21 @@ fn send_recv_headers_only() {
.read(&[0, 0, 1, 1, 5, 0, 0, 0, 1, 0x89])
.build();
let h2 = client::handshake(mock)
let mut h2 = Client::handshake(mock)
.wait().unwrap();
// Send the request
let mut request = request::Head::default();
request.uri = "https://http2.akamai.com/".parse().unwrap();
let request = Request::builder()
.uri("https://http2.akamai.com/")
.body(()).unwrap();
info!("sending request");
let h2 = h2.send_request(1.into(), request, true).wait().unwrap();
let mut stream = h2.request(request, true).unwrap();
// Get the response
let resp = h2.run(poll_fn(|| stream.poll_response())).unwrap();
assert_eq!(resp.status(), status::NO_CONTENT);
info!("getting response");
let (resp, h2) = h2.into_future().wait().unwrap();
match resp.unwrap() {
Frame::Headers { headers, .. } => {
assert_eq!(headers.status, status::NO_CONTENT);
}
_ => panic!("unexpected frame"),
}
// No more frames
info!("ensure no more responses");
assert!(Stream::wait(h2).next().is_none());;
h2.wait().unwrap();
}
#[test]
@@ -75,46 +63,44 @@ fn send_recv_data() {
])
.build();
let h2 = client::handshake(mock).wait().expect("handshake");
let mut h2 = Client::handshake2(mock)
.wait().unwrap();
// Send the request
let mut request = request::Head::default();
request.method = method::POST;
request.uri = "https://http2.akamai.com/".parse().unwrap();
let h2 = h2.send_request(1.into(), request, false).wait().expect("send request");
let request = Request::builder()
.method(method::POST)
.uri("https://http2.akamai.com/")
.body(()).unwrap();
let b = "hello";
info!("sending request");
let mut stream = h2.request(request, false).unwrap();
// Send the data
let h2 = h2.send_data(1.into(), b.into(), true).wait().expect("send data");
stream.send_data("hello", true).unwrap();
// Get the response headers
let (resp, h2) = h2.into_future().wait().expect("into future");
// Get the response
let resp = h2.run(poll_fn(|| stream.poll_response())).unwrap();
assert_eq!(resp.status(), status::OK);
match resp.expect("response headers") {
Frame::Headers { headers, .. } => {
assert_eq!(headers.status, status::OK);
}
_ => panic!("unexpected frame"),
}
// Take the body
let (_, body) = resp.into_parts();
// Get the response body
let (data, h2) = h2.into_future().wait().expect("into future");
// Wait for all the data frames to be received
let mut chunks = h2.run(body.collect()).unwrap();
match data.expect("response data") {
Frame::Data { id, data, end_of_stream, .. } => {
assert_eq!(id, 1.into());
assert_eq!(data, &b"world"[..]);
assert!(end_of_stream);
}
_ => panic!("unexpected frame"),
}
// Only one chunk since two frames are coalesced.
assert_eq!(1, chunks.len());
assert!(Stream::wait(h2).next().is_none());;
let data = chunks[0].pop_bytes().unwrap();
assert_eq!(data, &b"world"[..]);
assert!(chunks[0].pop_bytes().is_none());
// The H2 connection is closed
h2.wait().unwrap();
}
#[test]
fn send_headers_recv_data() {
fn send_headers_recv_data_single_frame() {
let _ = env_logger::init();
let mock = mock_io::Builder::new()
@@ -132,80 +118,42 @@ fn send_headers_recv_data() {
])
.build();
let h2 = client::handshake(mock)
let mut h2 = Client::handshake(mock)
.wait().unwrap();
// Send the request
let mut request = request::Head::default();
request.uri = "https://http2.akamai.com/".parse().unwrap();
let h2 = h2.send_request(1.into(), request, true).wait().unwrap();
let request = Request::builder()
.uri("https://http2.akamai.com/")
.body(()).unwrap();
// Get the response headers
let (resp, h2) = h2.into_future().wait().unwrap();
info!("sending request");
let mut stream = h2.request(request, true).unwrap();
match resp.unwrap() {
Frame::Headers { headers, .. } => {
assert_eq!(headers.status, status::OK);
}
_ => panic!("unexpected frame"),
}
let resp = h2.run(poll_fn(|| stream.poll_response())).unwrap();
assert_eq!(resp.status(), status::OK);
// Get the response body
let (data, h2) = h2.into_future().wait().unwrap();
// Take the body
let (_, body) = resp.into_parts();
match data.unwrap() {
Frame::Data { id, data, end_of_stream, .. } => {
assert_eq!(id, 1.into());
assert_eq!(data, &b"hello"[..]);
assert!(!end_of_stream);
}
_ => panic!("unexpected frame"),
}
// Wait for all the data frames to be received
let mut chunks = h2.run(body.collect()).unwrap();
// Get the response body
let (data, h2) = h2.into_future().wait().unwrap();
// Only one chunk since two frames are coalesced.
assert_eq!(1, chunks.len());
match data.unwrap() {
Frame::Data { id, data, end_of_stream, .. } => {
assert_eq!(id, 1.into());
assert_eq!(data, &b"world"[..]);
assert!(end_of_stream);
}
_ => panic!("unexpected frame"),
}
let data = chunks[0].pop_bytes().unwrap();
assert_eq!(data, &b"hello"[..]);
assert!(Stream::wait(h2).next().is_none());;
}
#[test]
fn send_headers_twice_with_same_stream_id() {
let _ = env_logger::init();
let mock = mock_io::Builder::new()
.handshake()
// Write GET /
.write(&[
0, 0, 0x10, 1, 5, 0, 0, 0, 1, 0x82, 0x87, 0x41, 0x8B, 0x9D, 0x29,
0xAC, 0x4B, 0x8F, 0xA8, 0xE9, 0x19, 0x97, 0x21, 0xE9, 0x84,
])
.build();
let h2 = client::handshake(mock)
.wait().unwrap();
// Send the request
let mut request = request::Head::default();
request.uri = "https://http2.akamai.com/".parse().unwrap();
let h2 = h2.send_request(1.into(), request, true).wait().unwrap();
// Send another request with the same stream ID
let mut request = request::Head::default();
request.uri = "https://http2.akamai.com/".parse().unwrap();
let err = h2.send_request(1.into(), request, true).wait().unwrap_err();
assert_user_err!(err, UnexpectedFrameType);
let data = chunks[0].pop_bytes().unwrap();
assert_eq!(data, &b"world"[..]);
assert!(chunks[0].pop_bytes().is_none());
// The H2 connection is closed
h2.wait().unwrap();
}
/*
#[test]
fn send_data_after_headers_eos() {
let _ = env_logger::init();
@@ -238,22 +186,8 @@ fn send_data_after_headers_eos() {
assert_user_err!(err, UnexpectedFrameType);
}
#[test]
fn send_data_without_headers() {
let mock = mock_io::Builder::new()
.handshake()
.build();
let h2 = client::handshake(mock)
.wait().unwrap();
let b = Bytes::from_static(b"hello world");
let err = h2.send_data(1.into(), b, true).wait().unwrap_err();
assert_user_err!(err, UnexpectedFrameType);
}
#[test]
#[ignore]
fn exceed_max_streams() {
}
*/

View File

@@ -3,6 +3,7 @@
pub extern crate bytes;
pub extern crate h2;
pub extern crate http;
pub extern crate tokio_io;
pub extern crate futures;
pub extern crate mock_io;
pub extern crate env_logger;
@@ -12,26 +13,30 @@ pub use self::futures::{
Sink,
Stream,
};
pub use self::futures::future::poll_fn;
pub use self::http::{
request,
response,
method,
status,
Request,
Response,
};
pub use self::h2::{
client,
server,
};
pub use self::h2::client::{self, Client};
// pub use self::h2::server;
pub use self::bytes::{
Buf,
BufMut,
Bytes,
BytesMut,
IntoBuf,
};
use tokio_io::{AsyncRead, AsyncWrite};
pub trait MockH2 {
fn handshake(&mut self) -> &mut Self;
}
@@ -46,6 +51,33 @@ impl MockH2 for mock_io::Builder {
}
}
pub trait ClientExt {
fn run<F: Future>(&mut self, f: F) -> Result<F::Item, F::Error>;
}
impl<T, B> ClientExt for Client<T, B>
where T: AsyncRead + AsyncWrite + 'static,
B: IntoBuf + 'static,
{
fn run<F: Future>(&mut self, f: F) -> Result<F::Item, F::Error> {
use futures::future::{self, Future};
use futures::future::Either::*;
let res = future::poll_fn(|| self.poll())
.select2(f).wait();
match res {
Ok(A((_, b))) => {
// Connection is done...
b.wait()
}
Ok(B((v, _))) => return Ok(v),
Err(A((e, _))) => panic!("err: {:?}", e),
Err(B((e, _))) => return Err(e),
}
}
}
pub mod frames {
//! Some useful frames