stackforge_core/layer/http2/
builder.rs1use super::frames::{Http2FrameType, flags};
9use super::hpack::HpackEncoder;
10
11#[must_use]
19pub fn build_frame(frame_type: u8, flags: u8, stream_id: u32, payload: &[u8]) -> Vec<u8> {
20 let len = payload.len() as u32;
21 let mut out = Vec::with_capacity(9 + payload.len());
22 out.push(((len >> 16) & 0xFF) as u8);
23 out.push(((len >> 8) & 0xFF) as u8);
24 out.push((len & 0xFF) as u8);
25 out.push(frame_type);
26 out.push(flags);
27 out.extend_from_slice(&(stream_id & 0x7FFFFFFF).to_be_bytes());
28 out.extend_from_slice(payload);
29 out
30}
31
32#[derive(Debug, Clone)]
47pub struct Http2FrameBuilder {
48 frame_type: Http2FrameType,
49 flags: u8,
50 stream_id: u32,
51 payload: Vec<u8>,
52}
53
54impl Http2FrameBuilder {
55 #[must_use]
57 pub fn new(frame_type: Http2FrameType) -> Self {
58 Http2FrameBuilder {
59 frame_type,
60 flags: 0,
61 stream_id: 0,
62 payload: Vec::new(),
63 }
64 }
65
66 #[must_use]
68 pub fn flags(mut self, flags: u8) -> Self {
69 self.flags = flags;
70 self
71 }
72
73 #[must_use]
75 pub fn add_flag(mut self, flag: u8) -> Self {
76 self.flags |= flag;
77 self
78 }
79
80 #[must_use]
82 pub fn stream_id(mut self, id: u32) -> Self {
83 self.stream_id = id;
84 self
85 }
86
87 #[must_use]
89 pub fn payload(mut self, data: Vec<u8>) -> Self {
90 self.payload = data;
91 self
92 }
93
94 #[must_use]
98 pub fn end_stream(mut self) -> Self {
99 self.flags |= 0x01;
100 self
101 }
102
103 #[must_use]
107 pub fn end_headers(mut self) -> Self {
108 self.flags |= 0x04;
109 self
110 }
111
112 #[must_use]
114 pub fn build(&self) -> Vec<u8> {
115 build_frame(
116 self.frame_type.as_u8(),
117 self.flags,
118 self.stream_id,
119 &self.payload,
120 )
121 }
122
123 #[must_use]
129 pub fn settings() -> Self {
130 Http2FrameBuilder::new(Http2FrameType::Settings)
131 .stream_id(0)
132 .flags(0)
133 }
134
135 #[must_use]
137 pub fn settings_ack() -> Self {
138 Http2FrameBuilder::new(Http2FrameType::Settings)
139 .stream_id(0)
140 .flags(flags::SETTINGS_ACK)
141 }
142
143 #[must_use]
147 pub fn settings_with_params(params: &[(u16, u32)]) -> Self {
148 let mut payload = Vec::with_capacity(params.len() * 6);
149 for &(id, val) in params {
150 payload.extend_from_slice(&id.to_be_bytes());
151 payload.extend_from_slice(&val.to_be_bytes());
152 }
153 Http2FrameBuilder::new(Http2FrameType::Settings)
154 .stream_id(0)
155 .payload(payload)
156 }
157
158 #[must_use]
160 pub fn ping(data: [u8; 8]) -> Self {
161 Http2FrameBuilder::new(Http2FrameType::Ping)
162 .stream_id(0)
163 .payload(data.to_vec())
164 }
165
166 #[must_use]
168 pub fn ping_ack(data: [u8; 8]) -> Self {
169 Http2FrameBuilder::new(Http2FrameType::Ping)
170 .stream_id(0)
171 .flags(flags::PING_ACK)
172 .payload(data.to_vec())
173 }
174
175 #[must_use]
181 pub fn goaway(last_stream: u32, error_code: u32) -> Self {
182 let mut payload = Vec::with_capacity(8);
183 payload.extend_from_slice(&(last_stream & 0x7FFFFFFF).to_be_bytes());
184 payload.extend_from_slice(&error_code.to_be_bytes());
185 Http2FrameBuilder::new(Http2FrameType::GoAway)
186 .stream_id(0)
187 .payload(payload)
188 }
189
190 #[must_use]
196 pub fn window_update(increment: u32, stream_id: u32) -> Self {
197 let mut payload = Vec::with_capacity(4);
198 payload.extend_from_slice(&(increment & 0x7FFFFFFF).to_be_bytes());
199 Http2FrameBuilder::new(Http2FrameType::WindowUpdate)
200 .stream_id(stream_id)
201 .payload(payload)
202 }
203
204 #[must_use]
210 pub fn rst_stream(stream_id: u32, error_code: u32) -> Self {
211 let mut payload = Vec::with_capacity(4);
212 payload.extend_from_slice(&error_code.to_be_bytes());
213 Http2FrameBuilder::new(Http2FrameType::RstStream)
214 .stream_id(stream_id)
215 .payload(payload)
216 }
217
218 #[must_use]
222 pub fn headers_frame(stream_id: u32, hpack_data: Vec<u8>) -> Self {
223 Http2FrameBuilder::new(Http2FrameType::Headers)
224 .stream_id(stream_id)
225 .flags(flags::HEADERS_END_HEADERS)
226 .payload(hpack_data)
227 }
228
229 #[must_use]
231 pub fn headers_frame_final(stream_id: u32, hpack_data: Vec<u8>) -> Self {
232 Http2FrameBuilder::new(Http2FrameType::Headers)
233 .stream_id(stream_id)
234 .flags(flags::HEADERS_END_HEADERS | flags::HEADERS_END_STREAM)
235 .payload(hpack_data)
236 }
237
238 #[must_use]
240 pub fn data_frame(stream_id: u32, data: Vec<u8>) -> Self {
241 Http2FrameBuilder::new(Http2FrameType::Data)
242 .stream_id(stream_id)
243 .payload(data)
244 }
245
246 #[must_use]
248 pub fn data_frame_final(stream_id: u32, data: Vec<u8>) -> Self {
249 Http2FrameBuilder::new(Http2FrameType::Data)
250 .stream_id(stream_id)
251 .flags(flags::DATA_END_STREAM)
252 .payload(data)
253 }
254
255 #[must_use]
257 pub fn continuation(stream_id: u32, hpack_data: Vec<u8>) -> Self {
258 Http2FrameBuilder::new(Http2FrameType::Continuation)
259 .stream_id(stream_id)
260 .payload(hpack_data)
261 }
262
263 #[must_use]
265 pub fn continuation_final(stream_id: u32, hpack_data: Vec<u8>) -> Self {
266 Http2FrameBuilder::new(Http2FrameType::Continuation)
267 .stream_id(stream_id)
268 .flags(flags::CONTINUATION_END_HEADERS)
269 .payload(hpack_data)
270 }
271
272 #[must_use]
280 pub fn priority_frame(stream_id: u32, exclusive: bool, stream_dep: u32, weight: u8) -> Self {
281 let dep = if exclusive {
282 stream_dep | 0x80000000
283 } else {
284 stream_dep & 0x7FFFFFFF
285 };
286 let mut payload = Vec::with_capacity(5);
287 payload.extend_from_slice(&dep.to_be_bytes());
288 payload.push(weight);
289 Http2FrameBuilder::new(Http2FrameType::Priority)
290 .stream_id(stream_id)
291 .payload(payload)
292 }
293
294 #[must_use]
301 pub fn push_promise(stream_id: u32, promised_stream_id: u32, hpack_data: Vec<u8>) -> Self {
302 let mut payload = Vec::with_capacity(4 + hpack_data.len());
303 payload.extend_from_slice(&(promised_stream_id & 0x7FFFFFFF).to_be_bytes());
304 payload.extend_from_slice(&hpack_data);
305 Http2FrameBuilder::new(Http2FrameType::PushPromise)
306 .stream_id(stream_id)
307 .flags(flags::PUSH_PROMISE_END_HEADERS)
308 .payload(payload)
309 }
310}
311
312#[derive(Debug, Clone)]
331pub struct Http2Builder {
332 include_preface: bool,
334 frames: Vec<Http2FrameBuilder>,
336}
337
338impl Default for Http2Builder {
339 fn default() -> Self {
340 Self::new()
341 }
342}
343
344impl Http2Builder {
345 #[must_use]
347 pub fn new() -> Self {
348 Http2Builder {
349 include_preface: true,
350 frames: Vec::new(),
351 }
352 }
353
354 #[must_use]
356 pub fn without_preface() -> Self {
357 Http2Builder {
358 include_preface: false,
359 frames: Vec::new(),
360 }
361 }
362
363 #[must_use]
365 pub fn frame(mut self, f: Http2FrameBuilder) -> Self {
366 self.frames.push(f);
367 self
368 }
369
370 #[must_use]
372 pub fn header_size(&self) -> usize {
373 let preface_len = if self.include_preface { 24 } else { 0 };
374 let frames_len: usize = self.frames.iter().map(|f| 9 + f.payload.len()).sum();
375 preface_len + frames_len
376 }
377
378 #[must_use]
380 pub fn build(&self) -> Vec<u8> {
381 let mut out = Vec::with_capacity(self.header_size());
382
383 if self.include_preface {
384 out.extend_from_slice(super::frames::HTTP2_PREFACE);
385 }
386
387 for frame in &self.frames {
388 out.extend_from_slice(&frame.build());
389 }
390
391 out
392 }
393}
394
395#[must_use]
408pub fn build_get_request(host: &str, path: &str, stream_id: u32) -> Vec<u8> {
409 let encoder = HpackEncoder::new();
410 let headers = vec![
411 (":method", "GET"),
412 (":path", path),
413 (":scheme", "https"),
414 (":authority", host),
415 ("accept", "*/*"),
416 ];
417 let hpack_data = encoder.encode(&headers);
418
419 Http2Builder::new()
420 .frame(Http2FrameBuilder::settings())
421 .frame(Http2FrameBuilder::headers_frame_final(
422 stream_id, hpack_data,
423 ))
424 .build()
425}
426
427#[must_use]
435pub fn build_response_200(stream_id: u32, body: Option<&[u8]>) -> Vec<u8> {
436 let encoder = HpackEncoder::new();
437 let headers = vec![(":status", "200"), ("content-type", "application/json")];
438 let hpack_data = encoder.encode(&headers);
439
440 let headers_flags = if body.is_none() {
441 flags::HEADERS_END_HEADERS | flags::HEADERS_END_STREAM
443 } else {
444 flags::HEADERS_END_HEADERS
445 };
446
447 let mut builder = Http2Builder::without_preface()
448 .frame(Http2FrameBuilder::settings_ack())
449 .frame(
450 Http2FrameBuilder::new(Http2FrameType::Headers)
451 .stream_id(stream_id)
452 .flags(headers_flags)
453 .payload(hpack_data),
454 );
455
456 if let Some(body_data) = body {
457 builder = builder.frame(Http2FrameBuilder::data_frame_final(
458 stream_id,
459 body_data.to_vec(),
460 ));
461 }
462
463 builder.build()
464}
465
466#[cfg(test)]
471mod tests {
472 use super::*;
473 use crate::layer::http2::frames::{
474 Http2Frame, parse_all_frames, parse_goaway, parse_rst_stream, parse_settings,
475 parse_window_update,
476 };
477
478 #[test]
479 fn test_build_settings_frame() {
480 let bytes = Http2FrameBuilder::settings().build();
481 assert_eq!(bytes.len(), 9); let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
483 assert_eq!(frame.frame_type, Http2FrameType::Settings);
484 assert!(!frame.is_ack());
485 assert_eq!(frame.stream_id, 0);
486 }
487
488 #[test]
489 fn test_build_settings_ack() {
490 let bytes = Http2FrameBuilder::settings_ack().build();
491 let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
492 assert_eq!(frame.frame_type, Http2FrameType::Settings);
493 assert!(frame.is_ack());
494 }
495
496 #[test]
497 fn test_build_settings_with_params() {
498 use crate::layer::http2::frames::settings_id;
499
500 let params = [
501 (settings_id::INITIAL_WINDOW_SIZE, 65535u32),
502 (settings_id::MAX_FRAME_SIZE, 16384),
503 ];
504 let bytes = Http2FrameBuilder::settings_with_params(¶ms).build();
505 let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
506
507 let settings = parse_settings(frame.payload(&bytes));
508 assert_eq!(settings.len(), 2);
509 assert_eq!(settings[0], (settings_id::INITIAL_WINDOW_SIZE, 65535));
510 assert_eq!(settings[1], (settings_id::MAX_FRAME_SIZE, 16384));
511 }
512
513 #[test]
514 fn test_build_ping() {
515 let data = [1u8, 2, 3, 4, 5, 6, 7, 8];
516 let bytes = Http2FrameBuilder::ping(data).build();
517 let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
518 assert_eq!(frame.frame_type, Http2FrameType::Ping);
519 assert!(!frame.is_ack());
520 assert_eq!(frame.payload(&bytes), &data);
521 }
522
523 #[test]
524 fn test_build_ping_ack() {
525 let data = [1u8, 2, 3, 4, 5, 6, 7, 8];
526 let bytes = Http2FrameBuilder::ping_ack(data).build();
527 let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
528 assert!(frame.is_ack());
529 assert_eq!(frame.payload(&bytes), &data);
530 }
531
532 #[test]
533 fn test_build_goaway() {
534 use crate::layer::http2::frames::error_codes;
535 let bytes = Http2FrameBuilder::goaway(3, error_codes::NO_ERROR).build();
536 let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
537 assert_eq!(frame.frame_type, Http2FrameType::GoAway);
538 let (last_id, error) = parse_goaway(frame.payload(&bytes)).unwrap();
539 assert_eq!(last_id, 3);
540 assert_eq!(error, error_codes::NO_ERROR);
541 }
542
543 #[test]
544 fn test_build_window_update() {
545 let bytes = Http2FrameBuilder::window_update(65535, 0).build();
546 let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
547 assert_eq!(frame.frame_type, Http2FrameType::WindowUpdate);
548 let increment = parse_window_update(frame.payload(&bytes)).unwrap();
549 assert_eq!(increment, 65535);
550 }
551
552 #[test]
553 fn test_build_rst_stream() {
554 use crate::layer::http2::frames::error_codes;
555 let bytes = Http2FrameBuilder::rst_stream(1, error_codes::CANCEL).build();
556 let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
557 assert_eq!(frame.frame_type, Http2FrameType::RstStream);
558 assert_eq!(frame.stream_id, 1);
559 let error = parse_rst_stream(frame.payload(&bytes)).unwrap();
560 assert_eq!(error, error_codes::CANCEL);
561 }
562
563 #[test]
564 fn test_build_headers_frame() {
565 let hpack_data = vec![0x82u8]; let bytes = Http2FrameBuilder::headers_frame(1, hpack_data.clone()).build();
567 let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
568 assert_eq!(frame.frame_type, Http2FrameType::Headers);
569 assert!(frame.is_end_headers());
570 assert!(!frame.is_end_stream());
571 assert_eq!(frame.payload(&bytes), &hpack_data);
572 }
573
574 #[test]
575 fn test_build_headers_final() {
576 let hpack_data = vec![0x82u8];
577 let bytes = Http2FrameBuilder::headers_frame_final(1, hpack_data).build();
578 let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
579 assert!(frame.is_end_headers());
580 assert!(frame.is_end_stream());
581 }
582
583 #[test]
584 fn test_build_data_frame() {
585 let data = b"Hello, HTTP/2!";
586 let bytes = Http2FrameBuilder::data_frame(1, data.to_vec()).build();
587 let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
588 assert_eq!(frame.frame_type, Http2FrameType::Data);
589 assert!(!frame.is_end_stream());
590 assert_eq!(frame.payload(&bytes), data);
591 }
592
593 #[test]
594 fn test_build_data_frame_final() {
595 let data = b"last chunk";
596 let bytes = Http2FrameBuilder::data_frame_final(1, data.to_vec()).build();
597 let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
598 assert!(frame.is_end_stream());
599 }
600
601 #[test]
602 fn test_http2_builder_with_preface() {
603 let bytes = Http2Builder::new()
604 .frame(Http2FrameBuilder::settings())
605 .frame(Http2FrameBuilder::settings_ack())
606 .build();
607
608 assert!(bytes.starts_with(super::super::frames::HTTP2_PREFACE));
610
611 let frames = parse_all_frames(&bytes);
612 assert_eq!(frames.len(), 2);
613 assert_eq!(frames[0].frame_type, Http2FrameType::Settings);
614 assert_eq!(frames[1].frame_type, Http2FrameType::Settings);
615 assert!(frames[1].is_ack());
616 }
617
618 #[test]
619 fn test_http2_builder_without_preface() {
620 let bytes = Http2Builder::without_preface()
621 .frame(Http2FrameBuilder::settings_ack())
622 .build();
623
624 assert!(!bytes.starts_with(super::super::frames::HTTP2_PREFACE));
625 let frames = parse_all_frames(&bytes);
626 assert_eq!(frames.len(), 1);
627 }
628
629 #[test]
630 fn test_http2_builder_header_size() {
631 let builder = Http2Builder::new()
632 .frame(Http2FrameBuilder::settings()) .frame(Http2FrameBuilder::settings_ack()); assert_eq!(builder.header_size(), 42);
637 assert_eq!(builder.build().len(), 42);
638 }
639
640 #[test]
641 fn test_build_get_request() {
642 let bytes = build_get_request("example.com", "/", 1);
643 assert!(bytes.starts_with(super::super::frames::HTTP2_PREFACE));
644
645 let frames = parse_all_frames(&bytes);
646 assert!(frames.len() >= 2);
648 assert_eq!(frames[0].frame_type, Http2FrameType::Settings);
649 assert_eq!(frames[1].frame_type, Http2FrameType::Headers);
650 assert!(frames[1].is_end_headers());
651 assert!(frames[1].is_end_stream());
652 assert_eq!(frames[1].stream_id, 1);
653 }
654
655 #[test]
656 fn test_build_response_200_no_body() {
657 let bytes = build_response_200(1, None);
658 let frames = parse_all_frames(&bytes);
659 assert!(frames.len() >= 2);
660 assert_eq!(frames[0].frame_type, Http2FrameType::Settings);
661 assert!(frames[0].is_ack());
662 assert_eq!(frames[1].frame_type, Http2FrameType::Headers);
663 }
664
665 #[test]
666 fn test_build_response_200_with_body() {
667 let body = b"{\"ok\": true}";
668 let bytes = build_response_200(1, Some(body));
669 let frames = parse_all_frames(&bytes);
670 assert!(frames.len() >= 3);
671 assert_eq!(frames[2].frame_type, Http2FrameType::Data);
672 assert!(frames[2].is_end_stream());
673 assert_eq!(frames[2].payload(&bytes), body);
674 }
675
676 #[test]
677 fn test_end_stream_and_end_headers_helpers() {
678 let builder = Http2FrameBuilder::new(Http2FrameType::Headers)
679 .stream_id(1)
680 .end_stream()
681 .end_headers()
682 .payload(vec![0x82]);
683
684 let bytes = builder.build();
685 let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
686 assert!(frame.is_end_stream());
687 assert!(frame.is_end_headers());
688 }
689
690 #[test]
691 fn test_priority_frame() {
692 let bytes = Http2FrameBuilder::priority_frame(1, false, 0, 15).build();
693 let frame = Http2Frame::parse_at(&bytes, 0).unwrap();
694 assert_eq!(frame.frame_type, Http2FrameType::Priority);
695 assert_eq!(frame.stream_id, 1);
696 assert_eq!(frame.length, 5);
697 }
698}