http1_spec/
body_framing.rs1use std::io::{Error as IoError, ErrorKind as IoErrorKind};
2
3use http::{
4 header::{CONTENT_LENGTH, TRANSFER_ENCODING},
5 HeaderMap, HeaderValue, Version,
6};
7
8use crate::CHUNKED;
9
10#[derive(Debug, PartialEq, Eq, Clone)]
15pub enum BodyFraming {
16 ContentLength(usize),
17 Chunked,
18 Neither,
19}
20
21impl BodyFraming {
22 pub fn update_content_length_value(&mut self, value: usize) -> Result<(), IoError> {
23 match self {
24 Self::ContentLength(n) => {
25 *n = value;
26 Ok(())
27 }
28 _ => Err(IoError::new(
29 IoErrorKind::InvalidInput,
30 "Not in ContentLength",
31 )),
32 }
33 }
34}
35
36pub trait BodyFramingDetector {
37 fn detect(&self) -> Result<BodyFraming, IoError>;
38}
39impl BodyFramingDetector for (&HeaderMap<HeaderValue>, &Version) {
40 fn detect(&self) -> Result<BodyFraming, IoError> {
41 let (headers, version) = *self;
42
43 if let Some(header_value) = headers.get(CONTENT_LENGTH) {
44 let value_str = header_value
45 .to_str()
46 .map_err(|err| IoError::new(IoErrorKind::InvalidInput, err))?;
47 let value: usize = value_str
48 .parse()
49 .map_err(|err| IoError::new(IoErrorKind::InvalidInput, err))?;
50 return Ok(BodyFraming::ContentLength(value));
51 }
52
53 if version == &Version::HTTP_11 {
54 if let Some(header_value) = headers.get(TRANSFER_ENCODING) {
55 if header_value == CHUNKED {
56 return Ok(BodyFraming::Chunked);
57 }
58 }
59 }
60
61 Ok(BodyFraming::Neither)
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn detect() -> Result<(), Box<dyn std::error::Error>> {
71 let mut header_map = HeaderMap::new();
72
73 header_map.insert("Content-Length", "1".parse().unwrap());
74 assert_eq!(
75 (&header_map, &Version::HTTP_11).detect()?,
76 BodyFraming::ContentLength(1)
77 );
78
79 header_map.clear();
80 header_map.insert("Transfer-Encoding", "chunked".parse().unwrap());
81 assert_eq!(
82 (&header_map, &Version::HTTP_10).detect()?,
83 BodyFraming::Neither
84 );
85 assert_eq!(
86 (&header_map, &Version::HTTP_11).detect()?,
87 BodyFraming::Chunked
88 );
89
90 header_map.clear();
91 assert_eq!(
92 (&header_map, &Version::HTTP_11).detect()?,
93 BodyFraming::Neither
94 );
95
96 Ok(())
97 }
98}