use derusted::mitm::http2_parser::{
extract_http2_request, extract_http2_response, has_end_headers, has_end_stream,
is_client_stream, is_response_frame, parse_frame_header, parse_http2_frame, FrameType,
HpackDecoder,
};
#[test]
fn test_http2_connection_preface() {
let preface = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
assert_eq!(preface.len(), 24);
assert_eq!(&preface[0..3], b"PRI");
assert_eq!(&preface[18..20], b"SM");
}
#[test]
fn test_parse_settings_frame() {
let frame_data = [
0x00, 0x00, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x64, ];
let (frame_type, flags, stream_id, length) = parse_frame_header(&frame_data[0..9]).unwrap();
assert_eq!(frame_type, FrameType::Settings);
assert_eq!(flags, 0x00);
assert_eq!(stream_id, 0);
assert_eq!(length, 6);
let frame = parse_http2_frame(&frame_data).unwrap();
assert_eq!(frame.frame_type, FrameType::Settings);
assert_eq!(frame.stream_id, 0);
assert_eq!(frame.payload.len(), 6);
}
#[test]
fn test_parse_headers_frame_with_hpack() {
use hpack::Encoder;
let headers = vec![
(b":method".to_vec(), b"GET".to_vec()),
(b":path".to_vec(), b"/api/test".to_vec()),
(b":scheme".to_vec(), b"https".to_vec()),
(b":authority".to_vec(), b"example.com".to_vec()),
];
let mut encoder = Encoder::new();
let mut encoded = Vec::new();
let header_refs: Vec<(&[u8], &[u8])> = headers
.iter()
.map(|(n, v)| (n.as_slice(), v.as_slice()))
.collect();
encoder.encode_into(header_refs, &mut encoded).unwrap();
let length = encoded.len();
let mut frame_data = vec![
((length >> 16) & 0xFF) as u8,
((length >> 8) & 0xFF) as u8,
(length & 0xFF) as u8,
0x01, 0x05, 0x00,
0x00,
0x00,
0x01, ];
frame_data.extend_from_slice(&encoded);
let frame = parse_http2_frame(&frame_data).unwrap();
assert_eq!(frame.frame_type, FrameType::Headers);
assert_eq!(frame.stream_id, 1);
assert!(has_end_stream(&frame));
assert!(has_end_headers(&frame));
assert!(is_client_stream(frame.stream_id));
let mut decoder = HpackDecoder::new();
let request = extract_http2_request(&[frame], &mut decoder).unwrap();
assert_eq!(request.method, "GET");
assert_eq!(request.path, "/api/test");
assert_eq!(request.scheme, "https");
assert_eq!(request.authority, "example.com");
}
#[test]
fn test_parse_data_frame_with_body() {
let body = b"{\"key\":\"value\"}";
let length = body.len();
let mut frame_data = vec![
((length >> 16) & 0xFF) as u8,
((length >> 8) & 0xFF) as u8,
(length & 0xFF) as u8,
0x00, 0x01, 0x00,
0x00,
0x00,
0x01, ];
frame_data.extend_from_slice(body);
let frame = parse_http2_frame(&frame_data).unwrap();
assert_eq!(frame.frame_type, FrameType::Data);
assert_eq!(frame.stream_id, 1);
assert_eq!(frame.payload, body);
assert!(has_end_stream(&frame));
}
#[test]
fn test_parse_continuation_frame() {
use hpack::Encoder;
let headers_part1 = vec![
(b":method".to_vec(), b"POST".to_vec()),
(b":path".to_vec(), b"/api/upload".to_vec()),
];
let headers_part2 = vec![
(b":scheme".to_vec(), b"https".to_vec()),
(b":authority".to_vec(), b"example.com".to_vec()),
];
let mut encoder = Encoder::new();
let mut encoded1 = Vec::new();
let header_refs1: Vec<(&[u8], &[u8])> = headers_part1
.iter()
.map(|(n, v)| (n.as_slice(), v.as_slice()))
.collect();
encoder.encode_into(header_refs1, &mut encoded1).unwrap();
let mut encoded2 = Vec::new();
let header_refs2: Vec<(&[u8], &[u8])> = headers_part2
.iter()
.map(|(n, v)| (n.as_slice(), v.as_slice()))
.collect();
encoder.encode_into(header_refs2, &mut encoded2).unwrap();
let length1 = encoded1.len();
let mut frame1_data = vec![
((length1 >> 16) & 0xFF) as u8,
((length1 >> 8) & 0xFF) as u8,
(length1 & 0xFF) as u8,
0x01, 0x00, 0x00,
0x00,
0x00,
0x03, ];
frame1_data.extend_from_slice(&encoded1);
let length2 = encoded2.len();
let mut frame2_data = vec![
((length2 >> 16) & 0xFF) as u8,
((length2 >> 8) & 0xFF) as u8,
(length2 & 0xFF) as u8,
0x09, 0x04, 0x00,
0x00,
0x00,
0x03, ];
frame2_data.extend_from_slice(&encoded2);
let frame1 = parse_http2_frame(&frame1_data).unwrap();
let frame2 = parse_http2_frame(&frame2_data).unwrap();
assert_eq!(frame1.frame_type, FrameType::Headers);
assert_eq!(frame2.frame_type, FrameType::Continuation);
assert_eq!(frame1.stream_id, frame2.stream_id);
assert!(!has_end_headers(&frame1));
assert!(has_end_headers(&frame2));
let mut decoder = HpackDecoder::new();
let request = extract_http2_request(&[frame1, frame2], &mut decoder).unwrap();
assert_eq!(request.method, "POST");
assert_eq!(request.path, "/api/upload");
}
#[test]
fn test_parse_http2_response() {
use hpack::Encoder;
let headers = vec![
(b":status".to_vec(), b"200".to_vec()),
(b"content-type".to_vec(), b"application/json".to_vec()),
];
let mut encoder = Encoder::new();
let mut encoded = Vec::new();
let header_refs: Vec<(&[u8], &[u8])> = headers
.iter()
.map(|(n, v)| (n.as_slice(), v.as_slice()))
.collect();
encoder.encode_into(header_refs, &mut encoded).unwrap();
let length = encoded.len();
let mut headers_frame_data = vec![
((length >> 16) & 0xFF) as u8,
((length >> 8) & 0xFF) as u8,
(length & 0xFF) as u8,
0x01, 0x04, 0x00,
0x00,
0x00,
0x01, ];
headers_frame_data.extend_from_slice(&encoded);
let body = b"{\"result\":\"success\"}";
let body_length = body.len();
let mut data_frame_data = vec![
((body_length >> 16) & 0xFF) as u8,
((body_length >> 8) & 0xFF) as u8,
(body_length & 0xFF) as u8,
0x00, 0x01, 0x00,
0x00,
0x00,
0x01, ];
data_frame_data.extend_from_slice(body);
let headers_frame = parse_http2_frame(&headers_frame_data).unwrap();
let data_frame = parse_http2_frame(&data_frame_data).unwrap();
assert_eq!(headers_frame.stream_id, 1);
assert_eq!(data_frame.stream_id, 1);
assert!(is_client_stream(headers_frame.stream_id)); assert!(is_response_frame(&headers_frame));
let mut decoder = HpackDecoder::new();
let response = extract_http2_response(&[headers_frame, data_frame], &mut decoder).unwrap();
assert_eq!(response.status, 200);
assert_eq!(
response.headers.get("content-type").unwrap(),
"application/json"
);
assert!(response.body_preview.contains("success"));
}
#[test]
fn test_multiple_concurrent_streams() {
use hpack::Encoder;
let mut encoder = Encoder::new();
let headers1 = vec![
(b":method".to_vec(), b"GET".to_vec()),
(b":path".to_vec(), b"/api/users".to_vec()),
(b":scheme".to_vec(), b"https".to_vec()),
(b":authority".to_vec(), b"example.com".to_vec()),
];
let mut encoded1 = Vec::new();
let header_refs1: Vec<(&[u8], &[u8])> = headers1
.iter()
.map(|(n, v)| (n.as_slice(), v.as_slice()))
.collect();
encoder.encode_into(header_refs1, &mut encoded1).unwrap();
let headers3 = vec![
(b":method".to_vec(), b"POST".to_vec()),
(b":path".to_vec(), b"/api/orders".to_vec()),
(b":scheme".to_vec(), b"https".to_vec()),
(b":authority".to_vec(), b"example.com".to_vec()),
];
let mut encoded3 = Vec::new();
let header_refs3: Vec<(&[u8], &[u8])> = headers3
.iter()
.map(|(n, v)| (n.as_slice(), v.as_slice()))
.collect();
encoder.encode_into(header_refs3, &mut encoded3).unwrap();
let length1 = encoded1.len();
let mut frame1_data = vec![
((length1 >> 16) & 0xFF) as u8,
((length1 >> 8) & 0xFF) as u8,
(length1 & 0xFF) as u8,
0x01,
0x05, 0x00,
0x00,
0x00,
0x01, ];
frame1_data.extend_from_slice(&encoded1);
let length3 = encoded3.len();
let mut frame3_data = vec![
((length3 >> 16) & 0xFF) as u8,
((length3 >> 8) & 0xFF) as u8,
(length3 & 0xFF) as u8,
0x01,
0x04, 0x00,
0x00,
0x00,
0x03, ];
frame3_data.extend_from_slice(&encoded3);
let frame1 = parse_http2_frame(&frame1_data).unwrap();
let frame3 = parse_http2_frame(&frame3_data).unwrap();
assert_eq!(frame1.stream_id, 1);
assert_eq!(frame3.stream_id, 3);
assert!(is_client_stream(frame1.stream_id));
assert!(is_client_stream(frame3.stream_id));
let mut decoder1 = HpackDecoder::new();
let request1 = extract_http2_request(&[frame1], &mut decoder1).unwrap();
assert_eq!(request1.method, "GET");
assert_eq!(request1.path, "/api/users");
let mut decoder3 = HpackDecoder::new();
let request3 = extract_http2_request(&[frame3], &mut decoder3).unwrap();
assert_eq!(request3.method, "POST");
assert_eq!(request3.path, "/api/orders");
}
#[test]
fn test_parse_goaway_frame() {
let frame_data = [
0x00, 0x00, 0x08, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, ];
let frame = parse_http2_frame(&frame_data).unwrap();
assert_eq!(frame.frame_type, FrameType::GoAway);
assert_eq!(frame.stream_id, 0); assert_eq!(frame.payload.len(), 8);
}
#[test]
fn test_parse_rst_stream_frame() {
let frame_data = [
0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, ];
let frame = parse_http2_frame(&frame_data).unwrap();
assert_eq!(frame.frame_type, FrameType::RstStream);
assert_eq!(frame.stream_id, 7);
assert_eq!(frame.payload, vec![0x00, 0x00, 0x00, 0x08]);
}
#[test]
fn test_body_preview_truncation() {
use hpack::Encoder;
let headers = vec![
(b":status".to_vec(), b"200".to_vec()),
(b"content-type".to_vec(), b"text/plain".to_vec()),
];
let mut encoder = Encoder::new();
let mut encoded = Vec::new();
let header_refs: Vec<(&[u8], &[u8])> = headers
.iter()
.map(|(n, v)| (n.as_slice(), v.as_slice()))
.collect();
encoder.encode_into(header_refs, &mut encoded).unwrap();
let length = encoded.len();
let mut headers_frame_data = vec![
((length >> 16) & 0xFF) as u8,
((length >> 8) & 0xFF) as u8,
(length & 0xFF) as u8,
0x01,
0x04, 0x00,
0x00,
0x00,
0x01, ];
headers_frame_data.extend_from_slice(&encoded);
let body = vec![b'A'; 2048];
let body_length = body.len();
let mut data_frame_data = vec![
((body_length >> 16) & 0xFF) as u8,
((body_length >> 8) & 0xFF) as u8,
(body_length & 0xFF) as u8,
0x00,
0x01, 0x00,
0x00,
0x00,
0x01, ];
data_frame_data.extend_from_slice(&body);
let headers_frame = parse_http2_frame(&headers_frame_data).unwrap();
let data_frame = parse_http2_frame(&data_frame_data).unwrap();
let mut decoder = HpackDecoder::new();
let response = extract_http2_response(&[headers_frame, data_frame], &mut decoder).unwrap();
assert!(response.body_preview.len() <= 1024);
assert_eq!(response.content_length, Some(2048));
}