tests pass
This commit is contained in:
@@ -16,7 +16,6 @@ ordermap = "0.2.10"
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
mock-io = { git = "https://github.com/carllerche/mock-io" }
|
mock-io = { git = "https://github.com/carllerche/mock-io" }
|
||||||
test_futures = "0.0.1"
|
|
||||||
|
|
||||||
# Fuzzing
|
# Fuzzing
|
||||||
quickcheck = "0.4.1"
|
quickcheck = "0.4.1"
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ impl<T, P, B> Connection<T, P, B>
|
|||||||
end_of_stream: bool)
|
end_of_stream: bool)
|
||||||
-> sink::Send<Self>
|
-> sink::Send<Self>
|
||||||
{
|
{
|
||||||
|
trace!("send_data: id={:?}", id);
|
||||||
self.send(Frame::Data {
|
self.send(Frame::Data {
|
||||||
id,
|
id,
|
||||||
data,
|
data,
|
||||||
|
|||||||
@@ -407,12 +407,12 @@ impl<T: ControlStreams> ControlStreams for FlowControl<T> {
|
|||||||
self.inner.send_flow_controller(id)
|
self.inner.send_flow_controller(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_can_send_data(&mut self, id: StreamId) -> Result<(), ConnectionError> {
|
fn can_send_data(&mut self, id: StreamId) -> bool {
|
||||||
self.inner.check_can_send_data(id)
|
self.inner.can_send_data(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_can_recv_data(&mut self, id: StreamId) -> Result<(), ConnectionError> {
|
fn can_recv_data(&mut self, id: StreamId) -> bool {
|
||||||
self.inner.check_can_recv_data(id)
|
self.inner.can_recv_data(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ impl<T, B> Sink for FramedWrite<T, B>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn poll_complete(&mut self) -> Poll<(), ConnectionError> {
|
fn poll_complete(&mut self) -> Poll<(), ConnectionError> {
|
||||||
trace!("FramedWrite::poll_complete");
|
trace!("poll_complete");
|
||||||
|
|
||||||
// TODO: implement
|
// TODO: implement
|
||||||
match self.next {
|
match self.next {
|
||||||
@@ -165,6 +165,7 @@ impl<T, B> Sink for FramedWrite<T, B>
|
|||||||
|
|
||||||
// As long as there is data to write, try to write it!
|
// As long as there is data to write, try to write it!
|
||||||
while !self.is_empty() {
|
while !self.is_empty() {
|
||||||
|
trace!("writing {}", self.buf.remaining());
|
||||||
try_ready!(self.inner.write_buf(&mut self.buf));
|
try_ready!(self.inner.write_buf(&mut self.buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use ConnectionError;
|
use ConnectionError;
|
||||||
use error::Reason::*;
|
use error::Reason::*;
|
||||||
use error::User::*;
|
|
||||||
use proto::{FlowControlState, WindowSize};
|
use proto::{FlowControlState, WindowSize};
|
||||||
|
|
||||||
/// Represents the state of an H2 stream
|
/// Represents the state of an H2 stream
|
||||||
@@ -156,40 +155,24 @@ impl StreamState {
|
|||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_can_send_data(&self) -> Result<(), ConnectionError> {
|
pub fn can_send_data(&self) -> bool {
|
||||||
use self::StreamState::*;
|
use self::StreamState::*;
|
||||||
match self {
|
match self {
|
||||||
&Open { ref remote, .. } => {
|
&Idle | &Closed | &HalfClosedRemote(..) => false,
|
||||||
try!(remote.check_streaming(UnexpectedFrameType.into()));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
&HalfClosedLocal(ref remote) => {
|
&Open { ref remote, .. } |
|
||||||
try!(remote.check_streaming(UnexpectedFrameType.into()));
|
&HalfClosedLocal(ref remote) => remote.is_streaming(),
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
&Idle | &Closed | &HalfClosedRemote(..) => {
|
|
||||||
Err(UnexpectedFrameType.into())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_can_recv_data(&self) -> Result<(), ConnectionError> {
|
pub fn can_recv_data(&self) -> bool {
|
||||||
use self::StreamState::*;
|
use self::StreamState::*;
|
||||||
match self {
|
match self {
|
||||||
&Open { ref local, .. } => {
|
&Idle | &Closed | &HalfClosedLocal(..) => false,
|
||||||
try!(local.check_streaming(ProtocolError.into()));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
&Open { ref local, .. } |
|
||||||
&HalfClosedRemote(ref local) => {
|
&HalfClosedRemote(ref local) => {
|
||||||
try!(local.check_streaming(ProtocolError.into()));
|
local.is_streaming()
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
&Idle | &Closed | &HalfClosedLocal(..) => {
|
|
||||||
Err(ProtocolError.into())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -288,11 +271,11 @@ impl PeerState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn check_streaming(&self, err: ConnectionError) -> Result<(), ConnectionError> {
|
fn is_streaming(&self) -> bool {
|
||||||
use self::PeerState::*;
|
use self::PeerState::*;
|
||||||
match self {
|
match self {
|
||||||
&Streaming(..) => Ok(()),
|
&Streaming(..) => true,
|
||||||
_ => Err(err),
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -157,12 +157,12 @@ impl<T: ControlStreams> ControlStreams for StreamRecvClose<T> {
|
|||||||
self.inner.send_flow_controller(id)
|
self.inner.send_flow_controller(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_can_send_data(&mut self, id: StreamId) -> Result<(), ConnectionError> {
|
fn can_send_data(&mut self, id: StreamId) -> bool {
|
||||||
self.inner.check_can_send_data(id)
|
self.inner.can_send_data(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_can_recv_data(&mut self, id: StreamId) -> Result<(), ConnectionError> {
|
fn can_recv_data(&mut self, id: StreamId) -> bool {
|
||||||
self.inner.check_can_recv_data(id)
|
self.inner.can_recv_data(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -170,7 +170,9 @@ impl<T, U> Stream for StreamRecvOpen<T>
|
|||||||
|
|
||||||
if let &Data(..) = &frame {
|
if let &Data(..) = &frame {
|
||||||
// Ensures we've already received headers for this stream.
|
// Ensures we've already received headers for this stream.
|
||||||
self.inner.check_can_recv_data(id)?;
|
if !self.inner.can_recv_data(id) {
|
||||||
|
return Err(ProtocolError.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the frame ends the stream, it will be handled in
|
// If the frame ends the stream, it will be handled in
|
||||||
@@ -400,12 +402,12 @@ impl<T: ControlStreams> ControlStreams for StreamRecvOpen<T> {
|
|||||||
self.inner.send_flow_controller(id)
|
self.inner.send_flow_controller(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_can_send_data(&mut self, id: StreamId) -> Result<(), ConnectionError> {
|
fn can_send_data(&mut self, id: StreamId) -> bool {
|
||||||
self.inner.check_can_send_data(id)
|
self.inner.can_send_data(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_can_recv_data(&mut self, id: StreamId) -> Result<(), ConnectionError> {
|
fn can_recv_data(&mut self, id: StreamId) -> bool {
|
||||||
self.inner.check_can_recv_data(id)
|
self.inner.can_recv_data(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -162,12 +162,12 @@ impl<T: ControlStreams> ControlStreams for StreamSendClose<T> {
|
|||||||
self.inner.send_flow_controller(id)
|
self.inner.send_flow_controller(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_can_send_data(&mut self, id: StreamId) -> Result<(), ConnectionError> {
|
fn can_send_data(&mut self, id: StreamId) -> bool {
|
||||||
self.inner.check_can_send_data(id)
|
self.inner.can_send_data(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_can_recv_data(&mut self, id: StreamId) -> Result<(), ConnectionError> {
|
fn can_recv_data(&mut self, id: StreamId) -> bool {
|
||||||
self.inner.check_can_recv_data(id)
|
self.inner.can_recv_data(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use ConnectionError;
|
use ConnectionError;
|
||||||
use error::User::{InvalidStreamId, StreamReset, Rejected};
|
use error::User::{InactiveStreamId, InvalidStreamId, StreamReset, Rejected, UnexpectedFrameType};
|
||||||
use frame::{Frame, SettingSet};
|
use frame::{Frame, SettingSet};
|
||||||
use proto::*;
|
use proto::*;
|
||||||
|
|
||||||
@@ -103,7 +103,11 @@ impl<T, U> Sink for StreamSendOpen<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
if T::local_valid_id(id) {
|
if T::local_valid_id(id) {
|
||||||
if !self.inner.is_local_active(id) {
|
if self.inner.is_local_active(id) {
|
||||||
|
if !self.inner.can_send_data(id) {
|
||||||
|
return Err(InactiveStreamId.into());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if !T::local_can_open() {
|
if !T::local_can_open() {
|
||||||
return Err(InvalidStreamId.into());
|
return Err(InvalidStreamId.into());
|
||||||
}
|
}
|
||||||
@@ -114,8 +118,11 @@ impl<T, U> Sink for StreamSendOpen<T>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("creating new local stream");
|
if let &Frame::Headers(..) = &frame {
|
||||||
self.inner.local_open(id, self.initial_window_size)?;
|
self.inner.local_open(id, self.initial_window_size)?;
|
||||||
|
} else {
|
||||||
|
return Err(InactiveStreamId.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If the frame is part of a remote stream, it MUST already exist.
|
// If the frame is part of a remote stream, it MUST already exist.
|
||||||
@@ -130,7 +137,9 @@ impl<T, U> Sink for StreamSendOpen<T>
|
|||||||
|
|
||||||
if let &Frame::Data(..) = &frame {
|
if let &Frame::Data(..) = &frame {
|
||||||
// Ensures we've already sent headers for this stream.
|
// Ensures we've already sent headers for this stream.
|
||||||
self.inner.check_can_send_data(id)?;
|
if !self.inner.can_send_data(id) {
|
||||||
|
return Err(InactiveStreamId.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("sending frame...");
|
trace!("sending frame...");
|
||||||
@@ -230,12 +239,12 @@ impl<T: ControlStreams> ControlStreams for StreamSendOpen<T> {
|
|||||||
self.inner.send_flow_controller(id)
|
self.inner.send_flow_controller(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_can_send_data(&mut self, id: StreamId) -> Result<(), ConnectionError> {
|
fn can_send_data(&mut self, id: StreamId) -> bool {
|
||||||
self.inner.check_can_send_data(id)
|
self.inner.can_send_data(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_can_recv_data(&mut self, id: StreamId) -> Result<(), ConnectionError> {
|
fn can_recv_data(&mut self, id: StreamId) -> bool {
|
||||||
self.inner.check_can_recv_data(id)
|
self.inner.can_recv_data(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,8 +76,8 @@ pub trait ControlStreams {
|
|||||||
fn update_inital_recv_window_size(&mut self, old_sz: u32, new_sz: u32);
|
fn update_inital_recv_window_size(&mut self, old_sz: u32, new_sz: u32);
|
||||||
fn update_inital_send_window_size(&mut self, old_sz: u32, new_sz: u32);
|
fn update_inital_send_window_size(&mut self, old_sz: u32, new_sz: u32);
|
||||||
|
|
||||||
fn check_can_send_data(&mut self, id: StreamId) -> Result<(), ConnectionError>;
|
fn can_send_data(&mut self, id: StreamId) -> bool;
|
||||||
fn check_can_recv_data(&mut self, id: StreamId) -> Result<(), ConnectionError>;
|
fn can_recv_data(&mut self, id: StreamId) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Holds the underlying stream state to be accessed by upper layers.
|
/// Holds the underlying stream state to be accessed by upper layers.
|
||||||
@@ -366,18 +366,18 @@ impl<T, P: Peer> ControlStreams for StreamStore<T, P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_can_send_data(&mut self, id: StreamId) -> Result<(), ConnectionError> {
|
fn can_send_data(&mut self, id: StreamId) -> bool {
|
||||||
if let Some(s) = self.get_active(id) {
|
match self.get_active(id) {
|
||||||
return s.check_can_send_data();
|
Some(s) => s.can_send_data(),
|
||||||
|
None => false,
|
||||||
}
|
}
|
||||||
Err(ProtocolError.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_can_recv_data(&mut self, id: StreamId) -> Result<(), ConnectionError> {
|
fn can_recv_data(&mut self, id: StreamId) -> bool {
|
||||||
if let Some(s) = self.get_active(id) {
|
match self.get_active(id) {
|
||||||
return s.check_can_recv_data();
|
Some(s) => s.can_recv_data(),
|
||||||
|
None => false,
|
||||||
}
|
}
|
||||||
Err(ProtocolError.into())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ extern crate futures;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate mock_io;
|
extern crate mock_io;
|
||||||
extern crate test_futures;
|
|
||||||
|
|
||||||
// scoped so `cargo test client_request` dtrt.
|
// scoped so `cargo test client_request` dtrt.
|
||||||
mod client_request {
|
mod client_request {
|
||||||
@@ -16,7 +15,6 @@ mod client_request {
|
|||||||
use futures::*;
|
use futures::*;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use mock_io;
|
use mock_io;
|
||||||
use test_futures::*;
|
|
||||||
|
|
||||||
// TODO: move into another file
|
// TODO: move into another file
|
||||||
macro_rules! assert_user_err {
|
macro_rules! assert_user_err {
|
||||||
@@ -50,12 +48,12 @@ mod client_request {
|
|||||||
.write(SETTINGS_ACK)
|
.write(SETTINGS_ACK)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let mut h2 = client::handshake(mock)
|
let h2 = client::handshake(mock)
|
||||||
.wait().unwrap();
|
.wait().unwrap();
|
||||||
trace!("hands have been shook");
|
trace!("hands have been shook");
|
||||||
|
|
||||||
// At this point, the connection should be closed
|
// At this point, the connection should be closed
|
||||||
sassert_done(&mut h2);
|
assert!(Stream::wait(h2).next().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -87,7 +85,7 @@ mod client_request {
|
|||||||
// Get the response
|
// Get the response
|
||||||
|
|
||||||
trace!("getting response");
|
trace!("getting response");
|
||||||
let (resp, mut h2) = h2.into_future().wait().unwrap();
|
let (resp, h2) = h2.into_future().wait().unwrap();
|
||||||
|
|
||||||
match resp.unwrap() {
|
match resp.unwrap() {
|
||||||
Frame::Headers { headers, .. } => {
|
Frame::Headers { headers, .. } => {
|
||||||
@@ -98,7 +96,7 @@ mod client_request {
|
|||||||
|
|
||||||
// No more frames
|
// No more frames
|
||||||
trace!("ensure no more responses");
|
trace!("ensure no more responses");
|
||||||
sassert_done(&mut h2);
|
assert!(Stream::wait(h2).next().is_none());;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -151,7 +149,7 @@ mod client_request {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the response body
|
// Get the response body
|
||||||
let (data, mut h2) = h2.into_future().wait().unwrap();
|
let (data, h2) = h2.into_future().wait().unwrap();
|
||||||
|
|
||||||
match data.unwrap() {
|
match data.unwrap() {
|
||||||
Frame::Data { id, data, end_of_stream, .. } => {
|
Frame::Data { id, data, end_of_stream, .. } => {
|
||||||
@@ -162,7 +160,7 @@ mod client_request {
|
|||||||
_ => panic!("unexpected frame"),
|
_ => panic!("unexpected frame"),
|
||||||
}
|
}
|
||||||
|
|
||||||
sassert_done(&mut h2);
|
assert!(Stream::wait(h2).next().is_none());;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -215,7 +213,7 @@ mod client_request {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the response body
|
// Get the response body
|
||||||
let (data, mut h2) = h2.into_future().wait().unwrap();
|
let (data, h2) = h2.into_future().wait().unwrap();
|
||||||
|
|
||||||
match data.unwrap() {
|
match data.unwrap() {
|
||||||
Frame::Data { id, data, end_of_stream, .. } => {
|
Frame::Data { id, data, end_of_stream, .. } => {
|
||||||
@@ -226,7 +224,7 @@ mod client_request {
|
|||||||
_ => panic!("unexpected frame"),
|
_ => panic!("unexpected frame"),
|
||||||
}
|
}
|
||||||
|
|
||||||
sassert_done(&mut h2);
|
assert!(Stream::wait(h2).next().is_none());;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -295,7 +293,7 @@ mod client_request {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the response body
|
// Get the response body
|
||||||
let (data, mut h2) = h2.into_future().wait().expect("into future");
|
let (data, h2) = h2.into_future().wait().expect("into future");
|
||||||
|
|
||||||
match data.expect("response data") {
|
match data.expect("response data") {
|
||||||
Frame::Data { id, data, end_of_stream, .. } => {
|
Frame::Data { id, data, end_of_stream, .. } => {
|
||||||
@@ -306,7 +304,7 @@ mod client_request {
|
|||||||
_ => panic!("unexpected frame"),
|
_ => panic!("unexpected frame"),
|
||||||
}
|
}
|
||||||
|
|
||||||
sassert_done(&mut h2);
|
assert!(Stream::wait(h2).next().is_none());;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -352,7 +350,7 @@ mod client_request {
|
|||||||
request.uri = "https://http2.akamai.com/".parse().unwrap();
|
request.uri = "https://http2.akamai.com/".parse().unwrap();
|
||||||
let err = h2.send_request(1.into(), request, true).wait().unwrap_err();
|
let err = h2.send_request(1.into(), request, true).wait().unwrap_err();
|
||||||
|
|
||||||
assert_user_err!(err, UnexpectedFrameType);
|
assert_user_err!(err, InactiveStreamId);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -399,7 +397,7 @@ mod client_request {
|
|||||||
|
|
||||||
// Send the data
|
// Send the data
|
||||||
let err = h2.send_data(id, body.into(), true).wait().unwrap_err();
|
let err = h2.send_data(id, body.into(), true).wait().unwrap_err();
|
||||||
assert_user_err!(err, UnexpectedFrameType);
|
assert_user_err!(err, InactiveStreamId);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user