wip
This commit is contained in:
@@ -32,6 +32,7 @@ mod reset;
|
|||||||
mod settings;
|
mod settings;
|
||||||
mod stream_id;
|
mod stream_id;
|
||||||
mod util;
|
mod util;
|
||||||
|
mod window_update;
|
||||||
|
|
||||||
pub use self::data::Data;
|
pub use self::data::Data;
|
||||||
pub use self::go_away::GoAway;
|
pub use self::go_away::GoAway;
|
||||||
@@ -41,6 +42,7 @@ pub use self::ping::Ping;
|
|||||||
pub use self::reset::Reset;
|
pub use self::reset::Reset;
|
||||||
pub use self::settings::{Settings, SettingSet};
|
pub use self::settings::{Settings, SettingSet};
|
||||||
pub use self::stream_id::StreamId;
|
pub use self::stream_id::StreamId;
|
||||||
|
pub use self::window_update::WindowUpdate;
|
||||||
|
|
||||||
// Re-export some constants
|
// Re-export some constants
|
||||||
pub use self::settings::{
|
pub use self::settings::{
|
||||||
@@ -56,7 +58,8 @@ pub enum Frame {
|
|||||||
Headers(Headers),
|
Headers(Headers),
|
||||||
PushPromise(PushPromise),
|
PushPromise(PushPromise),
|
||||||
Settings(Settings),
|
Settings(Settings),
|
||||||
Ping(Ping)
|
Ping(Ping),
|
||||||
|
WindowUpdate(WindowUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Errors that can occur during parsing an HTTP/2 frame.
|
/// Errors that can occur during parsing an HTTP/2 frame.
|
||||||
|
|||||||
48
src/frame/window_update.rs
Normal file
48
src/frame/window_update.rs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
use StreamId;
|
||||||
|
use byteorder::{ByteOrder, NetworkEndian};
|
||||||
|
use bytes::{BufMut};
|
||||||
|
use frame::{self, Head, Kind, Error};
|
||||||
|
|
||||||
|
const INCREMENT_MASK: u32 = 1 << 31;
|
||||||
|
|
||||||
|
type Increment = u32;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WindowUpdate {
|
||||||
|
stream_id: StreamId,
|
||||||
|
increment: Increment,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WindowUpdate {
|
||||||
|
pub fn stream_id(&self) -> StreamId {
|
||||||
|
self.stream_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn increment(&self) -> Increment {
|
||||||
|
self.increment
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds a `Ping` frame from a raw frame.
|
||||||
|
pub fn load(head: Head, bytes: &[u8]) -> Result<WindowUpdate, Error> {
|
||||||
|
debug_assert_eq!(head.kind(), ::frame::Kind::WindowUpdate);
|
||||||
|
Ok(WindowUpdate {
|
||||||
|
stream_id: head.stream_id(),
|
||||||
|
// Clear the most significant bit, as that is reserved and MUST be ignored when
|
||||||
|
// received.
|
||||||
|
increment: NetworkEndian::read_u32(bytes) & !INCREMENT_MASK,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn encode<B: BufMut>(&self, dst: &mut B) {
|
||||||
|
trace!("encoding WINDOW_UPDATE; id={:?}", self.stream_id);
|
||||||
|
let head = Head::new(Kind::Ping, 0, self.stream_id);
|
||||||
|
head.encode(4, dst);
|
||||||
|
dst.put_u32::<NetworkEndian>(self.increment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<WindowUpdate> for frame::Frame {
|
||||||
|
fn from(src: WindowUpdate) -> frame::Frame {
|
||||||
|
frame::Frame::WindowUpdate(src)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
use {frame, Frame, ConnectionError, Peer, StreamId};
|
use {Frame, ConnectionError, Peer, StreamId};
|
||||||
use client::Client;
|
use client::Client;
|
||||||
|
use frame::{Frame as WireFrame};
|
||||||
use server::Server;
|
use server::Server;
|
||||||
use proto::{self, ReadySink, State};
|
use proto::{self, ReadySink, State, WindowUpdate};
|
||||||
|
|
||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
@@ -15,17 +16,60 @@ use fnv::FnvHasher;
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::hash::BuildHasherDefault;
|
use std::hash::BuildHasherDefault;
|
||||||
|
|
||||||
|
pub struct FlowControlViolation;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct FlowController {
|
||||||
|
window_size: u32,
|
||||||
|
underflow: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlowController {
|
||||||
|
pub fn new(window_size: u32) -> FlowController {
|
||||||
|
FlowController {
|
||||||
|
window_size,
|
||||||
|
underflow: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shrink(&mut self, mut sz: u32) {
|
||||||
|
self.underflow += sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn consume(&mut self, mut sz: u32) -> Result<(), FlowControlViolation> {
|
||||||
|
if sz < self.window_size {
|
||||||
|
self.underflow -= sz;
|
||||||
|
return Err(FlowControlViolation);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.window_size -= sz;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn increment(&mut self, mut sz: u32) {
|
||||||
|
if sz <= self.underflow {
|
||||||
|
self.underflow -= sz;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sz -= self.underflow;
|
||||||
|
self.window_size += sz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An H2 connection
|
/// An H2 connection
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Connection<T, P> {
|
pub struct Connection<T, P> {
|
||||||
inner: proto::Inner<T>,
|
inner: proto::Inner<T>,
|
||||||
streams: StreamMap<State>,
|
streams: StreamMap<State>,
|
||||||
peer: PhantomData<P>,
|
peer: PhantomData<P>,
|
||||||
|
local_flow_controller: FlowController,
|
||||||
|
remote_flow_controller: FlowController,
|
||||||
}
|
}
|
||||||
|
|
||||||
type StreamMap<T> = OrderMap<StreamId, T, BuildHasherDefault<FnvHasher>>;
|
type StreamMap<T> = OrderMap<StreamId, T, BuildHasherDefault<FnvHasher>>;
|
||||||
|
|
||||||
pub fn new<T, P>(transport: proto::Inner<T>) -> Connection<T, P>
|
pub fn new<T, P>(transport: proto::Inner<T>, initial_local_window_size: u32, initial_remote_window_size: u32) -> Connection<T, P>
|
||||||
where T: AsyncRead + AsyncWrite,
|
where T: AsyncRead + AsyncWrite,
|
||||||
P: Peer,
|
P: Peer,
|
||||||
{
|
{
|
||||||
@@ -33,15 +77,35 @@ pub fn new<T, P>(transport: proto::Inner<T>) -> Connection<T, P>
|
|||||||
inner: transport,
|
inner: transport,
|
||||||
streams: StreamMap::default(),
|
streams: StreamMap::default(),
|
||||||
peer: PhantomData,
|
peer: PhantomData,
|
||||||
|
local_flow_controller: FlowController::new(initial_local_window_size),
|
||||||
|
remote_flow_controller: FlowController::new(initial_remote_window_size),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, P> Connection<T, P> {
|
impl<T, P> Connection<T, P> {
|
||||||
pub fn increment_local_window_size(&mut self, id: StreamId, increment: usize) {
|
/// Publishes stream window updates to the remote.
|
||||||
|
///
|
||||||
|
/// Connection window updates (StreamId=0) and stream window updates are published
|
||||||
|
/// distinctly.
|
||||||
|
pub fn increment_local_window(&mut self, up: WindowUpdate) {
|
||||||
|
let incr = up.increment();
|
||||||
|
let flow = match up {
|
||||||
|
WindowUpdate::Connection { .. } => Some(&self.local_flow_controller),
|
||||||
|
WindowUpdate::Stream { id, .. } => {
|
||||||
|
self.streams.get(&id).map(|s| s.local_flow_controller())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(flow) = flow {
|
||||||
|
flow.increment(incr);
|
||||||
|
}
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll_remote_window_size(&mut self, id: StreamId) -> Poll<usize, ()> {
|
/// Advertises stream window updates from the remote.
|
||||||
|
///
|
||||||
|
/// Connection window updates (StreamId=0) and stream window updates are advertised
|
||||||
|
/// distinctly.
|
||||||
|
pub fn poll_remote_window(&mut self) -> Poll<WindowUpdate, ()> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,8 +152,6 @@ impl<T, P> Stream for Connection<T, P>
|
|||||||
type Error = ConnectionError;
|
type Error = ConnectionError;
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<Option<Self::Item>, ConnectionError> {
|
fn poll(&mut self) -> Poll<Option<Self::Item>, ConnectionError> {
|
||||||
use frame::Frame::*;
|
|
||||||
|
|
||||||
trace!("Connection::poll");
|
trace!("Connection::poll");
|
||||||
|
|
||||||
let frame = match try!(self.inner.poll()) {
|
let frame = match try!(self.inner.poll()) {
|
||||||
@@ -105,7 +167,7 @@ impl<T, P> Stream for Connection<T, P>
|
|||||||
trace!("received; frame={:?}", frame);
|
trace!("received; frame={:?}", frame);
|
||||||
|
|
||||||
let frame = match frame {
|
let frame = match frame {
|
||||||
Some(Headers(v)) => {
|
Some(WireFrame::Headers(v)) => {
|
||||||
// TODO: Update stream state
|
// TODO: Update stream state
|
||||||
let stream_id = v.stream_id();
|
let stream_id = v.stream_id();
|
||||||
let end_of_stream = v.is_end_stream();
|
let end_of_stream = v.is_end_stream();
|
||||||
@@ -130,7 +192,7 @@ impl<T, P> Stream for Connection<T, P>
|
|||||||
end_of_stream: end_of_stream,
|
end_of_stream: end_of_stream,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(Data(v)) => {
|
Some(WireFrame::Data(v)) => {
|
||||||
// TODO: Validate frame
|
// TODO: Validate frame
|
||||||
|
|
||||||
let stream_id = v.stream_id();
|
let stream_id = v.stream_id();
|
||||||
@@ -189,7 +251,7 @@ impl<T, P> Sink for Connection<T, P>
|
|||||||
|
|
||||||
// We already ensured that the upstream can handle the frame, so
|
// We already ensured that the upstream can handle the frame, so
|
||||||
// panic if it gets rejected.
|
// panic if it gets rejected.
|
||||||
let res = try!(self.inner.start_send(frame::Frame::Headers(frame)));
|
let res = try!(self.inner.start_send(WireFrame::Headers(frame)));
|
||||||
|
|
||||||
// This is a one-way conversion. By checking `poll_ready` first,
|
// This is a one-way conversion. By checking `poll_ready` first,
|
||||||
// it's already been determined that the inner `Sink` can accept
|
// it's already been determined that the inner `Sink` can accept
|
||||||
|
|||||||
@@ -96,7 +96,10 @@ impl<T> FramedRead<T> {
|
|||||||
debug!("decoded; frame={:?}", frame);
|
debug!("decoded; frame={:?}", frame);
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
Kind::WindowUpdate => unimplemented!(),
|
Kind::WindowUpdate => {
|
||||||
|
let frame = try!(frame::WindowUpdate::load(head, &bytes[frame::HEADER_LEN..]));
|
||||||
|
frame.into()
|
||||||
|
}
|
||||||
Kind::Continuation => {
|
Kind::Continuation => {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,6 +120,10 @@ impl<T: AsyncWrite> Sink for FramedWrite<T> {
|
|||||||
v.encode(self.buf.get_mut());
|
v.encode(self.buf.get_mut());
|
||||||
trace!("encoded ping; rem={:?}", self.buf.remaining());
|
trace!("encoded ping; rem={:?}", self.buf.remaining());
|
||||||
}
|
}
|
||||||
|
Frame::WindowUpdate(v) => {
|
||||||
|
v.encode(self.buf.get_mut());
|
||||||
|
trace!("encoded window_update; rem={:?}", self.buf.remaining());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(AsyncSink::Ready)
|
Ok(AsyncSink::Ready)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ mod ping_pong;
|
|||||||
mod ready;
|
mod ready;
|
||||||
mod settings;
|
mod settings;
|
||||||
mod state;
|
mod state;
|
||||||
|
mod window_update;
|
||||||
|
|
||||||
pub use self::connection::{Connection};
|
pub use self::connection::{Connection};
|
||||||
pub use self::framed_read::FramedRead;
|
pub use self::framed_read::FramedRead;
|
||||||
@@ -13,6 +14,7 @@ pub use self::ping_pong::PingPong;
|
|||||||
pub use self::ready::ReadySink;
|
pub use self::ready::ReadySink;
|
||||||
pub use self::settings::Settings;
|
pub use self::settings::Settings;
|
||||||
pub use self::state::State;
|
pub use self::state::State;
|
||||||
|
pub use self::window_update::WindowUpdate;
|
||||||
|
|
||||||
use {frame, Peer};
|
use {frame, Peer};
|
||||||
|
|
||||||
@@ -83,5 +85,5 @@ pub fn from_server_handshaker<T, P>(transport: Settings<FramedWrite<T>>)
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Finally, return the constructed `Connection`
|
// Finally, return the constructed `Connection`
|
||||||
connection::new(settings)
|
connection::new(settings, 65_535, 65_535)
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/proto/window_update.rs
Normal file
16
src/proto/window_update.rs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
use StreamId;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum WindowUpdate {
|
||||||
|
Connection { increment: usize },
|
||||||
|
Stream { id: StreamId, increment: usize },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WindowUpdate {
|
||||||
|
pub fn increment(&self) -> usize {
|
||||||
|
match *self {
|
||||||
|
WindowUpdate::Connection { increment } |
|
||||||
|
WindowUpdate::Stream { increment, .. } => increment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user