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 pub fn new(start: usize, end: usize, has_preface: bool) -> Self {
77 Http2Layer {
78 index: LayerIndex::new(LayerKind::Http2, start, end),
79 has_preface,
80 }
81 }
82
83 pub fn from_index(index: LayerIndex, has_preface: bool) -> Self {
85 Http2Layer { index, has_preface }
86 }
87
88 pub fn has_preface_at(buf: &[u8], offset: usize) -> bool {
90 let end = offset + HTTP2_PREFACE.len();
91 if end > buf.len() {
92 return false;
93 }
94 &buf[offset..end] == HTTP2_PREFACE
95 }
96
97 pub fn frames_start(&self) -> usize {
99 if self.has_preface {
100 self.index.start + HTTP2_PREFACE.len()
101 } else {
102 self.index.start
103 }
104 }
105
106 pub fn first_frame<'a>(&self, buf: &'a [u8]) -> Option<Http2Frame> {
110 let offset = self.frames_start();
111 Http2Frame::parse_at(buf, offset)
112 }
113
114 pub fn all_frames(&self, buf: &[u8]) -> Vec<Http2Frame> {
116 let slice = self.index.slice(buf);
117 let preface_skip = if self.has_preface {
118 HTTP2_PREFACE.len()
119 } else {
120 0
121 };
122
123 if preface_skip > slice.len() {
124 return Vec::new();
125 }
126
127 let mut frames = Vec::new();
131 let mut offset = self.index.start + preface_skip;
132
133 loop {
134 match Http2Frame::parse_at(buf, offset) {
135 Some(frame) => {
136 if frame.payload_offset + frame.length as usize > self.index.end {
138 break;
139 }
140 let total = frame.total_size;
141 frames.push(frame);
142 offset += total;
143 if offset >= self.index.end {
144 break;
145 }
146 },
147 None => break,
148 }
149 }
150
151 frames
152 }
153
154 pub fn summary(&self, buf: &[u8]) -> String {
156 let preface_str = if self.has_preface { "Preface + " } else { "" };
157
158 if let Some(frame) = self.first_frame(buf) {
159 let type_name = frame.frame_type.name();
160 if self.has_preface {
161 format!(
162 "HTTP/2 {}[{}] stream={}",
163 preface_str, type_name, frame.stream_id
164 )
165 } else {
166 format!("HTTP/2 [{}] stream={}", type_name, frame.stream_id)
167 }
168 } else if self.has_preface {
169 "HTTP/2 Preface".to_string()
170 } else {
171 "HTTP/2".to_string()
172 }
173 }
174
175 pub fn header_len(&self, buf: &[u8]) -> usize {
182 if self.has_preface {
183 let frame_start = self.index.start + HTTP2_PREFACE.len();
185 if frame_start + HTTP2_FRAME_HEADER_LEN <= buf.len() {
186 HTTP2_PREFACE.len() + HTTP2_FRAME_HEADER_LEN } else {
188 HTTP2_PREFACE.len() }
190 } else {
191 HTTP2_FRAME_HEADER_LEN }
193 }
194
195 pub fn get_field(&self, buf: &[u8], name: &str) -> Option<Result<FieldValue, FieldError>> {
199 let frame = self.first_frame(buf)?;
200 match name {
201 "frame_type" => Some(Ok(FieldValue::U8(frame.frame_type.as_u8()))),
202 "flags" => Some(Ok(FieldValue::U8(frame.flags))),
203 "stream_id" => Some(Ok(FieldValue::U32(frame.stream_id))),
204 "length" => Some(Ok(FieldValue::U32(frame.length))),
205 _ => None,
206 }
207 }
208
209 pub fn set_field(
214 &self,
215 buf: &mut [u8],
216 name: &str,
217 value: FieldValue,
218 ) -> Option<Result<(), FieldError>> {
219 match name {
220 "stream_id" => {
221 let id = match value {
222 FieldValue::U32(v) => v,
223 FieldValue::U16(v) => v as u32,
224 FieldValue::U8(v) => v as u32,
225 _ => {
226 return Some(Err(FieldError::InvalidValue(format!(
227 "stream_id: expected integer, got {:?}",
228 value
229 ))));
230 },
231 };
232
233 let offset = self.frames_start() + 5; if offset + 4 > buf.len() {
235 return Some(Err(FieldError::BufferTooShort {
236 offset,
237 need: 4,
238 have: buf.len().saturating_sub(offset),
239 }));
240 }
241 let bytes = (id & 0x7FFFFFFF).to_be_bytes();
242 buf[offset..offset + 4].copy_from_slice(&bytes);
243 Some(Ok(()))
244 },
245 "flags" => {
246 let flag_val = match value {
247 FieldValue::U8(v) => v,
248 _ => {
249 return Some(Err(FieldError::InvalidValue(format!(
250 "flags: expected U8, got {:?}",
251 value
252 ))));
253 },
254 };
255
256 let offset = self.frames_start() + 4; if offset >= buf.len() {
258 return Some(Err(FieldError::BufferTooShort {
259 offset,
260 need: 1,
261 have: 0,
262 }));
263 }
264 buf[offset] = flag_val;
265 Some(Ok(()))
266 },
267 _ => None,
268 }
269 }
270
271 pub fn field_names() -> &'static [&'static str] {
273 HTTP2_FIELD_NAMES
274 }
275}
276
277impl Layer for Http2Layer {
282 fn kind(&self) -> LayerKind {
283 LayerKind::Http2
284 }
285
286 fn summary(&self, data: &[u8]) -> String {
287 self.summary(data)
288 }
289
290 fn header_len(&self, data: &[u8]) -> usize {
291 self.header_len(data)
292 }
293
294 fn field_names(&self) -> &'static [&'static str] {
295 HTTP2_FIELD_NAMES
296 }
297
298 fn hashret(&self, _data: &[u8]) -> Vec<u8> {
299 vec![]
301 }
302}
303
304pub fn is_http2_payload(data: &[u8]) -> bool {
313 if data.len() >= HTTP2_PREFACE.len() && data.starts_with(HTTP2_PREFACE) {
315 return true;
316 }
317
318 if data.len() < HTTP2_FRAME_HEADER_LEN {
320 return false;
321 }
322
323 let length = ((data[0] as u32) << 16) | ((data[1] as u32) << 8) | (data[2] as u32);
325 if length > 0x00FF_FFFF {
326 return false;
327 }
328
329 let frame_type = data[3];
331 let valid_type = frame_type <= 9;
332
333 let stream_word = u32::from_be_bytes([data[5], data[6], data[7], data[8]]);
335 let r_bit = (stream_word & 0x80000000) == 0; valid_type && r_bit && length <= 16384 }
339
340#[cfg(test)]
345mod tests {
346 use super::*;
347 use crate::layer::http2::builder::{Http2Builder, Http2FrameBuilder, build_get_request};
348
349 #[test]
350 fn test_http2_layer_summary_with_preface() {
351 let bytes = Http2Builder::new()
352 .frame(Http2FrameBuilder::settings())
353 .build();
354
355 let layer = Http2Layer::new(0, bytes.len(), true);
356 let summary = layer.summary(&bytes);
357 assert!(summary.contains("HTTP/2"));
358 assert!(summary.contains("Preface"));
359 assert!(summary.contains("SETTINGS"));
360 }
361
362 #[test]
363 fn test_http2_layer_summary_no_preface() {
364 let bytes = Http2FrameBuilder::settings_ack().build();
365 let layer = Http2Layer::new(0, bytes.len(), false);
366 let summary = layer.summary(&bytes);
367 assert!(summary.contains("HTTP/2"));
368 assert!(summary.contains("SETTINGS"));
369 }
370
371 #[test]
372 fn test_http2_layer_header_len_preface_and_frame() {
373 let bytes = Http2Builder::new()
374 .frame(Http2FrameBuilder::settings())
375 .build();
376 let layer = Http2Layer::new(0, bytes.len(), true);
377 assert_eq!(layer.header_len(&bytes), 33);
379 }
380
381 #[test]
382 fn test_http2_layer_header_len_no_preface() {
383 let bytes = Http2FrameBuilder::settings().build();
384 let layer = Http2Layer::new(0, bytes.len(), false);
385 assert_eq!(layer.header_len(&bytes), 9);
386 }
387
388 #[test]
389 fn test_http2_layer_get_field() {
390 let bytes = Http2FrameBuilder::headers_frame(3, vec![0x82]).build();
392 let layer = Http2Layer::new(0, bytes.len(), false);
393
394 let ft = layer.get_field(&bytes, "frame_type").unwrap().unwrap();
395 assert_eq!(ft, FieldValue::U8(1)); let sid = layer.get_field(&bytes, "stream_id").unwrap().unwrap();
398 assert_eq!(sid, FieldValue::U32(3));
399
400 let flags = layer.get_field(&bytes, "flags").unwrap().unwrap();
401 assert_eq!(flags, FieldValue::U8(0x04)); let len = layer.get_field(&bytes, "length").unwrap().unwrap();
404 assert_eq!(len, FieldValue::U32(1)); }
406
407 #[test]
408 fn test_http2_layer_set_stream_id() {
409 let mut bytes = Http2FrameBuilder::headers_frame(1, vec![0x82]).build();
410 let layer = Http2Layer::new(0, bytes.len(), false);
411
412 layer
413 .set_field(&mut bytes, "stream_id", FieldValue::U32(5))
414 .unwrap()
415 .unwrap();
416
417 let sid = layer.get_field(&bytes, "stream_id").unwrap().unwrap();
418 assert_eq!(sid, FieldValue::U32(5));
419 }
420
421 #[test]
422 fn test_http2_layer_all_frames() {
423 let bytes = Http2Builder::new()
424 .frame(Http2FrameBuilder::settings())
425 .frame(Http2FrameBuilder::settings_ack())
426 .frame(Http2FrameBuilder::headers_frame(1, vec![0x82]))
427 .build();
428
429 let layer = Http2Layer::new(0, bytes.len(), true);
430 let frames = layer.all_frames(&bytes);
431 assert_eq!(frames.len(), 3);
432 assert_eq!(frames[0].frame_type, Http2FrameType::Settings);
433 assert_eq!(frames[1].frame_type, Http2FrameType::Settings);
434 assert_eq!(frames[2].frame_type, Http2FrameType::Headers);
435 }
436
437 #[test]
438 fn test_has_preface_at() {
439 let mut buf = Vec::new();
440 buf.extend_from_slice(HTTP2_PREFACE);
441 buf.extend_from_slice(&Http2FrameBuilder::settings().build());
442
443 assert!(Http2Layer::has_preface_at(&buf, 0));
444 assert!(!Http2Layer::has_preface_at(&buf, 1));
445 assert!(!Http2Layer::has_preface_at(&[], 0));
446 }
447
448 #[test]
449 fn test_is_http2_payload_preface() {
450 let bytes = Http2Builder::new()
451 .frame(Http2FrameBuilder::settings())
452 .build();
453 assert!(is_http2_payload(&bytes));
454 }
455
456 #[test]
457 fn test_is_http2_payload_frame() {
458 let bytes = Http2FrameBuilder::settings_ack().build();
459 assert!(is_http2_payload(&bytes));
460 }
461
462 #[test]
463 fn test_is_http2_payload_not_http2() {
464 assert!(!is_http2_payload(b"HTTP/1.1 200 OK\r\n\r\n"));
465 assert!(!is_http2_payload(b"GET / HTTP/1.1\r\n"));
466 assert!(!is_http2_payload(&[]));
467 }
468
469 #[test]
470 fn test_layer_kind() {
471 let layer = Http2Layer::new(0, 9, false);
472 assert_eq!(layer.kind(), LayerKind::Http2);
473 }
474
475 #[test]
476 fn test_layer_field_names() {
477 let layer = Http2Layer::new(0, 9, false);
478 let names = layer.field_names();
479 assert!(names.contains(&"frame_type"));
480 assert!(names.contains(&"flags"));
481 assert!(names.contains(&"stream_id"));
482 assert!(names.contains(&"length"));
483 }
484
485 #[test]
486 fn test_get_request_integration() {
487 use crate::layer::http2::hpack::HpackDecoder;
488
489 let bytes = build_get_request("example.com", "/api/v1", 1);
490 let layer = Http2Layer::new(0, bytes.len(), true);
491
492 let frames = layer.all_frames(&bytes);
493 assert!(frames.len() >= 2);
494
495 let headers_frame = frames
497 .iter()
498 .find(|f| f.frame_type == Http2FrameType::Headers)
499 .unwrap();
500 assert!(headers_frame.is_end_headers());
501 assert!(headers_frame.is_end_stream());
502
503 let hpack_data = headers_frame_fragment(headers_frame, &bytes).unwrap();
505 let mut decoder = HpackDecoder::new();
506 let headers = decoder.decode(hpack_data).unwrap();
507
508 let method = headers
509 .iter()
510 .find(|(n, _)| n == ":method")
511 .map(|(_, v)| v.as_str());
512 let path = headers
513 .iter()
514 .find(|(n, _)| n == ":path")
515 .map(|(_, v)| v.as_str());
516
517 assert_eq!(method, Some("GET"));
518 assert_eq!(path, Some("/api/v1"));
519 }
520
521 fn headers_frame_fragment<'a>(frame: &Http2Frame, buf: &'a [u8]) -> Option<&'a [u8]> {
523 if frame.frame_type != Http2FrameType::Headers {
524 return None;
525 }
526 let payload = frame.payload(buf);
527 let mut start = 0;
528
529 if frame.is_padded() {
530 if payload.is_empty() {
531 return None;
532 }
533 start += payload[0] as usize + 1;
534 }
535
536 if frame.has_priority() {
537 start += 5;
538 }
539
540 Some(&payload[start..])
541 }
542}