mod common;
use common::*;
use simoom_h2::frame::{kind, setting};
use simoom_h2::{Budgets, Config, Connection, Error, ErrorCode};
#[test]
fn late_frames_on_long_reset_streams_are_ignored() {
let (mut srv, mut raw) = server(Config { max_concurrent_streams: 1000, ..quiet() });
for i in 0..300u32 {
raw.headers(1 + 2 * i, &[(":method", "POST"), (":scheme", "http"), (":path", "/"), (":authority", "a")], false);
}
feed(&mut srv, &raw.take(), 1);
for i in 0..300u32 {
let id = 1 + 2 * i;
srv.send_response(id, 200, &[], true).unwrap();
srv.stream_finished(id);
}
let frames = drain(&mut srv);
assert_eq!(rst(&frames, 1), Some(ErrorCode::NO_ERROR));
assert_eq!(srv.tracked_streams(), 0);
raw.data(1, b"late body", false).headers(1, &[("x-checksum", "1")], true).window_update(1, 100);
let (evs, frames) = feed(&mut srv, &raw.take(), 2);
assert!(evs.is_empty(), "{evs:?}");
assert!(goaway(&frames).is_none() && rst(&frames, 1).is_none(), "{frames:?}");
assert!(!srv.wants_close());
raw.get(1001);
feed(&mut srv, &raw.take(), 3);
srv.send_response(1001, 200, &[], true).unwrap();
srv.stream_finished(1001);
drain(&mut srv);
raw.data(1001, b"x", true);
let (_, frames) = feed(&mut srv, &raw.take(), 4);
assert_eq!(rst(&frames, 1001), Some(ErrorCode::STREAM_CLOSED));
raw.get(1003);
let (evs, _) = feed(&mut srv, &raw.take(), 5);
assert!(evs.iter().any(|e| matches!(e, Ev::Headers { stream: 1003, .. })));
}
#[test]
fn outgoing_header_blocks_respect_the_peer_limit() {
let (mut srv, mut raw) = server(quiet());
raw.settings(&[(setting::MAX_HEADER_LIST_SIZE, 200)]).get(1).get(3);
feed(&mut srv, &raw.take(), 1);
drain(&mut srv);
assert_eq!(srv.peer_max_header_list_size(), 200);
let big = vec![b'v'; 150];
assert_eq!(srv.send_response(1, 200, &[(b"x-big", &big)], true), Err(Error::HeaderListTooLarge));
assert!(drain(&mut srv).iter().all(|f| f.h.kind != kind::HEADERS), "nothing sent");
srv.send_response(1, 200, &[(b"x-small", b"1")], false).unwrap();
assert_eq!(srv.send_trailers(1, &[(b"x-big", &big), (b"x-more", b"1")]), Err(Error::HeaderListTooLarge));
srv.send_trailers(1, &[(b"x-t", b"1")]).unwrap();
let fit = vec![b'v'; 121];
srv.send_response(3, 200, &[(b"x-big", &fit)], true).unwrap();
let mut cli = Connection::client(Config::default());
let mut s = Connection::server(Config { max_header_list_size: 300, ..Config::default() });
let (mut ce, mut se) = (Vec::new(), Vec::new());
pump(&mut cli, &mut s, 1, &mut ce, &mut se);
assert_eq!(cli.peer_max_header_list_size(), 300);
assert_eq!(cli.send_request(b"GET", b"https", b"example.com", b"/", &[(b"x-long", &[b'a'; 100])], true), Err(Error::HeaderListTooLarge));
assert!(cli.send_request(b"GET", b"https", b"example.com", b"/", &[], true).is_ok());
}
#[test]
fn frame_budgets_are_configurable() {
let (mut srv, mut raw) = server(Config { budgets: Budgets { ping: 3, ..Budgets::default() }, ..quiet() });
for _ in 0..4 {
raw.ping(*b"pingping");
}
let (_, frames) = feed(&mut srv, &raw.take(), 1);
assert_eq!(goaway(&frames), Some(ErrorCode::ENHANCE_YOUR_CALM));
let (mut srv, mut raw) = server(Config { budgets: Budgets { ping: u32::MAX, ..Budgets::default() }, ..quiet() });
for _ in 0..1000 {
raw.ping(*b"pingping");
}
let (_, frames) = feed(&mut srv, &raw.take(), 1);
assert_eq!(goaway(&frames), None);
}