Skip to main content

stackforge_core/layer/http2/
builder.rs

1//! HTTP/2 frame and connection builders.
2//!
3//! Provides builder types for constructing HTTP/2 frames and complete
4//! HTTP/2 connections (preface + frames). Follows the "Permissive Builder"
5//! pattern: allows constructing any frame combination including malformed
6//! ones for security testing.
7
8use super::frames::{Http2FrameType, flags};
9use super::hpack::HpackEncoder;
10
11// ============================================================================
12// Core frame building function
13// ============================================================================
14
15/// Build raw bytes for an HTTP/2 frame.
16///
17/// Format: 3 bytes length (big-endian) | 1 byte type | 1 byte flags | 4 bytes stream_id | payload
18pub fn build_frame(frame_type: u8, flags: u8, stream_id: u32, payload: &[u8]) -> Vec<u8> {
19    let len = payload.len() as u32;
20    let mut out = Vec::with_capacity(9 + payload.len());
21    out.push(((len >> 16) & 0xFF) as u8);
22    out.push(((len >> 8) & 0xFF) as u8);
23    out.push((len & 0xFF) as u8);
24    out.push(frame_type);
25    out.push(flags);
26    out.extend_from_slice(&(stream_id & 0x7FFFFFFF).to_be_bytes());
27    out.extend_from_slice(payload);
28    out
29}
30
31// ============================================================================
32// Http2FrameBuilder
33// ============================================================================
34
35/// Builder for a single HTTP/2 frame.
36///
37/// # Example
38/// ```
39/// use stackforge_core::layer::http2::builder::Http2FrameBuilder;
40/// use stackforge_core::layer::http2::frames::Http2FrameType;
41///
42/// let frame = Http2FrameBuilder::settings_ack().build();
43/// assert_eq!(frame.len(), 9); // 9-byte header, empty payload
44/// ```
45#[derive(Debug, Clone)]
46pub struct Http2FrameBuilder {
47    frame_type: Http2FrameType,
48    flags: u8,
49    stream_id: u32,
50    payload: Vec<u8>,
51}
52
53impl Http2FrameBuilder {
54    /// Create a new frame builder for the given frame type.
55    pub fn new(frame_type: Http2FrameType) -> Self {
56        Http2FrameBuilder {
57            frame_type,
58            flags: 0,
59            stream_id: 0,
60            payload: Vec::new(),
61        }
62    }
63
64    /// Set the flags byte.
65    pub fn flags(mut self, flags: u8) -> Self {
66        self.flags = flags;
67        self
68    }
69
70    /// Set an additional flag bit (OR with existing flags).
71    pub fn add_flag(mut self, flag: u8) -> Self {
72        self.flags |= flag;
73        self
74    }
75
76    /// Set the stream ID.
77    pub fn stream_id(mut self, id: u32) -> Self {
78        self.stream_id = id;
79        self
80    }
81
82    /// Set the frame payload.
83    pub fn payload(mut self, data: Vec<u8>) -> Self {
84        self.payload = data;
85        self
86    }
87
88    /// Set the END_STREAM flag (0x1).
89    ///
90    /// Used with DATA and HEADERS frames.
91    pub fn end_stream(mut self) -> Self {
92        self.flags |= 0x01;
93        self
94    }
95
96    /// Set the END_HEADERS flag (0x4).
97    ///
98    /// Used with HEADERS, PUSH_PROMISE, and CONTINUATION frames.
99    pub fn end_headers(mut self) -> Self {
100        self.flags |= 0x04;
101        self
102    }
103
104    /// Build the frame into bytes.
105    pub fn build(&self) -> Vec<u8> {
106        build_frame(
107            self.frame_type.as_u8(),
108            self.flags,
109            self.stream_id,
110            &self.payload,
111        )
112    }
113
114    // -------------------------------------------------------------------------
115    // Frame factory methods
116    // -------------------------------------------------------------------------
117
118    /// Create an empty SETTINGS frame (stream 0).
119    pub fn settings() -> Self {
120        Http2FrameBuilder::new(Http2FrameType::Settings)
121            .stream_id(0)
122            .flags(0)
123    }
124
125    /// Create a SETTINGS ACK frame (stream 0, ACK flag set).
126    pub fn settings_ack() -> Self {
127        Http2FrameBuilder::new(Http2FrameType::Settings)
128            .stream_id(0)
129            .flags(flags::SETTINGS_ACK)
130    }
131
132    /// Create a SETTINGS frame with parameters.
133    ///
134    /// Each entry is (settings_id, value). The payload is 6 bytes per entry.
135    pub fn settings_with_params(params: &[(u16, u32)]) -> Self {
136        let mut payload = Vec::with_capacity(params.len() * 6);
137        for &(id, val) in params {
138            payload.extend_from_slice(&id.to_be_bytes());
139            payload.extend_from_slice(&val.to_be_bytes());
140        }
141        Http2FrameBuilder::new(Http2FrameType::Settings)
142            .stream_id(0)
143            .payload(payload)
144    }
145
146    /// Create a PING frame with 8 bytes of opaque data.
147    pub fn ping(data: [u8; 8]) -> Self {
148        Http2FrameBuilder::new(Http2FrameType::Ping)
149            .stream_id(0)
150            .payload(data.to_vec())
151    }
152
153    /// Create a PING ACK frame (response to a PING).
154    pub fn ping_ack(data: [u8; 8]) -> Self {
155        Http2FrameBuilder::new(Http2FrameType::Ping)
156            .stream_id(0)
157            .flags(flags::PING_ACK)
158            .payload(data.to_vec())
159    }
160
161    /// Create a GOAWAY frame.
162    ///
163    /// # Arguments
164    /// - `last_stream`: the last stream ID processed
165    /// - `error_code`: the error code (see `frames::error_codes`)
166    pub fn goaway(last_stream: u32, error_code: u32) -> Self {
167        let mut payload = Vec::with_capacity(8);
168        payload.extend_from_slice(&(last_stream & 0x7FFFFFFF).to_be_bytes());
169        payload.extend_from_slice(&error_code.to_be_bytes());
170        Http2FrameBuilder::new(Http2FrameType::GoAway)
171            .stream_id(0)
172            .payload(payload)
173    }
174
175    /// Create a WINDOW_UPDATE frame.
176    ///
177    /// # Arguments
178    /// - `increment`: window size increment (1-2^31-1)
179    /// - `stream_id`: stream ID (0 for connection-level)
180    pub fn window_update(increment: u32, stream_id: u32) -> Self {
181        let mut payload = Vec::with_capacity(4);
182        payload.extend_from_slice(&(increment & 0x7FFFFFFF).to_be_bytes());
183        Http2FrameBuilder::new(Http2FrameType::WindowUpdate)
184            .stream_id(stream_id)
185            .payload(payload)
186    }
187
188    /// Create a RST_STREAM frame.
189    ///
190    /// # Arguments
191    /// - `stream_id`: the stream to reset
192    /// - `error_code`: the error code
193    pub fn rst_stream(stream_id: u32, error_code: u32) -> Self {
194        let mut payload = Vec::with_capacity(4);
195        payload.extend_from_slice(&error_code.to_be_bytes());
196        Http2FrameBuilder::new(Http2FrameType::RstStream)
197            .stream_id(stream_id)
198            .payload(payload)
199    }
200
201    /// Create a HEADERS frame carrying HPACK-encoded header data.
202    ///
203    /// Sets END_HEADERS by default. Use `.flags()` to override.
204    pub fn headers_frame(stream_id: u32, hpack_data: Vec<u8>) -> Self {
205        Http2FrameBuilder::new(Http2FrameType::Headers)
206            .stream_id(stream_id)
207            .flags(flags::HEADERS_END_HEADERS)
208            .payload(hpack_data)
209    }
210
211    /// Create a HEADERS frame with END_STREAM + END_HEADERS flags set.
212    pub fn headers_frame_final(stream_id: u32, hpack_data: Vec<u8>) -> Self {
213        Http2FrameBuilder::new(Http2FrameType::Headers)
214            .stream_id(stream_id)
215            .flags(flags::HEADERS_END_HEADERS | flags::HEADERS_END_STREAM)
216            .payload(hpack_data)
217    }
218
219    /// Create a DATA frame.
220    pub fn data_frame(stream_id: u32, data: Vec<u8>) -> Self {
221        Http2FrameBuilder::new(Http2FrameType::Data)
222            .stream_id(stream_id)
223            .payload(data)
224    }
225
226    /// Create a DATA frame with END_STREAM set.
227    pub fn data_frame_final(stream_id: u32, data: Vec<u8>) -> Self {
228        Http2FrameBuilder::new(Http2FrameType::Data)
229            .stream_id(stream_id)
230            .flags(flags::DATA_END_STREAM)
231            .payload(data)
232    }
233
234    /// Create a CONTINUATION frame.
235    pub fn continuation(stream_id: u32, hpack_data: Vec<u8>) -> Self {
236        Http2FrameBuilder::new(Http2FrameType::Continuation)
237            .stream_id(stream_id)
238            .payload(hpack_data)
239    }
240
241    /// Create a CONTINUATION frame with END_HEADERS set.
242    pub fn continuation_final(stream_id: u32, hpack_data: Vec<u8>) -> Self {
243        Http2FrameBuilder::new(Http2FrameType::Continuation)
244            .stream_id(stream_id)
245            .flags(flags::CONTINUATION_END_HEADERS)
246            .payload(hpack_data)
247    }
248
249    /// Create a PRIORITY frame.
250    ///
251    /// # Arguments
252    /// - `stream_id`: the stream being prioritized
253    /// - `exclusive`: exclusive dependency flag
254    /// - `stream_dep`: stream dependency
255    /// - `weight`: priority weight (0-255, actual weight = weight + 1)
256    pub fn priority_frame(stream_id: u32, exclusive: bool, stream_dep: u32, weight: u8) -> Self {
257        let dep = if exclusive {
258            stream_dep | 0x80000000
259        } else {
260            stream_dep & 0x7FFFFFFF
261        };
262        let mut payload = Vec::with_capacity(5);
263        payload.extend_from_slice(&dep.to_be_bytes());
264        payload.push(weight);
265        Http2FrameBuilder::new(Http2FrameType::Priority)
266            .stream_id(stream_id)
267            .payload(payload)
268    }
269
270    /// Create a PUSH_PROMISE frame.
271    ///
272    /// # Arguments
273    /// - `stream_id`: the associated stream
274    /// - `promised_stream_id`: the stream ID being promised
275    /// - `hpack_data`: HPACK-encoded headers for the promised request
276    pub fn push_promise(stream_id: u32, promised_stream_id: u32, hpack_data: Vec<u8>) -> Self {
277        let mut payload = Vec::with_capacity(4 + hpack_data.len());
278        payload.extend_from_slice(&(promised_stream_id & 0x7FFFFFFF).to_be_bytes());
279        payload.extend_from_slice(&hpack_data);
280        Http2FrameBuilder::new(Http2FrameType::PushPromise)
281            .stream_id(stream_id)
282            .flags(flags::PUSH_PROMISE_END_HEADERS)
283            .payload(payload)
284    }
285}
286
287// ============================================================================
288// Http2Builder — full connection builder
289// ============================================================================
290
291/// Builder for a complete HTTP/2 connection sequence.
292///
293/// Optionally includes the client connection preface, followed by one or
294/// more frames.
295///
296/// # Example
297/// ```
298/// use stackforge_core::layer::http2::builder::{Http2Builder, Http2FrameBuilder};
299///
300/// let bytes = Http2Builder::new()
301///     .frame(Http2FrameBuilder::settings())
302///     .frame(Http2FrameBuilder::settings_ack())
303///     .build();
304/// ```
305#[derive(Debug, Clone)]
306pub struct Http2Builder {
307    /// Whether to prepend the client connection preface.
308    include_preface: bool,
309    /// Ordered list of frames to include.
310    frames: Vec<Http2FrameBuilder>,
311}
312
313impl Default for Http2Builder {
314    fn default() -> Self {
315        Self::new()
316    }
317}
318
319impl Http2Builder {
320    /// Create a builder that includes the HTTP/2 client connection preface.
321    pub fn new() -> Self {
322        Http2Builder {
323            include_preface: true,
324            frames: Vec::new(),
325        }
326    }
327
328    /// Create a builder without the connection preface.
329    pub fn without_preface() -> Self {
330        Http2Builder {
331            include_preface: false,
332            frames: Vec::new(),
333        }
334    }
335
336    /// Add a frame to the sequence.
337    pub fn frame(mut self, f: Http2FrameBuilder) -> Self {
338        self.frames.push(f);
339        self
340    }
341
342    /// Get the total byte size of the built output.
343    pub fn header_size(&self) -> usize {
344        let preface_len = if self.include_preface { 24 } else { 0 };
345        let frames_len: usize = self.frames.iter().map(|f| 9 + f.payload.len()).sum();
346        preface_len + frames_len
347    }
348
349    /// Build the complete HTTP/2 connection sequence into bytes.
350    pub fn build(&self) -> Vec<u8> {
351        let mut out = Vec::with_capacity(self.header_size());
352
353        if self.include_preface {
354            out.extend_from_slice(super::frames::HTTP2_PREFACE);
355        }
356
357        for frame in &self.frames {
358            out.extend_from_slice(&frame.build());
359        }
360
361        out
362    }
363}
364
365// ============================================================================
366// HTTP/2 request/response helpers
367// ============================================================================
368
369/// Build a complete HTTP/2 GET request as bytes.
370///
371/// Produces: preface + SETTINGS frame + HEADERS frame with HPACK-encoded headers.
372///
373/// # Arguments
374/// - `host`: the `:authority` (Host) header value
375/// - `path`: the `:path` value (e.g., "/")
376/// - `stream_id`: stream identifier (must be odd for client-initiated, typically 1)
377pub fn build_get_request(host: &str, path: &str, stream_id: u32) -> Vec<u8> {
378    let encoder = HpackEncoder::new();
379    let headers = vec![
380        (":method", "GET"),
381        (":path", path),
382        (":scheme", "https"),
383        (":authority", host),
384        ("accept", "*/*"),
385    ];
386    let hpack_data = encoder.encode(&headers);
387
388    Http2Builder::new()
389        .frame(Http2FrameBuilder::settings())
390        .frame(Http2FrameBuilder::headers_frame_final(
391            stream_id, hpack_data,
392        ))
393        .build()
394}
395
396/// Build a complete HTTP/2 200 OK response as bytes.
397///
398/// Produces: SETTINGS ACK + HEADERS frame + optional DATA frame.
399///
400/// # Arguments
401/// - `stream_id`: the stream ID to respond on
402/// - `body`: optional response body; if `Some`, a DATA frame with END_STREAM is appended
403pub fn build_response_200(stream_id: u32, body: Option<&[u8]>) -> Vec<u8> {
404    let encoder = HpackEncoder::new();
405    let headers = vec![(":status", "200"), ("content-type", "application/json")];
406    let hpack_data = encoder.encode(&headers);
407
408    let headers_flags = if body.is_none() {
409        // END_HEADERS | END_STREAM if no body
410        flags::HEADERS_END_HEADERS | flags::HEADERS_END_STREAM
411    } else {
412        flags::HEADERS_END_HEADERS
413    };
414
415    let mut builder = Http2Builder::without_preface()
416        .frame(Http2FrameBuilder::settings_ack())
417        .frame(
418            Http2FrameBuilder::new(Http2FrameType::Headers)
419                .stream_id(stream_id)
420                .flags(headers_flags)
421                .payload(hpack_data),
422        );
423
424    if let Some(body_data) = body {
425        builder = builder.frame(Http2FrameBuilder::data_frame_final(
426            stream_id,
427            body_data.to_vec(),
428        ));
429    }
430
431    builder.build()
432}
433
434// ============================================================================
435// Tests
436// ============================================================================
437
438#[cfg(test)]
439mod tests {
440    use super::*;
441    use crate::layer::http2::frames::{
442        Http2Frame, parse_all_frames, parse_goaway, parse_rst_stream, parse_settings,
443        parse_window_update,
444    };
445
446    #[test]
447    fn test_build_settings_frame() {
448        let bytes = Http2FrameBuilder::settings().build();
449        assert_eq!(bytes.len(), 9); // empty payload
450        let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
451        assert_eq!(frame.frame_type, Http2FrameType::Settings);
452        assert!(!frame.is_ack());
453        assert_eq!(frame.stream_id, 0);
454    }
455
456    #[test]
457    fn test_build_settings_ack() {
458        let bytes = Http2FrameBuilder::settings_ack().build();
459        let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
460        assert_eq!(frame.frame_type, Http2FrameType::Settings);
461        assert!(frame.is_ack());
462    }
463
464    #[test]
465    fn test_build_settings_with_params() {
466        use crate::layer::http2::frames::settings_id;
467
468        let params = [
469            (settings_id::INITIAL_WINDOW_SIZE, 65535u32),
470            (settings_id::MAX_FRAME_SIZE, 16384),
471        ];
472        let bytes = Http2FrameBuilder::settings_with_params(&params).build();
473        let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
474
475        let settings = parse_settings(frame.payload(&bytes));
476        assert_eq!(settings.len(), 2);
477        assert_eq!(settings[0], (settings_id::INITIAL_WINDOW_SIZE, 65535));
478        assert_eq!(settings[1], (settings_id::MAX_FRAME_SIZE, 16384));
479    }
480
481    #[test]
482    fn test_build_ping() {
483        let data = [1u8, 2, 3, 4, 5, 6, 7, 8];
484        let bytes = Http2FrameBuilder::ping(data).build();
485        let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
486        assert_eq!(frame.frame_type, Http2FrameType::Ping);
487        assert!(!frame.is_ack());
488        assert_eq!(frame.payload(&bytes), &data);
489    }
490
491    #[test]
492    fn test_build_ping_ack() {
493        let data = [1u8, 2, 3, 4, 5, 6, 7, 8];
494        let bytes = Http2FrameBuilder::ping_ack(data).build();
495        let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
496        assert!(frame.is_ack());
497        assert_eq!(frame.payload(&bytes), &data);
498    }
499
500    #[test]
501    fn test_build_goaway() {
502        use crate::layer::http2::frames::error_codes;
503        let bytes = Http2FrameBuilder::goaway(3, error_codes::NO_ERROR).build();
504        let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
505        assert_eq!(frame.frame_type, Http2FrameType::GoAway);
506        let (last_id, error) = parse_goaway(frame.payload(&bytes)).unwrap();
507        assert_eq!(last_id, 3);
508        assert_eq!(error, error_codes::NO_ERROR);
509    }
510
511    #[test]
512    fn test_build_window_update() {
513        let bytes = Http2FrameBuilder::window_update(65535, 0).build();
514        let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
515        assert_eq!(frame.frame_type, Http2FrameType::WindowUpdate);
516        let increment = parse_window_update(frame.payload(&bytes)).unwrap();
517        assert_eq!(increment, 65535);
518    }
519
520    #[test]
521    fn test_build_rst_stream() {
522        use crate::layer::http2::frames::error_codes;
523        let bytes = Http2FrameBuilder::rst_stream(1, error_codes::CANCEL).build();
524        let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
525        assert_eq!(frame.frame_type, Http2FrameType::RstStream);
526        assert_eq!(frame.stream_id, 1);
527        let error = parse_rst_stream(frame.payload(&bytes)).unwrap();
528        assert_eq!(error, error_codes::CANCEL);
529    }
530
531    #[test]
532    fn test_build_headers_frame() {
533        let hpack_data = vec![0x82u8]; // ":method: GET"
534        let bytes = Http2FrameBuilder::headers_frame(1, hpack_data.clone()).build();
535        let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
536        assert_eq!(frame.frame_type, Http2FrameType::Headers);
537        assert!(frame.is_end_headers());
538        assert!(!frame.is_end_stream());
539        assert_eq!(frame.payload(&bytes), &hpack_data);
540    }
541
542    #[test]
543    fn test_build_headers_final() {
544        let hpack_data = vec![0x82u8];
545        let bytes = Http2FrameBuilder::headers_frame_final(1, hpack_data).build();
546        let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
547        assert!(frame.is_end_headers());
548        assert!(frame.is_end_stream());
549    }
550
551    #[test]
552    fn test_build_data_frame() {
553        let data = b"Hello, HTTP/2!";
554        let bytes = Http2FrameBuilder::data_frame(1, data.to_vec()).build();
555        let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
556        assert_eq!(frame.frame_type, Http2FrameType::Data);
557        assert!(!frame.is_end_stream());
558        assert_eq!(frame.payload(&bytes), data);
559    }
560
561    #[test]
562    fn test_build_data_frame_final() {
563        let data = b"last chunk";
564        let bytes = Http2FrameBuilder::data_frame_final(1, data.to_vec()).build();
565        let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
566        assert!(frame.is_end_stream());
567    }
568
569    #[test]
570    fn test_http2_builder_with_preface() {
571        let bytes = Http2Builder::new()
572            .frame(Http2FrameBuilder::settings())
573            .frame(Http2FrameBuilder::settings_ack())
574            .build();
575
576        // Should start with preface
577        assert!(bytes.starts_with(super::super::frames::HTTP2_PREFACE));
578
579        let frames = parse_all_frames(&bytes);
580        assert_eq!(frames.len(), 2);
581        assert_eq!(frames[0].frame_type, Http2FrameType::Settings);
582        assert_eq!(frames[1].frame_type, Http2FrameType::Settings);
583        assert!(frames[1].is_ack());
584    }
585
586    #[test]
587    fn test_http2_builder_without_preface() {
588        let bytes = Http2Builder::without_preface()
589            .frame(Http2FrameBuilder::settings_ack())
590            .build();
591
592        assert!(!bytes.starts_with(super::super::frames::HTTP2_PREFACE));
593        let frames = parse_all_frames(&bytes);
594        assert_eq!(frames.len(), 1);
595    }
596
597    #[test]
598    fn test_http2_builder_header_size() {
599        let builder = Http2Builder::new()
600            .frame(Http2FrameBuilder::settings()) // 9 bytes
601            .frame(Http2FrameBuilder::settings_ack()); // 9 bytes
602
603        // 24 (preface) + 9 + 9 = 42
604        assert_eq!(builder.header_size(), 42);
605        assert_eq!(builder.build().len(), 42);
606    }
607
608    #[test]
609    fn test_build_get_request() {
610        let bytes = build_get_request("example.com", "/", 1);
611        assert!(bytes.starts_with(super::super::frames::HTTP2_PREFACE));
612
613        let frames = parse_all_frames(&bytes);
614        // Should have at least 2 frames: SETTINGS + HEADERS
615        assert!(frames.len() >= 2);
616        assert_eq!(frames[0].frame_type, Http2FrameType::Settings);
617        assert_eq!(frames[1].frame_type, Http2FrameType::Headers);
618        assert!(frames[1].is_end_headers());
619        assert!(frames[1].is_end_stream());
620        assert_eq!(frames[1].stream_id, 1);
621    }
622
623    #[test]
624    fn test_build_response_200_no_body() {
625        let bytes = build_response_200(1, None);
626        let frames = parse_all_frames(&bytes);
627        assert!(frames.len() >= 2);
628        assert_eq!(frames[0].frame_type, Http2FrameType::Settings);
629        assert!(frames[0].is_ack());
630        assert_eq!(frames[1].frame_type, Http2FrameType::Headers);
631    }
632
633    #[test]
634    fn test_build_response_200_with_body() {
635        let body = b"{\"ok\": true}";
636        let bytes = build_response_200(1, Some(body));
637        let frames = parse_all_frames(&bytes);
638        assert!(frames.len() >= 3);
639        assert_eq!(frames[2].frame_type, Http2FrameType::Data);
640        assert!(frames[2].is_end_stream());
641        assert_eq!(frames[2].payload(&bytes), body);
642    }
643
644    #[test]
645    fn test_end_stream_and_end_headers_helpers() {
646        let builder = Http2FrameBuilder::new(Http2FrameType::Headers)
647            .stream_id(1)
648            .end_stream()
649            .end_headers()
650            .payload(vec![0x82]);
651
652        let bytes = builder.build();
653        let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
654        assert!(frame.is_end_stream());
655        assert!(frame.is_end_headers());
656    }
657
658    #[test]
659    fn test_priority_frame() {
660        let bytes = Http2FrameBuilder::priority_frame(1, false, 0, 15).build();
661        let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
662        assert_eq!(frame.frame_type, Http2FrameType::Priority);
663        assert_eq!(frame.stream_id, 1);
664        assert_eq!(frame.length, 5);
665    }
666}