1 use bytes::BytesMut;
2 use http::HeaderMap;
3 use http::header::{CONTENT_LENGTH, TRANSFER_ENCODING};
4 use http::header::{HeaderValue, OccupiedEntry, ValueIter};
5
connection_keep_alive(value: &HeaderValue) -> bool6 pub fn connection_keep_alive(value: &HeaderValue) -> bool {
7 connection_has(value, "keep-alive")
8 }
9
connection_close(value: &HeaderValue) -> bool10 pub fn connection_close(value: &HeaderValue) -> bool {
11 connection_has(value, "close")
12 }
13
connection_has(value: &HeaderValue, needle: &str) -> bool14 fn connection_has(value: &HeaderValue, needle: &str) -> bool {
15 if let Ok(s) = value.to_str() {
16 for val in s.split(',') {
17 if val.trim().eq_ignore_ascii_case(needle) {
18 return true;
19 }
20 }
21 }
22 false
23 }
24
content_length_parse(value: &HeaderValue) -> Option<u64>25 pub fn content_length_parse(value: &HeaderValue) -> Option<u64> {
26 value
27 .to_str()
28 .ok()
29 .and_then(|s| s.parse().ok())
30 }
31
content_length_parse_all(headers: &HeaderMap) -> Option<u64>32 pub fn content_length_parse_all(headers: &HeaderMap) -> Option<u64> {
33 content_length_parse_all_values(headers.get_all(CONTENT_LENGTH).into_iter())
34 }
35
content_length_parse_all_values(values: ValueIter<HeaderValue>) -> Option<u64>36 pub fn content_length_parse_all_values(values: ValueIter<HeaderValue>) -> Option<u64> {
37 // If multiple Content-Length headers were sent, everything can still
38 // be alright if they all contain the same value, and all parse
39 // correctly. If not, then it's an error.
40
41 let folded = values
42 .fold(None, |prev, line| match prev {
43 Some(Ok(prev)) => {
44 Some(line
45 .to_str()
46 .map_err(|_| ())
47 .and_then(|s| s.parse().map_err(|_| ()))
48 .and_then(|n| if prev == n { Ok(n) } else { Err(()) }))
49 },
50 None => {
51 Some(line
52 .to_str()
53 .map_err(|_| ())
54 .and_then(|s| s.parse().map_err(|_| ())))
55 },
56 Some(Err(())) => Some(Err(())),
57 });
58
59 if let Some(Ok(n)) = folded {
60 Some(n)
61 } else {
62 None
63 }
64 }
65
set_content_length_if_missing(headers: &mut HeaderMap, len: u64)66 pub fn set_content_length_if_missing(headers: &mut HeaderMap, len: u64) {
67 headers
68 .entry(CONTENT_LENGTH)
69 .unwrap()
70 .or_insert_with(|| HeaderValue::from(len));
71 }
72
transfer_encoding_is_chunked(headers: &HeaderMap) -> bool73 pub fn transfer_encoding_is_chunked(headers: &HeaderMap) -> bool {
74 is_chunked(headers.get_all(TRANSFER_ENCODING).into_iter())
75 }
76
is_chunked(mut encodings: ValueIter<HeaderValue>) -> bool77 pub fn is_chunked(mut encodings: ValueIter<HeaderValue>) -> bool {
78 // chunked must always be the last encoding, according to spec
79 if let Some(line) = encodings.next_back() {
80 return is_chunked_(line);
81 }
82
83 false
84 }
85
is_chunked_(value: &HeaderValue) -> bool86 pub fn is_chunked_(value: &HeaderValue) -> bool {
87 // chunked must always be the last encoding, according to spec
88 if let Ok(s) = value.to_str() {
89 if let Some(encoding) = s.rsplit(',').next() {
90 return encoding.trim().eq_ignore_ascii_case("chunked");
91 }
92 }
93
94 false
95 }
96
add_chunked(mut entry: OccupiedEntry<HeaderValue>)97 pub fn add_chunked(mut entry: OccupiedEntry<HeaderValue>) {
98 const CHUNKED: &'static str = "chunked";
99
100 if let Some(line) = entry.iter_mut().next_back() {
101 // + 2 for ", "
102 let new_cap = line.as_bytes().len() + CHUNKED.len() + 2;
103 let mut buf = BytesMut::with_capacity(new_cap);
104 buf.copy_from_slice(line.as_bytes());
105 buf.copy_from_slice(b", ");
106 buf.copy_from_slice(CHUNKED.as_bytes());
107
108 *line = HeaderValue::from_shared(buf.freeze())
109 .expect("original header value plus ascii is valid");
110 return;
111 }
112
113 entry.insert(HeaderValue::from_static(CHUNKED));
114 }
115