ok, starting to look good
This commit is contained in:
@@ -1,10 +1,11 @@
|
|||||||
|
use FrameSize;
|
||||||
use frame::{util, Frame, Head, Error, StreamId, Kind};
|
use frame::{util, Frame, Head, Error, StreamId, Kind};
|
||||||
use bytes::{BufMut, Bytes, Buf};
|
use bytes::{BufMut, Bytes, Buf};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Data<T = Bytes> {
|
pub struct Data<T = Bytes> {
|
||||||
stream_id: StreamId,
|
stream_id: StreamId,
|
||||||
data_len: usize,
|
data_len: FrameSize,
|
||||||
data: T,
|
data: T,
|
||||||
flags: DataFlag,
|
flags: DataFlag,
|
||||||
pad_len: Option<u8>,
|
pad_len: Option<u8>,
|
||||||
@@ -29,7 +30,7 @@ impl Data<Bytes> {
|
|||||||
};
|
};
|
||||||
Ok(Data {
|
Ok(Data {
|
||||||
stream_id: head.stream_id(),
|
stream_id: head.stream_id(),
|
||||||
data_len: payload.len(),
|
data_len: payload.len() as FrameSize,
|
||||||
data: payload,
|
data: payload,
|
||||||
flags: flags,
|
flags: flags,
|
||||||
pad_len: pad_len,
|
pad_len: pad_len,
|
||||||
@@ -54,7 +55,7 @@ impl<T> Data<T> {
|
|||||||
Head::new(Kind::Data, self.flags.into(), self.stream_id)
|
Head::new(Kind::Data, self.flags.into(), self.stream_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> FrameSize {
|
||||||
self.data_len
|
self.data_len
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,20 +67,21 @@ impl<T> Data<T> {
|
|||||||
impl<T: Buf> Data<T> {
|
impl<T: Buf> Data<T> {
|
||||||
pub fn from_buf(stream_id: StreamId, data: T) -> Self {
|
pub fn from_buf(stream_id: StreamId, data: T) -> Self {
|
||||||
Data {
|
Data {
|
||||||
stream_id: stream_id,
|
stream_id,
|
||||||
data_len: data.remaining(),
|
data_len: data.remaining() as FrameSize,
|
||||||
data: data,
|
data,
|
||||||
flags: DataFlag::default(),
|
flags: DataFlag::default(),
|
||||||
pad_len: None,
|
pad_len: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode_chunk<U: BufMut>(&mut self, dst: &mut U) {
|
pub fn encode_chunk<U: BufMut>(&mut self, dst: &mut U) {
|
||||||
if self.len() > dst.remaining_mut() {
|
let len = self.len() as usize;
|
||||||
|
if len > dst.remaining_mut() {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.head().encode(self.len(), dst);
|
self.head().encode(len, dst);
|
||||||
dst.put(&mut self.data);
|
dst.put(&mut self.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use FrameSize;
|
||||||
use frame::{Frame, Error, Head, Kind, StreamId};
|
use frame::{Frame, Error, Head, Kind, StreamId};
|
||||||
use bytes::{BytesMut, BufMut, BigEndian};
|
use bytes::{BytesMut, BufMut, BigEndian};
|
||||||
|
|
||||||
@@ -45,7 +46,7 @@ const ACK: u8 = 0x1;
|
|||||||
const ALL: u8 = ACK;
|
const ALL: u8 = ACK;
|
||||||
|
|
||||||
pub const DEFAULT_SETTINGS_HEADER_TABLE_SIZE: usize = 4_096;
|
pub const DEFAULT_SETTINGS_HEADER_TABLE_SIZE: usize = 4_096;
|
||||||
pub const DEFAULT_MAX_FRAME_SIZE: usize = 16_384;
|
pub const DEFAULT_MAX_FRAME_SIZE: FrameSize = 16_384;
|
||||||
|
|
||||||
// ===== impl Settings =====
|
// ===== impl Settings =====
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ pub use proto::Connection;
|
|||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
|
||||||
|
pub type FrameSize = u32;
|
||||||
|
|
||||||
/// An H2 connection frame
|
/// An H2 connection frame
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Frame<T, B = Bytes> {
|
pub enum Frame<T, B = Bytes> {
|
||||||
@@ -52,7 +54,7 @@ pub enum Frame<T, B = Bytes> {
|
|||||||
id: StreamId,
|
id: StreamId,
|
||||||
data: B,
|
data: B,
|
||||||
/// TODO figure out how to make this a requirement on `B`
|
/// TODO figure out how to make this a requirement on `B`
|
||||||
data_len: usize,
|
data_len: FrameSize,
|
||||||
end_of_stream: bool,
|
end_of_stream: bool,
|
||||||
},
|
},
|
||||||
Trailers {
|
Trailers {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use Frame;
|
use {Frame, FrameSize};
|
||||||
use client::Client;
|
use client::Client;
|
||||||
use error::{self, ConnectionError};
|
use error::{self, ConnectionError};
|
||||||
use frame::{self, StreamId};
|
use frame::{self, StreamId};
|
||||||
use proto::{self, Peer, ReadySink, State, FlowController};
|
use proto::{self, Peer, ReadySink, State, FlowController, WindowSize};
|
||||||
use server::Server;
|
use server::Server;
|
||||||
|
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
@@ -26,12 +26,12 @@ pub struct Connection<T, P, B: IntoBuf = Bytes> {
|
|||||||
peer: PhantomData<P>,
|
peer: PhantomData<P>,
|
||||||
|
|
||||||
/// Tracks connection-level flow control.
|
/// Tracks connection-level flow control.
|
||||||
local_flow_controller: FlowController,
|
recv_flow_controller: FlowController,
|
||||||
remote_flow_controller: FlowController,
|
send_flow_controller: FlowController,
|
||||||
|
|
||||||
|
|
||||||
pending_local_window_update: Option<frame::WindowUpdate>,
|
pending_send_window_update: Option<frame::WindowUpdate>,
|
||||||
blocked_remote_window_update: Option<task::Task>,
|
blocked_recv_window_update: Option<task::Task>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type StreamMap<T> = OrderMap<StreamId, T, BuildHasherDefault<FnvHasher>>;
|
type StreamMap<T> = OrderMap<StreamId, T, BuildHasherDefault<FnvHasher>>;
|
||||||
@@ -42,37 +42,47 @@ pub fn new<T, P, B>(transport: proto::Inner<T, B::Buf>)
|
|||||||
P: Peer,
|
P: Peer,
|
||||||
B: IntoBuf,
|
B: IntoBuf,
|
||||||
{
|
{
|
||||||
let local_window_size = transport.local_settings().initial_window_size();
|
let recv_window_size = transport.local_settings().initial_window_size();
|
||||||
let remote_window_size = transport.remote_settings().initial_window_size();
|
let send_window_size = transport.remote_settings().initial_window_size();
|
||||||
Connection {
|
Connection {
|
||||||
inner: transport,
|
inner: transport,
|
||||||
streams: StreamMap::default(),
|
streams: StreamMap::default(),
|
||||||
peer: PhantomData,
|
peer: PhantomData,
|
||||||
|
|
||||||
local_flow_controller: FlowController::new(local_window_size),
|
recv_flow_controller: FlowController::new(recv_window_size),
|
||||||
remote_flow_controller: FlowController::new(remote_window_size),
|
send_flow_controller: FlowController::new(send_window_size),
|
||||||
|
|
||||||
pending_local_window_update: None,
|
pending_send_window_update: None,
|
||||||
blocked_remote_window_update: None,
|
blocked_recv_window_update: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, P, B: IntoBuf> Connection<T, P, B> {
|
impl<T, P, B: IntoBuf> Connection<T, P, B> {
|
||||||
pub fn poll_remote_window_update(&mut self, id: StreamId) -> Poll<u32, ConnectionError> {
|
#[inline]
|
||||||
if id.is_zero() {
|
fn claim_connection_recv_window(&mut self, len: WindowSize) -> Result<(), ConnectionError> {
|
||||||
return match self.local_flow_controller.take_window_update() {
|
self.recv_flow_controller.claim_window(len)
|
||||||
Some(incr) => Ok(Async::Ready(incr)),
|
.map_err(|_| error::Reason::FlowControlError.into())
|
||||||
None => {
|
}
|
||||||
self.blocked_remote_window_update = Some(task::current());
|
|
||||||
Ok(Async::NotReady)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.streams.get_mut(&id).and_then(|mut s| s.take_remote_window_update()) {
|
#[inline]
|
||||||
|
fn claim_connection_send_window(&mut self, len: WindowSize) -> Result<(), ConnectionError> {
|
||||||
|
self.send_flow_controller.claim_window(len)
|
||||||
|
.map_err(|_| error::Reason::FlowControlError.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO check max frame size
|
||||||
|
|
||||||
|
pub fn poll_remote_window_update(&mut self, id: StreamId) -> Poll<WindowSize, ConnectionError> {
|
||||||
|
let added = if id.is_zero() {
|
||||||
|
self.send_flow_controller.take_window_update()
|
||||||
|
} else {
|
||||||
|
self.streams.get_mut(&id).and_then(|mut s| s.take_recv_window_update())
|
||||||
|
};
|
||||||
|
|
||||||
|
match added {
|
||||||
Some(incr) => Ok(Async::Ready(incr)),
|
Some(incr) => Ok(Async::Ready(incr)),
|
||||||
None => {
|
None => {
|
||||||
self.blocked_remote_window_update = Some(task::current());
|
self.blocked_recv_window_update = Some(task::current());
|
||||||
Ok(Async::NotReady)
|
Ok(Async::NotReady)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,18 +93,18 @@ impl<T, P, B: IntoBuf> Connection<T, P, B> {
|
|||||||
///
|
///
|
||||||
/// Connection window updates (StreamId=0) and stream window must be published
|
/// Connection window updates (StreamId=0) and stream window must be published
|
||||||
/// distinctly.
|
/// distinctly.
|
||||||
pub fn init_send_window_update(&mut self, id: StreamId, incr: u32) {
|
pub fn init_send_window_update(&mut self, id: StreamId, incr: WindowSize) {
|
||||||
assert!(self.pending_local_window_update.is_none());
|
assert!(self.pending_send_window_update.is_none());
|
||||||
|
|
||||||
let added = if id.is_zero() {
|
let added = if id.is_zero() {
|
||||||
self.remote_flow_controller.add_to_window(incr);
|
self.send_flow_controller.add_to_window(incr);
|
||||||
self.remote_flow_controller.take_window_update()
|
self.send_flow_controller.take_window_update()
|
||||||
} else {
|
} else {
|
||||||
self.streams.get_mut(&id).and_then(|mut s| s.send_window_update(incr))
|
self.streams.get_mut(&id).and_then(|mut s| s.send_window_update(incr))
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(added) = added {
|
if let Some(added) = added {
|
||||||
self.pending_local_window_update = Some(frame::WindowUpdate::new(id, added));
|
self.pending_send_window_update = Some(frame::WindowUpdate::new(id, added));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,9 +112,9 @@ impl<T, P, B: IntoBuf> Connection<T, P, B> {
|
|||||||
///
|
///
|
||||||
/// Connection window updates (id=0) and stream window updates are advertised
|
/// Connection window updates (id=0) and stream window updates are advertised
|
||||||
/// distinctly.
|
/// distinctly.
|
||||||
fn recv_window_update(&mut self, id: StreamId, incr: u32) {
|
fn recv_window_update(&mut self, id: StreamId, incr: WindowSize) {
|
||||||
if id.is_zero() {
|
if id.is_zero() {
|
||||||
return self.remote_flow_controller.add_to_window(incr);
|
return self.recv_flow_controller.add_to_window(incr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(mut s) = self.streams.get_mut(&id) {
|
if let Some(mut s) = self.streams.get_mut(&id) {
|
||||||
@@ -116,28 +126,34 @@ impl<T, P, B: IntoBuf> Connection<T, P, B> {
|
|||||||
impl<T, P, B> Connection<T, P, B>
|
impl<T, P, B> Connection<T, P, B>
|
||||||
where T: AsyncRead + AsyncWrite,
|
where T: AsyncRead + AsyncWrite,
|
||||||
P: Peer,
|
P: Peer,
|
||||||
B: IntoBuf,
|
B: IntoBuf
|
||||||
{
|
{
|
||||||
|
/// Attempts to send a window update to the remote.
|
||||||
fn poll_send_window_update(&mut self) -> Poll<(), ConnectionError> {
|
fn poll_send_window_update(&mut self) -> Poll<(), ConnectionError> {
|
||||||
if let Some(f) = self.pending_local_window_update.take() {
|
if let Some(f) = self.pending_send_window_update.take() {
|
||||||
if self.inner.start_send(f.into())?.is_not_ready() {
|
if self.inner.start_send(f.into())?.is_not_ready() {
|
||||||
self.pending_local_window_update = Some(f);
|
self.pending_send_window_update = Some(f);
|
||||||
return Ok(Async::NotReady);
|
return Ok(Async::NotReady);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Async::Ready(()))
|
Ok(Async::Ready(()))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: this is bytes-specific for now so that we can know the payload's length.
|
||||||
|
impl<T, P> Connection<T, P, Bytes>
|
||||||
|
where T: AsyncRead + AsyncWrite,
|
||||||
|
P: Peer,
|
||||||
|
{
|
||||||
pub fn send_data(self,
|
pub fn send_data(self,
|
||||||
id: StreamId,
|
id: StreamId,
|
||||||
data: B,
|
data: Bytes,
|
||||||
data_len: usize,
|
|
||||||
end_of_stream: bool)
|
end_of_stream: bool)
|
||||||
-> sink::Send<Self>
|
-> sink::Send<Self>
|
||||||
{
|
{
|
||||||
self.send(Frame::Data {
|
self.send(Frame::Data {
|
||||||
id,
|
id,
|
||||||
data_len,
|
data_len: data.len() as FrameSize,
|
||||||
data,
|
data,
|
||||||
end_of_stream,
|
end_of_stream,
|
||||||
})
|
})
|
||||||
@@ -196,10 +212,15 @@ impl<T, P, B> Stream for Connection<T, P, B>
|
|||||||
let frame = match try!(self.inner.poll()) {
|
let frame = match try!(self.inner.poll()) {
|
||||||
Async::Ready(f) => f,
|
Async::Ready(f) => f,
|
||||||
Async::NotReady => {
|
Async::NotReady => {
|
||||||
// Because receiving new frames may depend on ensuring that the
|
// Receiving new frames may depend on ensuring that the write buffer
|
||||||
// write buffer is clear, `poll_complete` is called here.
|
// is clear (e.g. if window updates need to be sent), so `poll_ready`
|
||||||
let _ = try!(self.poll_complete());
|
// is called here.
|
||||||
return Ok(Async::NotReady);
|
try_ready!(self.poll_ready());
|
||||||
|
|
||||||
|
// If the snder sink is ready, we attempt to poll the underlying
|
||||||
|
// stream once more because it, may have been made ready by flushing
|
||||||
|
// the sink.
|
||||||
|
try_ready!(self.inner.poll())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -234,22 +255,30 @@ impl<T, P, B> Stream for Connection<T, P, B>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Some(Data(v)) => {
|
Some(Data(v)) => {
|
||||||
let stream_id = v.stream_id();
|
let id = v.stream_id();
|
||||||
let end_of_stream = v.is_end_stream();
|
let end_of_stream = v.is_end_stream();
|
||||||
match self.streams.get_mut(&stream_id) {
|
|
||||||
|
self.claim_connection_recv_window(v.len())?;
|
||||||
|
match self.streams.get_mut(&id) {
|
||||||
None => return Err(error::Reason::ProtocolError.into()),
|
None => return Err(error::Reason::ProtocolError.into()),
|
||||||
Some(state) => try!(state.recv_data(end_of_stream, v.len())),
|
Some(state) => state.recv_data(end_of_stream, v.len())?,
|
||||||
}
|
}
|
||||||
|
|
||||||
Frame::Data {
|
Frame::Data {
|
||||||
id: stream_id,
|
id,
|
||||||
|
end_of_stream,
|
||||||
data_len: v.len(),
|
data_len: v.len(),
|
||||||
data: v.into_payload(),
|
data: v.into_payload(),
|
||||||
end_of_stream,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(WindowUpdate(v)) => {
|
Some(WindowUpdate(v)) => {
|
||||||
|
// When a window update is read from the remote, apply that update to
|
||||||
|
// the proper stream.
|
||||||
self.recv_window_update(v.stream_id(), v.size_increment());
|
self.recv_window_update(v.stream_id(), v.size_increment());
|
||||||
|
|
||||||
|
// There's nothing to return yet, so continue attempting to read
|
||||||
|
// additional frames.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,11 +307,11 @@ impl<T, P, B> Sink for Connection<T, P, B>
|
|||||||
|
|
||||||
// First ensure that the upstream can process a new item. This ensures, for
|
// First ensure that the upstream can process a new item. This ensures, for
|
||||||
// instance, that any pending local window updates have been sent to the remote
|
// instance, that any pending local window updates have been sent to the remote
|
||||||
// before sending any other frames.
|
// before sending any other (i.e. DATA) frames.
|
||||||
if try!(self.poll_ready()).is_not_ready() {
|
if try!(self.poll_ready()).is_not_ready() {
|
||||||
return Ok(AsyncSink::NotReady(item));
|
return Ok(AsyncSink::NotReady(item));
|
||||||
}
|
}
|
||||||
assert!(self.pending_local_window_update.is_none());
|
assert!(self.pending_send_window_update.is_none());
|
||||||
|
|
||||||
match item {
|
match item {
|
||||||
Frame::Headers { id, headers, end_of_stream } => {
|
Frame::Headers { id, headers, end_of_stream } => {
|
||||||
@@ -324,6 +353,8 @@ impl<T, P, B> Sink for Connection<T, P, B>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Frame::Data { id, data, data_len, end_of_stream } => {
|
Frame::Data { id, data, data_len, end_of_stream } => {
|
||||||
|
self.claim_connection_send_window(data_len)?;
|
||||||
|
|
||||||
// The stream must be initialized at this point
|
// The stream must be initialized at this point
|
||||||
match self.streams.get_mut(&id) {
|
match self.streams.get_mut(&id) {
|
||||||
None => return Err(error::User::InactiveStreamId.into()),
|
None => return Err(error::User::InactiveStreamId.into()),
|
||||||
@@ -331,14 +362,15 @@ impl<T, P, B> Sink for Connection<T, P, B>
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut frame = frame::Data::from_buf(id, data.into_buf());
|
let mut frame = frame::Data::from_buf(id, data.into_buf());
|
||||||
|
|
||||||
if end_of_stream {
|
if end_of_stream {
|
||||||
frame.set_end_stream();
|
frame.set_end_stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = try!(self.inner.start_send(frame.into()));
|
let res = try!(self.inner.start_send(frame.into()));
|
||||||
|
|
||||||
// poll_ready has already been called.
|
// poll_ready has already been called.
|
||||||
assert!(res.is_ready());
|
assert!(res.is_ready());
|
||||||
|
|
||||||
Ok(AsyncSink::Ready)
|
Ok(AsyncSink::Ready)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
|
use proto::WindowSize;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct WindowUnderflow;
|
pub struct WindowUnderflow;
|
||||||
|
|
||||||
pub const DEFAULT_INITIAL_WINDOW_SIZE: u32 = 65_535;
|
pub const DEFAULT_INITIAL_WINDOW_SIZE: WindowSize = 65_535;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct FlowController {
|
pub struct FlowController {
|
||||||
/// Amount that may be claimed.
|
/// Amount that may be claimed.
|
||||||
window_size: u32,
|
window_size: WindowSize,
|
||||||
/// Amount to be removed by future increments.
|
/// Amount to be removed by future increments.
|
||||||
underflow: u32,
|
underflow: WindowSize,
|
||||||
/// The amount that has been incremented but not yet advertised (to the application or
|
/// The amount that has been incremented but not yet advertised (to the application or
|
||||||
/// the remote).
|
/// the remote).
|
||||||
next_window_update: u32,
|
next_window_update: WindowSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FlowController {
|
impl Default for FlowController {
|
||||||
@@ -21,7 +23,7 @@ impl Default for FlowController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FlowController {
|
impl FlowController {
|
||||||
pub fn new(window_size: u32) -> FlowController {
|
pub fn new(window_size: WindowSize) -> FlowController {
|
||||||
FlowController {
|
FlowController {
|
||||||
window_size,
|
window_size,
|
||||||
underflow: 0,
|
underflow: 0,
|
||||||
@@ -29,19 +31,15 @@ impl FlowController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn window_size(&self) -> u32 {
|
|
||||||
self.window_size
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reduce future capacity of the window.
|
/// Reduce future capacity of the window.
|
||||||
///
|
///
|
||||||
/// This accomodates updates to SETTINGS_INITIAL_WINDOW_SIZE.
|
/// This accomodates updates to SETTINGS_INITIAL_WINDOW_SIZE.
|
||||||
pub fn shrink_window(&mut self, decr: u32) {
|
pub fn shrink_window(&mut self, decr: WindowSize) {
|
||||||
self.underflow += decr;
|
self.underflow += decr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Claim the provided amount from the window, if there is enough space.
|
/// Claim the provided amount from the window, if there is enough space.
|
||||||
pub fn claim_window(&mut self, sz: u32) -> Result<(), WindowUnderflow> {
|
pub fn claim_window(&mut self, sz: WindowSize) -> Result<(), WindowUnderflow> {
|
||||||
if self.window_size < sz {
|
if self.window_size < sz {
|
||||||
return Err(WindowUnderflow);
|
return Err(WindowUnderflow);
|
||||||
}
|
}
|
||||||
@@ -51,7 +49,7 @@ impl FlowController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Applies a window increment immediately.
|
/// Applies a window increment immediately.
|
||||||
pub fn add_to_window(&mut self, sz: u32) {
|
pub fn add_to_window(&mut self, sz: WindowSize) {
|
||||||
if sz <= self.underflow {
|
if sz <= self.underflow {
|
||||||
self.underflow -= sz;
|
self.underflow -= sz;
|
||||||
return;
|
return;
|
||||||
@@ -64,7 +62,7 @@ impl FlowController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Obtains and clears an unadvertised window update.
|
/// Obtains and clears an unadvertised window update.
|
||||||
pub fn take_window_update(&mut self) -> Option<u32> {
|
pub fn take_window_update(&mut self) -> Option<WindowSize> {
|
||||||
if self.next_window_update == 0 {
|
if self.next_window_update == 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,12 +46,24 @@ impl<T> FramedRead<T> {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
let frame = match head.kind() {
|
let kind = head.kind();
|
||||||
|
debug!("received {:?}", kind);
|
||||||
|
|
||||||
|
let frame = match kind {
|
||||||
|
Kind::Settings => {
|
||||||
|
frame::Settings::load(head, &bytes[frame::HEADER_LEN..])?.into()
|
||||||
|
}
|
||||||
|
Kind::Ping => {
|
||||||
|
frame::Ping::load(head, &bytes[frame::HEADER_LEN..])?.into()
|
||||||
|
}
|
||||||
|
Kind::WindowUpdate => {
|
||||||
|
frame::WindowUpdate::load(head, &bytes[frame::HEADER_LEN..])?.into()
|
||||||
|
}
|
||||||
Kind::Data => {
|
Kind::Data => {
|
||||||
let _ = bytes.split_to(frame::HEADER_LEN);
|
let _ = bytes.split_to(frame::HEADER_LEN);
|
||||||
let frame = try!(frame::Data::load(head, bytes));
|
frame::Data::load(head, bytes)?.into()
|
||||||
frame.into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Kind::Headers => {
|
Kind::Headers => {
|
||||||
let mut buf = Cursor::new(bytes);
|
let mut buf = Cursor::new(bytes);
|
||||||
buf.set_position(frame::HEADER_LEN as u64);
|
buf.set_position(frame::HEADER_LEN as u64);
|
||||||
@@ -67,41 +79,25 @@ impl<T> FramedRead<T> {
|
|||||||
|
|
||||||
frame.into()
|
frame.into()
|
||||||
}
|
}
|
||||||
Kind::Priority => unimplemented!(),
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
Kind::Reset => {
|
Kind::Reset => {
|
||||||
let frame = try!(frame::Reset::load(head, &bytes[frame::HEADER_LEN..]));
|
let _todo = try!(frame::Reset::load(head, &bytes[frame::HEADER_LEN..]));
|
||||||
debug!("decoded; frame={:?}", frame);
|
unimplemented!();
|
||||||
// TODO: implement
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
Kind::Settings => {
|
|
||||||
let frame = try!(frame::Settings::load(head, &bytes[frame::HEADER_LEN..]));
|
|
||||||
frame.into()
|
|
||||||
}
|
|
||||||
Kind::PushPromise => {
|
|
||||||
debug!("received PUSH_PROMISE");
|
|
||||||
// TODO: implement
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
Kind::Ping => {
|
|
||||||
try!(frame::Ping::load(head, &bytes[frame::HEADER_LEN..])).into()
|
|
||||||
}
|
}
|
||||||
Kind::GoAway => {
|
Kind::GoAway => {
|
||||||
let frame = try!(frame::GoAway::load(&bytes[frame::HEADER_LEN..]));
|
let _todo = try!(frame::GoAway::load(&bytes[frame::HEADER_LEN..]));
|
||||||
debug!("decoded; frame={:?}", frame);
|
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
Kind::WindowUpdate => {
|
Kind::PushPromise |
|
||||||
// TODO: IMPLEMENT
|
Kind::Priority |
|
||||||
let frame = try!(frame::WindowUpdate::load(head, &bytes[frame::HEADER_LEN..]));
|
Kind::Continuation |
|
||||||
debug!("decoded; frame={:?}", frame);
|
Kind::Unknown => {
|
||||||
return Ok(None);
|
unimplemented!()
|
||||||
},
|
|
||||||
Kind::Continuation => {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
}
|
||||||
Kind::Unknown => return Ok(None),
|
|
||||||
};
|
};
|
||||||
|
debug!("decoded; frame={:?}", frame);
|
||||||
|
|
||||||
Ok(Some(frame))
|
Ok(Some(frame))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use {hpack, ConnectionError};
|
use {hpack, ConnectionError, FrameSize};
|
||||||
use frame::{self, Frame};
|
use frame::{self, Frame};
|
||||||
use proto::ReadySink;
|
use proto::ReadySink;
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ pub struct FramedWrite<T, B> {
|
|||||||
next: Option<Next<B>>,
|
next: Option<Next<B>>,
|
||||||
|
|
||||||
/// Max frame size, this is specified by the peer
|
/// Max frame size, this is specified by the peer
|
||||||
max_frame_size: usize,
|
max_frame_size: FrameSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -74,7 +74,7 @@ impl<T, B> FramedWrite<T, B>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn frame_len(&self, data: &frame::Data<B>) -> usize {
|
fn frame_len(&self, data: &frame::Data<B>) -> usize {
|
||||||
cmp::min(self.max_frame_size, data.len())
|
cmp::min(self.max_frame_size, data.len()) as usize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ impl<T, B> Sink for FramedWrite<T, B>
|
|||||||
|
|
||||||
match item {
|
match item {
|
||||||
Frame::Data(mut v) => {
|
Frame::Data(mut v) => {
|
||||||
if v.len() >= CHAIN_THRESHOLD {
|
if v.len() >= (CHAIN_THRESHOLD as FrameSize) {
|
||||||
let head = v.head();
|
let head = v.head();
|
||||||
let len = self.frame_len(&v);
|
let len = self.frame_len(&v);
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ type Framed<T, B> =
|
|||||||
FramedRead<
|
FramedRead<
|
||||||
FramedWrite<T, B>>;
|
FramedWrite<T, B>>;
|
||||||
|
|
||||||
|
|
||||||
|
pub type WindowSize = u32;
|
||||||
|
|
||||||
/// Create a full H2 transport from an I/O handle.
|
/// Create a full H2 transport from an I/O handle.
|
||||||
///
|
///
|
||||||
/// This is called as the final step of the client handshake future.
|
/// This is called as the final step of the client handshake future.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use Peer;
|
use {FrameSize, Peer};
|
||||||
use error::ConnectionError;
|
use error::ConnectionError;
|
||||||
use error::Reason::*;
|
use error::Reason::*;
|
||||||
use error::User::*;
|
use error::User::*;
|
||||||
@@ -102,7 +102,7 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_remote_window_update(&mut self) -> Option<u32> {
|
pub fn take_recv_window_update(&mut self) -> Option<u32> {
|
||||||
use self::State::*;
|
use self::State::*;
|
||||||
use self::PeerState::*;
|
use self::PeerState::*;
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ impl State {
|
|||||||
/// > flow-control window and MUST NOT send new flow-controlled frames until it
|
/// > flow-control window and MUST NOT send new flow-controlled frames until it
|
||||||
/// > receives WINDOW_UPDATE frames that cause the flow-control window to become
|
/// > receives WINDOW_UPDATE frames that cause the flow-control window to become
|
||||||
/// > positive.
|
/// > positive.
|
||||||
pub fn update_remote_initial_window_size(&mut self, old: u32, new: u32) {
|
pub fn update_initial_recv_window_size(&mut self, old: u32, new: u32) {
|
||||||
use self::State::*;
|
use self::State::*;
|
||||||
use self::PeerState::*;
|
use self::PeerState::*;
|
||||||
|
|
||||||
@@ -147,7 +147,7 @@ impl State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// TODO Connection doesn't have an API for local updates yet.
|
/// TODO Connection doesn't have an API for local updates yet.
|
||||||
pub fn update_local_initial_window_size(&mut self, _old: u32, _new: u32) {
|
pub fn update_initial_send_window_size(&mut self, _old: u32, _new: u32) {
|
||||||
//use self::State::*;
|
//use self::State::*;
|
||||||
//use self::PeerState::*;
|
//use self::PeerState::*;
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
@@ -159,7 +159,7 @@ impl State {
|
|||||||
/// stream id. `Err` is returned if this is an invalid state transition.
|
/// stream id. `Err` is returned if this is an invalid state transition.
|
||||||
pub fn recv_headers<P: Peer>(&mut self,
|
pub fn recv_headers<P: Peer>(&mut self,
|
||||||
eos: bool,
|
eos: bool,
|
||||||
remote_window_size: u32)
|
initial_recv_window_size: u32)
|
||||||
-> Result<bool, ConnectionError>
|
-> Result<bool, ConnectionError>
|
||||||
{
|
{
|
||||||
use self::State::*;
|
use self::State::*;
|
||||||
@@ -171,7 +171,7 @@ impl State {
|
|||||||
if eos {
|
if eos {
|
||||||
*self = HalfClosedRemote(local);
|
*self = HalfClosedRemote(local);
|
||||||
} else {
|
} else {
|
||||||
*self = Open { local, remote: Data(FlowController::new(remote_window_size)) };
|
*self = Open { local, remote: Data(FlowController::new(initial_recv_window_size)) };
|
||||||
}
|
}
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
@@ -191,7 +191,7 @@ impl State {
|
|||||||
if eos {
|
if eos {
|
||||||
*self = Closed;
|
*self = Closed;
|
||||||
} else {
|
} else {
|
||||||
*self = HalfClosedLocal(Data(FlowController::new(remote_window_size)));
|
*self = HalfClosedLocal(Data(FlowController::new(initial_recv_window_size)));
|
||||||
};
|
};
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
@@ -204,22 +204,22 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recv_data(&mut self, eos: bool, len: usize) -> Result<(), ConnectionError> {
|
pub fn recv_data(&mut self, eos: bool, len: FrameSize) -> Result<(), ConnectionError> {
|
||||||
use self::State::*;
|
use self::State::*;
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
Open { local, remote } => {
|
Open { local, mut remote } => {
|
||||||
try!(remote.check_is_data(ProtocolError.into()));
|
try!(remote.check_is_data(ProtocolError.into()));
|
||||||
try!(remote.check_window_size(len, FlowControlError.into()));
|
try!(remote.claim_window_size(len, FlowControlError.into()));
|
||||||
if eos {
|
if eos {
|
||||||
*self = HalfClosedRemote(local);
|
*self = HalfClosedRemote(local);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
HalfClosedLocal(remote) => {
|
HalfClosedLocal(mut remote) => {
|
||||||
try!(remote.check_is_data(ProtocolError.into()));
|
try!(remote.check_is_data(ProtocolError.into()));
|
||||||
try!(remote.check_window_size(len, FlowControlError.into()));
|
try!(remote.claim_window_size(len, FlowControlError.into()));
|
||||||
if eos {
|
if eos {
|
||||||
*self = Closed;
|
*self = Closed;
|
||||||
}
|
}
|
||||||
@@ -238,7 +238,11 @@ impl State {
|
|||||||
///
|
///
|
||||||
/// Returns true if this state transition results in initializing the stream
|
/// Returns true if this state transition results in initializing the stream
|
||||||
/// id. `Err` is returned if this is an invalid state transition.
|
/// id. `Err` is returned if this is an invalid state transition.
|
||||||
pub fn send_headers<P: Peer>(&mut self, eos: bool, local_window_size: u32) -> Result<bool, ConnectionError> {
|
pub fn send_headers<P: Peer>(&mut self,
|
||||||
|
eos: bool,
|
||||||
|
initial_send_window_size: u32)
|
||||||
|
-> Result<bool, ConnectionError>
|
||||||
|
{
|
||||||
use self::State::*;
|
use self::State::*;
|
||||||
use self::PeerState::*;
|
use self::PeerState::*;
|
||||||
|
|
||||||
@@ -248,7 +252,7 @@ impl State {
|
|||||||
HalfClosedLocal(Headers)
|
HalfClosedLocal(Headers)
|
||||||
} else {
|
} else {
|
||||||
Open {
|
Open {
|
||||||
local: Data(FlowController::new(local_window_size)),
|
local: Data(FlowController::new(initial_send_window_size)),
|
||||||
remote: Headers,
|
remote: Headers,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -262,7 +266,7 @@ impl State {
|
|||||||
*self = if eos {
|
*self = if eos {
|
||||||
HalfClosedLocal(remote)
|
HalfClosedLocal(remote)
|
||||||
} else {
|
} else {
|
||||||
let local = Data(FlowController::new(local_window_size));
|
let local = Data(FlowController::new(initial_send_window_size));
|
||||||
Open { local, remote }
|
Open { local, remote }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -275,7 +279,7 @@ impl State {
|
|||||||
*self = if eos {
|
*self = if eos {
|
||||||
Closed
|
Closed
|
||||||
} else {
|
} else {
|
||||||
HalfClosedRemote(Data(FlowController::new(local_window_size)))
|
HalfClosedRemote(Data(FlowController::new(initial_send_window_size)))
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(false)
|
Ok(false)
|
||||||
@@ -289,22 +293,22 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_data(&mut self, eos: bool, len: usize) -> Result<(), ConnectionError> {
|
pub fn send_data(&mut self, eos: bool, len: FrameSize) -> Result<(), ConnectionError> {
|
||||||
use self::State::*;
|
use self::State::*;
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
Open { local, remote } => {
|
Open { mut local, remote } => {
|
||||||
try!(local.check_is_data(UnexpectedFrameType.into()));
|
try!(local.check_is_data(UnexpectedFrameType.into()));
|
||||||
try!(local.check_window_size(len, FlowControlViolation.into()));
|
try!(local.claim_window_size(len, FlowControlViolation.into()));
|
||||||
if eos {
|
if eos {
|
||||||
*self = HalfClosedLocal(remote);
|
*self = HalfClosedLocal(remote);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
HalfClosedRemote(local) => {
|
HalfClosedRemote(mut local) => {
|
||||||
try!(local.check_is_data(UnexpectedFrameType.into()));
|
try!(local.check_is_data(UnexpectedFrameType.into()));
|
||||||
try!(local.check_window_size(len, FlowControlViolation.into()));
|
try!(local.claim_window_size(len, FlowControlViolation.into()));
|
||||||
if eos {
|
if eos {
|
||||||
*self = Closed;
|
*self = Closed;
|
||||||
}
|
}
|
||||||
@@ -353,10 +357,10 @@ impl PeerState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn check_window_size(&self, len: usize, err: ConnectionError) -> Result<(), ConnectionError> {
|
fn claim_window_size(&mut self, sz: FrameSize, err: ConnectionError) -> Result<(), ConnectionError> {
|
||||||
use self::PeerState::*;
|
use self::PeerState::*;
|
||||||
match self {
|
match self {
|
||||||
&Data(ref fc) if len <= fc.window_size() as usize=> Ok(()),
|
&mut Data(ref mut fc) => fc.claim_window(sz).map_err(|_| err),
|
||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user