Limit send flow control bug to window_size (#78)

Senders could set the available capacity greater than the current
`window_size`.  This caused a panic when the sender attempted
to send more than the receiver could accept.
This commit is contained in:
Carl Lerche
2017-09-12 10:48:11 -07:00
committed by Oliver Gould
parent 9448a19408
commit 93925e6d1f
8 changed files with 192 additions and 44 deletions

View File

@@ -6,6 +6,8 @@ pub extern crate http;
#[macro_use]
pub extern crate tokio_io;
#[macro_use]
pub extern crate futures;
pub extern crate mock_io;
pub extern crate env_logger;
@@ -19,6 +21,7 @@ pub mod raw;
pub mod frames;
pub mod prelude;
pub mod mock;
pub mod util;
mod future_ext;

View File

@@ -5,6 +5,7 @@ use h2::frame::{self, Frame};
use futures::{Async, Future, Stream, Poll};
use futures::task::{self, Task};
use futures::sync::oneshot;
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::io::read_exact;
@@ -100,12 +101,18 @@ impl Handle {
}
/// Perform the H2 handshake
pub fn assert_client_handshake(mut self)
pub fn assert_client_handshake(self)
-> Box<Future<Item = (frame::Settings, Self), Error = h2::Error>>
{
self.assert_client_handshake_with_settings(frame::Settings::default())
}
/// Perform the H2 handshake
pub fn assert_client_handshake_with_settings(mut self, settings: frame::Settings)
-> Box<Future<Item = (frame::Settings, Self), Error = h2::Error>>
{
// Send a settings frame
let frame = frame::Settings::default();
self.send(frame.into()).unwrap();
self.send(settings.into()).unwrap();
let ret = self.read_preface().unwrap()
.and_then(|me| me.into_future().unwrap())
@@ -336,6 +343,31 @@ pub trait HandleFutureExt {
}
}
fn idle_ms(self, ms: usize) -> Box<Future<Item=Handle, Error=Self::Error>>
where Self: Sized + 'static,
Self: Future<Item=Handle>,
Self::Error: fmt::Debug,
{
use std::thread;
use std::time::Duration;
Box::new(self.and_then(move |handle| {
// This is terrible... but oh well
let (tx, rx) = oneshot::channel();
thread::spawn(move || {
thread::sleep(Duration::from_millis(ms as u64));
tx.send(()).unwrap();
});
Idle {
handle: Some(handle),
timeout: rx,
}.map_err(|_| unreachable!())
}))
}
fn close(self) -> Box<Future<Item=(), Error=()>>
where Self: Future<Error = ()> + Sized + 'static,
{
@@ -387,6 +419,29 @@ impl<T> Future for SendFrameFut<T>
}
}
pub struct Idle {
handle: Option<Handle>,
timeout: oneshot::Receiver<()>,
}
impl Future for Idle {
type Item = Handle;
type Error = ();
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
if self.timeout.poll().unwrap().is_ready() {
return Ok(self.handle.take().unwrap().into());
}
match self.handle.as_mut().unwrap().poll() {
Ok(Async::NotReady) => Ok(Async::NotReady),
res => {
panic!("Received unexpected frame on handle; frame={:?}", res);
}
}
}
}
impl<T> HandleFutureExt for T
where T: Future + 'static,
{

View File

@@ -13,6 +13,9 @@ pub use super::mock::{self, HandleFutureExt};
// Re-export frames helpers
pub use super::frames;
// Re-export utility mod
pub use super::util;
// Re-export some type defines
pub use super::{Codec, SendFrame};

44
tests/support/src/util.rs Normal file
View File

@@ -0,0 +1,44 @@
use h2::client;
use futures::{Poll, Async, Future};
use bytes::Bytes;
pub fn wait_for_capacity(stream: client::Stream<Bytes>,
target: usize)
-> WaitForCapacity
{
WaitForCapacity {
stream: Some(stream),
target: target,
}
}
pub struct WaitForCapacity {
stream: Option<client::Stream<Bytes>>,
target: usize,
}
impl WaitForCapacity {
fn stream(&mut self) -> &mut client::Stream<Bytes> {
self.stream.as_mut().unwrap()
}
}
impl Future for WaitForCapacity {
type Item = client::Stream<Bytes>;
type Error = ();
fn poll(&mut self) -> Poll<Self::Item, ()> {
let _ = try_ready!(self.stream().poll_capacity().map_err(|_| panic!()));
let act = self.stream().capacity();
println!("CAP={:?}", act);
if act >= self.target {
return Ok(self.stream.take().unwrap().into())
}
Ok(Async::NotReady)
}
}