mod support;
use ntex_bytes::BytesMut;
use ntex_codec::Decoder;
use ntex_h2::{Codec, frame, frame::FrameError};
use ntex_http::{HeaderMap, HeaderName, Method, StatusCode};
use ntex_io::testing::IoTest;
use ntex_util::future::join;
use support::{build_large_headers, frames};
#[macro_export]
macro_rules! decode_frame {
($type: ident, $bytes: ident) => {{
use ntex_h2::frame::Frame;
match Codec::default().decode(&mut $bytes) {
Ok(Some(Frame::$type(frame))) => frame,
frame => panic!("unexpected frame; actual={:?}", frame),
}
}};
}
#[macro_export]
macro_rules! decode_err {
($bytes: ident, $type: expr) => {{
match Codec::default().decode(&mut $bytes) {
Err(e) => assert_eq!(e, $type),
frame => panic!("expected error; actual={:?}", frame),
}
}};
}
#[test]
fn read_data_no_padding() {
let mut buf = BytesMut::new();
buf.extend_from_slice(&[0, 0, 5, 0, 0, 0, 0, 0, 1]);
buf.extend_from_slice(b"hello");
let data = decode_frame!(Data, buf);
assert_eq!(data.stream_id(), 1);
assert_eq!(data.payload(), &b"hello"[..]);
assert!(!data.is_end_stream());
}
#[test]
fn read_data_empty_payload() {
let mut buf = BytesMut::new();
buf.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 1]);
let data = decode_frame!(Data, buf);
assert_eq!(data.stream_id(), 1);
assert_eq!(data.payload(), &b""[..]);
assert!(!data.is_end_stream());
}
#[test]
fn read_data_end_stream() {
let mut buf = BytesMut::new();
buf.extend_from_slice(&[0, 0, 5, 0, 1, 0, 0, 0, 1]);
buf.extend_from_slice(b"hello");
let data = decode_frame!(Data, buf);
assert_eq!(data.stream_id(), 1);
assert_eq!(data.payload(), &b"hello"[..]);
assert!(data.is_end_stream());
}
#[test]
fn read_data_padding() {
let mut buf = BytesMut::new();
buf.extend_from_slice(&[0, 0, 16, 0, 0x8, 0, 0, 0, 1]);
buf.extend_from_slice(&[5]); buf.extend_from_slice(b"helloworld"); buf.extend_from_slice(b"\0\0\0\0\0");
let data = decode_frame!(Data, buf);
assert_eq!(data.stream_id(), 1);
assert_eq!(data.payload(), &b"helloworld"[..]);
assert!(!data.is_end_stream());
}
#[test]
fn read_push_promise() {
let mut buf = BytesMut::new();
buf.extend_from_slice(&[
0, 0, 0x5, 0x5, 0x4, 0, 0, 0, 0x1, 0, 0, 0, 0x2, 0x82, ]);
decode_err!(buf, FrameError::UnexpectedPushPromise);
}
#[test]
fn read_data_stream_id_zero() {
let mut buf = BytesMut::new();
buf.extend_from_slice(&[0, 0, 5, 0, 0, 0, 0, 0, 0]);
buf.extend_from_slice(b"hello");
decode_err!(buf, FrameError::InvalidStreamId);
}
#[ntex::test]
async fn read_continuation_frames() {
let (cli, srv) = IoTest::create();
let large = build_large_headers();
let frame = large
.iter()
.fold(
frames::headers(1).response(200),
|frame, &(name, ref value)| frame.field(name, &value[..]),
)
.eos();
let srv_rx = support::start_server(srv);
let client = support::start_client(cli);
let srv_fut = async move {
let msg = srv_rx.recv().await.unwrap();
let hdrs = frame.into_fields();
msg.stream()
.send_response(StatusCode::OK, hdrs, true)
.unwrap();
let (pseudo, _hdrs, eof) = get_headers!(msg);
assert_eq!(pseudo.path, Some("/index.html".into()));
assert!(eof);
};
let client_fut = async move {
let (_snd, rcv) = client
.send(Method::GET, "/index.html".into(), HeaderMap::new(), true)
.await
.expect("response");
let msg = rcv.recv().await.unwrap();
let (pseudo, hdrs, _eof) = get_headers!(msg);
assert_eq!(pseudo.status, Some(StatusCode::OK));
let expected = large
.iter()
.fold(HeaderMap::new(), |mut map, &(name, ref value)| {
map.append(HeaderName::try_from(name).unwrap(), value.parse().unwrap());
map
});
assert_eq!(hdrs, expected);
};
join(srv_fut, client_fut).await;
}
#[test]
fn update_max_frame_len_at_rest() {
let mut buf = BytesMut::new();
buf.extend_from_slice(&[0, 0, 5, 0, 0, 0, 0, 0, 1]);
buf.extend_from_slice(b"hello");
buf.extend_from_slice(&[0, 64, 1, 0, 0, 0, 0, 0, 1]);
buf.extend_from_slice(&vec![0; 16_385]);
assert_eq!(decode_frame!(Data, buf).payload(), &b"hello"[..]);
let codec = Codec::default();
codec.set_recv_frame_size(16_384);
assert_eq!(codec.recv_frame_size(), 16_384);
assert_eq!(
codec.decode(&mut buf).unwrap_err().to_string(),
"Frame size exceeded"
);
}
#[test]
fn read_goaway_with_debug_data() {
let mut buf = BytesMut::new();
buf.extend_from_slice(&[
0, 0, 22, 7, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 11,
]);
buf.extend_from_slice(b"too_many_pings");
let data = decode_frame!(GoAway, buf);
assert_eq!(data.reason(), frame::Reason::ENHANCE_YOUR_CALM);
assert_eq!(data.last_stream_id(), 1);
assert_eq!(&**data.data(), b"too_many_pings");
}