stackforge_core/layer/http2/
builder.rs1use super::frames::{Http2FrameType, flags};
9use super::hpack::HpackEncoder;
10
11pub 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#[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 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 pub fn flags(mut self, flags: u8) -> Self {
66 self.flags = flags;
67 self
68 }
69
70 pub fn add_flag(mut self, flag: u8) -> Self {
72 self.flags |= flag;
73 self
74 }
75
76 pub fn stream_id(mut self, id: u32) -> Self {
78 self.stream_id = id;
79 self
80 }
81
82 pub fn payload(mut self, data: Vec<u8>) -> Self {
84 self.payload = data;
85 self
86 }
87
88 pub fn end_stream(mut self) -> Self {
92 self.flags |= 0x01;
93 self
94 }
95
96 pub fn end_headers(mut self) -> Self {
100 self.flags |= 0x04;
101 self
102 }
103
104 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 pub fn settings() -> Self {
120 Http2FrameBuilder::new(Http2FrameType::Settings)
121 .stream_id(0)
122 .flags(0)
123 }
124
125 pub fn settings_ack() -> Self {
127 Http2FrameBuilder::new(Http2FrameType::Settings)
128 .stream_id(0)
129 .flags(flags::SETTINGS_ACK)
130 }
131
132 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 pub fn ping(data: [u8; 8]) -> Self {
148 Http2FrameBuilder::new(Http2FrameType::Ping)
149 .stream_id(0)
150 .payload(data.to_vec())
151 }
152
153 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 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 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 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 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 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 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 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 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 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 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 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#[derive(Debug, Clone)]
306pub struct Http2Builder {
307 include_preface: bool,
309 frames: Vec<Http2FrameBuilder>,
311}
312
313impl Default for Http2Builder {
314 fn default() -> Self {
315 Self::new()
316 }
317}
318
319impl Http2Builder {
320 pub fn new() -> Self {
322 Http2Builder {
323 include_preface: true,
324 frames: Vec::new(),
325 }
326 }
327
328 pub fn without_preface() -> Self {
330 Http2Builder {
331 include_preface: false,
332 frames: Vec::new(),
333 }
334 }
335
336 pub fn frame(mut self, f: Http2FrameBuilder) -> Self {
338 self.frames.push(f);
339 self
340 }
341
342 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 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
365pub 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
396pub 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 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#[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); 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(¶ms).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]; 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 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()) .frame(Http2FrameBuilder::settings_ack()); 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 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}