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