http_types/headers/
header_value.rs

1use std::convert::TryFrom;
2use std::fmt::{self, Debug, Display};
3use std::str::FromStr;
4
5use crate::headers::HeaderValues;
6#[cfg(feature = "cookies")]
7use crate::Cookie;
8use crate::Error;
9use crate::Mime;
10
11/// A header value.
12#[derive(Clone, Eq, PartialEq, Hash)]
13pub struct HeaderValue {
14    inner: String,
15}
16
17impl HeaderValue {
18    /// Create a new `HeaderValue` from a Vec of ASCII bytes.
19    ///
20    /// # Error
21    ///
22    /// This function will error if the bytes is not valid ASCII.
23    pub fn from_bytes(bytes: Vec<u8>) -> Result<Self, Error> {
24        crate::ensure!(bytes.is_ascii(), "Bytes should be valid ASCII");
25
26        // This is permitted because ASCII is valid UTF-8, and we just checked that.
27        let string = unsafe { String::from_utf8_unchecked(bytes) };
28        Ok(Self { inner: string })
29    }
30
31    /// Converts a vector of bytes to a `HeaderValue` without checking that the string contains
32    /// valid ASCII.
33    ///
34    /// # Safety
35    ///
36    /// This function is unsafe because it does not check that the bytes passed to it are valid
37    /// ASCII. If this constraint is violated, it may cause memory
38    /// unsafety issues with future users of the HeaderValue, as the rest of the library assumes
39    /// that Strings are valid ASCII.
40    pub unsafe fn from_bytes_unchecked(bytes: Vec<u8>) -> Self {
41        let string = String::from_utf8_unchecked(bytes);
42        Self { inner: string }
43    }
44
45    /// Get the header value as a `&str`
46    pub fn as_str(&self) -> &str {
47        &self.inner
48    }
49}
50
51impl From<Mime> for HeaderValue {
52    fn from(mime: Mime) -> Self {
53        HeaderValue {
54            inner: format!("{}", mime),
55        }
56    }
57}
58
59#[cfg(feature = "cookies")]
60impl From<Cookie<'_>> for HeaderValue {
61    fn from(cookie: Cookie<'_>) -> Self {
62        HeaderValue {
63            inner: cookie.to_string(),
64        }
65    }
66}
67
68impl From<&Mime> for HeaderValue {
69    fn from(mime: &Mime) -> Self {
70        HeaderValue {
71            inner: format!("{}", mime),
72        }
73    }
74}
75
76impl FromStr for HeaderValue {
77    type Err = Error;
78
79    /// Create a new `HeaderValue`.
80    ///
81    /// This checks it's valid ASCII.
82    fn from_str(s: &str) -> Result<Self, Self::Err> {
83        crate::ensure!(s.is_ascii(), "String slice should be valid ASCII");
84        Ok(Self {
85            inner: String::from(s),
86        })
87    }
88}
89
90impl<'a> TryFrom<&'a str> for HeaderValue {
91    type Error = Error;
92
93    fn try_from(value: &'a str) -> Result<Self, Self::Error> {
94        Self::from_str(value)
95    }
96}
97
98impl Debug for HeaderValue {
99    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100        write!(f, "{:?}", self.inner)
101    }
102}
103
104impl Display for HeaderValue {
105    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106        write!(f, "{}", self.inner)
107    }
108}
109
110impl PartialEq<str> for HeaderValue {
111    fn eq(&self, other: &str) -> bool {
112        self.inner == other
113    }
114}
115
116impl<'a> PartialEq<&'a str> for HeaderValue {
117    fn eq(&self, other: &&'a str) -> bool {
118        &self.inner == other
119    }
120}
121
122impl PartialEq<String> for HeaderValue {
123    fn eq(&self, other: &String) -> bool {
124        &self.inner == other
125    }
126}
127
128impl<'a> PartialEq<&String> for HeaderValue {
129    fn eq(&self, other: &&String) -> bool {
130        &&self.inner == other
131    }
132}
133
134impl From<HeaderValues> for HeaderValue {
135    fn from(mut other: HeaderValues) -> Self {
136        other.inner.reverse();
137        other
138            .inner
139            .pop()
140            .expect("HeaderValues should contain at least one value")
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use super::*;
147
148    #[test]
149    fn test_debug() {
150        let header_value = HeaderValue::from_str("foo0").unwrap();
151        assert_eq!(format!("{:?}", header_value), "\"foo0\"");
152    }
153}