huginn_net_http/
http2_parser.rs

1use crate::http;
2use crate::http_common::{HeaderSource, HttpCookie, HttpHeader, ParsingMetadata};
3use hpack_patched::Decoder;
4use std::cell::RefCell;
5use std::collections::HashMap;
6use std::time::Instant;
7
8pub const HTTP2_CONNECTION_PREFACE: &[u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
9
10#[derive(Debug, Clone, PartialEq)]
11#[repr(u8)]
12pub enum Http2FrameType {
13    Data = 0x0,
14    Headers = 0x1,
15    Priority = 0x2,
16    RstStream = 0x3,
17    Settings = 0x4,
18    PushPromise = 0x5,
19    Ping = 0x6,
20    GoAway = 0x7,
21    WindowUpdate = 0x8,
22    Continuation = 0x9,
23    Unknown(u8),
24}
25
26impl From<u8> for Http2FrameType {
27    fn from(frame_type: u8) -> Self {
28        match frame_type {
29            0x0 => Http2FrameType::Data,
30            0x1 => Http2FrameType::Headers,
31            0x2 => Http2FrameType::Priority,
32            0x3 => Http2FrameType::RstStream,
33            0x4 => Http2FrameType::Settings,
34            0x5 => Http2FrameType::PushPromise,
35            0x6 => Http2FrameType::Ping,
36            0x7 => Http2FrameType::GoAway,
37            0x8 => Http2FrameType::WindowUpdate,
38            0x9 => Http2FrameType::Continuation,
39            other => Http2FrameType::Unknown(other),
40        }
41    }
42}
43
44#[derive(Debug, Clone)]
45pub struct Http2Frame {
46    pub frame_type: Http2FrameType,
47    pub stream_id: u32,
48    pub flags: u8,
49    pub payload: Vec<u8>,
50    pub length: u32,
51}
52
53#[derive(Debug, Clone, Default)]
54pub struct Http2Settings {
55    pub header_table_size: Option<u32>,
56    pub enable_push: Option<bool>,
57    pub max_concurrent_streams: Option<u32>,
58    pub initial_window_size: Option<u32>,
59    pub max_frame_size: Option<u32>,
60    pub max_header_list_size: Option<u32>,
61}
62
63#[derive(Debug, Clone)]
64pub struct Http2Stream {
65    pub stream_id: u32,
66    pub headers: Vec<HttpHeader>,
67    pub method: Option<String>,
68    pub path: Option<String>,
69    pub authority: Option<String>,
70    pub scheme: Option<String>,
71    pub status: Option<u16>,
72}
73
74pub struct Http2Config {
75    pub max_frame_size: u32,
76    pub max_streams: u32,
77    pub enable_hpack: bool,
78    pub strict_parsing: bool,
79}
80
81impl Default for Http2Config {
82    fn default() -> Self {
83        Self {
84            max_frame_size: 16384,
85            max_streams: 100,
86            enable_hpack: false,
87            strict_parsing: false,
88        }
89    }
90}
91
92#[derive(Debug, Clone)]
93pub struct Http2Request {
94    pub method: String,
95    pub path: String,
96    pub authority: Option<String>,
97    pub scheme: Option<String>,
98    pub version: http::Version,
99    pub headers: Vec<HttpHeader>,
100    pub cookies: Vec<HttpCookie>,
101    pub referer: Option<String>,
102    pub stream_id: u32,
103    pub parsing_metadata: ParsingMetadata,
104    pub frame_sequence: Vec<Http2FrameType>,
105    pub settings: Http2Settings,
106}
107
108#[derive(Debug, Clone)]
109pub struct Http2Response {
110    pub status: u16,
111    pub version: http::Version,
112    pub headers: Vec<HttpHeader>,
113    pub stream_id: u32,
114    pub parsing_metadata: ParsingMetadata,
115    pub frame_sequence: Vec<Http2FrameType>,
116    pub server: Option<String>,
117    pub content_type: Option<String>,
118}
119
120#[derive(Debug, Clone)]
121pub enum Http2ParseError {
122    InvalidPreface,
123    InvalidFrameHeader,
124    InvalidFrameLength(u32),
125    InvalidStreamId(u32),
126    FrameTooLarge(u32),
127    MissingRequiredHeaders,
128    InvalidPseudoHeader(String),
129    IncompleteFrame,
130    InvalidUtf8,
131    UnsupportedFeature(String),
132    HpackDecodingFailed,
133}
134
135impl std::fmt::Display for Http2ParseError {
136    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137        match self {
138            Self::InvalidPreface => write!(f, "Invalid HTTP/2 connection preface"),
139            Self::InvalidFrameHeader => write!(f, "Invalid HTTP/2 frame header"),
140            Self::InvalidFrameLength(len) => write!(f, "Invalid frame length: {len}"),
141            Self::InvalidStreamId(id) => write!(f, "Invalid stream ID: {id}"),
142            Self::FrameTooLarge(size) => write!(f, "Frame too large: {size} bytes"),
143            Self::MissingRequiredHeaders => write!(f, "Missing required pseudo-headers"),
144            Self::InvalidPseudoHeader(name) => write!(f, "Invalid pseudo-header: {name}"),
145            Self::IncompleteFrame => write!(f, "Incomplete HTTP/2 frame"),
146            Self::InvalidUtf8 => write!(f, "Invalid UTF-8 in HTTP/2 data"),
147            Self::UnsupportedFeature(feature) => write!(f, "Unsupported feature: {feature}"),
148            Self::HpackDecodingFailed => write!(f, "HPACK decoding failed"),
149        }
150    }
151}
152
153impl std::error::Error for Http2ParseError {}
154
155/// HTTP/2 Protocol Parser
156///
157/// Provides parsing capabilities for HTTP/2 requests and responses according to RFC 7540.
158/// Supports HPACK header compression and handles various frame types.
159///
160/// # Thread Safety
161///
162/// **This parser is NOT thread-safe.** Each thread should create its own instance.
163/// The internal HPACK decoder maintains state and uses `RefCell` for interior mutability.
164pub struct Http2Parser<'a> {
165    config: Http2Config,
166    hpack_decoder: RefCell<Decoder<'a>>,
167}
168
169impl<'a> Default for Http2Parser<'a> {
170    fn default() -> Self {
171        Self::new()
172    }
173}
174
175impl<'a> Http2Parser<'a> {
176    pub fn new() -> Self {
177        Self {
178            config: Http2Config::default(),
179            hpack_decoder: RefCell::new(Decoder::new()),
180        }
181    }
182
183    /// Parse HTTP/2 request from binary data
184    pub fn parse_request(&self, data: &[u8]) -> Result<Option<Http2Request>, Http2ParseError> {
185        let start_time = Instant::now();
186
187        if !self.has_http2_preface(data) {
188            return Err(Http2ParseError::InvalidPreface);
189        }
190
191        let frame_data = &data[HTTP2_CONNECTION_PREFACE.len()..];
192        let frames = self.parse_frames(frame_data)?;
193
194        if frames.is_empty() {
195            return Ok(None);
196        }
197
198        let Some(stream_id) = self.find_primary_stream(&frames) else {
199            return Ok(None);
200        };
201        let stream = self.build_stream(stream_id, &frames)?;
202
203        let method = stream
204            .method
205            .ok_or(Http2ParseError::MissingRequiredHeaders)?;
206        let path = stream.path.ok_or(Http2ParseError::MissingRequiredHeaders)?;
207
208        let parsing_time = start_time.elapsed().as_nanos() as u64;
209        let frame_sequence: Vec<Http2FrameType> =
210            frames.iter().map(|f| f.frame_type.clone()).collect();
211
212        let mut headers = Vec::new();
213        let mut headers_map = HashMap::new();
214        let mut referer: Option<String> = None;
215        let mut cookie_headers: Vec<&HttpHeader> = Vec::new();
216
217        for header in &stream.headers {
218            let header_name_lower = header.name.to_lowercase();
219
220            if header_name_lower == "cookie" {
221                cookie_headers.push(header);
222            } else if header_name_lower == "referer" {
223                if let Some(ref value) = header.value {
224                    referer = Some(value.clone());
225                }
226            } else {
227                if let Some(ref value) = header.value {
228                    headers_map.insert(header_name_lower, value.clone());
229                }
230                // Clone the header to move into the filtered headers vec
231                headers.push(header.clone());
232            }
233        }
234
235        let cookies = self.parse_cookies_from_headers(&cookie_headers);
236
237        let metadata = ParsingMetadata {
238            header_count: headers.len(),
239            duplicate_headers: Vec::new(),
240            case_variations: HashMap::new(),
241            parsing_time_ns: parsing_time,
242            has_malformed_headers: false,
243            request_line_length: 0,
244            total_headers_length: headers
245                .iter()
246                .map(|h| {
247                    h.name
248                        .len()
249                        .saturating_add(h.value.as_ref().map_or(0, |v| v.len()))
250                })
251                .sum(),
252        };
253
254        Ok(Some(Http2Request {
255            method,
256            path,
257            authority: stream.authority,
258            scheme: stream.scheme,
259            version: http::Version::V20,
260            headers,
261            cookies,
262            referer,
263            stream_id,
264            parsing_metadata: metadata,
265            frame_sequence,
266            settings: self.extract_settings(&frames),
267        }))
268    }
269
270    /// Parse HTTP/2 response from binary data
271    pub fn parse_response(&self, data: &[u8]) -> Result<Option<Http2Response>, Http2ParseError> {
272        let start_time = Instant::now();
273
274        let frames = self.parse_frames(data)?;
275
276        if frames.is_empty() {
277            return Ok(None);
278        }
279
280        let Some(stream_id) = self.find_primary_stream(&frames) else {
281            return Ok(None);
282        };
283        let stream = self.build_stream(stream_id, &frames)?;
284
285        let status = stream
286            .status
287            .ok_or(Http2ParseError::MissingRequiredHeaders)?;
288
289        let parsing_time = start_time.elapsed().as_nanos() as u64;
290        let frame_sequence: Vec<Http2FrameType> =
291            frames.iter().map(|f| f.frame_type.clone()).collect();
292
293        let mut headers_map = HashMap::new();
294        for header in &stream.headers {
295            if let Some(ref value) = header.value {
296                headers_map.insert(header.name.to_lowercase(), value.clone());
297            }
298        }
299
300        let metadata = ParsingMetadata {
301            header_count: stream.headers.len(),
302            duplicate_headers: Vec::new(),
303            case_variations: HashMap::new(),
304            parsing_time_ns: parsing_time,
305            has_malformed_headers: false,
306            request_line_length: 0,
307            total_headers_length: stream
308                .headers
309                .iter()
310                .map(|h| {
311                    h.name
312                        .len()
313                        .saturating_add(h.value.as_ref().map_or(0, |v| v.len()))
314                })
315                .sum(),
316        };
317
318        Ok(Some(Http2Response {
319            status,
320            version: http::Version::V20,
321            headers: stream.headers,
322            stream_id,
323            parsing_metadata: metadata,
324            frame_sequence,
325            server: headers_map.get("server").cloned(),
326            content_type: headers_map.get("content-type").cloned(),
327        }))
328    }
329
330    fn has_http2_preface(&self, data: &[u8]) -> bool {
331        data.starts_with(HTTP2_CONNECTION_PREFACE)
332    }
333
334    fn parse_frames(&self, data: &[u8]) -> Result<Vec<Http2Frame>, Http2ParseError> {
335        let mut frames = Vec::new();
336        let mut remaining = data;
337
338        while remaining.len() >= 9 {
339            // Check if we have enough data for the complete frame
340            let frame_length = u32::from_be_bytes([0, remaining[0], remaining[1], remaining[2]]);
341            let frame_total_size = match usize::try_from(9_u32.saturating_add(frame_length)) {
342                Ok(size) => size,
343                Err(_) => break, // Frame too large, skip remaining data
344            };
345
346            if remaining.len() < frame_total_size {
347                // Incomplete frame at the end, stop parsing here
348                break;
349            }
350
351            match self.parse_single_frame(remaining) {
352                Ok((rest, frame)) => {
353                    frames.push(frame);
354                    remaining = rest;
355                }
356                Err(_) => {
357                    // Skip this frame and continue
358                    break;
359                }
360            }
361        }
362
363        Ok(frames)
364    }
365
366    fn parse_single_frame<'b>(
367        &self,
368        data: &'b [u8],
369    ) -> Result<(&'b [u8], Http2Frame), Http2ParseError> {
370        if data.len() < 9 {
371            return Err(Http2ParseError::IncompleteFrame);
372        }
373
374        let length = u32::from_be_bytes([0, data[0], data[1], data[2]]);
375        let frame_type_byte = data[3];
376        let flags = data[4];
377        let stream_id = u32::from_be_bytes([data[5], data[6], data[7], data[8]]) & 0x7FFF_FFFF;
378
379        if length > self.config.max_frame_size {
380            return Err(Http2ParseError::FrameTooLarge(length));
381        }
382
383        let frame_total_size = match usize::try_from(9_u32.saturating_add(length)) {
384            Ok(size) => size,
385            Err(_) => return Err(Http2ParseError::FrameTooLarge(length)),
386        };
387
388        if data.len() < frame_total_size {
389            return Err(Http2ParseError::IncompleteFrame);
390        }
391
392        let payload_start = 9;
393        let payload_end = frame_total_size;
394        let payload = data[payload_start..payload_end].to_vec();
395
396        let frame = Http2Frame {
397            frame_type: Http2FrameType::from(frame_type_byte),
398            stream_id,
399            flags,
400            payload,
401            length,
402        };
403
404        Ok((&data[payload_end..], frame))
405    }
406
407    fn find_primary_stream(&self, frames: &[Http2Frame]) -> Option<u32> {
408        for frame in frames {
409            if frame.stream_id > 0 && frame.frame_type == Http2FrameType::Headers {
410                return Some(frame.stream_id);
411            }
412        }
413        None
414    }
415
416    fn build_stream(
417        &self,
418        stream_id: u32,
419        frames: &[Http2Frame],
420    ) -> Result<Http2Stream, Http2ParseError> {
421        let mut headers = Vec::new();
422        let mut method = None;
423        let mut path = None;
424        let mut authority = None;
425        let mut scheme = None;
426        let mut status = None;
427
428        let stream_frames: Vec<&Http2Frame> =
429            frames.iter().filter(|f| f.stream_id == stream_id).collect();
430
431        for frame in stream_frames {
432            match frame.frame_type {
433                Http2FrameType::Headers | Http2FrameType::Continuation => {
434                    let frame_headers = self.parse_headers_payload(&frame.payload)?;
435                    for header in frame_headers {
436                        match header.name.as_str() {
437                            ":method" => method = Some(header.value.clone().unwrap_or_default()),
438                            ":path" => path = Some(header.value.clone().unwrap_or_default()),
439                            ":authority" => {
440                                authority = Some(header.value.clone().unwrap_or_default())
441                            }
442                            ":scheme" => scheme = Some(header.value.clone().unwrap_or_default()),
443                            ":status" => {
444                                status = header.value.as_ref().and_then(|v| v.parse().ok())
445                            }
446                            _ => headers.push(header),
447                        }
448                    }
449                }
450                _ => {}
451            }
452        }
453
454        Ok(Http2Stream {
455            stream_id,
456            headers,
457            method,
458            path,
459            authority,
460            scheme,
461            status,
462        })
463    }
464
465    fn parse_headers_payload(&self, payload: &[u8]) -> Result<Vec<HttpHeader>, Http2ParseError> {
466        let headers = self
467            .hpack_decoder
468            .borrow_mut()
469            .decode(payload)
470            .map_err(|_| Http2ParseError::HpackDecodingFailed)?;
471
472        let mut http_headers = Vec::new();
473
474        for (position, (name, value)) in headers.iter().enumerate() {
475            let name_str = String::from_utf8_lossy(name).to_string();
476            let value_str = String::from_utf8_lossy(value);
477            let value_opt = if value_str.is_empty() {
478                None
479            } else {
480                Some(value_str.to_string())
481            };
482
483            http_headers.push(HttpHeader {
484                name: name_str,
485                value: value_opt,
486                position,
487                source: HeaderSource::Http2Header,
488            });
489        }
490
491        Ok(http_headers)
492    }
493
494    fn extract_settings(&self, frames: &[Http2Frame]) -> Http2Settings {
495        let mut settings = Http2Settings::default();
496
497        for frame in frames {
498            if frame.frame_type == Http2FrameType::Settings {
499                let payload = &frame.payload;
500                for chunk in payload.chunks_exact(6) {
501                    if chunk.len() == 6 {
502                        let id = u16::from_be_bytes([chunk[0], chunk[1]]);
503                        let value = u32::from_be_bytes([chunk[2], chunk[3], chunk[4], chunk[5]]);
504
505                        match id {
506                            1 => settings.header_table_size = Some(value),
507                            2 => settings.enable_push = Some(value != 0),
508                            3 => settings.max_concurrent_streams = Some(value),
509                            4 => settings.initial_window_size = Some(value),
510                            5 => settings.max_frame_size = Some(value),
511                            6 => settings.max_header_list_size = Some(value),
512                            _ => {}
513                        }
514                    }
515                }
516            }
517        }
518
519        settings
520    }
521
522    /// HTTP/2 cookie parsing - handles multiple cookie headers according to RFC 7540
523    fn parse_cookies_from_headers(&self, cookie_headers: &[&HttpHeader]) -> Vec<HttpCookie> {
524        let mut cookies = Vec::new();
525        let mut position = 0;
526
527        for header in cookie_headers {
528            if let Some(ref cookie_value) = header.value {
529                // Each cookie header can contain multiple cookies separated by '; '
530                for cookie_str in cookie_value.split(';') {
531                    let cookie_str = cookie_str.trim();
532                    if cookie_str.is_empty() {
533                        continue;
534                    }
535
536                    if let Some(eq_pos) = cookie_str.find('=') {
537                        let name = cookie_str[..eq_pos].trim().to_string();
538                        let value = Some(
539                            cookie_str
540                                .get(eq_pos.saturating_add(1)..)
541                                .unwrap_or("")
542                                .trim()
543                                .to_string(),
544                        );
545                        cookies.push(HttpCookie {
546                            name,
547                            value,
548                            position,
549                        });
550                    } else {
551                        cookies.push(HttpCookie {
552                            name: cookie_str.to_string(),
553                            value: None,
554                            position,
555                        });
556                    }
557                    position = position.saturating_add(1);
558                }
559            }
560        }
561
562        cookies
563    }
564}
565
566pub fn is_http2_traffic(data: &[u8]) -> bool {
567    data.starts_with(HTTP2_CONNECTION_PREFACE)
568}
569
570#[cfg(test)]
571mod tests {
572    use super::*;
573
574    fn assert_parser_error<T>(
575        result: Result<Option<T>, Http2ParseError>,
576        expected_discriminant: Http2ParseError,
577    ) {
578        match result {
579            Err(actual) => assert_eq!(
580                std::mem::discriminant(&actual),
581                std::mem::discriminant(&expected_discriminant),
582                "Expected error type {expected_discriminant:?} but got {actual:?}"
583            ),
584            Ok(_) => panic!("Expected error {expected_discriminant:?} but got Ok"),
585        }
586    }
587
588    fn create_http2_frame(frame_type: u8, stream_id: u32, payload: &[u8]) -> Vec<u8> {
589        let mut frame = Vec::new();
590
591        // Length (24 bits)
592        let length = payload.len() as u32;
593        frame.push(((length >> 16) & 0xFF) as u8);
594        frame.push(((length >> 8) & 0xFF) as u8);
595        frame.push((length & 0xFF) as u8);
596
597        // Type (8 bits)
598        frame.push(frame_type);
599
600        // Flags (8 bits)
601        frame.push(0x00);
602
603        // Stream ID (32 bits, with R bit cleared)
604        frame.extend_from_slice(&(stream_id & 0x7FFFFFFF).to_be_bytes());
605
606        // Payload
607        frame.extend_from_slice(payload);
608
609        frame
610    }
611
612    fn create_http2_request_with_preface(frames: &[Vec<u8>]) -> Vec<u8> {
613        let mut data = Vec::from(HTTP2_CONNECTION_PREFACE);
614        for frame in frames {
615            data.extend_from_slice(frame);
616        }
617        data
618    }
619
620    #[test]
621    fn test_http2_preface_detection() {
622        let http2_data = HTTP2_CONNECTION_PREFACE;
623        assert!(is_http2_traffic(http2_data));
624
625        let http1_data = b"GET / HTTP/1.1\r\n";
626        assert!(!is_http2_traffic(http1_data));
627
628        // Edge case: partial preface
629        let partial_preface = &HTTP2_CONNECTION_PREFACE[..10];
630        assert!(!is_http2_traffic(partial_preface));
631
632        // Edge case: empty data
633        assert!(!is_http2_traffic(&[]));
634    }
635
636    #[test]
637    fn test_frame_type_conversion() {
638        assert_eq!(Http2FrameType::from(0x0), Http2FrameType::Data);
639        assert_eq!(Http2FrameType::from(0x1), Http2FrameType::Headers);
640        assert_eq!(Http2FrameType::from(0x2), Http2FrameType::Priority);
641        assert_eq!(Http2FrameType::from(0x3), Http2FrameType::RstStream);
642        assert_eq!(Http2FrameType::from(0x4), Http2FrameType::Settings);
643        assert_eq!(Http2FrameType::from(0x5), Http2FrameType::PushPromise);
644        assert_eq!(Http2FrameType::from(0x6), Http2FrameType::Ping);
645        assert_eq!(Http2FrameType::from(0x7), Http2FrameType::GoAway);
646        assert_eq!(Http2FrameType::from(0x8), Http2FrameType::WindowUpdate);
647        assert_eq!(Http2FrameType::from(0x9), Http2FrameType::Continuation);
648        assert_eq!(Http2FrameType::from(0xFF), Http2FrameType::Unknown(0xFF));
649    }
650
651    #[test]
652    fn test_invalid_preface() {
653        let parser = Http2Parser::new();
654        let invalid_data = b"GET / HTTP/1.1\r\n\r\n";
655
656        assert_parser_error(
657            parser.parse_request(invalid_data),
658            Http2ParseError::InvalidPreface,
659        );
660    }
661
662    #[test]
663    fn test_empty_data() {
664        let parser = Http2Parser::new();
665
666        // Empty data should fail preface check
667        assert_parser_error(parser.parse_request(&[]), Http2ParseError::InvalidPreface);
668
669        // Only preface, no frames
670        let result = parser.parse_request(HTTP2_CONNECTION_PREFACE);
671        match result {
672            Ok(None) => {} // Expected: no request without frames
673            Ok(Some(_)) => panic!("Should not return a request without frames"),
674            Err(e) => panic!("Should not error: {e:?}"),
675        }
676    }
677
678    #[test]
679    fn test_incomplete_frame_header() {
680        let parser = Http2Parser::new();
681
682        // Preface + incomplete frame header (less than 9 bytes)
683        let mut data = Vec::from(HTTP2_CONNECTION_PREFACE);
684        data.extend_from_slice(&[0x00, 0x00, 0x00, 0x01]); // Only 4 bytes of frame header
685
686        let result = parser.parse_request(&data);
687        match result {
688            Ok(None) => {} // Expected: incomplete data
689            Ok(Some(_)) => panic!("Should not return a request with incomplete data"),
690            Err(e) => panic!("Should not error: {e:?}"),
691        }
692    }
693
694    #[test]
695    fn test_frame_too_large() {
696        let parser = Http2Parser::new();
697
698        // Create frame with length exceeding max_frame_size (16384)
699        let large_length = 20000u32;
700        let mut frame = Vec::new();
701
702        // Length (24 bits) - exceeds max_frame_size
703        frame.push(((large_length >> 16) & 0xFF) as u8);
704        frame.push(((large_length >> 8) & 0xFF) as u8);
705        frame.push((large_length & 0xFF) as u8);
706
707        // Complete frame header
708        frame.extend_from_slice(&[0x01, 0x00, 0x00, 0x00, 0x00, 0x01]); // Headers frame, stream 1
709
710        let data = create_http2_request_with_preface(&[frame]);
711        let result = parser.parse_request(&data);
712        match result {
713            Ok(None) => {} // Expected: frame too large
714            Ok(Some(_)) => panic!("Should not return a request with frame too large"),
715            Err(e) => panic!("Should not error: {e:?}"),
716        }
717    }
718
719    #[test]
720    fn test_incomplete_frame_payload() {
721        let parser = Http2Parser::new();
722
723        // Frame header says 100 bytes payload, but we only provide 50
724        let mut frame = Vec::new();
725        frame.extend_from_slice(&[0x00, 0x00, 0x64]); // Length: 100
726        frame.extend_from_slice(&[0x01, 0x00, 0x00, 0x00, 0x00, 0x01]); // Headers frame, stream 1
727        frame.extend_from_slice(&[0x00; 50]); // Only 50 bytes instead of 100
728
729        let data = create_http2_request_with_preface(&[frame]);
730        let result = parser.parse_request(&data);
731        match result {
732            Ok(None) => {} // Expected: incomplete payload
733            Ok(Some(_)) => panic!("Should not return a request with incomplete payload"),
734            Err(e) => panic!("Should not error: {e:?}"),
735        }
736    }
737
738    #[test]
739    fn test_zero_length_frame() {
740        let parser = Http2Parser::new();
741
742        // Valid zero-length frame
743        let frame = create_http2_frame(0x04, 0, &[]); // Settings frame with no payload
744        let data = create_http2_request_with_preface(&[frame]);
745
746        let result = parser.parse_request(&data);
747        match result {
748            Ok(None) => {} // Expected: no headers frame
749            Ok(Some(_)) => panic!("Should not return a request without headers frame"),
750            Err(e) => panic!("Should not error: {e:?}"),
751        }
752    }
753
754    #[test]
755    fn test_maximum_valid_frame_size() {
756        let parser = Http2Parser::new();
757
758        // Frame with exactly max_frame_size (16384 bytes)
759        let max_payload = vec![0x00; 16384];
760        let frame = create_http2_frame(0x00, 1, &max_payload); // Data frame
761        let data = create_http2_request_with_preface(&[frame]);
762
763        let result = parser.parse_request(&data);
764        match result {
765            Ok(None) => {} // Expected: no headers frame, only data frame
766            Ok(Some(_)) => panic!("Should not return a request without headers frame"),
767            Err(e) => panic!("Should not error: {e:?}"),
768        }
769    }
770
771    #[test]
772    fn test_invalid_stream_id_zero_for_headers() {
773        let parser = Http2Parser::new();
774
775        // Headers frame with stream ID 0 (invalid)
776        let frame = create_http2_frame(0x01, 0, &[0x00]); // Headers frame, stream 0
777        let data = create_http2_request_with_preface(&[frame]);
778
779        let result = parser.parse_request(&data);
780        match result {
781            Ok(None) => {} // Expected: invalid stream ID 0
782            Ok(Some(_)) => panic!("Should not return a request with invalid stream ID"),
783            Err(e) => panic!("Should not error: {e:?}"),
784        }
785    }
786
787    #[test]
788    fn test_multiple_frames_parsing() {
789        let parser = Http2Parser::new();
790
791        // Multiple frames: Settings + Headers
792        let settings_frame = create_http2_frame(0x04, 0, &[]); // Settings frame
793        let headers_frame = create_http2_frame(0x01, 1, &[0x00]); // Headers frame
794
795        let data = create_http2_request_with_preface(&[settings_frame, headers_frame]);
796        let result = parser.parse_request(&data);
797
798        // Should handle gracefully - either Ok(None) or Err due to invalid HPACK
799        match result {
800            Ok(None) => {
801                // Expected: no valid request parsed due to invalid HPACK
802            }
803            Err(Http2ParseError::HpackDecodingFailed) => {
804                // Also expected: HPACK decoding failed
805            }
806            other => {
807                panic!("Unexpected result: {other:?}");
808            }
809        }
810    }
811
812    #[test]
813    fn test_arithmetic_overflow_protection() {
814        let parser = Http2Parser::new();
815
816        // Test frame length that would cause overflow when added to 9
817        let mut frame = Vec::new();
818        frame.extend_from_slice(&[0xFF, 0xFF, 0xFF]); // Maximum 24-bit length
819        frame.extend_from_slice(&[0x01, 0x00, 0x00, 0x00, 0x00, 0x01]); // Headers frame
820
821        let data = create_http2_request_with_preface(&[frame]);
822        let result = parser.parse_request(&data);
823
824        // Should handle overflow gracefully without panicking
825        assert!(result.is_ok());
826    }
827
828    #[test]
829    fn test_hpack_decoding_failure() {
830        let parser = Http2Parser::new();
831
832        // Headers frame with invalid HPACK data
833        let invalid_hpack = vec![0xFF; 10]; // Invalid HPACK data
834        let frame = create_http2_frame(0x01, 1, &invalid_hpack);
835        let data = create_http2_request_with_preface(&[frame]);
836
837        let result = parser.parse_request(&data);
838        // Should handle HPACK decoding failure gracefully
839        match result {
840            Ok(None) => {} // Expected: HPACK decoding failed or no valid request
841            Ok(Some(_)) => panic!("Should not return a request with HPACK decoding failure"),
842            Err(_) => {} // Also expected: HPACK decoding error
843        }
844    }
845
846    #[test]
847    fn test_missing_required_headers() {
848        let parser = Http2Parser::new();
849
850        // This test would require valid HPACK encoding without required pseudo-headers
851        // For now, we test the error path exists
852        let frame = create_http2_frame(0x01, 1, &[0x00]);
853        let data = create_http2_request_with_preface(&[frame]);
854
855        let result = parser.parse_request(&data);
856        // Should either fail HPACK decoding or missing headers check
857        match result {
858            Ok(None) => {} // Expected: missing required headers or HPACK failure
859            Ok(Some(_)) => panic!("Should not return a request with missing required headers"),
860            Err(_) => {} // Also expected: HPACK decoding error
861        }
862    }
863
864    #[test]
865    fn test_response_parsing_without_preface() {
866        let parser = Http2Parser::new();
867
868        // Response parsing doesn't require preface
869        let frame = create_http2_frame(0x01, 1, &[0x00]); // Headers frame
870
871        let result = parser.parse_response(&frame);
872        // Should handle gracefully (likely HPACK failure)
873        match result {
874            Ok(None) => {} // Expected: HPACK failure or no valid response
875            Ok(Some(_)) => panic!("Should not return a response with HPACK failure"),
876            Err(_) => {} // Also expected: HPACK decoding error
877        }
878    }
879
880    #[test]
881    fn test_frame_parsing_edge_cases() {
882        let parser = Http2Parser::new();
883
884        // Test various edge cases in frame parsing
885        let test_cases = [
886            // Case 1: Frame with reserved bit set in stream ID
887            {
888                let mut frame = create_http2_frame(0x01, 1, &[0x00]);
889                // Set reserved bit in stream ID
890                frame[5] |= 0x80;
891                frame
892            },
893            // Case 2: Continuation frame (should be handled)
894            create_http2_frame(0x09, 1, &[0x00]),
895            // Case 3: Unknown frame type
896            create_http2_frame(0xFF, 1, &[0x00]),
897        ];
898
899        for (i, frame) in test_cases.iter().enumerate() {
900            let data = create_http2_request_with_preface(std::slice::from_ref(frame));
901            let result = parser.parse_request(&data);
902
903            // All should handle gracefully without panicking
904            assert!(result.is_ok() || result.is_err(), "Test case {i} failed");
905        }
906    }
907
908    #[test]
909    fn test_settings_frame_parsing() {
910        let parser = Http2Parser::new();
911
912        // Valid settings frame with some settings
913        let mut settings_payload = Vec::new();
914
915        // SETTINGS_HEADER_TABLE_SIZE = 4096
916        settings_payload.extend_from_slice(&[0x00, 0x01]); // ID
917        settings_payload.extend_from_slice(&[0x00, 0x00, 0x10, 0x00]); // Value: 4096
918
919        // SETTINGS_ENABLE_PUSH = 0
920        settings_payload.extend_from_slice(&[0x00, 0x02]); // ID
921        settings_payload.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]); // Value: 0
922
923        let settings_frame = create_http2_frame(0x04, 0, &settings_payload);
924        let headers_frame = create_http2_frame(0x01, 1, &[0x00]);
925
926        let data = create_http2_request_with_preface(&[settings_frame, headers_frame]);
927        let result = parser.parse_request(&data);
928
929        // Should parse settings and attempt headers (likely fail on HPACK)
930        assert!(result.is_ok() || result.is_err());
931    }
932
933    #[test]
934    fn test_cookie_parsing_edge_cases() {
935        use crate::http_common::HttpHeader;
936        let parser = Http2Parser::new();
937
938        let test_cases = vec![
939            ("", 0),
940            ("name=value", 1),
941            ("name=", 1),
942            ("name", 1),
943            ("name=value; other=test", 2),
944            ("  name  =  value  ", 1),
945            ("name=value;", 1),
946            (";name=value", 1),
947            ("name=value;;other=test", 2),
948        ];
949
950        for (cookie_str, expected_count) in test_cases {
951            let headers = [HttpHeader {
952                name: "cookie".to_string(),
953                value: if cookie_str.is_empty() {
954                    None
955                } else {
956                    Some(cookie_str.to_string())
957                },
958                position: 0,
959                source: crate::http_common::HeaderSource::Http2Header,
960            }];
961
962            let cookie_headers: Vec<&HttpHeader> = headers
963                .iter()
964                .filter(|h| h.name.to_lowercase() == "cookie")
965                .collect();
966            let cookies = parser.parse_cookies_from_headers(&cookie_headers);
967            assert_eq!(
968                cookies.len(),
969                expected_count,
970                "Failed for case: '{cookie_str}'"
971            );
972
973            match cookie_str {
974                "" => {
975                    assert!(cookies.is_empty());
976                }
977                "name=value" => {
978                    assert_eq!(cookies[0].name, "name");
979                    assert_eq!(cookies[0].value, Some("value".to_string()));
980                }
981                "name=" => {
982                    assert_eq!(cookies[0].name, "name");
983                    assert_eq!(cookies[0].value, Some("".to_string()));
984                }
985                "name" => {
986                    assert_eq!(cookies[0].name, "name");
987                    assert_eq!(cookies[0].value, None);
988                }
989                "name=value; other=test" => {
990                    assert_eq!(cookies[0].name, "name");
991                    assert_eq!(cookies[0].value, Some("value".to_string()));
992                    assert_eq!(cookies[1].name, "other");
993                    assert_eq!(cookies[1].value, Some("test".to_string()));
994                }
995                "  name  =  value  " => {
996                    assert_eq!(cookies[0].name, "name");
997                    assert_eq!(cookies[0].value, Some("value".to_string()));
998                }
999                "name=value;" => {
1000                    assert_eq!(cookies[0].name, "name");
1001                    assert_eq!(cookies[0].value, Some("value".to_string()));
1002                }
1003                ";name=value" => {
1004                    assert_eq!(cookies[0].name, "name");
1005                    assert_eq!(cookies[0].value, Some("value".to_string()));
1006                }
1007                "name=value;;other=test" => {
1008                    assert_eq!(cookies[0].name, "name");
1009                    assert_eq!(cookies[0].value, Some("value".to_string()));
1010                    assert_eq!(cookies[1].name, "other");
1011                    assert_eq!(cookies[1].value, Some("test".to_string()));
1012                }
1013                _ => {}
1014            }
1015        }
1016    }
1017
1018    #[test]
1019    fn test_multiple_cookie_headers_http2() {
1020        use crate::http_common::HttpHeader;
1021        let parser = Http2Parser::new();
1022
1023        // HTTP/2 can have multiple cookie headers according to RFC 7540
1024        let headers = [
1025            HttpHeader {
1026                name: "cookie".to_string(),
1027                value: Some("session_id=abc123".to_string()),
1028                position: 0,
1029                source: crate::http_common::HeaderSource::Http2Header,
1030            },
1031            HttpHeader {
1032                name: "cookie".to_string(),
1033                value: Some("user_id=456".to_string()),
1034                position: 1,
1035                source: crate::http_common::HeaderSource::Http2Header,
1036            },
1037            HttpHeader {
1038                name: "cookie".to_string(),
1039                value: Some("theme=dark; lang=en".to_string()),
1040                position: 2,
1041                source: crate::http_common::HeaderSource::Http2Header,
1042            },
1043        ];
1044
1045        let cookie_headers: Vec<&HttpHeader> = headers
1046            .iter()
1047            .filter(|h| h.name.to_lowercase() == "cookie")
1048            .collect();
1049        let cookies = parser.parse_cookies_from_headers(&cookie_headers);
1050
1051        assert_eq!(cookies.len(), 4);
1052        assert_eq!(cookies[0].name, "session_id");
1053        assert_eq!(cookies[0].value, Some("abc123".to_string()));
1054        assert_eq!(cookies[1].name, "user_id");
1055        assert_eq!(cookies[1].value, Some("456".to_string()));
1056        assert_eq!(cookies[2].name, "theme");
1057        assert_eq!(cookies[2].value, Some("dark".to_string()));
1058        assert_eq!(cookies[3].name, "lang");
1059        assert_eq!(cookies[3].value, Some("en".to_string()));
1060    }
1061
1062    #[test]
1063    fn test_security_malformed_frames() {
1064        let parser = Http2Parser::new();
1065
1066        // Test cases that could potentially cause security issues
1067        let malicious_cases = [
1068            // Case 1: Frame with malformed length field
1069            vec![0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01],
1070            // Case 2: Frame with zero stream ID for non-connection frames
1071            vec![0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF],
1072            // Case 3: Extremely large payload declaration
1073            vec![0x7F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01],
1074            // Case 4: Invalid frame type with large payload
1075            vec![0x00, 0x10, 0x00, 0xFE, 0xFF, 0x80, 0x00, 0x00, 0x01],
1076        ];
1077
1078        for malicious_frame in malicious_cases.iter() {
1079            let data = create_http2_request_with_preface(std::slice::from_ref(malicious_frame));
1080            let result = parser.parse_request(&data);
1081
1082            // Should handle all malicious cases without panicking
1083            match result {
1084                Ok(_) | Err(_) => {
1085                    // Both outcomes are acceptable as long as no panic occurs
1086                }
1087            }
1088
1089            // Also test response parsing
1090            let response_result = parser.parse_response(malicious_frame);
1091            match response_result {
1092                Ok(_) | Err(_) => {
1093                    // Both outcomes are acceptable as long as no panic occurs
1094                }
1095            }
1096        }
1097    }
1098
1099    #[test]
1100    fn test_memory_exhaustion_protection() {
1101        let parser = Http2Parser::new();
1102
1103        // Test with many small frames to ensure no memory exhaustion
1104        let mut frames = Vec::new();
1105        for i in 0..1000 {
1106            let frame = create_http2_frame(0x00, (i % 100) + 1, &[0x00]); // Data frames
1107            frames.push(frame);
1108        }
1109
1110        let data = create_http2_request_with_preface(&frames);
1111        let result = parser.parse_request(&data);
1112
1113        // Should handle large number of frames gracefully
1114        assert!(result.is_ok());
1115    }
1116
1117    #[test]
1118    fn test_stream_id_edge_cases() {
1119        let parser = Http2Parser::new();
1120
1121        let test_cases = vec![
1122            (0x00000001, true),  // Valid client stream ID
1123            (0x00000003, true),  // Valid client stream ID
1124            (0x00000002, true),  // Valid server stream ID (should still parse)
1125            (0x7FFFFFFF, true),  // Maximum valid stream ID
1126            (0x80000001, true),  // Stream ID with reserved bit (should be masked)
1127            (0x00000000, false), // Invalid for headers frame
1128        ];
1129
1130        for (stream_id, should_find_stream) in test_cases {
1131            let frame = create_http2_frame(0x01, stream_id, &[0x00]); // Headers frame
1132            let data = create_http2_request_with_preface(&[frame]);
1133            let result = parser.parse_request(&data);
1134
1135            if should_find_stream {
1136                // Should attempt to parse (likely fail on HPACK but find the stream)
1137                match result {
1138                    Ok(None) => {} // Expected: HPACK failure but stream found
1139                    Ok(Some(_)) => panic!("Should not return a request with HPACK failure"),
1140                    Err(_) => {} // Also expected: HPACK decoding error
1141                }
1142            } else {
1143                // Should return None (no valid stream found)
1144                match result {
1145                    Ok(None) => {} // Expected: no valid stream
1146                    Ok(Some(_)) => panic!("Should not return a request with invalid stream"),
1147                    Err(e) => panic!("Should not error for invalid stream: {e:?}"),
1148                }
1149            }
1150        }
1151    }
1152
1153    #[test]
1154    fn test_frame_flag_handling() {
1155        let parser = Http2Parser::new();
1156
1157        // Test different flag combinations
1158        let flag_cases = vec![
1159            0x00, // No flags
1160            0x01, // END_STREAM
1161            0x04, // END_HEADERS
1162            0x05, // END_STREAM | END_HEADERS
1163            0x08, // PADDED
1164            0x20, // PRIORITY
1165            0xFF, // All flags set
1166        ];
1167
1168        for flags in flag_cases {
1169            let mut frame = create_http2_frame(0x01, 1, &[0x00]); // Headers frame
1170            frame[4] = flags; // Set flags byte
1171
1172            let data = create_http2_request_with_preface(&[frame]);
1173            let result = parser.parse_request(&data);
1174
1175            // Should handle all flag combinations without panicking
1176            assert!(result.is_ok() || result.is_err());
1177        }
1178    }
1179
1180    #[test]
1181    fn test_utf8_validation() {
1182        let parser = Http2Parser::new();
1183
1184        // Test cases with invalid UTF-8 sequences
1185        let invalid_utf8_cases = vec![
1186            vec![0xFF, 0xFE, 0xFD], // Invalid UTF-8 start bytes
1187            vec![0x80, 0x80, 0x80], // Invalid continuation bytes
1188            vec![0xC0, 0x80],       // Overlong encoding
1189            vec![0xED, 0xA0, 0x80], // Surrogate pair
1190        ];
1191
1192        for invalid_utf8 in invalid_utf8_cases {
1193            let frame = create_http2_frame(0x01, 1, &invalid_utf8);
1194            let data = create_http2_request_with_preface(&[frame]);
1195            let result = parser.parse_request(&data);
1196
1197            // Should handle invalid UTF-8 gracefully
1198            match result {
1199                Ok(_) => {
1200                    // If it succeeds, the UTF-8 handling converted it safely
1201                }
1202                Err(Http2ParseError::HpackDecodingFailed) => {
1203                    // Expected: HPACK decoder rejected invalid data
1204                }
1205                Err(Http2ParseError::InvalidUtf8) => {
1206                    // Also acceptable: explicit UTF-8 validation
1207                }
1208                Err(_) => {
1209                    // Other errors are also acceptable
1210                }
1211            }
1212        }
1213    }
1214
1215    #[test]
1216    fn test_error_display_formatting() {
1217        // Test that all error types format correctly
1218        let errors = vec![
1219            Http2ParseError::InvalidPreface,
1220            Http2ParseError::InvalidFrameHeader,
1221            Http2ParseError::InvalidFrameLength(12345),
1222            Http2ParseError::InvalidStreamId(67890),
1223            Http2ParseError::FrameTooLarge(999999),
1224            Http2ParseError::MissingRequiredHeaders,
1225            Http2ParseError::InvalidPseudoHeader(":invalid".to_string()),
1226            Http2ParseError::IncompleteFrame,
1227            Http2ParseError::InvalidUtf8,
1228            Http2ParseError::UnsupportedFeature("test".to_string()),
1229            Http2ParseError::HpackDecodingFailed,
1230        ];
1231
1232        for error in errors {
1233            let formatted = format!("{error}");
1234            assert!(!formatted.is_empty());
1235            assert!(!formatted.contains("Debug")); // Should be Display, not Debug
1236        }
1237    }
1238
1239    #[test]
1240    fn test_config_edge_cases() {
1241        // Test parser with different configurations
1242        let config = Http2Config {
1243            max_frame_size: 1, // Very small max frame size
1244            strict_parsing: true,
1245            ..Default::default()
1246        };
1247
1248        let parser = Http2Parser {
1249            config,
1250            hpack_decoder: RefCell::new(Decoder::new()),
1251        };
1252
1253        // Even small valid frames should be rejected
1254        let frame = create_http2_frame(0x01, 1, &[0x00, 0x00]); // 2 bytes > max_frame_size(1)
1255        let data = create_http2_request_with_preface(&[frame]);
1256        let result = parser.parse_request(&data);
1257
1258        // Should handle configuration limits gracefully
1259        assert!(result.is_ok());
1260    }
1261
1262    #[test]
1263    fn test_multiple_streams_handling() {
1264        let parser = Http2Parser::new();
1265
1266        // Create frames for multiple streams
1267        let frame1 = create_http2_frame(0x01, 1, &[0x00]); // Headers for stream 1
1268        let frame2 = create_http2_frame(0x01, 3, &[0x00]); // Headers for stream 3
1269        let frame3 = create_http2_frame(0x00, 1, &[0x48, 0x65, 0x6c, 0x6c, 0x6f]); // Data for stream 1
1270
1271        let data = create_http2_request_with_preface(&[frame1, frame2, frame3]);
1272        let result = parser.parse_request(&data);
1273
1274        // Should handle multiple streams and pick the first valid one
1275        match result {
1276            Ok(Some(req)) => {
1277                assert_eq!(req.stream_id, 1); // Should pick stream 1 (first HEADERS frame)
1278            }
1279            Ok(None) => {}
1280            Err(_) => {}
1281        }
1282    }
1283
1284    #[test]
1285    fn test_continuation_frames() {
1286        let parser = Http2Parser::new();
1287
1288        // Create HEADERS frame followed by CONTINUATION frame
1289        let headers_frame = create_http2_frame(0x01, 1, &[0x00, 0x01]); // Headers (incomplete)
1290        let continuation_frame = create_http2_frame(0x09, 1, &[0x02, 0x03]); // Continuation
1291
1292        let data = create_http2_request_with_preface(&[headers_frame, continuation_frame]);
1293        let result = parser.parse_request(&data);
1294
1295        // Should handle CONTINUATION frames properly
1296        match result {
1297            Ok(_) | Err(_) => {} // Both outcomes acceptable as long as no panic
1298        }
1299    }
1300
1301    #[test]
1302    fn test_settings_frame_with_invalid_payload() {
1303        let parser = Http2Parser::new();
1304
1305        // Create SETTINGS frame with invalid payload (not multiple of 6 bytes)
1306        let invalid_settings = create_http2_frame(0x04, 0, &[0x00, 0x01, 0x00, 0x00, 0x10]); // 5 bytes instead of 6
1307        let headers_frame = create_http2_frame(0x01, 1, &[0x00]);
1308
1309        let data = create_http2_request_with_preface(&[invalid_settings, headers_frame]);
1310        let result = parser.parse_request(&data);
1311
1312        // Should handle malformed SETTINGS gracefully
1313        match result {
1314            Ok(_) | Err(_) => {} // Both outcomes acceptable
1315        }
1316    }
1317
1318    #[test]
1319    fn test_priority_frame_handling() {
1320        let parser = Http2Parser::new();
1321
1322        // Create PRIORITY frame followed by HEADERS
1323        let priority_frame = create_http2_frame(0x02, 1, &[0x00, 0x00, 0x00, 0x02, 0x10]); // Priority frame
1324        let headers_frame = create_http2_frame(0x01, 1, &[0x00]);
1325
1326        let data = create_http2_request_with_preface(&[priority_frame, headers_frame]);
1327        let result = parser.parse_request(&data);
1328
1329        // Should handle PRIORITY frames without issues
1330        match result {
1331            Ok(_) | Err(_) => {} // Both outcomes acceptable
1332        }
1333    }
1334
1335    #[test]
1336    fn test_window_update_frame() {
1337        let parser = Http2Parser::new();
1338
1339        // Create WINDOW_UPDATE frame
1340        let window_update = create_http2_frame(0x08, 0, &[0x00, 0x00, 0x10, 0x00]); // Window update
1341        let headers_frame = create_http2_frame(0x01, 1, &[0x00]);
1342
1343        let data = create_http2_request_with_preface(&[window_update, headers_frame]);
1344        let result = parser.parse_request(&data);
1345
1346        // Should handle WINDOW_UPDATE frames
1347        match result {
1348            Ok(_) | Err(_) => {} // Both outcomes acceptable
1349        }
1350    }
1351
1352    #[test]
1353    fn test_data_frame_without_headers() {
1354        let parser = Http2Parser::new();
1355
1356        // Create DATA frame without preceding HEADERS
1357        let data_frame = create_http2_frame(0x00, 1, &[0x48, 0x65, 0x6c, 0x6c, 0x6f]); // "Hello"
1358
1359        let data = create_http2_request_with_preface(&[data_frame]);
1360        let result = parser.parse_request(&data);
1361
1362        // Should return None (no valid request without HEADERS)
1363        match result {
1364            Ok(None) => {} // Expected
1365            Ok(Some(_)) => panic!("Should not return request without HEADERS frame"),
1366            Err(_) => {} // Also acceptable
1367        }
1368    }
1369
1370    #[test]
1371    fn test_stream_id_zero_for_headers() {
1372        let parser = Http2Parser::new();
1373
1374        // Create HEADERS frame with stream ID 0 (invalid for HEADERS)
1375        let invalid_headers = create_http2_frame(0x01, 0, &[0x00]); // Stream ID 0 is invalid for HEADERS
1376
1377        let data = create_http2_request_with_preface(&[invalid_headers]);
1378        let result = parser.parse_request(&data);
1379
1380        // Should return None (no valid stream found)
1381        match result {
1382            Ok(None) => {} // Expected
1383            Ok(Some(_)) => panic!("Should not return request with invalid stream ID"),
1384            Err(_) => {} // Also acceptable
1385        }
1386    }
1387
1388    #[test]
1389    fn test_mixed_frame_types_sequence() {
1390        let parser = Http2Parser::new();
1391
1392        // Create a realistic sequence of frames
1393        let settings_frame = create_http2_frame(0x04, 0, &[0x00, 0x02, 0x00, 0x00, 0x00, 0x01]); // SETTINGS
1394        let window_update = create_http2_frame(0x08, 0, &[0x00, 0x00, 0x10, 0x00]); // WINDOW_UPDATE
1395        let headers_frame = create_http2_frame(0x01, 1, &[0x00]); // HEADERS
1396        let data_frame = create_http2_frame(0x00, 1, &[0x48, 0x65, 0x6c, 0x6c, 0x6f]); // DATA
1397
1398        let data = create_http2_request_with_preface(&[
1399            settings_frame,
1400            window_update,
1401            headers_frame,
1402            data_frame,
1403        ]);
1404        let result = parser.parse_request(&data);
1405
1406        // Should handle mixed frame sequence properly
1407        match result {
1408            Ok(Some(req)) => {
1409                assert_eq!(req.stream_id, 1);
1410                assert!(req.frame_sequence.len() >= 2); // Should have at least SETTINGS and HEADERS
1411            }
1412            Ok(None) => {} // Acceptable if HPACK fails
1413            Err(_) => {}   // Also acceptable for HPACK errors
1414        }
1415    }
1416
1417    #[test]
1418    fn test_response_with_invalid_status() {
1419        let parser = Http2Parser::new();
1420
1421        // Create response frame that would result in missing :status pseudo-header
1422        let headers_frame = create_http2_frame(0x01, 1, &[0x00]); // Headers without proper HPACK encoding
1423
1424        let result = parser.parse_response(&headers_frame);
1425
1426        // Should handle missing :status gracefully
1427        match result {
1428            Ok(None) => {}                                     // Expected when :status is missing
1429            Err(Http2ParseError::MissingRequiredHeaders) => {} // Also expected
1430            Err(Http2ParseError::HpackDecodingFailed) => {}    // HPACK might fail first
1431            other => panic!("Unexpected result: {other:?}"),
1432        }
1433    }
1434
1435    #[test]
1436    fn test_frame_flags_handling() {
1437        let parser = Http2Parser::new();
1438
1439        // Create frame with various flags set
1440        let mut frame = create_http2_frame(0x01, 1, &[0x00]);
1441        frame[4] = 0x05; // Set END_HEADERS (0x04) and END_STREAM (0x01) flags
1442
1443        let data = create_http2_request_with_preface(&[frame]);
1444        let result = parser.parse_request(&data);
1445
1446        // Should handle frame flags properly
1447        match result {
1448            Ok(_) | Err(_) => {} // Both outcomes acceptable
1449        }
1450    }
1451
1452    #[test]
1453    fn test_large_stream_id() {
1454        let parser = Http2Parser::new();
1455
1456        // Create frame with maximum valid stream ID (2^31 - 1)
1457        let max_stream_id = 0x7FFFFFFF;
1458        let headers_frame = create_http2_frame(0x01, max_stream_id, &[0x00]);
1459
1460        let data = create_http2_request_with_preface(&[headers_frame]);
1461        let result = parser.parse_request(&data);
1462
1463        // Should handle large stream IDs
1464        match result {
1465            Ok(Some(req)) => {
1466                assert_eq!(req.stream_id, max_stream_id);
1467            }
1468            Ok(None) => {} // Acceptable if HPACK fails
1469            Err(_) => {}   // Also acceptable
1470        }
1471    }
1472
1473    #[test]
1474    fn test_empty_payload_frames() {
1475        let parser = Http2Parser::new();
1476
1477        // Create frames with empty payloads
1478        let empty_headers = create_http2_frame(0x01, 1, &[]); // Empty HEADERS
1479        let empty_data = create_http2_frame(0x00, 1, &[]); // Empty DATA
1480
1481        let data = create_http2_request_with_preface(&[empty_headers, empty_data]);
1482        let result = parser.parse_request(&data);
1483
1484        // Should handle empty payloads gracefully
1485        match result {
1486            Ok(_) | Err(_) => {} // Both outcomes acceptable
1487        }
1488    }
1489
1490    #[test]
1491    fn test_cookie_and_referer_excluded_from_headers_list_http2() {
1492        use crate::http_common::HttpHeader;
1493        let parser = Http2Parser::new();
1494
1495        // Create HTTP/2 headers including cookie and referer
1496        let headers = [
1497            HttpHeader {
1498                name: ":method".to_string(),
1499                value: Some("GET".to_string()),
1500                position: 0,
1501                source: crate::http_common::HeaderSource::Http2Header,
1502            },
1503            HttpHeader {
1504                name: ":path".to_string(),
1505                value: Some("/page".to_string()),
1506                position: 1,
1507                source: crate::http_common::HeaderSource::Http2Header,
1508            },
1509            HttpHeader {
1510                name: ":authority".to_string(),
1511                value: Some("example.com".to_string()),
1512                position: 2,
1513                source: crate::http_common::HeaderSource::Http2Header,
1514            },
1515            HttpHeader {
1516                name: "cookie".to_string(),
1517                value: Some("session=abc123".to_string()),
1518                position: 3,
1519                source: crate::http_common::HeaderSource::Http2Header,
1520            },
1521            HttpHeader {
1522                name: "referer".to_string(),
1523                value: Some("https://google.com".to_string()),
1524                position: 4,
1525                source: crate::http_common::HeaderSource::Http2Header,
1526            },
1527            HttpHeader {
1528                name: "user-agent".to_string(),
1529                value: Some("test-browser".to_string()),
1530                position: 5,
1531                source: crate::http_common::HeaderSource::Http2Header,
1532            },
1533            HttpHeader {
1534                name: "accept".to_string(),
1535                value: Some("text/html".to_string()),
1536                position: 6,
1537                source: crate::http_common::HeaderSource::Http2Header,
1538            },
1539        ];
1540
1541        let cookie_headers: Vec<&HttpHeader> = headers
1542            .iter()
1543            .filter(|h| h.name.to_lowercase() == "cookie")
1544            .collect();
1545        let cookies = parser.parse_cookies_from_headers(&cookie_headers);
1546
1547        assert_eq!(cookies.len(), 1);
1548        assert_eq!(cookies[0].name, "session");
1549        assert_eq!(cookies[0].value, Some("abc123".to_string()));
1550
1551        let mut filtered_headers = Vec::new();
1552        let mut referer_found: Option<String> = None;
1553
1554        for header in headers {
1555            let header_name_lower = header.name.to_lowercase();
1556
1557            if header_name_lower == "cookie" {
1558                continue;
1559            } else if header_name_lower == "referer" {
1560                if let Some(ref value) = header.value {
1561                    referer_found = Some(value.clone());
1562                }
1563            } else {
1564                filtered_headers.push(header);
1565            }
1566        }
1567
1568        assert_eq!(referer_found, Some("https://google.com".to_string()));
1569
1570        let header_names: Vec<String> = filtered_headers
1571            .iter()
1572            .map(|h| h.name.to_lowercase())
1573            .collect();
1574        assert!(
1575            !header_names.contains(&"cookie".to_string()),
1576            "Cookie header should not be in headers list"
1577        );
1578        assert!(
1579            !header_names.contains(&"referer".to_string()),
1580            "Referer header should not be in headers list"
1581        );
1582
1583        assert!(header_names.contains(&":method".to_string()));
1584        assert!(header_names.contains(&":path".to_string()));
1585        assert!(header_names.contains(&":authority".to_string()));
1586        assert!(header_names.contains(&"user-agent".to_string()));
1587        assert!(header_names.contains(&"accept".to_string()));
1588
1589        assert_eq!(filtered_headers.len(), 5);
1590    }
1591}