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:
committed by
Oliver Gould
parent
9448a19408
commit
93925e6d1f
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
{
|
||||
|
||||
@@ -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
44
tests/support/src/util.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user