typed_headers/impls/
content_length.rs

1use http::header::{self, HeaderName, HeaderValue, CONTENT_LENGTH};
2use std::ops::{Deref, DerefMut};
3
4use crate::{util, Error, Header, ToValues};
5
6/// `Content-Length` header, defined in
7/// [RFC7230](http://tools.ietf.org/html/rfc7230#section-3.3.2)
8///
9/// When a message does not have a `Transfer-Encoding` header field, a
10/// Content-Length header field can provide the anticipated size, as a
11/// decimal number of octets, for a potential payload body.  For messages
12/// that do include a payload body, the Content-Length field-value
13/// provides the framing information necessary for determining where the
14/// body (and message) ends.  For messages that do not include a payload
15/// body, the Content-Length indicates the size of the selected
16/// representation.
17///
18/// # ABNF
19///
20/// ```text
21/// Content-Length = 1*DIGIT
22/// ```
23///
24/// # Example values
25///
26/// * `3495`
27#[derive(Clone, Debug, PartialEq)]
28pub struct ContentLength(pub u64);
29
30impl Deref for ContentLength {
31    type Target = u64;
32
33    #[inline]
34    fn deref(&self) -> &u64 {
35        &self.0
36    }
37}
38
39impl DerefMut for ContentLength {
40    #[inline]
41    fn deref_mut(&mut self) -> &mut u64 {
42        &mut self.0
43    }
44}
45
46impl Header for ContentLength {
47    #[inline]
48    fn name() -> &'static HeaderName {
49        &CONTENT_LENGTH
50    }
51
52    // RFC 7230 permits multiple identical copies of Content-Length, and there apparently exist
53    // implementations that produce that!
54    // https://github.com/request/request/issues/2091#issuecomment-328715113
55    #[inline]
56    fn from_values(
57        values: &mut header::ValueIter<HeaderValue>,
58    ) -> Result<Option<ContentLength>, Error> {
59        let mut length = None;
60
61        for value in values {
62            let value = value.to_str().map_err(|_| Error::invalid_value())?;
63            if value.trim().is_empty() {
64                return Err(Error::invalid_value());
65            }
66
67            for elem in value.split(',') {
68                let elem = elem.trim();
69                if elem.is_empty() {
70                    continue;
71                }
72
73                let elem = elem.parse().map_err(|_| Error::invalid_value())?;
74                match length {
75                    Some(length) if length != elem => return Err(Error::invalid_value()),
76                    Some(_) => {}
77                    None => length = Some(elem),
78                }
79            }
80        }
81
82        Ok(length.map(ContentLength))
83    }
84
85    #[inline]
86    fn to_values(&self, values: &mut ToValues) {
87        util::encode_single_value(&self.0, values);
88    }
89}