1use std::{convert::Infallible, str};
2
3use derive_more::{Deref, DerefMut};
4
5use crate::{
6 error::ParseError,
7 http::header::{
8 from_one_raw_str, Header, HeaderName, HeaderValue, TryIntoHeaderValue, CONTENT_LENGTH,
9 },
10 HttpMessage,
11};
12
13#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Deref, DerefMut)]
42pub struct ContentLength(pub usize);
43
44impl ContentLength {
45 pub fn into_inner(&self) -> usize {
47 self.0
48 }
49}
50
51impl str::FromStr for ContentLength {
52 type Err = <usize as str::FromStr>::Err;
53
54 #[inline]
55 fn from_str(val: &str) -> Result<Self, Self::Err> {
56 let val = val.trim();
57
58 debug_assert!(!val.starts_with('+'));
60
61 val.parse().map(Self)
62 }
63}
64
65impl TryIntoHeaderValue for ContentLength {
66 type Error = Infallible;
67
68 fn try_into_value(self) -> Result<HeaderValue, Self::Error> {
69 Ok(HeaderValue::from(self.0))
70 }
71}
72
73impl Header for ContentLength {
74 fn name() -> HeaderName {
75 CONTENT_LENGTH
76 }
77
78 fn parse<M: HttpMessage>(msg: &M) -> Result<Self, ParseError> {
79 let val = from_one_raw_str(msg.headers().get(Self::name()))?;
80
81 debug_assert_eq!(msg.headers().get_all(Self::name()).count(), 1);
83
84 Ok(val)
85 }
86}
87
88impl From<ContentLength> for usize {
89 fn from(ContentLength(len): ContentLength) -> Self {
90 len
91 }
92}
93
94impl From<usize> for ContentLength {
95 fn from(len: usize) -> Self {
96 ContentLength(len)
97 }
98}
99
100impl PartialEq<usize> for ContentLength {
101 fn eq(&self, other: &usize) -> bool {
102 self.0 == *other
103 }
104}
105
106impl PartialEq<ContentLength> for usize {
107 fn eq(&self, other: &ContentLength) -> bool {
108 *self == other.0
109 }
110}
111
112impl PartialOrd<usize> for ContentLength {
113 fn partial_cmp(&self, other: &usize) -> Option<std::cmp::Ordering> {
114 self.0.partial_cmp(other)
115 }
116}
117
118impl PartialOrd<ContentLength> for usize {
119 fn partial_cmp(&self, other: &ContentLength) -> Option<std::cmp::Ordering> {
120 self.partial_cmp(&other.0)
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use std::fmt;
127
128 use super::*;
129 use crate::{test::TestRequest, HttpRequest};
130
131 fn req_from_raw_headers<H: Header, I: IntoIterator<Item = V>, V: AsRef<[u8]>>(
132 header_lines: I,
133 ) -> HttpRequest {
134 header_lines
135 .into_iter()
136 .fold(TestRequest::default(), |req, item| {
137 req.append_header((H::name(), item.as_ref().to_vec()))
138 })
139 .to_http_request()
140 }
141
142 #[track_caller]
143 pub(crate) fn assert_parse_fail<
144 H: Header + fmt::Debug,
145 I: IntoIterator<Item = V>,
146 V: AsRef<[u8]>,
147 >(
148 headers: I,
149 ) {
150 let req = req_from_raw_headers::<H, _, _>(headers);
151 H::parse(&req).unwrap_err();
152 }
153
154 #[track_caller]
155 pub(crate) fn assert_parse_eq<
156 H: Header + fmt::Debug + PartialEq,
157 I: IntoIterator<Item = V>,
158 V: AsRef<[u8]>,
159 >(
160 headers: I,
161 expect: H,
162 ) {
163 let req = req_from_raw_headers::<H, _, _>(headers);
164 assert_eq!(H::parse(&req).unwrap(), expect);
165 }
166
167 #[test]
168 fn missing_header() {
169 assert_parse_fail::<ContentLength, _, _>([""; 0]);
170 assert_parse_fail::<ContentLength, _, _>([""]);
171 }
172
173 #[test]
174 fn bad_header() {
175 assert_parse_fail::<ContentLength, _, _>(["-123"]);
176 assert_parse_fail::<ContentLength, _, _>(["123_456"]);
177 assert_parse_fail::<ContentLength, _, _>(["123.456"]);
178
179 assert_parse_fail::<ContentLength, _, _>(["18446744073709551616"]);
181 assert_parse_fail::<ContentLength, _, _>(["18446744073709551617"]);
182
183 assert_parse_fail::<ContentLength, _, _>(["0x123"]);
185
186 assert_parse_fail::<ContentLength, _, _>(["0, 123"]);
188 }
189
190 #[test]
191 #[should_panic]
192 fn bad_header_plus() {
193 assert_parse_fail::<ContentLength, _, _>(["+123"]);
195 }
196
197 #[test]
198 #[should_panic]
199 fn bad_multiple_value() {
200 assert_parse_fail::<ContentLength, _, _>(["0", "123"]);
202 }
203
204 #[test]
205 fn good_header() {
206 assert_parse_eq::<ContentLength, _, _>(["0"], ContentLength(0));
207 assert_parse_eq::<ContentLength, _, _>(["1"], ContentLength(1));
208 assert_parse_eq::<ContentLength, _, _>(["123"], ContentLength(123));
209
210 assert_parse_eq::<ContentLength, _, _>(["0123"], ContentLength(123));
212
213 assert_parse_eq::<ContentLength, _, _>([" 0"], ContentLength(0));
215 assert_parse_eq::<ContentLength, _, _>(["0 "], ContentLength(0));
216 assert_parse_eq::<ContentLength, _, _>([" 0 "], ContentLength(0));
217
218 assert_parse_eq::<ContentLength, _, _>(
220 ["18446744073709551615"],
221 ContentLength(18_446_744_073_709_551_615),
222 );
223 }
224
225 #[test]
226 fn equality() {
227 assert!(ContentLength(0) == ContentLength(0));
228 assert!(ContentLength(0) == 0);
229 assert!(0 != ContentLength(123));
230 }
231
232 #[test]
233 fn ordering() {
234 assert!(ContentLength(0) < ContentLength(123));
235 assert!(ContentLength(0) < 123);
236 assert!(0 < ContentLength(123));
237 }
238}