Merge branch 'master' into ver/flowio
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
use {Frame, ConnectionError, Peer, StreamId};
|
||||
use Frame;
|
||||
use client::Client;
|
||||
use frame::{Frame as WireFrame};
|
||||
use proto::{self, FlowController, ReadySink, PeerState, State, WindowUpdate};
|
||||
use error::{self, ConnectionError};
|
||||
use frame::{self, StreamId};
|
||||
use proto::{self, Peer, ReadySink, State, PeerState, WindowUpdate, FlowController};
|
||||
use server::Server;
|
||||
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
|
||||
use http::{request, response};
|
||||
use bytes::{Bytes, IntoBuf};
|
||||
|
||||
use futures::*;
|
||||
|
||||
@@ -21,8 +23,8 @@ use std::marker::PhantomData;
|
||||
|
||||
/// An H2 connection
|
||||
#[derive(Debug)]
|
||||
pub struct Connection<T, P> {
|
||||
inner: proto::Inner<T>,
|
||||
pub struct Connection<T, P, B: IntoBuf = Bytes> {
|
||||
inner: proto::Inner<T, B::Buf>,
|
||||
streams: StreamMap<State>,
|
||||
peer: PhantomData<P>,
|
||||
|
||||
@@ -39,12 +41,13 @@ pub struct Connection<T, P> {
|
||||
|
||||
type StreamMap<T> = OrderMap<StreamId, T, BuildHasherDefault<FnvHasher>>;
|
||||
|
||||
pub fn new<T, P>(transport: proto::Inner<T>,
|
||||
pub fn new<T, P, B>(transport: proto::Inner<T, B::Buf>,
|
||||
initial_local_window_size: u32,
|
||||
initial_remote_window_size: u32)
|
||||
-> Connection<T, P>
|
||||
-> Connection<T, P, B>
|
||||
where T: AsyncRead + AsyncWrite,
|
||||
P: Peer,
|
||||
B: IntoBuf,
|
||||
{
|
||||
Connection {
|
||||
inner: transport,
|
||||
@@ -62,7 +65,8 @@ pub fn new<T, P>(transport: proto::Inner<T>,
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, P> Connection<T, P> {
|
||||
impl<T, P, B: IntoBuf> Connection<T, P, B> {
|
||||
|
||||
/// Publishes local stream window updates to the remote.
|
||||
///
|
||||
/// Connection window updates (StreamId=0) and stream window must be published
|
||||
@@ -118,8 +122,28 @@ impl<T, P> Connection<T, P> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Connection<T, Client>
|
||||
impl<T, P, B> Connection<T, P, B>
|
||||
where T: AsyncRead + AsyncWrite,
|
||||
P: Peer,
|
||||
B: IntoBuf,
|
||||
{
|
||||
pub fn send_data(self,
|
||||
id: StreamId,
|
||||
data: B,
|
||||
end_of_stream: bool)
|
||||
-> sink::Send<Self>
|
||||
{
|
||||
self.send(Frame::Data {
|
||||
id: id,
|
||||
data: data,
|
||||
end_of_stream: end_of_stream,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, B> Connection<T, Client, B>
|
||||
where T: AsyncRead + AsyncWrite,
|
||||
B: IntoBuf,
|
||||
{
|
||||
pub fn send_request(self,
|
||||
id: StreamId, // TODO: Generate one internally?
|
||||
@@ -135,8 +159,9 @@ impl<T> Connection<T, Client>
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Connection<T, Server>
|
||||
impl<T, B> Connection<T, Server, B>
|
||||
where T: AsyncRead + AsyncWrite,
|
||||
B: IntoBuf,
|
||||
{
|
||||
pub fn send_response(self,
|
||||
id: StreamId, // TODO: Generate one internally?
|
||||
@@ -152,17 +177,19 @@ impl<T> Connection<T, Server>
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, P> Stream for Connection<T, P>
|
||||
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> {
|
||||
use frame::Frame::*;
|
||||
trace!("Connection::poll");
|
||||
|
||||
loop {
|
||||
loop {
|
||||
let frame = match try!(self.inner.poll()) {
|
||||
Async::Ready(f) => f,
|
||||
Async::NotReady => {
|
||||
@@ -176,7 +203,7 @@ impl<T, P> Stream for Connection<T, P>
|
||||
trace!("received; frame={:?}", frame);
|
||||
|
||||
let frame = match frame {
|
||||
Some(WireFrame::Headers(v)) => {
|
||||
Some(Headers(v)) => {
|
||||
// TODO: Update stream state
|
||||
let stream_id = v.stream_id();
|
||||
let end_of_stream = v.is_end_stream();
|
||||
@@ -204,20 +231,24 @@ impl<T, P> Stream for Connection<T, P>
|
||||
end_of_stream: end_of_stream,
|
||||
}
|
||||
}
|
||||
Some(WireFrame::Data(v)) => {
|
||||
Some(Data(v)) => {
|
||||
// TODO: Validate frame
|
||||
|
||||
let stream_id = v.stream_id();
|
||||
let end_of_stream = v.is_end_stream();
|
||||
match self.streams.get_mut(&stream_id) {
|
||||
None => return Err(error::Reason::ProtocolError.into()),
|
||||
Some(state) => try!(state.recv_data(end_of_stream)),
|
||||
}
|
||||
|
||||
Frame::Body {
|
||||
Frame::Data {
|
||||
id: stream_id,
|
||||
chunk: v.into_payload(),
|
||||
data: v.into_payload(),
|
||||
end_of_stream: end_of_stream,
|
||||
}
|
||||
}
|
||||
Some(WireFrame::WindowUpdate(v)) => {
|
||||
self.increment_remote_window(v.stream_id(), v.increment());
|
||||
Some(WindowUpdate(v)) => {
|
||||
self.increment_remote_window(v.stream_id(), v.size_increment());
|
||||
continue;
|
||||
}
|
||||
Some(frame) => panic!("unexpected frame; frame={:?}", frame),
|
||||
@@ -229,16 +260,19 @@ impl<T, P> Stream for Connection<T, P>
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, P> Sink for Connection<T, P>
|
||||
impl<T, P, B> Sink for Connection<T, P, B>
|
||||
where T: AsyncRead + AsyncWrite,
|
||||
P: Peer,
|
||||
B: IntoBuf,
|
||||
{
|
||||
type SinkItem = Frame<P::Send>;
|
||||
type SinkItem = Frame<P::Send, B>;
|
||||
type SinkError = ConnectionError;
|
||||
|
||||
fn start_send(&mut self, item: Self::SinkItem)
|
||||
-> StartSend<Self::SinkItem, Self::SinkError>
|
||||
{
|
||||
use frame::Frame::Headers;
|
||||
|
||||
// First ensure that the upstream can process a new item
|
||||
if !try!(self.poll_ready()).is_ready() {
|
||||
return Ok(AsyncSink::NotReady(item));
|
||||
@@ -262,7 +296,8 @@ impl<T, P> Sink for Connection<T, P>
|
||||
// connections should not be factored.
|
||||
//
|
||||
if !P::is_valid_local_stream_id(id) {
|
||||
unimplemented!();
|
||||
// TODO: clear state
|
||||
return Err(error::User::InvalidStreamId.into());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +305,7 @@ impl<T, P> Sink for Connection<T, P>
|
||||
|
||||
// We already ensured that the upstream can handle the frame, so
|
||||
// panic if it gets rejected.
|
||||
let res = try!(self.inner.start_send(WireFrame::Headers(frame)));
|
||||
let res = try!(self.inner.start_send(Headers(frame)));
|
||||
|
||||
// This is a one-way conversion. By checking `poll_ready` first,
|
||||
// it's already been determined that the inner `Sink` can accept
|
||||
@@ -279,6 +314,25 @@ impl<T, P> Sink for Connection<T, P>
|
||||
|
||||
Ok(AsyncSink::Ready)
|
||||
}
|
||||
Frame::Data { id, data, end_of_stream } => {
|
||||
// The stream must be initialized at this point
|
||||
match self.streams.get_mut(&id) {
|
||||
None => return Err(error::User::InactiveStreamId.into()),
|
||||
Some(state) => try!(state.send_data(end_of_stream)),
|
||||
}
|
||||
|
||||
let mut frame = frame::Data::new(id, data.into_buf());
|
||||
|
||||
if end_of_stream {
|
||||
frame.set_end_stream();
|
||||
}
|
||||
|
||||
let res = try!(self.inner.start_send(frame.into()));
|
||||
|
||||
assert!(res.is_ready());
|
||||
|
||||
Ok(AsyncSink::Ready)
|
||||
}
|
||||
/*
|
||||
Frame::Trailers { id, headers } => {
|
||||
unimplemented!();
|
||||
@@ -302,9 +356,10 @@ impl<T, P> Sink for Connection<T, P>
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, P> ReadySink for Connection<T, P>
|
||||
impl<T, P, B> ReadySink for Connection<T, P, B>
|
||||
where T: AsyncRead + AsyncWrite,
|
||||
P: Peer,
|
||||
B: IntoBuf,
|
||||
{
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::SinkError> {
|
||||
self.inner.poll_ready()
|
||||
|
||||
@@ -29,10 +29,7 @@ enum Partial {
|
||||
// PushPromise(frame::PushPromise),
|
||||
}
|
||||
|
||||
impl<T> FramedRead<T>
|
||||
where T: AsyncRead,
|
||||
T: Sink<SinkItem = Frame, SinkError = ConnectionError>,
|
||||
{
|
||||
impl<T> FramedRead<T> {
|
||||
pub fn new(inner: length_delimited::FramedRead<T>) -> FramedRead<T> {
|
||||
FramedRead {
|
||||
inner: inner,
|
||||
@@ -40,9 +37,7 @@ impl<T> FramedRead<T>
|
||||
partial: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FramedRead<T> {
|
||||
fn decode_frame(&mut self, mut bytes: Bytes) -> Result<Option<Frame>, ConnectionError> {
|
||||
// Parse the head
|
||||
let head = frame::Head::parse(&bytes);
|
||||
@@ -97,9 +92,11 @@ impl<T> FramedRead<T> {
|
||||
unimplemented!();
|
||||
}
|
||||
Kind::WindowUpdate => {
|
||||
// TODO: IMPLEMENT
|
||||
let frame = try!(frame::WindowUpdate::load(head, &bytes[frame::HEADER_LEN..]));
|
||||
frame.into()
|
||||
}
|
||||
debug!("decoded; frame={:?}", frame);
|
||||
return Ok(None);
|
||||
},
|
||||
Kind::Continuation => {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use std::cmp;
|
||||
use std::io::{self, Cursor};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FramedWrite<T> {
|
||||
pub struct FramedWrite<T, B> {
|
||||
/// Upstream `AsyncWrite`
|
||||
inner: T,
|
||||
|
||||
@@ -21,20 +21,20 @@ pub struct FramedWrite<T> {
|
||||
buf: Cursor<BytesMut>,
|
||||
|
||||
/// Next frame to encode
|
||||
next: Option<Next>,
|
||||
next: Option<Next<B>>,
|
||||
|
||||
/// Max frame size, this is specified by the peer
|
||||
max_frame_size: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Next {
|
||||
enum Next<B> {
|
||||
Data {
|
||||
/// Length of the current frame being written
|
||||
frame_len: usize,
|
||||
|
||||
/// Data frame to encode
|
||||
data: frame::Data
|
||||
data: frame::Data<B>,
|
||||
},
|
||||
Continuation(frame::Continuation),
|
||||
}
|
||||
@@ -50,8 +50,12 @@ const MIN_BUFFER_CAPACITY: usize = frame::HEADER_LEN + CHAIN_THRESHOLD;
|
||||
/// than 16kb, so not even close).
|
||||
const CHAIN_THRESHOLD: usize = 256;
|
||||
|
||||
impl<T: AsyncWrite> FramedWrite<T> {
|
||||
pub fn new(inner: T) -> FramedWrite<T> {
|
||||
// TODO: Make generic
|
||||
impl<T, B> FramedWrite<T, B>
|
||||
where T: AsyncWrite,
|
||||
B: Buf,
|
||||
{
|
||||
pub fn new(inner: T) -> FramedWrite<T, B> {
|
||||
FramedWrite {
|
||||
inner: inner,
|
||||
hpack: hpack::Encoder::default(),
|
||||
@@ -69,24 +73,27 @@ impl<T: AsyncWrite> FramedWrite<T> {
|
||||
self.next.is_none() && !self.buf.has_remaining()
|
||||
}
|
||||
|
||||
fn frame_len(&self, data: &frame::Data) -> usize {
|
||||
fn frame_len(&self, data: &frame::Data<B>) -> usize {
|
||||
cmp::min(self.max_frame_size, data.len())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsyncWrite> Sink for FramedWrite<T> {
|
||||
type SinkItem = Frame;
|
||||
impl<T, B> Sink for FramedWrite<T, B>
|
||||
where T: AsyncWrite,
|
||||
B: Buf,
|
||||
{
|
||||
type SinkItem = Frame<B>;
|
||||
type SinkError = ConnectionError;
|
||||
|
||||
fn start_send(&mut self, item: Frame) -> StartSend<Frame, ConnectionError> {
|
||||
debug!("start_send; frame={:?}", item);
|
||||
|
||||
fn start_send(&mut self, item: Self::SinkItem)
|
||||
-> StartSend<Self::SinkItem, ConnectionError>
|
||||
{
|
||||
if !try!(self.poll_ready()).is_ready() {
|
||||
return Ok(AsyncSink::NotReady(item));
|
||||
}
|
||||
|
||||
match item {
|
||||
Frame::Data(v) => {
|
||||
Frame::Data(mut v) => {
|
||||
if v.len() >= CHAIN_THRESHOLD {
|
||||
let head = v.head();
|
||||
let len = self.frame_len(&v);
|
||||
@@ -100,7 +107,11 @@ impl<T: AsyncWrite> Sink for FramedWrite<T> {
|
||||
data: v,
|
||||
});
|
||||
} else {
|
||||
v.encode(self.buf.get_mut());
|
||||
v.encode_chunk(self.buf.get_mut());
|
||||
|
||||
// The chunk has been fully encoded, so there is no need to
|
||||
// keep it around
|
||||
assert_eq!(v.len(), 0, "chunk not fully encoded");
|
||||
}
|
||||
}
|
||||
Frame::Headers(v) => {
|
||||
@@ -140,7 +151,6 @@ impl<T: AsyncWrite> Sink for FramedWrite<T> {
|
||||
|
||||
// As long as there is data to write, try to write it!
|
||||
while !self.is_empty() {
|
||||
trace!("writing buffer; next={:?}; rem={:?}", self.next, self.buf.remaining());
|
||||
try_ready!(self.inner.write_buf(&mut self.buf));
|
||||
}
|
||||
|
||||
@@ -161,7 +171,10 @@ impl<T: AsyncWrite> Sink for FramedWrite<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsyncWrite> ReadySink for FramedWrite<T> {
|
||||
impl<T, B> ReadySink for FramedWrite<T, B>
|
||||
where T: AsyncWrite,
|
||||
B: Buf,
|
||||
{
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::SinkError> {
|
||||
if !self.has_capacity() {
|
||||
// Try flushing
|
||||
@@ -176,7 +189,7 @@ impl<T: AsyncWrite> ReadySink for FramedWrite<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Stream> Stream for FramedWrite<T> {
|
||||
impl<T: Stream, B> Stream for FramedWrite<T, B> {
|
||||
type Item = T::Item;
|
||||
type Error = T::Error;
|
||||
|
||||
@@ -185,14 +198,14 @@ impl<T: Stream> Stream for FramedWrite<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: io::Read> io::Read for FramedWrite<T> {
|
||||
impl<T: io::Read, B> io::Read for FramedWrite<T, B> {
|
||||
fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
|
||||
self.inner.read(dst)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsyncRead> AsyncRead for FramedWrite<T> {
|
||||
fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Poll<usize, io::Error>
|
||||
impl<T: AsyncRead, B> AsyncRead for FramedWrite<T, B> {
|
||||
fn read_buf<B2: BufMut>(&mut self, buf: &mut B2) -> Poll<usize, io::Error>
|
||||
where Self: Sized,
|
||||
{
|
||||
self.inner.read_buf(buf)
|
||||
|
||||
@@ -23,24 +23,28 @@ use {frame, Peer};
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
use tokio_io::codec::length_delimited;
|
||||
|
||||
type Inner<T> =
|
||||
use bytes::{Buf, IntoBuf};
|
||||
|
||||
type Inner<T, B> =
|
||||
Settings<
|
||||
PingPong<
|
||||
Framed<T>>>;
|
||||
Framed<T, B>,
|
||||
B>>;
|
||||
|
||||
type Framed<T> =
|
||||
type Framed<T, B> =
|
||||
FramedRead<
|
||||
FramedWrite<T>>;
|
||||
FramedWrite<T, B>>;
|
||||
|
||||
/// Create a full H2 transport from an I/O handle.
|
||||
///
|
||||
/// This is called as the final step of the client handshake future.
|
||||
pub fn from_io<T, P>(io: T, settings: frame::SettingSet)
|
||||
-> Connection<T, P>
|
||||
pub fn from_io<T, P, B>(io: T, settings: frame::SettingSet)
|
||||
-> Connection<T, P, B>
|
||||
where T: AsyncRead + AsyncWrite,
|
||||
P: Peer,
|
||||
B: IntoBuf,
|
||||
{
|
||||
let framed_write = FramedWrite::new(io);
|
||||
let framed_write: FramedWrite<_, B::Buf> = FramedWrite::new(io);
|
||||
|
||||
// To avoid code duplication, we're going to go this route. It is a bit
|
||||
// weird, but oh well...
|
||||
@@ -55,9 +59,10 @@ pub fn from_io<T, P>(io: T, settings: frame::SettingSet)
|
||||
/// When the server is performing the handshake, it is able to only send
|
||||
/// `Settings` frames and is expected to receive the client preface as a byte
|
||||
/// stream. To represent this, `Settings<FramedWrite<T>>` is returned.
|
||||
pub fn server_handshaker<T>(io: T, settings: frame::SettingSet)
|
||||
-> Settings<FramedWrite<T>>
|
||||
pub fn server_handshaker<T, B>(io: T, settings: frame::SettingSet)
|
||||
-> Settings<FramedWrite<T, B>>
|
||||
where T: AsyncRead + AsyncWrite,
|
||||
B: Buf,
|
||||
{
|
||||
let framed_write = FramedWrite::new(io);
|
||||
|
||||
@@ -65,10 +70,11 @@ pub fn server_handshaker<T>(io: T, settings: frame::SettingSet)
|
||||
}
|
||||
|
||||
/// Create a full H2 transport from the server handshaker
|
||||
pub fn from_server_handshaker<T, P>(transport: Settings<FramedWrite<T>>)
|
||||
-> Connection<T, P>
|
||||
pub fn from_server_handshaker<T, P, B>(transport: Settings<FramedWrite<T, B::Buf>>)
|
||||
-> Connection<T, P, B>
|
||||
where T: AsyncRead + AsyncWrite,
|
||||
P: Peer,
|
||||
B: IntoBuf,
|
||||
{
|
||||
let settings = transport.swap_inner(|io| {
|
||||
// Delimit the frames
|
||||
|
||||
@@ -5,16 +5,16 @@ use proto::ReadySink;
|
||||
|
||||
/// Acknowledges ping requests from the remote.
|
||||
#[derive(Debug)]
|
||||
pub struct PingPong<T> {
|
||||
pub struct PingPong<T, U> {
|
||||
inner: T,
|
||||
pong: Option<Frame>,
|
||||
pong: Option<Frame<U>>,
|
||||
}
|
||||
|
||||
impl<T> PingPong<T>
|
||||
impl<T, U> PingPong<T, U>
|
||||
where T: Stream<Item = Frame, Error = ConnectionError>,
|
||||
T: Sink<SinkItem = Frame, SinkError = ConnectionError>,
|
||||
T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
||||
{
|
||||
pub fn new(inner: T) -> PingPong<T> {
|
||||
pub fn new(inner: T) -> Self {
|
||||
PingPong {
|
||||
inner,
|
||||
pong: None,
|
||||
@@ -38,9 +38,9 @@ impl<T> PingPong<T>
|
||||
/// > a PING frame with the ACK flag set in response, with an identical
|
||||
/// > payload. PING responses SHOULD be given higher priority than any
|
||||
/// > other frame.
|
||||
impl<T> Stream for PingPong<T>
|
||||
impl<T, U> Stream for PingPong<T, U>
|
||||
where T: Stream<Item = Frame, Error = ConnectionError>,
|
||||
T: Sink<SinkItem = Frame, SinkError = ConnectionError>,
|
||||
T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
||||
{
|
||||
type Item = Frame;
|
||||
type Error = ConnectionError;
|
||||
@@ -76,14 +76,16 @@ impl<T> Stream for PingPong<T>
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Sink for PingPong<T>
|
||||
impl<T, U> Sink for PingPong<T, U>
|
||||
where T: Stream<Item = Frame, Error = ConnectionError>,
|
||||
T: Sink<SinkItem = Frame, SinkError = ConnectionError>,
|
||||
T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
||||
{
|
||||
type SinkItem = Frame;
|
||||
type SinkItem = Frame<U>;
|
||||
type SinkError = ConnectionError;
|
||||
|
||||
fn start_send(&mut self, item: Frame) -> StartSend<Frame, ConnectionError> {
|
||||
fn start_send(&mut self, item: Self::SinkItem)
|
||||
-> StartSend<Self::SinkItem, Self::SinkError>
|
||||
{
|
||||
// Pings _SHOULD_ have priority over other messages, so attempt to send pending
|
||||
// ping frames before attempting to send `item`.
|
||||
if self.try_send_pong()?.is_not_ready() {
|
||||
@@ -100,9 +102,9 @@ impl<T> Sink for PingPong<T>
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ReadySink for PingPong<T>
|
||||
impl<T, U> ReadySink for PingPong<T, U>
|
||||
where T: Stream<Item = Frame, Error = ConnectionError>,
|
||||
T: Sink<SinkItem = Frame, SinkError = ConnectionError>,
|
||||
T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
||||
T: ReadySink,
|
||||
{
|
||||
fn poll_ready(&mut self) -> Poll<(), ConnectionError> {
|
||||
|
||||
@@ -29,8 +29,8 @@ pub struct Settings<T> {
|
||||
received_remote: bool,
|
||||
}
|
||||
|
||||
impl<T> Settings<T>
|
||||
where T: Sink<SinkItem = Frame, SinkError = ConnectionError>,
|
||||
impl<T, U> Settings<T>
|
||||
where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
||||
{
|
||||
pub fn new(inner: T, local: frame::SettingSet) -> Settings<T> {
|
||||
Settings {
|
||||
@@ -44,7 +44,7 @@ impl<T> Settings<T>
|
||||
}
|
||||
|
||||
/// Swap the inner transport while maintaining the current state.
|
||||
pub fn swap_inner<U, F: FnOnce(T) -> U>(self, f: F) -> Settings<U> {
|
||||
pub fn swap_inner<T2, F: FnOnce(T) -> T2>(self, f: F) -> Settings<T2> {
|
||||
let inner = f(self.inner);
|
||||
|
||||
Settings {
|
||||
@@ -88,9 +88,9 @@ impl<T> Settings<T>
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Stream for Settings<T>
|
||||
impl<T, U> Stream for Settings<T>
|
||||
where T: Stream<Item = Frame, Error = ConnectionError>,
|
||||
T: Sink<SinkItem = Frame, SinkError = ConnectionError>,
|
||||
T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
||||
{
|
||||
type Item = Frame;
|
||||
type Error = ConnectionError;
|
||||
@@ -118,13 +118,15 @@ impl<T> Stream for Settings<T>
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Sink for Settings<T>
|
||||
where T: Sink<SinkItem = Frame, SinkError = ConnectionError>,
|
||||
impl<T, U> Sink for Settings<T>
|
||||
where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
||||
{
|
||||
type SinkItem = Frame;
|
||||
type SinkItem = Frame<U>;
|
||||
type SinkError = ConnectionError;
|
||||
|
||||
fn start_send(&mut self, item: Frame) -> StartSend<Frame, ConnectionError> {
|
||||
fn start_send(&mut self, item: Self::SinkItem)
|
||||
-> StartSend<Self::SinkItem, Self::SinkError>
|
||||
{
|
||||
// Settings frames take priority, so `item` cannot be sent if there are
|
||||
// any pending acks OR the local settings have been changed w/o sending
|
||||
// an associated frame.
|
||||
@@ -147,8 +149,8 @@ impl<T> Sink for Settings<T>
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ReadySink for Settings<T>
|
||||
where T: Sink<SinkItem = Frame, SinkError = ConnectionError>,
|
||||
impl<T, U> ReadySink for Settings<T>
|
||||
where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
|
||||
T: ReadySink,
|
||||
{
|
||||
fn poll_ready(&mut self) -> Poll<(), ConnectionError> {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use {ConnectionError, Reason, Peer};
|
||||
use Peer;
|
||||
use error::ConnectionError;
|
||||
use error::Reason::*;
|
||||
use error::User::*;
|
||||
use proto::FlowController;
|
||||
|
||||
/// Represents the state of an H2 stream
|
||||
@@ -101,7 +104,7 @@ impl State {
|
||||
Ok(true)
|
||||
}
|
||||
Open { local, remote } => {
|
||||
try!(remote.check_is_headers(Reason::ProtocolError));
|
||||
try!(remote.check_is_headers(ProtocolError.into()));
|
||||
|
||||
*self = if eos {
|
||||
HalfClosedRemote(local)
|
||||
@@ -113,7 +116,7 @@ impl State {
|
||||
Ok(false)
|
||||
}
|
||||
HalfClosedLocal(remote) => {
|
||||
try!(remote.check_is_headers(Reason::ProtocolError));
|
||||
try!(remote.check_is_headers(ProtocolError.into()));
|
||||
|
||||
*self = if eos {
|
||||
Closed
|
||||
@@ -124,7 +127,36 @@ impl State {
|
||||
Ok(false)
|
||||
}
|
||||
Closed | HalfClosedRemote(..) => {
|
||||
Err(Reason::ProtocolError.into())
|
||||
Err(ProtocolError.into())
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recv_data(&mut self, eos: bool) -> Result<(), ConnectionError> {
|
||||
use self::State::*;
|
||||
|
||||
match *self {
|
||||
Open { local, remote } => {
|
||||
try!(remote.check_is_data(ProtocolError.into()));
|
||||
|
||||
if eos {
|
||||
*self = HalfClosedRemote(local);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
HalfClosedLocal(remote) => {
|
||||
try!(remote.check_is_data(ProtocolError.into()));
|
||||
|
||||
if eos {
|
||||
*self = Closed;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Closed | HalfClosedRemote(..) => {
|
||||
Err(ProtocolError.into())
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
@@ -152,7 +184,7 @@ impl State {
|
||||
Ok(true)
|
||||
}
|
||||
Open { local, remote } => {
|
||||
try!(local.check_is_headers(Reason::InternalError));
|
||||
try!(local.check_is_headers(UnexpectedFrameType.into()));
|
||||
|
||||
*self = if eos {
|
||||
HalfClosedLocal(remote)
|
||||
@@ -164,7 +196,7 @@ impl State {
|
||||
Ok(false)
|
||||
}
|
||||
HalfClosedRemote(local) => {
|
||||
try!(local.check_is_headers(Reason::InternalError));
|
||||
try!(local.check_is_headers(UnexpectedFrameType.into()));
|
||||
|
||||
*self = if eos {
|
||||
Closed
|
||||
@@ -175,7 +207,36 @@ impl State {
|
||||
Ok(false)
|
||||
}
|
||||
Closed | HalfClosedLocal(..) => {
|
||||
Err(Reason::InternalError.into())
|
||||
Err(UnexpectedFrameType.into())
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_data(&mut self, eos: bool) -> Result<(), ConnectionError> {
|
||||
use self::State::*;
|
||||
|
||||
match *self {
|
||||
Open { local, remote } => {
|
||||
try!(local.check_is_data(UnexpectedFrameType.into()));
|
||||
|
||||
if eos {
|
||||
*self = HalfClosedLocal(remote);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
HalfClosedRemote(local) => {
|
||||
try!(local.check_is_data(UnexpectedFrameType.into()));
|
||||
|
||||
if eos {
|
||||
*self = Closed;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Closed | HalfClosedLocal(..) => {
|
||||
Err(UnexpectedFrameType.into())
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
@@ -184,12 +245,22 @@ impl State {
|
||||
|
||||
impl PeerState {
|
||||
#[inline]
|
||||
fn check_is_headers(&self, err: Reason) -> Result<(), ConnectionError> {
|
||||
fn check_is_headers(&self, err: ConnectionError) -> Result<(), ConnectionError> {
|
||||
use self::PeerState::*;
|
||||
|
||||
match *self {
|
||||
Headers => Ok(()),
|
||||
_ => Err(err.into()),
|
||||
_ => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn check_is_data(&self, err: ConnectionError) -> Result<(), ConnectionError> {
|
||||
use self::PeerState::*;
|
||||
|
||||
match *self {
|
||||
Data { .. } => Ok(()),
|
||||
_ => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user