use std::borrow::Cow;
use std::borrow::Borrow;
use http::{Header, StreamId, HttpError, HttpResult, HttpScheme, WindowSize,
ErrorCode, INITIAL_CONNECTION_WINDOW_SIZE};
use http::priority::DataPrioritizer;
use http::session::Session;
use http::frame::{Frame, FrameIR, RawFrame, DataFrame, DataFlag, HeadersFrame, HeadersFlag,
SettingsFrame, RstStreamFrame, PingFrame, GoawayFrame, WindowUpdateFrame};
use hpack;
#[derive(PartialEq)]
#[derive(Debug)]
#[derive(Clone)]
pub enum HttpFrame<'a> {
DataFrame(DataFrame<'a>),
HeadersFrame(HeadersFrame<'a>),
RstStreamFrame(RstStreamFrame),
SettingsFrame(SettingsFrame),
PingFrame(PingFrame),
GoawayFrame(GoawayFrame<'a>),
WindowUpdateFrame(WindowUpdateFrame),
UnknownFrame(RawFrame<'a>),
}
impl<'a> HttpFrame<'a> {
pub fn from_raw(raw_frame: &'a RawFrame) -> HttpResult<HttpFrame<'a>> {
let frame = match raw_frame.header().1 {
0x0 => HttpFrame::DataFrame(try!(HttpFrame::parse_frame(&raw_frame))),
0x1 => HttpFrame::HeadersFrame(try!(HttpFrame::parse_frame(&raw_frame))),
0x3 => HttpFrame::RstStreamFrame(try!(HttpFrame::parse_frame(&raw_frame))),
0x4 => HttpFrame::SettingsFrame(try!(HttpFrame::parse_frame(&raw_frame))),
0x6 => HttpFrame::PingFrame(try!(HttpFrame::parse_frame(&raw_frame))),
0x7 => HttpFrame::GoawayFrame(try!(HttpFrame::parse_frame(&raw_frame))),
0x8 => HttpFrame::WindowUpdateFrame(try!(HttpFrame::parse_frame(&raw_frame))),
_ => HttpFrame::UnknownFrame(raw_frame.as_ref().into()),
};
Ok(frame)
}
#[inline]
fn parse_frame<F: Frame<'a>>(raw_frame: &'a RawFrame) -> HttpResult<F> {
Frame::from_raw(&raw_frame).ok_or(HttpError::InvalidFrame)
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum SendStatus {
Sent,
Nothing,
}
pub struct HttpConnection {
decoder: hpack::Decoder<'static>,
encoder: hpack::Encoder<'static>,
out_window_size: WindowSize,
in_window_size: WindowSize,
pub scheme: HttpScheme,
}
pub trait SendFrame {
fn send_frame<F: FrameIR>(&mut self, frame: F) -> HttpResult<()>;
}
pub trait ReceiveFrame {
fn recv_frame(&mut self) -> HttpResult<HttpFrame>;
}
pub struct DataChunk<'a> {
pub data: Cow<'a, [u8]>,
pub stream_id: StreamId,
pub end_stream: EndStream,
}
impl<'a> DataChunk<'a> {
pub fn new(data: Cow<'a, [u8]>, stream_id: StreamId, end_stream: EndStream) -> DataChunk<'a> {
DataChunk {
data: data,
stream_id: stream_id,
end_stream: end_stream,
}
}
pub fn new_borrowed<D: Borrow<&'a [u8]>>(data: D,
stream_id: StreamId,
end_stream: EndStream)
-> DataChunk<'a> {
DataChunk {
data: Cow::Borrowed(data.borrow()),
stream_id: stream_id,
end_stream: end_stream,
}
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum EndStream {
Yes,
No,
}
pub struct HttpConnectionSender<'a, S>
where S: SendFrame + 'a
{
sender: &'a mut S,
conn: &'a mut HttpConnection,
}
impl<'a, S> HttpConnectionSender<'a, S>
where S: SendFrame + 'a
{
#[inline]
fn send_frame<F: FrameIR>(&mut self, frame: F) -> HttpResult<()> {
self.sender.send_frame(frame)
}
pub fn rst_stream(&mut self, id: StreamId, code: ErrorCode) -> HttpResult<()> {
self.send_frame(RstStreamFrame::new(id, code))
}
pub fn send_settings_ack(&mut self) -> HttpResult<()> {
self.send_frame(SettingsFrame::new_ack())
}
pub fn send_ping_ack(&mut self, bytes: u64) -> HttpResult<()> {
self.send_frame(PingFrame::new_ack(bytes))
}
pub fn send_ping(&mut self, bytes: u64) -> HttpResult<()> {
self.send_frame(PingFrame::with_data(bytes))
}
pub fn send_headers<'n, 'v, H: Into<Vec<Header<'n, 'v>>>>(&mut self,
headers: H,
stream_id: StreamId,
end_stream: EndStream)
-> HttpResult<()> {
let headers_fragment = self.conn
.encoder
.encode(headers.into().iter().map(|h| (h.name(), h.value())));
let mut frame = HeadersFrame::new(headers_fragment, stream_id);
frame.set_flag(HeadersFlag::EndHeaders);
if end_stream == EndStream::Yes {
frame.set_flag(HeadersFlag::EndStream);
}
self.send_frame(frame)
}
pub fn send_data(&mut self, chunk: DataChunk) -> HttpResult<()> {
let DataChunk { data, stream_id, end_stream } = chunk;
let mut frame = DataFrame::with_data(stream_id, data.as_ref());
if end_stream == EndStream::Yes {
frame.set_flag(DataFlag::EndStream);
}
try!(self.conn.decrease_out_window(frame.payload_len()));
trace!("New OUT WINDOW size = {}", self.conn.out_window_size());
self.send_frame(frame)
}
pub fn send_next_data<P: DataPrioritizer>(&mut self,
prioritizer: &mut P)
-> HttpResult<SendStatus> {
let chunk = try!(prioritizer.get_next_chunk());
match chunk {
None => Ok(SendStatus::Nothing),
Some(chunk) => {
try!(self.send_data(chunk));
Ok(SendStatus::Sent)
}
}
}
}
impl HttpConnection {
pub fn new(scheme: HttpScheme) -> HttpConnection {
HttpConnection {
scheme: scheme,
decoder: hpack::Decoder::new(),
encoder: hpack::Encoder::new(),
in_window_size: WindowSize::new(INITIAL_CONNECTION_WINDOW_SIZE),
out_window_size: WindowSize::new(INITIAL_CONNECTION_WINDOW_SIZE),
}
}
pub fn sender<'a, S: SendFrame>(&'a mut self, sender: &'a mut S) -> HttpConnectionSender<S> {
HttpConnectionSender {
sender: sender,
conn: self,
}
}
pub fn in_window_size(&self) -> i32 {
self.in_window_size.size()
}
pub fn out_window_size(&self) -> i32 {
self.out_window_size.size()
}
pub fn expect_settings<Recv: ReceiveFrame, Sess: Session>(&mut self,
rx: &mut Recv,
session: &mut Sess)
-> HttpResult<()> {
let frame = rx.recv_frame();
match frame {
Ok(HttpFrame::SettingsFrame(settings)) => {
if settings.is_ack() {
Err(HttpError::UnableToConnect)
} else {
debug!("Correctly received a SETTINGS frame from the server");
try!(self.handle_frame(HttpFrame::SettingsFrame(settings), session));
Ok(())
}
}
Ok(_) => Err(HttpError::UnableToConnect),
Err(e) => Err(e),
}
}
pub fn handle_next_frame<Recv: ReceiveFrame, Sess: Session>(&mut self,
rx: &mut Recv,
session: &mut Sess)
-> HttpResult<()> {
debug!("Waiting for frame...");
let frame = match rx.recv_frame() {
Ok(frame) => frame,
Err(e) => {
debug!("Encountered an HTTP/2 error, stopping.");
return Err(e);
}
};
self.handle_frame(frame, session)
}
fn handle_frame<Sess: Session>(&mut self,
frame: HttpFrame,
session: &mut Sess)
-> HttpResult<()> {
match frame {
HttpFrame::DataFrame(frame) => {
debug!("Data frame received");
self.handle_data_frame(frame, session)
}
HttpFrame::HeadersFrame(frame) => {
debug!("Headers frame received");
self.handle_headers_frame(frame, session)
}
HttpFrame::RstStreamFrame(frame) => {
debug!("RST_STREAM frame received");
self.handle_rst_stream_frame(frame, session)
}
HttpFrame::SettingsFrame(frame) => {
debug!("Settings frame received");
self.handle_settings_frame::<Sess>(frame, session)
},
HttpFrame::PingFrame(frame) => {
debug!("PING frame received");
self.handle_ping_frame(frame, session)
},
HttpFrame::GoawayFrame(frame) => {
debug!("GOAWAY frame received");
session.on_goaway(frame.last_stream_id(),
frame.error_code(),
frame.debug_data(),
self)
}
HttpFrame::WindowUpdateFrame(_) => {
debug!("WINDOW_UPDATE frame received");
Ok(())
}
HttpFrame::UnknownFrame(frame) => {
debug!("Unknown frame received; raw = {:?}", frame);
Ok(())
}
}
}
fn handle_data_frame<Sess: Session>(&mut self,
frame: DataFrame,
session: &mut Sess)
-> HttpResult<()> {
try!(self.decrease_in_window(frame.payload_len()));
trace!("New IN WINDOW size = {}", self.in_window_size());
try!(session.new_data_chunk(frame.get_stream_id(), &frame.data, self));
if frame.is_set(DataFlag::EndStream) {
debug!("End of stream {}", frame.get_stream_id());
try!(session.end_of_stream(frame.get_stream_id(), self));
}
Ok(())
}
fn handle_headers_frame<Sess: Session>(&mut self,
frame: HeadersFrame,
session: &mut Sess)
-> HttpResult<()> {
let headers = try!(self.decoder
.decode(&frame.header_fragment())
.map_err(HttpError::CompressionError));
let headers = headers.into_iter().map(|h| h.into()).collect();
try!(session.new_headers(frame.get_stream_id(), headers, self));
if frame.is_end_of_stream() {
debug!("End of stream {}", frame.get_stream_id());
try!(session.end_of_stream(frame.get_stream_id(), self));
}
Ok(())
}
#[inline]
fn handle_rst_stream_frame<Sess: Session>(&mut self,
frame: RstStreamFrame,
session: &mut Sess)
-> HttpResult<()> {
session.rst_stream(frame.get_stream_id(), frame.error_code(), self)
}
fn handle_ping_frame<Sess: Session>(&mut self, frame: PingFrame, session: &mut Sess)
-> HttpResult<()> {
if frame.is_ack() {
session.on_pong(&frame, self)
} else {
session.on_ping(&frame, self)
}
}
fn handle_settings_frame<Sess: Session>(&mut self,
frame: SettingsFrame,
session: &mut Sess)
-> HttpResult<()> {
if !frame.is_ack() {
trace!("New settings frame {:#?}", frame);
try!(session.new_settings(frame.settings, self));
}
Ok(())
}
fn decrease_out_window(&mut self, size: u32) -> HttpResult<()> {
debug_assert!(size < 0x80000000);
self.out_window_size
.try_decrease(size as i32)
.map_err(|_| HttpError::WindowSizeOverflow)
}
fn decrease_in_window(&mut self, size: u32) -> HttpResult<()> {
debug_assert!(size < 0x80000000);
self.in_window_size
.try_decrease(size as i32)
.map_err(|_| HttpError::WindowSizeOverflow)
}
}
#[cfg(test)]
mod tests {
use std::borrow::Cow;
use std::io;
use super::{HttpConnection, HttpFrame, SendFrame, EndStream, DataChunk, SendStatus};
use http::tests::common::{build_mock_http_conn, StubDataPrioritizer, TestSession,
MockReceiveFrame, MockSendFrame};
use http::frame::{Frame, DataFrame, HeadersFrame, RstStreamFrame, GoawayFrame, SettingsFrame,
PingFrame, pack_header, RawFrame, FrameIR};
use http::{HttpResult, HttpScheme, Header, OwnedHeader, ErrorCode};
use hpack;
fn send_frame<S: SendFrame>(sender: &mut S,
conn: &mut HttpConnection,
frame: HttpFrame)
-> HttpResult<()> {
match frame {
HttpFrame::DataFrame(frame) => conn.sender(sender).send_frame(frame),
HttpFrame::SettingsFrame(frame) => conn.sender(sender).send_frame(frame),
HttpFrame::RstStreamFrame(frame) => conn.sender(sender).send_frame(frame),
HttpFrame::HeadersFrame(frame) => conn.sender(sender).send_frame(frame),
HttpFrame::PingFrame(frame) => conn.sender(sender).send_frame(frame),
HttpFrame::GoawayFrame(frame) => conn.sender(sender).send_frame(frame),
HttpFrame::WindowUpdateFrame(frame) => conn.sender(sender).send_frame(frame),
HttpFrame::UnknownFrame(_) => Ok(()),
}
}
#[test]
fn test_http_frame_from_raw() {
fn to_raw<'a, F: FrameIR>(frame: F) -> RawFrame<'static> {
let mut buf = io::Cursor::new(Vec::new());
frame.serialize_into(&mut buf).unwrap();
RawFrame::from(buf.into_inner())
}
assert!(match HttpFrame::from_raw(&to_raw(DataFrame::new(1))) {
Ok(HttpFrame::DataFrame(_)) => true,
_ => false,
});
assert!(match HttpFrame::from_raw(&to_raw(HeadersFrame::new(vec![], 1))) {
Ok(HttpFrame::HeadersFrame(_)) => true,
_ => false,
});
assert!(match HttpFrame::from_raw(&to_raw(SettingsFrame::new())) {
Ok(HttpFrame::SettingsFrame(_)) => true,
_ => false,
});
let unknown_frame = RawFrame::from({
let mut buf: Vec<u8> = Vec::new();
let header = (1u32, 10u8, 0u8, 1u32);
buf.extend(pack_header(&header).to_vec().into_iter());
buf.push(1);
buf
});
assert!(match HttpFrame::from_raw(&unknown_frame) {
Ok(HttpFrame::UnknownFrame(_)) => true,
_ => false,
});
let invalid_frame = HeadersFrame::new(vec![], 0);
assert!(HttpFrame::from_raw(&to_raw(invalid_frame)).is_err());
}
fn expect_frame_list(expected: Vec<HttpFrame>, sent: Vec<RawFrame>) {
for (expect, actual) in expected.into_iter().zip(sent.into_iter()) {
let actual = HttpFrame::from_raw(&actual).unwrap();
assert_eq!(expect, actual);
}
}
#[test]
fn test_write_single_frame() {
let frames: Vec<HttpFrame> = vec![
HttpFrame::HeadersFrame(HeadersFrame::new(vec![], 1)),
];
let expected = frames.clone();
let mut conn = build_mock_http_conn();
let mut sender = MockSendFrame::new();
for frame in frames.into_iter() {
send_frame(&mut sender, &mut conn, frame).unwrap();
}
expect_frame_list(expected, sender.sent);
}
#[test]
fn test_send_next_data() {
fn expect_chunk(expected: &[u8], frame: &HttpFrame) {
let frame = match frame {
&HttpFrame::DataFrame(ref frame) => frame,
_ => panic!("Expected a data frame"),
};
assert_eq!(expected, &frame.data[..]);
}
let mut conn = build_mock_http_conn();
let mut sender = MockSendFrame::new();
let chunks = vec![
vec![1, 2, 3, 4],
vec![5, 6],
vec![7],
vec![],
];
let mut prioritizer = StubDataPrioritizer::new(chunks.clone());
let mut expected_window = 65_535;
assert_eq!(conn.out_window_size(), expected_window);
for chunk in chunks.iter() {
assert_eq!(SendStatus::Sent,
conn.sender(&mut sender).send_next_data(&mut prioritizer).unwrap());
let last = sender.sent.pop().unwrap();
expect_chunk(&chunk, &HttpFrame::from_raw(&last).unwrap());
expected_window -= chunk.len() as i32;
assert_eq!(conn.out_window_size(), expected_window);
}
assert_eq!(SendStatus::Nothing,
conn.sender(&mut sender).send_next_data(&mut prioritizer).unwrap());
assert_eq!(conn.out_window_size(), expected_window);
}
#[test]
fn test_write_multiple_frames() {
let frames: Vec<HttpFrame> = vec![
HttpFrame::HeadersFrame(HeadersFrame::new(vec![], 1)),
HttpFrame::DataFrame(DataFrame::new(1)),
HttpFrame::DataFrame(DataFrame::new(3)),
HttpFrame::HeadersFrame(HeadersFrame::new(vec![], 3)),
];
let expected = frames.clone();
let mut conn = build_mock_http_conn();
let mut sender = MockSendFrame::new();
for frame in frames.into_iter() {
send_frame(&mut sender, &mut conn, frame).unwrap();
}
expect_frame_list(expected, sender.sent);
}
#[test]
fn test_send_headers_single_frame() {
fn assert_correct_headers(headers: &[Header], frame: &HeadersFrame) {
let buf = frame.header_fragment();
let frame_headers = hpack::Decoder::new().decode(buf).unwrap();
let headers: Vec<OwnedHeader> = headers.iter().map(|h| h.clone().into()).collect();
assert_eq!(headers, frame_headers);
}
let headers: Vec<Header> = vec![
Header::new(b":method", b"GET"),
Header::new(b":scheme", b"http"),
];
{
let mut conn = build_mock_http_conn();
let mut sender = MockSendFrame::new();
conn.sender(&mut sender).send_headers(&headers[..], 1, EndStream::Yes).unwrap();
assert_eq!(sender.sent.len(), 1);
let frame = match HttpFrame::from_raw(&sender.sent[0]).unwrap() {
HttpFrame::HeadersFrame(frame) => frame,
_ => panic!("Headers frame not sent"),
};
assert!(frame.is_headers_end());
assert!(frame.is_end_of_stream());
assert_correct_headers(&headers, &frame);
}
{
let mut conn = build_mock_http_conn();
let mut sender = MockSendFrame::new();
conn.sender(&mut sender).send_headers(&headers[..], 1, EndStream::No).unwrap();
assert_eq!(sender.sent.len(), 1);
let frame = match HttpFrame::from_raw(&sender.sent[0]).unwrap() {
HttpFrame::HeadersFrame(frame) => frame,
_ => panic!("Headers frame not sent"),
};
assert!(frame.is_headers_end());
assert!(!frame.is_end_of_stream());
assert_correct_headers(&headers, &frame);
}
{
let mut conn = build_mock_http_conn();
let mut sender = MockSendFrame::new();
conn.sender(&mut sender).send_headers(headers.clone(), 1, EndStream::Yes).unwrap();
assert_eq!(sender.sent.len(), 1);
let frame = match HttpFrame::from_raw(&sender.sent[0]).unwrap() {
HttpFrame::HeadersFrame(frame) => frame,
_ => panic!("Headers frame not sent"),
};
assert!(frame.is_headers_end());
assert!(frame.is_end_of_stream());
assert_correct_headers(&headers, &frame);
}
}
#[test]
fn test_send_data_single_frame() {
{
let mut conn = build_mock_http_conn();
let mut sender = MockSendFrame::new();
let data: &[u8] = b"1234";
conn.sender(&mut sender)
.send_data(DataChunk::new_borrowed(data, 1, EndStream::No))
.unwrap();
assert_eq!(sender.sent.len(), 1);
let raw = sender.sent.remove(0);
let parsed_frame = HttpFrame::from_raw(&raw);
let frame = match parsed_frame {
Ok(HttpFrame::DataFrame(frame)) => frame,
_ => panic!("Data frame not sent"),
};
assert_eq!(&frame.data[..], data);
assert!(!frame.is_end_of_stream());
assert_eq!(conn.out_window_size(), 65_535 - data.len() as i32);
}
{
let mut conn = build_mock_http_conn();
let mut sender = MockSendFrame::new();
let data: &[u8] = b"1234";
conn.sender(&mut sender)
.send_data(DataChunk::new_borrowed(data, 1, EndStream::Yes))
.unwrap();
assert_eq!(sender.sent.len(), 1);
let raw = sender.sent.remove(0);
let parsed_frame = HttpFrame::from_raw(&raw).unwrap();
let frame = match parsed_frame {
HttpFrame::DataFrame(frame) => frame,
_ => panic!("Data frame not sent"),
};
assert_eq!(&frame.data[..], data);
assert!(frame.is_end_of_stream());
assert_eq!(conn.out_window_size(), 65_535 - data.len() as i32);
}
{
let mut conn = build_mock_http_conn();
let mut sender = MockSendFrame::new();
let data: &[u8] = b"1234";
let chunk = DataChunk {
data: Cow::Owned(data.to_vec()),
stream_id: 1,
end_stream: EndStream::Yes,
};
conn.sender(&mut sender).send_data(chunk).unwrap();
assert_eq!(sender.sent.len(), 1);
let raw = sender.sent.remove(0);
let parsed_frame = HttpFrame::from_raw(&raw).unwrap();
let frame = match parsed_frame {
HttpFrame::DataFrame(frame) => frame,
_ => panic!("Data frame not sent"),
};
assert_eq!(&frame.data[..], data);
assert!(frame.is_end_of_stream());
assert_eq!(conn.out_window_size(), 65_535 - data.len() as i32);
}
}
#[test]
fn test_send_rst_stream() {
let expected = vec![
HttpFrame::RstStreamFrame(RstStreamFrame::new(1, ErrorCode::InternalError)),
];
let mut conn = build_mock_http_conn();
let mut sender = MockSendFrame::new();
conn.sender(&mut sender).rst_stream(1, ErrorCode::InternalError).unwrap();
expect_frame_list(expected, sender.sent);
}
#[test]
fn test_http_conn_notifies_session_header() {
let frames: Vec<HttpFrame> = vec![
HttpFrame::HeadersFrame(HeadersFrame::new(vec![], 1)),
];
let mut conn = HttpConnection::new(HttpScheme::Http);
let mut session = TestSession::new();
let mut frame_provider = MockReceiveFrame::new(frames);
conn.handle_next_frame(&mut frame_provider, &mut session).unwrap();
assert_eq!(session.curr_header, 1);
assert_eq!(session.curr_chunk, 0);
assert_eq!(session.rst_streams.len(), 0);
}
#[test]
fn test_http_conn_notifies_session_data() {
let frames: Vec<HttpFrame> = vec![
HttpFrame::DataFrame(DataFrame::with_data(1, vec![1, 2, 3, 4, 5, 6])),
];
let mut conn = HttpConnection::new(HttpScheme::Http);
let mut session = TestSession::new();
let mut frame_provider = MockReceiveFrame::new(frames);
conn.handle_next_frame(&mut frame_provider, &mut session).unwrap();
assert_eq!(session.curr_header, 0);
assert_eq!(session.curr_chunk, 1);
assert_eq!(session.rst_streams.len(), 0);
assert_eq!(conn.in_window_size(), 65_535 - 6);
}
#[test]
fn test_http_conn_session_gets_headers_data_values() {
let expected_headers = vec![(b":method".to_vec(), b"GET".to_vec())];
let frames: Vec<HttpFrame> = vec![
HttpFrame::HeadersFrame(HeadersFrame::new(
hpack::Encoder::new().encode(
expected_headers.iter().map(|h| (&h.0[..], &h.1[..]))),
1)),
HttpFrame::DataFrame(DataFrame::new(1)), {
let frame = DataFrame::with_data(1, &b"1234"[..]);
HttpFrame::DataFrame(frame)
},
];
let mut conn = HttpConnection::new(HttpScheme::Http);
let mut session = TestSession::new_verify(vec![expected_headers],
vec![b"".to_vec(), b"1234".to_vec()]);
let mut frame_provider = MockReceiveFrame::new(frames);
conn.handle_next_frame(&mut frame_provider, &mut session).unwrap();
conn.handle_next_frame(&mut frame_provider, &mut session).unwrap();
conn.handle_next_frame(&mut frame_provider, &mut session).unwrap();
assert_eq!(conn.in_window_size(), 65_535 - 4);
assert_eq!(session.curr_chunk, 2);
assert_eq!(session.curr_header, 1);
}
#[test]
fn test_conn_rst_stream() {
let frames = vec![
HttpFrame::RstStreamFrame(RstStreamFrame::new(1, ErrorCode::ProtocolError)),
];
let mut conn = HttpConnection::new(HttpScheme::Http);
let mut session = TestSession::new();
let mut frame_provider = MockReceiveFrame::new(frames);
conn.handle_next_frame(&mut frame_provider, &mut session).unwrap();
assert_eq!(session.rst_streams.len(), 1);
assert_eq!(session.rst_streams[0], 1);
}
#[test]
fn test_conn_on_goaway() {
let frames = vec![
HttpFrame::GoawayFrame(GoawayFrame::new(0, ErrorCode::ProtocolError)),
];
let mut conn = HttpConnection::new(HttpScheme::Http);
let mut session = TestSession::new();
let mut frame_provider = MockReceiveFrame::new(frames);
conn.handle_next_frame(&mut frame_provider, &mut session).unwrap();
assert_eq!(session.goaways.len(), 1);
assert_eq!(session.goaways[0], ErrorCode::ProtocolError);
assert_eq!(session.curr_header, 0);
assert_eq!(session.curr_chunk, 0);
assert_eq!(session.rst_streams.len(), 0);
}
#[test]
fn test_conn_initial_windows() {
let conn = HttpConnection::new(HttpScheme::Http);
assert_eq!(conn.in_window_size(), 65_535);
assert_eq!(conn.out_window_size(), 65_535);
}
#[test]
fn test_http_conn_expect_settings() {
{
let frames = vec![HttpFrame::SettingsFrame(SettingsFrame::new())];
let mut conn = HttpConnection::new(HttpScheme::Http);
let mut frame_provider = MockReceiveFrame::new(frames);
assert!(conn.expect_settings(&mut frame_provider, &mut TestSession::new()).is_ok());
}
{
let frames = vec![HttpFrame::DataFrame(DataFrame::new(1))];
let mut conn = HttpConnection::new(HttpScheme::Http);
let mut frame_provider = MockReceiveFrame::new(frames);
assert!(conn.expect_settings(&mut frame_provider, &mut TestSession::new()).is_err());
}
{
let frames = vec![HttpFrame::SettingsFrame(SettingsFrame::new_ack())];
let mut conn = HttpConnection::new(HttpScheme::Http);
let mut frame_provider = MockReceiveFrame::new(frames);
assert!(conn.expect_settings(&mut frame_provider, &mut TestSession::new()).is_err());
}
}
#[test]
fn test_on_ping() {
let frames = vec![HttpFrame::PingFrame(PingFrame::new())];
let mut conn = HttpConnection::new(HttpScheme::Http);
let mut session = TestSession::new();
let mut frame_provider = MockReceiveFrame::new(frames);
conn.handle_next_frame(&mut frame_provider, &mut session).unwrap();
assert_eq!(session.pings, vec![0]);
assert_eq!(session.pongs, vec![]);
}
#[test]
fn test_on_pong() {
let frames = vec![HttpFrame::PingFrame(PingFrame::new_ack(123))];
let mut conn = HttpConnection::new(HttpScheme::Http);
let mut session = TestSession::new();
let mut frame_provider = MockReceiveFrame::new(frames);
conn.handle_next_frame(&mut frame_provider, &mut session).unwrap();
assert_eq!(session.pongs, vec![123]);
assert_eq!(session.pings, vec![]);
}
}