stackforge_core/layer/http2/
mod.rs1pub mod builder;
37pub mod frames;
38pub mod hpack;
39
40pub use builder::{Http2Builder, Http2FrameBuilder, build_frame};
41pub use frames::{
42 HTTP2_FRAME_HEADER_LEN, HTTP2_PREFACE, Http2Frame, Http2FrameType, error_codes, flags,
43 parse_all_frames, parse_goaway, parse_rst_stream, parse_settings, parse_window_update,
44 settings_id,
45};
46pub use hpack::{HpackDecoder, HpackEncoder, STATIC_TABLE};
47
48use crate::layer::field::{FieldError, FieldValue};
49use crate::layer::{Layer, LayerIndex, LayerKind};
50
51pub const HTTP2_FIELD_NAMES: &[&str] = &["frame_type", "flags", "stream_id", "length"];
57
58#[derive(Debug, Clone)]
67pub struct Http2Layer {
68 pub index: LayerIndex,
70 pub has_preface: bool,
72}
73
74impl Http2Layer {
75 #[must_use]
77 pub fn new(start: usize, end: usize, has_preface: bool) -> Self {
78 Http2Layer {
79 index: LayerIndex::new(LayerKind::Http2, start, end),
80 has_preface,
81 }
82 }
83
84 #[must_use]
86 pub fn from_index(index: LayerIndex, has_preface: bool) -> Self {
87 Http2Layer { index, has_preface }
88 }
89
90 #[must_use]
92 pub fn has_preface_at(buf: &[u8], offset: usize) -> bool {
93 let end = offset + HTTP2_PREFACE.len();
94 if end > buf.len() {
95 return false;
96 }
97 &buf[offset..end] == HTTP2_PREFACE
98 }
99
100 #[must_use]
102 pub fn frames_start(&self) -> usize {
103 if self.has_preface {
104 self.index.start + HTTP2_PREFACE.len()
105 } else {
106 self.index.start
107 }
108 }
109
110 #[must_use]
114 pub fn first_frame(&self, buf: &[u8]) -> Option<Http2Frame> {
115 let offset = self.frames_start();
116 Http2Frame::parse_at(buf, offset)
117 }
118
119 #[must_use]
121 pub fn all_frames(&self, buf: &[u8]) -> Vec<Http2Frame> {
122 let slice = self.index.slice(buf);
123 let preface_skip = if self.has_preface {
124 HTTP2_PREFACE.len()
125 } else {
126 0
127 };
128
129 if preface_skip > slice.len() {
130 return Vec::new();
131 }
132
133 let mut frames = Vec::new();
137 let mut offset = self.index.start + preface_skip;
138
139 loop {
140 match Http2Frame::parse_at(buf, offset) {
141 Some(frame) => {
142 if frame.payload_offset + frame.length as usize > self.index.end {
144 break;
145 }
146 let total = frame.total_size;
147 frames.push(frame);
148 offset += total;
149 if offset >= self.index.end {
150 break;
151 }
152 },
153 None => break,
154 }
155 }
156
157 frames
158 }
159
160 #[must_use]
162 pub fn summary(&self, buf: &[u8]) -> String {
163 let preface_str = if self.has_preface { "Preface + " } else { "" };
164
165 if let Some(frame) = self.first_frame(buf) {
166 let type_name = frame.frame_type.name();
167 if self.has_preface {
168 format!(
169 "HTTP/2 {}[{}] stream={}",
170 preface_str, type_name, frame.stream_id
171 )
172 } else {
173 format!("HTTP/2 [{}] stream={}", type_name, frame.stream_id)
174 }
175 } else if self.has_preface {
176 "HTTP/2 Preface".to_string()
177 } else {
178 "HTTP/2".to_string()
179 }
180 }
181
182 #[must_use]
189 pub fn header_len(&self, buf: &[u8]) -> usize {
190 if self.has_preface {
191 let frame_start = self.index.start + HTTP2_PREFACE.len();
193 if frame_start + HTTP2_FRAME_HEADER_LEN <= buf.len() {
194 HTTP2_PREFACE.len() + HTTP2_FRAME_HEADER_LEN } else {
196 HTTP2_PREFACE.len() }
198 } else {
199 HTTP2_FRAME_HEADER_LEN }
201 }
202
203 #[must_use]
207 pub fn get_field(&self, buf: &[u8], name: &str) -> Option<Result<FieldValue, FieldError>> {
208 let frame = self.first_frame(buf)?;
209 match name {
210 "frame_type" => Some(Ok(FieldValue::U8(frame.frame_type.as_u8()))),
211 "flags" => Some(Ok(FieldValue::U8(frame.flags))),
212 "stream_id" => Some(Ok(FieldValue::U32(frame.stream_id))),
213 "length" => Some(Ok(FieldValue::U32(frame.length))),
214 _ => None,
215 }
216 }
217
218 pub fn set_field(
223 &self,
224 buf: &mut [u8],
225 name: &str,
226 value: FieldValue,
227 ) -> Option<Result<(), FieldError>> {
228 match name {
229 "stream_id" => {
230 let id = match value {
231 FieldValue::U32(v) => v,
232 FieldValue::U16(v) => u32::from(v),
233 FieldValue::U8(v) => u32::from(v),
234 _ => {
235 return Some(Err(FieldError::InvalidValue(format!(
236 "stream_id: expected integer, got {value:?}"
237 ))));
238 },
239 };
240
241 let offset = self.frames_start() + 5; if offset + 4 > buf.len() {
243 return Some(Err(FieldError::BufferTooShort {
244 offset,
245 need: 4,
246 have: buf.len().saturating_sub(offset),
247 }));
248 }
249 let bytes = (id & 0x7FFFFFFF).to_be_bytes();
250 buf[offset..offset + 4].copy_from_slice(&bytes);
251 Some(Ok(()))
252 },
253 "flags" => {
254 let flag_val = match value {
255 FieldValue::U8(v) => v,
256 _ => {
257 return Some(Err(FieldError::InvalidValue(format!(
258 "flags: expected U8, got {value:?}"
259 ))));
260 },
261 };
262
263 let offset = self.frames_start() + 4; if offset >= buf.len() {
265 return Some(Err(FieldError::BufferTooShort {
266 offset,
267 need: 1,
268 have: 0,
269 }));
270 }
271 buf[offset] = flag_val;
272 Some(Ok(()))
273 },
274 _ => None,
275 }
276 }
277
278 #[must_use]
280 pub fn field_names() -> &'static [&'static str] {
281 HTTP2_FIELD_NAMES
282 }
283}
284
285impl Layer for Http2Layer {
290 fn kind(&self) -> LayerKind {
291 LayerKind::Http2
292 }
293
294 fn summary(&self, data: &[u8]) -> String {
295 self.summary(data)
296 }
297
298 fn header_len(&self, data: &[u8]) -> usize {
299 self.header_len(data)
300 }
301
302 fn field_names(&self) -> &'static [&'static str] {
303 HTTP2_FIELD_NAMES
304 }
305
306 fn hashret(&self, _data: &[u8]) -> Vec<u8> {
307 vec![]
309 }
310}
311
312#[must_use]
321pub fn is_http2_payload(data: &[u8]) -> bool {
322 if data.len() >= HTTP2_PREFACE.len() && data.starts_with(HTTP2_PREFACE) {
324 return true;
325 }
326
327 if data.len() < HTTP2_FRAME_HEADER_LEN {
329 return false;
330 }
331
332 let length = (u32::from(data[0]) << 16) | (u32::from(data[1]) << 8) | u32::from(data[2]);
334 if length > 0x00FF_FFFF {
335 return false;
336 }
337
338 let frame_type = data[3];
340 let valid_type = frame_type <= 9;
341
342 let stream_word = u32::from_be_bytes([data[5], data[6], data[7], data[8]]);
344 let r_bit = (stream_word & 0x80000000) == 0; valid_type && r_bit && length <= 16384 }
348
349#[cfg(test)]
354mod tests {
355 use super::*;
356 use crate::layer::http2::builder::{Http2Builder, Http2FrameBuilder, build_get_request};
357
358 #[test]
359 fn test_http2_layer_summary_with_preface() {
360 let bytes = Http2Builder::new()
361 .frame(Http2FrameBuilder::settings())
362 .build();
363
364 let layer = Http2Layer::new(0, bytes.len(), true);
365 let summary = layer.summary(&bytes);
366 assert!(summary.contains("HTTP/2"));
367 assert!(summary.contains("Preface"));
368 assert!(summary.contains("SETTINGS"));
369 }
370
371 #[test]
372 fn test_http2_layer_summary_no_preface() {
373 let bytes = Http2FrameBuilder::settings_ack().build();
374 let layer = Http2Layer::new(0, bytes.len(), false);
375 let summary = layer.summary(&bytes);
376 assert!(summary.contains("HTTP/2"));
377 assert!(summary.contains("SETTINGS"));
378 }
379
380 #[test]
381 fn test_http2_layer_header_len_preface_and_frame() {
382 let bytes = Http2Builder::new()
383 .frame(Http2FrameBuilder::settings())
384 .build();
385 let layer = Http2Layer::new(0, bytes.len(), true);
386 assert_eq!(layer.header_len(&bytes), 33);
388 }
389
390 #[test]
391 fn test_http2_layer_header_len_no_preface() {
392 let bytes = Http2FrameBuilder::settings().build();
393 let layer = Http2Layer::new(0, bytes.len(), false);
394 assert_eq!(layer.header_len(&bytes), 9);
395 }
396
397 #[test]
398 fn test_http2_layer_get_field() {
399 let bytes = Http2FrameBuilder::headers_frame(3, vec![0x82]).build();
401 let layer = Http2Layer::new(0, bytes.len(), false);
402
403 let ft = layer.get_field(&bytes, "frame_type").unwrap().unwrap();
404 assert_eq!(ft, FieldValue::U8(1)); let sid = layer.get_field(&bytes, "stream_id").unwrap().unwrap();
407 assert_eq!(sid, FieldValue::U32(3));
408
409 let flags = layer.get_field(&bytes, "flags").unwrap().unwrap();
410 assert_eq!(flags, FieldValue::U8(0x04)); let len = layer.get_field(&bytes, "length").unwrap().unwrap();
413 assert_eq!(len, FieldValue::U32(1)); }
415
416 #[test]
417 fn test_http2_layer_set_stream_id() {
418 let mut bytes = Http2FrameBuilder::headers_frame(1, vec![0x82]).build();
419 let layer = Http2Layer::new(0, bytes.len(), false);
420
421 layer
422 .set_field(&mut bytes, "stream_id", FieldValue::U32(5))
423 .unwrap()
424 .unwrap();
425
426 let sid = layer.get_field(&bytes, "stream_id").unwrap().unwrap();
427 assert_eq!(sid, FieldValue::U32(5));
428 }
429
430 #[test]
431 fn test_http2_layer_all_frames() {
432 let bytes = Http2Builder::new()
433 .frame(Http2FrameBuilder::settings())
434 .frame(Http2FrameBuilder::settings_ack())
435 .frame(Http2FrameBuilder::headers_frame(1, vec![0x82]))
436 .build();
437
438 let layer = Http2Layer::new(0, bytes.len(), true);
439 let frames = layer.all_frames(&bytes);
440 assert_eq!(frames.len(), 3);
441 assert_eq!(frames[0].frame_type, Http2FrameType::Settings);
442 assert_eq!(frames[1].frame_type, Http2FrameType::Settings);
443 assert_eq!(frames[2].frame_type, Http2FrameType::Headers);
444 }
445
446 #[test]
447 fn test_has_preface_at() {
448 let mut buf = Vec::new();
449 buf.extend_from_slice(HTTP2_PREFACE);
450 buf.extend_from_slice(&Http2FrameBuilder::settings().build());
451
452 assert!(Http2Layer::has_preface_at(&buf, 0));
453 assert!(!Http2Layer::has_preface_at(&buf, 1));
454 assert!(!Http2Layer::has_preface_at(&[], 0));
455 }
456
457 #[test]
458 fn test_is_http2_payload_preface() {
459 let bytes = Http2Builder::new()
460 .frame(Http2FrameBuilder::settings())
461 .build();
462 assert!(is_http2_payload(&bytes));
463 }
464
465 #[test]
466 fn test_is_http2_payload_frame() {
467 let bytes = Http2FrameBuilder::settings_ack().build();
468 assert!(is_http2_payload(&bytes));
469 }
470
471 #[test]
472 fn test_is_http2_payload_not_http2() {
473 assert!(!is_http2_payload(b"HTTP/1.1 200 OK\r\n\r\n"));
474 assert!(!is_http2_payload(b"GET / HTTP/1.1\r\n"));
475 assert!(!is_http2_payload(&[]));
476 }
477
478 #[test]
479 fn test_layer_kind() {
480 let layer = Http2Layer::new(0, 9, false);
481 assert_eq!(layer.kind(), LayerKind::Http2);
482 }
483
484 #[test]
485 fn test_layer_field_names() {
486 let layer = Http2Layer::new(0, 9, false);
487 let names = layer.field_names();
488 assert!(names.contains(&"frame_type"));
489 assert!(names.contains(&"flags"));
490 assert!(names.contains(&"stream_id"));
491 assert!(names.contains(&"length"));
492 }
493
494 #[test]
495 fn test_get_request_integration() {
496 use crate::layer::http2::hpack::HpackDecoder;
497
498 let bytes = build_get_request("example.com", "/api/v1", 1);
499 let layer = Http2Layer::new(0, bytes.len(), true);
500
501 let frames = layer.all_frames(&bytes);
502 assert!(frames.len() >= 2);
503
504 let headers_frame = frames
506 .iter()
507 .find(|f| f.frame_type == Http2FrameType::Headers)
508 .unwrap();
509 assert!(headers_frame.is_end_headers());
510 assert!(headers_frame.is_end_stream());
511
512 let hpack_data = headers_frame_fragment(headers_frame, &bytes).unwrap();
514 let mut decoder = HpackDecoder::new();
515 let headers = decoder.decode(hpack_data).unwrap();
516
517 let method = headers
518 .iter()
519 .find(|(n, _)| n == ":method")
520 .map(|(_, v)| v.as_str());
521 let path = headers
522 .iter()
523 .find(|(n, _)| n == ":path")
524 .map(|(_, v)| v.as_str());
525
526 assert_eq!(method, Some("GET"));
527 assert_eq!(path, Some("/api/v1"));
528 }
529
530 fn headers_frame_fragment<'a>(frame: &Http2Frame, buf: &'a [u8]) -> Option<&'a [u8]> {
532 if frame.frame_type != Http2FrameType::Headers {
533 return None;
534 }
535 let payload = frame.payload(buf);
536 let mut start = 0;
537
538 if frame.is_padded() {
539 if payload.is_empty() {
540 return None;
541 }
542 start += payload[0] as usize + 1;
543 }
544
545 if frame.has_priority() {
546 start += 5;
547 }
548
549 Some(&payload[start..])
550 }
551}