1#![deny(missing_docs)]
12
13use packet_dissector_core::dissector::{DispatchHint, DissectResult, Dissector};
14use packet_dissector_core::error::PacketError;
15use packet_dissector_core::field::{FieldDescriptor, FieldType, FieldValue};
16use packet_dissector_core::packet::DissectBuffer;
17use packet_dissector_core::util::{intern_content_type, slice_offset, str_offset, trim_ows};
18
19const MAX_HEADERS: usize = 64;
21
22const MIN_START_LINE_LEN: usize = 16;
24
25const FD_IS_RESPONSE: usize = 0;
31const FD_METHOD: usize = 1;
32const FD_URI: usize = 2;
33const FD_VERSION: usize = 3;
34const FD_STATUS_CODE: usize = 4;
35const FD_REASON_PHRASE: usize = 5;
36const FD_HEADERS: usize = 6;
37const FD_CONTENT_LENGTH: usize = 7;
38const FD_CONTENT_TYPE: usize = 8;
39
40const HC_NAME: usize = 0;
42const HC_VALUE: usize = 1;
43
44static HEADER_CHILDREN: &[FieldDescriptor] = &[
46 FieldDescriptor::new("name", "Name", FieldType::Str),
47 FieldDescriptor::new("value", "Value", FieldType::Str),
48];
49
50static FD_HEADER: FieldDescriptor = FieldDescriptor {
58 name: "header",
59 display_name: "Header",
60 field_type: FieldType::Object,
61 optional: false,
62 children: None,
63 display_fn: None,
64 format_fn: None,
65};
66
67static FIELD_DESCRIPTORS: &[FieldDescriptor] = &[
69 FieldDescriptor::new("is_response", "Is Response", FieldType::U8),
71 FieldDescriptor::new("method", "Method", FieldType::Str).optional(),
73 FieldDescriptor::new("uri", "Request URI", FieldType::Str).optional(),
75 FieldDescriptor::new("version", "Version", FieldType::Str),
77 FieldDescriptor::new("status_code", "Status Code", FieldType::U16).optional(),
79 FieldDescriptor::new("reason_phrase", "Reason Phrase", FieldType::Str).optional(),
81 FieldDescriptor::new("headers", "Headers", FieldType::Array)
83 .optional()
84 .with_children(HEADER_CHILDREN),
85 FieldDescriptor::new("content_length", "Content Length", FieldType::U32).optional(),
87 FieldDescriptor::new("content_type", "Content Type", FieldType::Str).optional(),
90];
91
92pub struct HttpDissector;
98
99impl Dissector for HttpDissector {
100 fn name(&self) -> &'static str {
101 "HyperText Transfer Protocol"
102 }
103
104 fn short_name(&self) -> &'static str {
105 "HTTP"
106 }
107
108 fn field_descriptors(&self) -> &'static [FieldDescriptor] {
109 FIELD_DESCRIPTORS
110 }
111
112 fn dissect<'pkt>(
113 &self,
114 data: &'pkt [u8],
115 buf: &mut DissectBuffer<'pkt>,
116 offset: usize,
117 ) -> Result<DissectResult, PacketError> {
118 if data.len() < MIN_START_LINE_LEN {
119 return Err(PacketError::Truncated {
120 expected: MIN_START_LINE_LEN,
121 actual: data.len(),
122 });
123 }
124
125 let is_response = data.starts_with(b"HTTP/");
127
128 buf.begin_layer("HTTP", None, FIELD_DESCRIPTORS, offset..offset);
129
130 buf.push_field(
131 &FIELD_DESCRIPTORS[FD_IS_RESPONSE],
132 FieldValue::U8(u8::from(is_response)),
133 offset..offset + 1,
134 );
135
136 let header_len = if is_response {
137 parse_response(data, offset, buf)?
138 } else {
139 parse_request(data, offset, buf)?
140 };
141
142 let content_length =
144 extract_header_value(buf, "Content-Length").and_then(|v| v.parse::<u32>().ok());
145 let content_type = extract_header_value(buf, "Content-Type");
146
147 if let Some(cl) = content_length {
148 buf.push_field(
149 &FIELD_DESCRIPTORS[FD_CONTENT_LENGTH],
150 FieldValue::U32(cl),
151 offset..offset + header_len,
152 );
153 }
154
155 if let Some(ct) = content_type {
156 buf.push_field(
157 &FIELD_DESCRIPTORS[FD_CONTENT_TYPE],
158 FieldValue::Str(ct),
159 offset..offset + header_len,
160 );
161 }
162
163 let body_len = content_length.unwrap_or(0) as usize;
165 let total = header_len + body_len;
166
167 if total > data.len() {
168 if let Some(layer) = buf.last_layer_mut() {
170 layer.range = offset..offset + header_len;
171 }
172 buf.end_layer();
173 return Err(PacketError::Truncated {
174 expected: total,
175 actual: data.len(),
176 });
177 }
178
179 if body_len > 0 {
185 if let Some(ct) = extract_header_value(buf, "Content-Type") {
186 if let Some(interned) = intern_content_type(ct) {
187 if let Some(layer) = buf.last_layer_mut() {
188 layer.range = offset..offset + header_len;
189 }
190 buf.end_layer();
191 return Ok(DissectResult::new(
192 header_len,
193 DispatchHint::ByContentType(interned),
194 ));
195 }
196 }
197 }
198
199 if let Some(layer) = buf.last_layer_mut() {
200 layer.range = offset..offset + total;
201 }
202 buf.end_layer();
203
204 Ok(DissectResult::new(total, DispatchHint::End))
205 }
206}
207
208fn version_str(v: u8) -> &'static str {
210 match v {
211 0 => "HTTP/1.0",
212 1 => "HTTP/1.1",
213 _ => "HTTP/1.x",
214 }
215}
216
217fn parse_request<'pkt>(
220 data: &'pkt [u8],
221 offset: usize,
222 buf: &mut DissectBuffer<'pkt>,
223) -> Result<usize, PacketError> {
224 let mut headers_buf = [httparse::EMPTY_HEADER; MAX_HEADERS];
225 let mut req = httparse::Request::new(&mut headers_buf);
226
227 let header_len = match req.parse(data) {
228 Ok(httparse::Status::Complete(len)) => len,
229 Ok(httparse::Status::Partial) => {
230 return Err(PacketError::Truncated {
231 expected: data.len() + 1,
232 actual: data.len(),
233 });
234 }
235 Err(_) => {
236 return Err(PacketError::InvalidHeader("invalid HTTP request line"));
237 }
238 };
239
240 if let Some(method) = req.method {
242 let start = str_offset(data, method)?;
243 buf.push_field(
244 &FIELD_DESCRIPTORS[FD_METHOD],
245 FieldValue::Str(method),
246 offset + start..offset + start + method.len(),
247 );
248 }
249
250 if let Some(path) = req.path {
252 let start = str_offset(data, path)?;
253 buf.push_field(
254 &FIELD_DESCRIPTORS[FD_URI],
255 FieldValue::Str(path),
256 offset + start..offset + start + path.len(),
257 );
258 }
259
260 if let Some(version) = req.version {
262 let vs = version_str(version);
263 buf.push_field(
264 &FIELD_DESCRIPTORS[FD_VERSION],
265 FieldValue::Str(vs),
266 offset..offset + header_len,
267 );
268 }
269
270 build_header_fields(data, offset, req.headers, buf)?;
272
273 Ok(header_len)
274}
275
276fn parse_response<'pkt>(
279 data: &'pkt [u8],
280 offset: usize,
281 buf: &mut DissectBuffer<'pkt>,
282) -> Result<usize, PacketError> {
283 let mut headers_buf = [httparse::EMPTY_HEADER; MAX_HEADERS];
284 let mut resp = httparse::Response::new(&mut headers_buf);
285
286 let header_len = match resp.parse(data) {
287 Ok(httparse::Status::Complete(len)) => len,
288 Ok(httparse::Status::Partial) => {
289 return Err(PacketError::Truncated {
290 expected: data.len() + 1,
291 actual: data.len(),
292 });
293 }
294 Err(_) => {
295 return Err(PacketError::InvalidHeader("invalid HTTP status line"));
296 }
297 };
298
299 if let Some(version) = resp.version {
301 let vs = version_str(version);
302 buf.push_field(
303 &FIELD_DESCRIPTORS[FD_VERSION],
304 FieldValue::Str(vs),
305 offset..offset + header_len,
306 );
307 }
308
309 if let Some(code) = resp.code {
311 buf.push_field(
312 &FIELD_DESCRIPTORS[FD_STATUS_CODE],
313 FieldValue::U16(code),
314 offset..offset + header_len,
315 );
316 }
317
318 if let Some(reason) = resp.reason {
320 if !reason.is_empty() {
321 buf.push_field(
322 &FIELD_DESCRIPTORS[FD_REASON_PHRASE],
323 FieldValue::Str(reason),
324 offset..offset + header_len,
325 );
326 }
327 }
328
329 build_header_fields(data, offset, resp.headers, buf)?;
331
332 Ok(header_len)
333}
334
335fn build_header_fields<'pkt>(
337 data: &'pkt [u8],
338 offset: usize,
339 headers: &[httparse::Header<'pkt>],
340 buf: &mut DissectBuffer<'pkt>,
341) -> Result<(), PacketError> {
342 if headers.is_empty() {
343 return Ok(());
344 }
345
346 let first_header = &headers[0];
349 let last_header = &headers[headers.len() - 1];
350 let first_name_start = str_offset(data, first_header.name)? + offset;
351 let last_value_end = slice_offset(data, last_header.value)? + last_header.value.len() + offset;
352
353 let array_idx = buf.begin_container(
354 &FIELD_DESCRIPTORS[FD_HEADERS],
355 FieldValue::Array(0..0),
356 first_name_start..last_value_end,
357 );
358
359 for header in headers {
360 let name = header.name;
361 let trimmed_value = trim_ows(header.value);
362 let value_str = core::str::from_utf8(trimmed_value)
363 .map_err(|_| PacketError::InvalidHeader("header value is not valid UTF-8"))?;
364
365 let name_start = str_offset(data, name)?;
367 let value_end = slice_offset(data, header.value)? + header.value.len();
368 let header_range = offset + name_start..offset + value_end;
369
370 let obj_idx =
371 buf.begin_container(&FD_HEADER, FieldValue::Object(0..0), header_range.clone());
372 buf.push_field(
373 &HEADER_CHILDREN[HC_NAME],
374 FieldValue::Str(name),
375 header_range.clone(),
376 );
377 buf.push_field(
378 &HEADER_CHILDREN[HC_VALUE],
379 FieldValue::Str(value_str),
380 header_range,
381 );
382 buf.end_container(obj_idx);
383 }
384
385 buf.end_container(array_idx);
386
387 Ok(())
388}
389
390fn extract_header_value<'pkt>(buf: &DissectBuffer<'pkt>, header_name: &str) -> Option<&'pkt str> {
398 let layer = buf.layers().last()?;
400 let start = layer.field_range.start as usize;
401 let fields = &buf.fields()[start..];
402 let headers_field = fields.iter().find(|f| f.name() == "headers")?;
403 let array_range = match &headers_field.value {
404 FieldValue::Array(r) => r,
405 _ => return None,
406 };
407
408 let children = buf.nested_fields(array_range);
410 for field in children {
411 if let FieldValue::Object(ref obj_range) = field.value {
412 let obj_fields = buf.nested_fields(obj_range);
413 let name_field = obj_fields.iter().find(|f| f.name() == "name")?;
414 let value_field = obj_fields.iter().find(|f| f.name() == "value")?;
415 if let FieldValue::Str(n) = &name_field.value {
416 if n.eq_ignore_ascii_case(header_name) {
417 if let FieldValue::Str(v) = &value_field.value {
418 return Some(v);
419 }
420 }
421 }
422 }
423 }
424 None
425}
426
427#[cfg(test)]
428mod tests {
429 use super::*;
430
431 fn dissect(data: &[u8]) -> Result<DissectBuffer<'_>, PacketError> {
456 let dissector = HttpDissector;
457 let mut buf = DissectBuffer::new();
458 dissector.dissect(data, &mut buf, 0)?;
459 Ok(buf)
460 }
461
462 fn dissect_err(data: &[u8]) -> PacketError {
463 let dissector = HttpDissector;
464 let mut buf = DissectBuffer::new();
465 dissector.dissect(data, &mut buf, 0).unwrap_err()
466 }
467
468 #[test]
469 fn parse_http_request_basic() {
470 let data = b"GET / HTTP/1.1\r\n\r\n";
471 let buf = dissect(data).unwrap();
472 let layer = buf.layer_by_name("HTTP").unwrap();
473
474 assert_eq!(
475 buf.field_by_name(layer, "is_response").unwrap().value,
476 FieldValue::U8(0)
477 );
478 assert_eq!(
479 buf.field_by_name(layer, "method").unwrap().value,
480 FieldValue::Str("GET")
481 );
482 assert_eq!(
483 buf.field_by_name(layer, "uri").unwrap().value,
484 FieldValue::Str("/")
485 );
486 assert_eq!(
487 buf.field_by_name(layer, "version").unwrap().value,
488 FieldValue::Str("HTTP/1.1")
489 );
490 assert!(buf.field_by_name(layer, "status_code").is_none());
491 }
492
493 #[test]
494 fn header_container_descriptor_distinct_from_inner_name() {
495 let data = b"GET / HTTP/1.1\r\nContent-Type: text/html\r\n\r\n";
499 let buf = dissect(data).unwrap();
500
501 let (idx, field) = buf
502 .fields()
503 .iter()
504 .enumerate()
505 .find(|(_, f)| f.name() == "header")
506 .expect("header container not found");
507 assert!(matches!(field.value, FieldValue::Object(_)));
508 assert_eq!(field.display_name(), "Header");
509 assert_eq!(buf.resolve_container_display_name(idx as u32), None);
510 }
511
512 #[test]
513 fn parse_http_post_request() {
514 let body = b"key=value";
515 let header = b"POST /submit HTTP/1.1\r\nContent-Length: 9\r\n\r\n";
516 let mut data = Vec::new();
517 data.extend_from_slice(header);
518 data.extend_from_slice(body);
519
520 let buf = dissect(&data).unwrap();
521 let layer = buf.layer_by_name("HTTP").unwrap();
522
523 assert_eq!(
524 buf.field_by_name(layer, "method").unwrap().value,
525 FieldValue::Str("POST")
526 );
527 assert_eq!(
528 buf.field_by_name(layer, "uri").unwrap().value,
529 FieldValue::Str("/submit")
530 );
531 assert_eq!(
532 buf.field_by_name(layer, "content_length").unwrap().value,
533 FieldValue::U32(9)
534 );
535 assert_eq!(layer.range, 0..data.len());
536 }
537
538 #[test]
539 fn parse_http_response_basic() {
540 let data = b"HTTP/1.1 200 OK\r\n\r\n";
541 let buf = dissect(data).unwrap();
542 let layer = buf.layer_by_name("HTTP").unwrap();
543
544 assert_eq!(
545 buf.field_by_name(layer, "is_response").unwrap().value,
546 FieldValue::U8(1)
547 );
548 assert_eq!(
549 buf.field_by_name(layer, "version").unwrap().value,
550 FieldValue::Str("HTTP/1.1")
551 );
552 assert_eq!(
553 buf.field_by_name(layer, "status_code").unwrap().value,
554 FieldValue::U16(200)
555 );
556 assert_eq!(
557 buf.field_by_name(layer, "reason_phrase").unwrap().value,
558 FieldValue::Str("OK")
559 );
560 assert!(buf.field_by_name(layer, "method").is_none());
561 }
562
563 #[test]
564 fn parse_http_response_no_reason() {
565 let data = b"HTTP/1.1 204\r\n\r\n";
566 let buf = dissect(data).unwrap();
567 let layer = buf.layer_by_name("HTTP").unwrap();
568
569 assert_eq!(
570 buf.field_by_name(layer, "status_code").unwrap().value,
571 FieldValue::U16(204)
572 );
573 assert!(buf.field_by_name(layer, "reason_phrase").is_none());
574 }
575
576 #[test]
577 fn parse_http_request_with_headers() {
578 let data = b"GET /index.html HTTP/1.1\r\nHost: example.com\r\nAccept: text/html\r\n\r\n";
579 let buf = dissect(data).unwrap();
580 let layer = buf.layer_by_name("HTTP").unwrap();
581
582 let headers_field = buf.field_by_name(layer, "headers").unwrap();
583 let array_range = match &headers_field.value {
584 FieldValue::Array(r) => r,
585 _ => panic!("expected Array"),
586 };
587
588 let children = buf.nested_fields(array_range);
589 let objects: Vec<_> = children.iter().filter(|f| f.value.is_object()).collect();
591 assert_eq!(objects.len(), 2);
592
593 if let FieldValue::Object(ref r) = objects[0].value {
594 let obj_fields = buf.nested_fields(r);
595 assert_eq!(obj_fields[0].value, FieldValue::Str("Host"));
596 assert_eq!(obj_fields[1].value, FieldValue::Str("example.com"));
597 }
598
599 if let FieldValue::Object(ref r) = objects[1].value {
600 let obj_fields = buf.nested_fields(r);
601 assert_eq!(obj_fields[0].value, FieldValue::Str("Accept"));
602 assert_eq!(obj_fields[1].value, FieldValue::Str("text/html"));
603 }
604 }
605
606 #[test]
607 fn parse_http_request_with_body() {
608 let body = b"Hello, World!";
609 let header = b"POST /api HTTP/1.1\r\nContent-Length: 13\r\n\r\n";
610 let mut data = Vec::new();
611 data.extend_from_slice(header);
612 data.extend_from_slice(body);
613
614 let buf = dissect(&data).unwrap();
615 let layer = buf.layer_by_name("HTTP").unwrap();
616
617 assert_eq!(
618 buf.field_by_name(layer, "content_length").unwrap().value,
619 FieldValue::U32(13)
620 );
621 assert_eq!(layer.range, 0..data.len());
623 }
624
625 #[test]
626 fn parse_http_truncated() {
627 let data = b"GET /";
628 assert!(matches!(dissect_err(data), PacketError::Truncated { .. }));
629 }
630
631 #[test]
632 fn parse_http_truncated_headers() {
633 let data = b"GET / HTTP/1.1\r\nHost: example.com";
635 assert!(matches!(dissect_err(data), PacketError::Truncated { .. }));
636 }
637
638 #[test]
639 fn parse_http_truncated_body() {
640 let data = b"POST / HTTP/1.1\r\nContent-Length: 100\r\n\r\nHello";
642 assert!(matches!(dissect_err(data), PacketError::Truncated { .. }));
643 }
644
645 #[test]
646 fn parse_http_invalid_request_line() {
647 let data = b"INVALIDREQUESTLINE\r\n\r\n";
649 assert!(matches!(dissect_err(data), PacketError::InvalidHeader(_)));
650 }
651
652 #[test]
653 fn parse_http_header_ows_trimming() {
654 let data = b"GET / HTTP/1.1\r\nHost: example.com \r\n\r\n";
656 let buf = dissect(data).unwrap();
657 let layer = buf.layer_by_name("HTTP").unwrap();
658
659 let headers_field = buf.field_by_name(layer, "headers").unwrap();
660 if let FieldValue::Array(ref r) = headers_field.value {
661 let children = buf.nested_fields(r);
662 let obj = children.iter().find(|f| f.value.is_object()).unwrap();
663 if let FieldValue::Object(ref obj_r) = obj.value {
664 let obj_fields = buf.nested_fields(obj_r);
665 assert_eq!(obj_fields[1].value, FieldValue::Str("example.com"));
666 }
667 }
668 }
669
670 #[test]
671 fn parse_http_response_with_body() {
672 let body = b"<html></html>";
673 let header = b"HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\n";
674 let mut data = Vec::new();
675 data.extend_from_slice(header);
676 data.extend_from_slice(body);
677
678 let buf = dissect(&data).unwrap();
679 let layer = buf.layer_by_name("HTTP").unwrap();
680
681 assert_eq!(
682 buf.field_by_name(layer, "status_code").unwrap().value,
683 FieldValue::U16(200)
684 );
685 assert_eq!(
686 buf.field_by_name(layer, "content_length").unwrap().value,
687 FieldValue::U32(13)
688 );
689 assert_eq!(layer.range, 0..data.len());
690 }
691
692 #[test]
693 fn parse_http_with_offset() {
694 let data = b"GET / HTTP/1.1\r\n\r\n";
695 let dissector = HttpDissector;
696 let mut buf = DissectBuffer::new();
697 let result = dissector.dissect(data, &mut buf, 42).unwrap();
698
699 let layer = buf.layer_by_name("HTTP").unwrap();
700 assert_eq!(layer.range.start, 42);
701 assert_eq!(layer.range.end, 42 + data.len());
702 assert_eq!(result.bytes_consumed, data.len());
703 assert_eq!(result.next, DispatchHint::End);
704 }
705
706 #[test]
707 fn parse_http_request_bare_lf() {
708 let data = b"GET / HTTP/1.1\nHost: example.com\n\n";
710 let buf = dissect(data).unwrap();
711 let layer = buf.layer_by_name("HTTP").unwrap();
712
713 assert_eq!(
714 buf.field_by_name(layer, "method").unwrap().value,
715 FieldValue::Str("GET")
716 );
717 let headers_field = buf.field_by_name(layer, "headers").unwrap();
718 if let FieldValue::Array(ref r) = headers_field.value {
719 let children = buf.nested_fields(r);
720 let obj = children.iter().find(|f| f.value.is_object()).unwrap();
721 if let FieldValue::Object(ref obj_r) = obj.value {
722 let obj_fields = buf.nested_fields(obj_r);
723 assert_eq!(obj_fields[1].value, FieldValue::Str("example.com"));
724 }
725 }
726 }
727
728 #[test]
729 fn parse_http_response_bare_lf() {
730 let data = b"HTTP/1.1 200 OK\nContent-Length: 2\n\nhi";
732 let buf = dissect(data).unwrap();
733 let layer = buf.layer_by_name("HTTP").unwrap();
734
735 assert_eq!(
736 buf.field_by_name(layer, "status_code").unwrap().value,
737 FieldValue::U16(200)
738 );
739 assert_eq!(
740 buf.field_by_name(layer, "content_length").unwrap().value,
741 FieldValue::U32(2)
742 );
743 }
744
745 #[test]
746 fn parse_http_response_invalid_status() {
747 let data = b"HTTP/1.1 200OK\r\n\r\n";
749 assert!(matches!(dissect_err(data), PacketError::InvalidHeader(_)));
750 }
751
752 #[test]
753 fn parse_http_empty_header_name() {
754 let data = b"GET / HTTP/1.1\r\n: value\r\n\r\n";
756 assert!(matches!(dissect_err(data), PacketError::InvalidHeader(_)));
757 }
758
759 #[test]
760 fn parse_http_post_content_type_dispatch() {
761 let body = b"{\"key\":\"value\"}";
762 let header =
763 b"POST /api HTTP/1.1\r\nContent-Type: application/json\r\nContent-Length: 15\r\n\r\n";
764 let mut data = Vec::new();
765 data.extend_from_slice(header);
766 data.extend_from_slice(body);
767
768 let dissector = HttpDissector;
769 let mut buf = DissectBuffer::new();
770 let result = dissector.dissect(&data, &mut buf, 0).unwrap();
771
772 assert_eq!(result.next, DispatchHint::ByContentType("application/json"));
773 assert_eq!(result.bytes_consumed, header.len());
774
775 let layer = buf.layer_by_name("HTTP").unwrap();
776 assert_eq!(layer.range, 0..header.len());
777 assert_eq!(
778 buf.field_by_name(layer, "content_type").unwrap().value,
779 FieldValue::Str("application/json")
780 );
781 }
782
783 #[test]
784 fn parse_http_response_content_type_dispatch() {
785 let body = b"<html></html>";
786 let header = b"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: 13\r\n\r\n";
787 let mut data = Vec::new();
788 data.extend_from_slice(header);
789 data.extend_from_slice(body);
790
791 let dissector = HttpDissector;
792 let mut buf = DissectBuffer::new();
793 let result = dissector.dissect(&data, &mut buf, 0).unwrap();
794
795 assert_eq!(result.next, DispatchHint::ByContentType("text/html"));
796 assert_eq!(result.bytes_consumed, header.len());
797
798 let layer = buf.layer_by_name("HTTP").unwrap();
799 assert_eq!(layer.range, 0..header.len());
800 }
801
802 #[test]
803 fn parse_http_content_type_with_params() {
804 let body = b"{\"a\":1}";
805 let header = b"POST /api HTTP/1.1\r\nContent-Type: application/json; charset=utf-8\r\nContent-Length: 7\r\n\r\n";
806 let mut data = Vec::new();
807 data.extend_from_slice(header);
808 data.extend_from_slice(body);
809
810 let dissector = HttpDissector;
811 let mut buf = DissectBuffer::new();
812 let result = dissector.dissect(&data, &mut buf, 0).unwrap();
813
814 assert_eq!(result.next, DispatchHint::ByContentType("application/json"));
816
817 let layer = buf.layer_by_name("HTTP").unwrap();
819 assert_eq!(
820 buf.field_by_name(layer, "content_type").unwrap().value,
821 FieldValue::Str("application/json; charset=utf-8")
822 );
823 }
824
825 #[test]
826 fn parse_http_content_type_case_insensitive() {
827 let body = b"{\"a\":1}";
828 let header =
829 b"POST /api HTTP/1.1\r\nContent-Type: Application/JSON\r\nContent-Length: 7\r\n\r\n";
830 let mut data = Vec::new();
831 data.extend_from_slice(header);
832 data.extend_from_slice(body);
833
834 let dissector = HttpDissector;
835 let mut buf = DissectBuffer::new();
836 let result = dissector.dissect(&data, &mut buf, 0).unwrap();
837
838 assert_eq!(result.next, DispatchHint::ByContentType("application/json"));
840 }
841
842 #[test]
843 fn parse_http_no_content_type_with_body() {
844 let body = b"key=value";
845 let header = b"POST /submit HTTP/1.1\r\nContent-Length: 9\r\n\r\n";
846 let mut data = Vec::new();
847 data.extend_from_slice(header);
848 data.extend_from_slice(body);
849
850 let dissector = HttpDissector;
851 let mut buf = DissectBuffer::new();
852 let result = dissector.dissect(&data, &mut buf, 0).unwrap();
853
854 assert_eq!(result.next, DispatchHint::End);
855 assert_eq!(result.bytes_consumed, data.len());
856
857 let layer = buf.layer_by_name("HTTP").unwrap();
858 assert_eq!(layer.range, 0..data.len());
859 assert!(buf.field_by_name(layer, "content_type").is_none());
860 }
861
862 #[test]
863 fn parse_http_no_body_with_content_type() {
864 let data = b"GET / HTTP/1.1\r\nContent-Type: text/plain\r\n\r\n";
865
866 let dissector = HttpDissector;
867 let mut buf = DissectBuffer::new();
868 let result = dissector.dissect(data, &mut buf, 0).unwrap();
869
870 assert_eq!(result.next, DispatchHint::End);
871
872 let layer = buf.layer_by_name("HTTP").unwrap();
873 assert_eq!(
874 buf.field_by_name(layer, "content_type").unwrap().value,
875 FieldValue::Str("text/plain")
876 );
877 }
878
879 #[test]
880 fn dissector_metadata() {
881 let d = HttpDissector;
882 assert_eq!(d.name(), "HyperText Transfer Protocol");
883 assert_eq!(d.short_name(), "HTTP");
884 assert!(!d.field_descriptors().is_empty());
885 }
886}