Skip to main content

specter/transport/h2/
frame.rs

1//! HTTP/2 frame types and binary serialization.
2//!
3//! Implements RFC 9113 frame format with full control over frame ordering
4//! and content for fingerprint accuracy.
5
6use bytes::{Buf, BufMut, Bytes, BytesMut};
7
8/// Frame header size (9 bytes per RFC 9113).
9pub const FRAME_HEADER_SIZE: usize = 9;
10
11/// Default maximum frame size (16KB per RFC 9113).
12pub const DEFAULT_MAX_FRAME_SIZE: u32 = 16384;
13
14/// HTTP/2 connection preface (client must send this first).
15pub const CONNECTION_PREFACE: &[u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
16
17/// Frame type identifiers per RFC 9113.
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19#[repr(u8)]
20pub enum FrameType {
21    Data = 0x0,
22    Headers = 0x1,
23    Priority = 0x2,
24    RstStream = 0x3,
25    Settings = 0x4,
26    PushPromise = 0x5,
27    Ping = 0x6,
28    GoAway = 0x7,
29    WindowUpdate = 0x8,
30    Continuation = 0x9,
31    Unknown(u8),
32}
33
34impl From<u8> for FrameType {
35    fn from(v: u8) -> Self {
36        match v {
37            0x0 => Self::Data,
38            0x1 => Self::Headers,
39            0x2 => Self::Priority,
40            0x3 => Self::RstStream,
41            0x4 => Self::Settings,
42            0x5 => Self::PushPromise,
43            0x6 => Self::Ping,
44            0x7 => Self::GoAway,
45            0x8 => Self::WindowUpdate,
46            0x9 => Self::Continuation,
47            other => Self::Unknown(other),
48        }
49    }
50}
51
52impl From<FrameType> for u8 {
53    fn from(ft: FrameType) -> u8 {
54        match ft {
55            FrameType::Data => 0x0,
56            FrameType::Headers => 0x1,
57            FrameType::Priority => 0x2,
58            FrameType::RstStream => 0x3,
59            FrameType::Settings => 0x4,
60            FrameType::PushPromise => 0x5,
61            FrameType::Ping => 0x6,
62            FrameType::GoAway => 0x7,
63            FrameType::WindowUpdate => 0x8,
64            FrameType::Continuation => 0x9,
65            FrameType::Unknown(v) => v,
66        }
67    }
68}
69
70/// Frame flags.
71pub mod flags {
72    pub const END_STREAM: u8 = 0x1;
73    pub const ACK: u8 = 0x1; // Same value, different context (SETTINGS/PING)
74    pub const END_HEADERS: u8 = 0x4;
75    pub const PADDED: u8 = 0x8;
76    pub const PRIORITY: u8 = 0x20;
77}
78
79/// SETTINGS frame parameter identifiers.
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81#[repr(u16)]
82pub enum SettingsId {
83    HeaderTableSize = 0x1,
84    EnablePush = 0x2,
85    MaxConcurrentStreams = 0x3,
86    InitialWindowSize = 0x4,
87    MaxFrameSize = 0x5,
88    MaxHeaderListSize = 0x6,
89    EnableConnectProtocol = 0x8,
90}
91
92impl TryFrom<u16> for SettingsId {
93    type Error = ();
94
95    fn try_from(v: u16) -> Result<Self, Self::Error> {
96        match v {
97            0x1 => Ok(Self::HeaderTableSize),
98            0x2 => Ok(Self::EnablePush),
99            0x3 => Ok(Self::MaxConcurrentStreams),
100            0x4 => Ok(Self::InitialWindowSize),
101            0x5 => Ok(Self::MaxFrameSize),
102            0x6 => Ok(Self::MaxHeaderListSize),
103            0x8 => Ok(Self::EnableConnectProtocol),
104            _ => Err(()),
105        }
106    }
107}
108
109impl From<SettingsId> for u16 {
110    fn from(id: SettingsId) -> Self {
111        id as u16
112    }
113}
114
115/// HTTP/2 error codes per RFC 9113 Section 7.
116#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117#[repr(u32)]
118pub enum ErrorCode {
119    NoError = 0x0,
120    ProtocolError = 0x1,
121    InternalError = 0x2,
122    FlowControlError = 0x3,
123    SettingsTimeout = 0x4,
124    StreamClosed = 0x5,
125    FrameSizeError = 0x6,
126    RefusedStream = 0x7,
127    Cancel = 0x8,
128    CompressionError = 0x9,
129    ConnectError = 0xa,
130    EnhanceYourCalm = 0xb,
131    InadequateSecurity = 0xc,
132    Http11Required = 0xd,
133}
134
135/// Parsed frame header.
136#[derive(Debug, Clone)]
137pub struct FrameHeader {
138    pub length: u32,
139    pub frame_type: FrameType,
140    pub flags: u8,
141    pub stream_id: u32,
142}
143
144impl FrameHeader {
145    /// Parse a frame header from bytes.
146    /// Returns None if header is invalid (e.g., reserved bits set incorrectly).
147    pub fn parse(buf: &[u8]) -> Option<Self> {
148        if buf.len() < FRAME_HEADER_SIZE {
149            return None;
150        }
151
152        let length = ((buf[0] as u32) << 16) | ((buf[1] as u32) << 8) | (buf[2] as u32);
153        let frame_type = FrameType::from(buf[3]);
154        let flags = buf[4];
155
156        // RFC 9113 Section 4.1: Stream ID is 31 bits, high bit (bit 0 of first byte) is reserved
157        // Check reserved bit - must be 0
158        if (buf[5] & 0x80) != 0 {
159            return None; // Reserved bit set - invalid frame
160        }
161
162        let stream_id = ((buf[5] as u32 & 0x7f) << 24)
163            | ((buf[6] as u32) << 16)
164            | ((buf[7] as u32) << 8)
165            | (buf[8] as u32);
166
167        Some(Self {
168            length,
169            frame_type,
170            flags,
171            stream_id,
172        })
173    }
174
175    /// Serialize frame header to bytes.
176    pub fn serialize(&self, buf: &mut BytesMut) {
177        // Length (24 bits)
178        buf.put_u8((self.length >> 16) as u8);
179        buf.put_u8((self.length >> 8) as u8);
180        buf.put_u8(self.length as u8);
181        // Type (8 bits)
182        buf.put_u8(self.frame_type.into());
183        // Flags (8 bits)
184        buf.put_u8(self.flags);
185        // Stream ID (31 bits, high bit reserved and must be 0)
186        // RFC 9113 Section 4.1: Stream ID is 31-bit unsigned integer
187        buf.put_u32(self.stream_id & 0x7fffffff);
188    }
189}
190
191/// SETTINGS frame payload.
192#[derive(Debug, Clone)]
193pub struct SettingsFrame {
194    /// Settings to send, in order.
195    /// Each tuple is (id, value).
196    /// Order matters for fingerprinting!
197    pub settings: Vec<(u16, u32)>,
198    pub ack: bool,
199}
200
201impl SettingsFrame {
202    /// Create a new SETTINGS frame.
203    pub fn new() -> Self {
204        Self {
205            settings: Vec::new(),
206            ack: false,
207        }
208    }
209
210    /// Create a SETTINGS ACK frame.
211    pub fn ack() -> Self {
212        Self {
213            settings: Vec::new(),
214            ack: true,
215        }
216    }
217
218    /// Add a setting. Order of calls determines wire order.
219    pub fn set<T: Into<u16>>(&mut self, id: T, value: u32) -> &mut Self {
220        self.settings.push((id.into(), value));
221        self
222    }
223
224    /// Serialize to bytes (including frame header).
225    pub fn serialize(&self) -> BytesMut {
226        let payload_len = if self.ack { 0 } else { self.settings.len() * 6 };
227        let mut buf = BytesMut::with_capacity(FRAME_HEADER_SIZE + payload_len);
228
229        // Frame header
230        let header = FrameHeader {
231            length: payload_len as u32,
232            frame_type: FrameType::Settings,
233            flags: if self.ack { flags::ACK } else { 0 },
234            stream_id: 0, // SETTINGS always on stream 0
235        };
236        header.serialize(&mut buf);
237
238        // Payload (only if not ACK)
239        if !self.ack {
240            for (id, value) in &self.settings {
241                buf.put_u16(*id);
242                buf.put_u32(*value);
243            }
244        }
245
246        buf
247    }
248
249    /// Parse a SETTINGS frame payload.
250    pub fn parse(flags: u8, mut payload: Bytes) -> Self {
251        let ack = (flags & flags::ACK) != 0;
252        let mut settings = Vec::new();
253
254        while payload.remaining() >= 6 {
255            let id = payload.get_u16();
256            let value = payload.get_u32();
257            settings.push((id, value));
258        }
259
260        Self { settings, ack }
261    }
262}
263
264impl Default for SettingsFrame {
265    fn default() -> Self {
266        Self::new()
267    }
268}
269
270/// WINDOW_UPDATE frame.
271#[derive(Debug, Clone)]
272pub struct WindowUpdateFrame {
273    pub stream_id: u32,
274    pub increment: u32,
275}
276
277impl WindowUpdateFrame {
278    /// Create a new WINDOW_UPDATE frame.
279    pub fn new(stream_id: u32, increment: u32) -> Self {
280        Self {
281            stream_id,
282            increment,
283        }
284    }
285
286    /// Serialize to bytes (including frame header).
287    pub fn serialize(&self) -> BytesMut {
288        let mut buf = BytesMut::with_capacity(FRAME_HEADER_SIZE + 4);
289
290        let header = FrameHeader {
291            length: 4,
292            frame_type: FrameType::WindowUpdate,
293            flags: 0,
294            stream_id: self.stream_id,
295        };
296        header.serialize(&mut buf);
297
298        // Window size increment (31 bits, high bit reserved)
299        buf.put_u32(self.increment & 0x7fffffff);
300
301        buf
302    }
303
304    /// Parse from payload.
305    /// Returns None if frame is invalid (e.g., increment is 0).
306    pub fn parse(stream_id: u32, mut payload: Bytes) -> Option<Self> {
307        if payload.remaining() < 4 {
308            return None;
309        }
310        let increment_raw = payload.get_u32();
311        let increment = increment_raw & 0x7fffffff;
312
313        // RFC 9113 Section 6.9.1: Window size increment MUST be between 1 and 2^31-1
314        // A value of 0 is invalid and MUST be treated as a connection error (FLOW_CONTROL_ERROR)
315        if increment == 0 {
316            return None;
317        }
318
319        Some(Self {
320            stream_id,
321            increment,
322        })
323    }
324}
325
326/// HEADERS frame.
327#[derive(Debug, Clone)]
328pub struct HeadersFrame {
329    pub stream_id: u32,
330    pub header_block: Bytes,
331    pub end_stream: bool,
332    pub end_headers: bool,
333    pub priority: Option<PriorityData>,
334}
335
336/// Priority data (optional in HEADERS frame).
337#[derive(Debug, Clone, Copy)]
338pub struct PriorityData {
339    pub exclusive: bool,
340    pub stream_dependency: u32,
341    pub weight: u8,
342}
343
344impl HeadersFrame {
345    /// Create a new HEADERS frame.
346    pub fn new(stream_id: u32, header_block: Bytes) -> Self {
347        Self {
348            stream_id,
349            header_block,
350            end_stream: false,
351            end_headers: true,
352            priority: None,
353        }
354    }
355
356    /// Set end_stream flag.
357    pub fn end_stream(mut self, end: bool) -> Self {
358        self.end_stream = end;
359        self
360    }
361
362    /// Set priority data.
363    pub fn with_priority(mut self, priority: PriorityData) -> Self {
364        self.priority = Some(priority);
365        self
366    }
367
368    /// Set end_headers flag.
369    pub fn end_headers(mut self, end: bool) -> Self {
370        self.end_headers = end;
371        self
372    }
373
374    /// Serialize to bytes (including frame header).
375    /// Padding is not currently supported in serialization as it is not required
376    /// for accurate browser fingerprinting.
377    pub fn serialize(&self) -> BytesMut {
378        let priority_len = if self.priority.is_some() { 5 } else { 0 };
379        let payload_len = priority_len + self.header_block.len();
380        let mut buf = BytesMut::with_capacity(FRAME_HEADER_SIZE + payload_len);
381
382        let mut frame_flags = 0u8;
383        if self.end_stream {
384            frame_flags |= flags::END_STREAM;
385        }
386        if self.end_headers {
387            frame_flags |= flags::END_HEADERS;
388        }
389        if self.priority.is_some() {
390            frame_flags |= flags::PRIORITY;
391        }
392
393        let header = FrameHeader {
394            length: payload_len as u32,
395            frame_type: FrameType::Headers,
396            flags: frame_flags,
397            stream_id: self.stream_id,
398        };
399        header.serialize(&mut buf);
400
401        // Priority data (optional)
402        if let Some(priority) = &self.priority {
403            let dep = if priority.exclusive {
404                priority.stream_dependency | 0x80000000
405            } else {
406                priority.stream_dependency
407            };
408            buf.put_u32(dep);
409            buf.put_u8(priority.weight);
410        }
411
412        // Header block fragment
413        buf.extend_from_slice(&self.header_block);
414
415        buf
416    }
417
418    /// Parse a HEADERS frame from payload (with padding and priority handling).
419    /// Returns None if frame is invalid.
420    pub fn parse(stream_id: u32, flags: u8, mut payload: Bytes) -> Result<Self, String> {
421        if stream_id == 0 {
422            return Err("HEADERS frame must have non-zero stream ID".to_string());
423        }
424
425        let end_stream = (flags & flags::END_STREAM) != 0;
426        let end_headers = (flags & flags::END_HEADERS) != 0;
427        let padded = (flags & flags::PADDED) != 0;
428        let priority_flag = (flags & flags::PRIORITY) != 0;
429
430        // Parse padding length (if PADDED flag set)
431        let pad_len = if padded {
432            if payload.remaining() < 1 {
433                return Err("PADDED HEADERS frame missing padding length".to_string());
434            }
435            let pad_len = payload.get_u8() as usize;
436            if pad_len >= payload.remaining() {
437                return Err("Padding length exceeds payload size".to_string());
438            }
439            pad_len
440        } else {
441            0
442        };
443
444        // Parse priority (if PRIORITY flag set)
445        let priority = if priority_flag {
446            if payload.remaining() < 5 {
447                return Err("HEADERS frame with PRIORITY flag missing priority data".to_string());
448            }
449            let dep_raw = payload.get_u32();
450            let exclusive = (dep_raw & 0x80000000) != 0;
451            let stream_dependency = dep_raw & 0x7fffffff;
452            let weight = payload.get_u8();
453            Some(PriorityData {
454                exclusive,
455                stream_dependency,
456                weight,
457            })
458        } else {
459            None
460        };
461
462        // Extract header block (remaining payload minus padding)
463        let header_block_len = payload.remaining() - pad_len;
464        if header_block_len == 0 {
465            return Err("HEADERS frame header block is empty".to_string());
466        }
467        let header_block = payload.copy_to_bytes(header_block_len);
468        // Skip padding bytes
469        payload.advance(pad_len);
470
471        Ok(Self {
472            stream_id,
473            header_block,
474            end_stream,
475            end_headers,
476            priority,
477        })
478    }
479}
480
481/// CONTINUATION frame (RFC 9113 Section 6.10).
482#[derive(Debug, Clone)]
483pub struct ContinuationFrame {
484    pub stream_id: u32,
485    pub flags: u8,
486    pub header_fragment: Bytes,
487}
488
489impl ContinuationFrame {
490    /// Create a new CONTINUATION frame.
491    pub fn new(stream_id: u32, header_fragment: Bytes, end_headers: bool) -> Self {
492        let flags = if end_headers { flags::END_HEADERS } else { 0 };
493        Self {
494            stream_id,
495            flags,
496            header_fragment,
497        }
498    }
499
500    /// Check if END_HEADERS flag is set.
501    pub fn end_headers(&self) -> bool {
502        self.flags & flags::END_HEADERS != 0
503    }
504
505    /// Serialize to bytes (including frame header).
506    pub fn serialize(&self) -> BytesMut {
507        let payload_len = self.header_fragment.len();
508        let mut buf = BytesMut::with_capacity(FRAME_HEADER_SIZE + payload_len);
509
510        let header = FrameHeader {
511            length: payload_len as u32,
512            frame_type: FrameType::Continuation,
513            flags: self.flags,
514            stream_id: self.stream_id,
515        };
516        header.serialize(&mut buf);
517
518        // Header fragment payload
519        buf.extend_from_slice(&self.header_fragment);
520
521        buf
522    }
523
524    /// Parse a CONTINUATION frame from payload.
525    pub fn parse(stream_id: u32, flags: u8, payload: Bytes) -> Result<Self, String> {
526        if stream_id == 0 {
527            return Err("CONTINUATION frame must have non-zero stream ID".to_string());
528        }
529
530        Ok(Self {
531            stream_id,
532            flags,
533            header_fragment: payload,
534        })
535    }
536}
537
538/// DATA frame.
539#[derive(Debug, Clone)]
540pub struct DataFrame {
541    pub stream_id: u32,
542    pub data: Bytes,
543    pub end_stream: bool,
544    pub padding_len: u8,
545}
546
547impl DataFrame {
548    /// Create a new DATA frame.
549    pub fn new(stream_id: u32, data: Bytes) -> Self {
550        Self {
551            stream_id,
552            data,
553            end_stream: false,
554            padding_len: 0,
555        }
556    }
557
558    /// Set end_stream flag.
559    pub fn end_stream(mut self, end: bool) -> Self {
560        self.end_stream = end;
561        self
562    }
563
564    /// Set padding length (0-255 bytes).
565    pub fn with_padding(mut self, padding_len: u8) -> Self {
566        self.padding_len = padding_len;
567        self
568    }
569
570    /// Serialize to bytes (including frame header).
571    pub fn serialize(&self) -> BytesMut {
572        let payload_len = if self.padding_len > 0 {
573            // Padding length byte + data + padding
574            1 + self.data.len() + self.padding_len as usize
575        } else {
576            self.data.len()
577        };
578
579        let mut buf = BytesMut::with_capacity(FRAME_HEADER_SIZE + payload_len);
580
581        let mut frame_flags = if self.end_stream {
582            flags::END_STREAM
583        } else {
584            0
585        };
586        if self.padding_len > 0 {
587            frame_flags |= flags::PADDED;
588        }
589
590        let header = FrameHeader {
591            length: payload_len as u32,
592            frame_type: FrameType::Data,
593            flags: frame_flags,
594            stream_id: self.stream_id,
595        };
596        header.serialize(&mut buf);
597
598        // Padding length byte (if padded)
599        if self.padding_len > 0 {
600            buf.put_u8(self.padding_len);
601        }
602
603        // Data
604        buf.extend_from_slice(&self.data);
605
606        // Padding bytes (zeros)
607        if self.padding_len > 0 {
608            buf.extend_from_slice(&vec![0u8; self.padding_len as usize]);
609        }
610
611        buf
612    }
613
614    /// Parse a DATA frame from payload (with padding handling).
615    /// Returns None if frame is invalid.
616    pub fn parse(stream_id: u32, flags: u8, mut payload: Bytes) -> Result<Self, String> {
617        if stream_id == 0 {
618            return Err("DATA frame must have non-zero stream ID".to_string());
619        }
620
621        let end_stream = (flags & flags::END_STREAM) != 0;
622        let padded = (flags & flags::PADDED) != 0;
623
624        let (data, padding_len) = if padded {
625            if payload.remaining() < 1 {
626                return Err("PADDED DATA frame missing padding length".to_string());
627            }
628            let pad_len = payload.get_u8() as usize;
629            if pad_len >= payload.remaining() {
630                return Err("Padding length exceeds payload size".to_string());
631            }
632            let data_len = payload.remaining() - pad_len;
633            let data = payload.copy_to_bytes(data_len);
634            // Skip padding bytes
635            payload.advance(pad_len);
636            (data, pad_len as u8)
637        } else {
638            (payload, 0)
639        };
640
641        Ok(Self {
642            stream_id,
643            data,
644            end_stream,
645            padding_len,
646        })
647    }
648}
649
650/// PING frame.
651#[derive(Debug, Clone)]
652pub struct PingFrame {
653    pub ack: bool,
654    pub data: [u8; 8],
655}
656
657impl PingFrame {
658    /// Create a new PING frame.
659    pub fn new(data: [u8; 8]) -> Self {
660        Self { ack: false, data }
661    }
662
663    /// Create a PING ACK frame.
664    pub fn ack(data: [u8; 8]) -> Self {
665        Self { ack: true, data }
666    }
667
668    /// Serialize to bytes.
669    pub fn serialize(&self) -> BytesMut {
670        let mut buf = BytesMut::with_capacity(FRAME_HEADER_SIZE + 8);
671
672        let header = FrameHeader {
673            length: 8,
674            frame_type: FrameType::Ping,
675            flags: if self.ack { flags::ACK } else { 0 },
676            stream_id: 0,
677        };
678        header.serialize(&mut buf);
679        buf.extend_from_slice(&self.data);
680
681        buf
682    }
683
684    /// Parse from payload.
685    pub fn parse(flags: u8, payload: &[u8]) -> Option<Self> {
686        if payload.len() != 8 {
687            return None;
688        }
689        let mut data = [0u8; 8];
690        data.copy_from_slice(payload);
691        Some(Self {
692            ack: (flags & flags::ACK) != 0,
693            data,
694        })
695    }
696}
697
698/// GOAWAY frame.
699#[derive(Debug, Clone)]
700pub struct GoAwayFrame {
701    pub last_stream_id: u32,
702    pub error_code: ErrorCode,
703    pub debug_data: Bytes,
704}
705
706impl GoAwayFrame {
707    /// Create a new GOAWAY frame.
708    pub fn new(last_stream_id: u32, error_code: ErrorCode) -> Self {
709        Self {
710            last_stream_id,
711            error_code,
712            debug_data: Bytes::new(),
713        }
714    }
715
716    /// Serialize to bytes.
717    pub fn serialize(&self) -> BytesMut {
718        let payload_len = 8 + self.debug_data.len();
719        let mut buf = BytesMut::with_capacity(FRAME_HEADER_SIZE + payload_len);
720
721        let header = FrameHeader {
722            length: payload_len as u32,
723            frame_type: FrameType::GoAway,
724            flags: 0,
725            stream_id: 0,
726        };
727        header.serialize(&mut buf);
728        buf.put_u32(self.last_stream_id & 0x7fffffff);
729        buf.put_u32(self.error_code as u32);
730        buf.extend_from_slice(&self.debug_data);
731
732        buf
733    }
734
735    /// Parse from payload.
736    pub fn parse(mut payload: Bytes) -> Option<Self> {
737        if payload.remaining() < 8 {
738            return None;
739        }
740        let last_stream_id = payload.get_u32() & 0x7fffffff;
741        let error_code_raw = payload.get_u32();
742        let error_code = match error_code_raw {
743            0x0 => ErrorCode::NoError,
744            0x1 => ErrorCode::ProtocolError,
745            0x2 => ErrorCode::InternalError,
746            0x3 => ErrorCode::FlowControlError,
747            0x4 => ErrorCode::SettingsTimeout,
748            0x5 => ErrorCode::StreamClosed,
749            0x6 => ErrorCode::FrameSizeError,
750            0x7 => ErrorCode::RefusedStream,
751            0x8 => ErrorCode::Cancel,
752            0x9 => ErrorCode::CompressionError,
753            0xa => ErrorCode::ConnectError,
754            0xb => ErrorCode::EnhanceYourCalm,
755            0xc => ErrorCode::InadequateSecurity,
756            0xd => ErrorCode::Http11Required,
757            _ => ErrorCode::ProtocolError,
758        };
759        let debug_data = payload.copy_to_bytes(payload.remaining());
760
761        Some(Self {
762            last_stream_id,
763            error_code,
764            debug_data,
765        })
766    }
767}
768
769/// PRIORITY frame (RFC 9113 Section 6.3).
770#[derive(Debug, Clone)]
771pub struct PriorityFrame {
772    pub stream_id: u32,
773    pub exclusive: bool,
774    pub stream_dependency: u32,
775    pub weight: u8,
776}
777
778impl PriorityFrame {
779    /// Create a new PRIORITY frame.
780    pub fn new(stream_id: u32, stream_dependency: u32, weight: u8, exclusive: bool) -> Self {
781        Self {
782            stream_id,
783            exclusive,
784            stream_dependency,
785            weight,
786        }
787    }
788
789    /// Serialize to bytes.
790    pub fn serialize(&self) -> BytesMut {
791        let mut buf = BytesMut::with_capacity(FRAME_HEADER_SIZE + 5);
792
793        let header = FrameHeader {
794            length: 5,
795            frame_type: FrameType::Priority,
796            flags: 0,
797            stream_id: self.stream_id,
798        };
799        header.serialize(&mut buf);
800
801        let dep = if self.exclusive {
802            self.stream_dependency | 0x80000000
803        } else {
804            self.stream_dependency
805        };
806        buf.put_u32(dep);
807        buf.put_u8(self.weight);
808
809        buf
810    }
811
812    /// Parse from payload.
813    pub fn parse(stream_id: u32, mut payload: Bytes) -> Result<Self, String> {
814        if stream_id == 0 {
815            return Err("PRIORITY frame must have non-zero stream ID".to_string());
816        }
817        if payload.remaining() < 5 {
818            return Err("PRIORITY frame payload too short".to_string());
819        }
820
821        let dep_raw = payload.get_u32();
822        let exclusive = (dep_raw & 0x80000000) != 0;
823        let stream_dependency = dep_raw & 0x7fffffff;
824        let weight = payload.get_u8();
825
826        // RFC 9113 Section 6.3: Stream cannot depend on itself
827        if stream_dependency == stream_id {
828            return Err("PRIORITY frame stream cannot depend on itself".to_string());
829        }
830
831        Ok(Self {
832            stream_id,
833            exclusive,
834            stream_dependency,
835            weight,
836        })
837    }
838}
839
840/// PUSH_PROMISE frame (RFC 9113 Section 6.6).
841#[derive(Debug, Clone)]
842pub struct PushPromiseFrame {
843    pub stream_id: u32,
844    pub promised_stream_id: u32,
845    pub header_block: Bytes,
846    pub end_headers: bool,
847}
848
849impl PushPromiseFrame {
850    /// Create a new PUSH_PROMISE frame.
851    pub fn new(stream_id: u32, promised_stream_id: u32, header_block: Bytes) -> Self {
852        Self {
853            stream_id,
854            promised_stream_id,
855            header_block,
856            end_headers: true,
857        }
858    }
859
860    /// Set end_headers flag.
861    pub fn end_headers(mut self, end: bool) -> Self {
862        self.end_headers = end;
863        self
864    }
865
866    /// Serialize to bytes.
867    pub fn serialize(&self) -> BytesMut {
868        let payload_len = 4 + self.header_block.len(); // promised_stream_id (4) + header_block
869        let mut buf = BytesMut::with_capacity(FRAME_HEADER_SIZE + payload_len);
870
871        let header = FrameHeader {
872            length: payload_len as u32,
873            frame_type: FrameType::PushPromise,
874            flags: if self.end_headers {
875                flags::END_HEADERS
876            } else {
877                0
878            },
879            stream_id: self.stream_id,
880        };
881        header.serialize(&mut buf);
882
883        // Promised stream ID (31 bits, reserved bit must be 0)
884        buf.put_u32(self.promised_stream_id & 0x7fffffff);
885        buf.extend_from_slice(&self.header_block);
886
887        buf
888    }
889
890    /// Parse from payload (with padding handling).
891    pub fn parse(stream_id: u32, flags: u8, mut payload: Bytes) -> Result<Self, String> {
892        if stream_id == 0 {
893            return Err("PUSH_PROMISE frame must have non-zero stream ID".to_string());
894        }
895
896        let end_headers = (flags & flags::END_HEADERS) != 0;
897        let padded = (flags & flags::PADDED) != 0;
898
899        // Parse padding length (if PADDED flag set)
900        let pad_len = if padded {
901            if payload.remaining() < 1 {
902                return Err("PADDED PUSH_PROMISE frame missing padding length".to_string());
903            }
904            let pad_len = payload.get_u8() as usize;
905            if pad_len >= payload.remaining() {
906                return Err("Padding length exceeds payload size".to_string());
907            }
908            pad_len
909        } else {
910            0
911        };
912
913        // Parse promised stream ID
914        if payload.remaining() < 4 {
915            return Err("PUSH_PROMISE frame missing promised stream ID".to_string());
916        }
917        let promised_stream_id_raw = payload.get_u32();
918        if (promised_stream_id_raw & 0x80000000) != 0 {
919            return Err("PUSH_PROMISE frame reserved bit set in promised stream ID".to_string());
920        }
921        let promised_stream_id = promised_stream_id_raw & 0x7fffffff;
922
923        // Extract header block (remaining payload minus padding)
924        let header_block_len = payload.remaining() - pad_len;
925        if header_block_len == 0 {
926            return Err("PUSH_PROMISE frame header block is empty".to_string());
927        }
928        let header_block = payload.copy_to_bytes(header_block_len);
929        // Skip padding bytes
930        payload.advance(pad_len);
931
932        Ok(Self {
933            stream_id,
934            promised_stream_id,
935            header_block,
936            end_headers,
937        })
938    }
939}
940
941/// RST_STREAM frame.
942#[derive(Debug, Clone)]
943pub struct RstStreamFrame {
944    pub stream_id: u32,
945    pub error_code: ErrorCode,
946}
947
948impl RstStreamFrame {
949    /// Create a new RST_STREAM frame.
950    pub fn new(stream_id: u32, error_code: ErrorCode) -> Self {
951        Self {
952            stream_id,
953            error_code,
954        }
955    }
956
957    /// Serialize to bytes.
958    pub fn serialize(&self) -> BytesMut {
959        let mut buf = BytesMut::with_capacity(FRAME_HEADER_SIZE + 4);
960
961        let header = FrameHeader {
962            length: 4,
963            frame_type: FrameType::RstStream,
964            flags: 0,
965            stream_id: self.stream_id,
966        };
967        header.serialize(&mut buf);
968        buf.put_u32(self.error_code as u32);
969
970        buf
971    }
972
973    /// Parse from payload.
974    pub fn parse(stream_id: u32, mut payload: Bytes) -> Result<Self, String> {
975        if stream_id == 0 {
976            return Err("RST_STREAM frame must have non-zero stream ID".to_string());
977        }
978        if payload.remaining() < 4 {
979            return Err("RST_STREAM frame payload too short".to_string());
980        }
981
982        let error_code_raw = payload.get_u32();
983        let error_code = match error_code_raw {
984            0x0 => ErrorCode::NoError,
985            0x1 => ErrorCode::ProtocolError,
986            0x2 => ErrorCode::InternalError,
987            0x3 => ErrorCode::FlowControlError,
988            0x4 => ErrorCode::SettingsTimeout,
989            0x5 => ErrorCode::StreamClosed,
990            0x6 => ErrorCode::FrameSizeError,
991            0x7 => ErrorCode::RefusedStream,
992            0x8 => ErrorCode::Cancel,
993            0x9 => ErrorCode::CompressionError,
994            0xa => ErrorCode::ConnectError,
995            0xb => ErrorCode::EnhanceYourCalm,
996            0xc => ErrorCode::InadequateSecurity,
997            0xd => ErrorCode::Http11Required,
998            _ => ErrorCode::ProtocolError,
999        };
1000
1001        Ok(Self {
1002            stream_id,
1003            error_code,
1004        })
1005    }
1006}
1007
1008#[cfg(test)]
1009mod tests {
1010    use super::*;
1011
1012    #[test]
1013    fn test_settings_frame_serialization() {
1014        let mut settings = SettingsFrame::new();
1015        settings
1016            .set(SettingsId::HeaderTableSize, 65536)
1017            .set(SettingsId::MaxConcurrentStreams, 1000)
1018            .set(SettingsId::InitialWindowSize, 6291456);
1019
1020        let buf = settings.serialize();
1021
1022        // Frame header (9) + 3 settings (3 * 6 = 18) = 27 bytes
1023        assert_eq!(buf.len(), 27);
1024
1025        // Verify frame header
1026        assert_eq!(buf[0..3], [0, 0, 18]); // Length = 18
1027        assert_eq!(buf[3], 0x4); // Type = SETTINGS
1028        assert_eq!(buf[4], 0); // Flags = 0
1029        assert_eq!(buf[5..9], [0, 0, 0, 0]); // Stream ID = 0
1030    }
1031
1032    #[test]
1033    fn test_settings_ack_frame() {
1034        let settings = SettingsFrame::ack();
1035        let buf = settings.serialize();
1036
1037        assert_eq!(buf.len(), 9); // Just header, no payload
1038        assert_eq!(buf[0..3], [0, 0, 0]); // Length = 0
1039        assert_eq!(buf[3], 0x4); // Type = SETTINGS
1040        assert_eq!(buf[4], 0x1); // Flags = ACK
1041    }
1042
1043    #[test]
1044    fn test_window_update_frame() {
1045        let frame = WindowUpdateFrame::new(0, 15663105);
1046        let buf = frame.serialize();
1047
1048        assert_eq!(buf.len(), 13); // 9 header + 4 payload
1049        assert_eq!(buf[3], 0x8); // Type = WINDOW_UPDATE
1050    }
1051
1052    #[test]
1053    fn test_frame_header_parse() {
1054        let bytes = [0, 0, 18, 0x4, 0, 0, 0, 0, 0];
1055        let header = FrameHeader::parse(&bytes).unwrap();
1056
1057        assert_eq!(header.length, 18);
1058        assert_eq!(header.frame_type, FrameType::Settings);
1059        assert_eq!(header.flags, 0);
1060        assert_eq!(header.stream_id, 0);
1061    }
1062}