Skip to main content

rama_http_types/header/
value.rs

1use bytes::{Bytes, BytesMut};
2
3use std::convert::TryFrom;
4use std::error::Error;
5use std::fmt::Write;
6use std::hash::{Hash, Hasher};
7use std::str::FromStr;
8use std::{cmp, fmt, str};
9
10use crate::header::name::HeaderName;
11
12/// Represents an HTTP header field value.
13///
14/// In practice, HTTP header field values are usually valid ASCII. However, the
15/// HTTP spec allows for a header value to contain opaque bytes as well. In this
16/// case, the header field value is not able to be represented as a string.
17///
18/// To handle this, the `HeaderValue` is usable as a type and can be compared
19/// with strings and implements `Debug`. A `to_str` fn is provided that returns
20/// an `Err` if the header value contains non visible ascii characters.
21///
22/// Its human-readable Serde form is a string when possible and a byte sequence
23/// otherwise. The sensitivity marker controls diagnostics and compression, not
24/// wire data, and is intentionally not preserved by Serde.
25#[derive(Clone)]
26pub struct HeaderValue {
27    inner: Bytes,
28    is_sensitive: bool,
29}
30
31/// A possible error when converting a `HeaderValue` from a string or byte
32/// slice.
33pub struct InvalidHeaderValue {
34    _priv: (),
35}
36
37/// A possible error when converting a `HeaderValue` to a string representation.
38///
39/// Header field values may contain opaque bytes, in which case it is not
40/// possible to represent the value as a string.
41#[derive(Debug)]
42pub struct ToStrError {
43    _priv: (),
44}
45
46impl HeaderValue {
47    /// Convert a static string to a `HeaderValue`.
48    ///
49    /// This function will not perform any copying, however the string is
50    /// checked to ensure that no invalid characters are present. Only visible
51    /// ASCII characters (32-126) and horizontal tab are permitted.
52    ///
53    /// # Panics
54    ///
55    /// This function panics if the argument contains invalid header value
56    /// characters.
57    ///
58    /// # Examples
59    ///
60    /// ```
61    /// # use rama_http_types::header::HeaderValue;
62    /// let val = HeaderValue::from_static("hello");
63    /// assert_eq!(val, "hello");
64    /// ```
65    #[inline]
66    pub const fn from_static(src: &'static str) -> HeaderValue {
67        let bytes = src.as_bytes();
68        let mut i = 0;
69        while i < bytes.len() {
70            if !is_valid_ascii(bytes[i]) {
71                panic!("HeaderValue::from_static with invalid bytes")
72            }
73            i += 1;
74        }
75
76        HeaderValue {
77            inner: Bytes::from_static(bytes),
78            is_sensitive: false,
79        }
80    }
81
82    /// Attempt to convert a string to a `HeaderValue`.
83    ///
84    /// If the argument contains invalid header value characters, an error is
85    /// returned. Only visible ASCII characters (32-126) and horizontal tab are
86    /// permitted. Use
87    /// `from_bytes` to create a `HeaderValue` that includes opaque octets
88    /// (128-255).
89    ///
90    /// This function is intended to be replaced in the future by a `TryFrom`
91    /// implementation once the trait is stabilized in std.
92    ///
93    /// # Examples
94    ///
95    /// ```
96    /// # use rama_http_types::header::HeaderValue;
97    /// let val = HeaderValue::from_str("hello").unwrap();
98    /// assert_eq!(val, "hello");
99    /// ```
100    ///
101    /// An invalid value
102    ///
103    /// ```
104    /// # use rama_http_types::header::HeaderValue;
105    /// let val = HeaderValue::from_str("\n");
106    /// assert!(val.is_err());
107    /// ```
108    #[inline]
109    #[allow(clippy::should_implement_trait)]
110    pub fn from_str(src: &str) -> Result<HeaderValue, InvalidHeaderValue> {
111        HeaderValue::try_from_generic(
112            src,
113            |s| Bytes::copy_from_slice(s.as_bytes()),
114            is_valid_ascii,
115        )
116    }
117
118    /// Converts a HeaderName into a HeaderValue
119    ///
120    /// Since every valid HeaderName is a valid HeaderValue this is done infallibly.
121    ///
122    /// # Examples
123    ///
124    /// ```
125    /// # use rama_http_types::header::{HeaderValue, HeaderName};
126    /// # use rama_http_types::header::ACCEPT;
127    /// let val = HeaderValue::from_name(ACCEPT);
128    /// assert_eq!(val, HeaderValue::from_bytes(b"accept").unwrap());
129    /// ```
130    #[inline]
131    pub fn from_name(name: HeaderName) -> HeaderValue {
132        name.into()
133    }
134
135    /// Attempt to convert a byte slice to a `HeaderValue`.
136    ///
137    /// If the argument contains invalid header value bytes, an error is
138    /// returned. Only byte values between 32 and 255 (inclusive) are permitted,
139    /// excluding byte 127 (DEL).
140    ///
141    /// This function is intended to be replaced in the future by a `TryFrom`
142    /// implementation once the trait is stabilized in std.
143    ///
144    /// # Examples
145    ///
146    /// ```
147    /// # use rama_http_types::header::HeaderValue;
148    /// let val = HeaderValue::from_bytes(b"hello\xfa").unwrap();
149    /// assert_eq!(val, &b"hello\xfa"[..]);
150    /// ```
151    ///
152    /// An invalid value
153    ///
154    /// ```
155    /// # use rama_http_types::header::HeaderValue;
156    /// let val = HeaderValue::from_bytes(b"\n");
157    /// assert!(val.is_err());
158    /// ```
159    #[inline]
160    pub fn from_bytes(src: &[u8]) -> Result<HeaderValue, InvalidHeaderValue> {
161        HeaderValue::try_from_generic(src, Bytes::copy_from_slice, is_valid_ascii_or_opaque_byte)
162    }
163
164    /// Attempt to convert a `Bytes` buffer to a `HeaderValue`.
165    ///
166    /// This will try to prevent a copy if the type passed is the type used
167    /// internally, and will copy the data if it is not.
168    pub fn from_maybe_shared<T>(src: T) -> Result<HeaderValue, InvalidHeaderValue>
169    where
170        T: AsRef<[u8]> + 'static,
171    {
172        if_downcast_into!(T, Bytes, src, {
173            return HeaderValue::from_shared(src);
174        });
175
176        HeaderValue::from_bytes(src.as_ref())
177    }
178
179    /// Convert a `Bytes` directly into a `HeaderValue` without validating.
180    ///
181    /// This function does NOT validate that illegal bytes are not contained
182    /// within the buffer.
183    ///
184    /// ## Panics
185    /// In a debug build this will panic if `src` is not valid UTF-8.
186    ///
187    /// ## Safety
188    /// `src` must contain valid UTF-8. In a release build it is undefined
189    /// behaviour to call this with `src` that is not valid UTF-8.
190    pub unsafe fn from_maybe_shared_unchecked<T>(src: T) -> HeaderValue
191    where
192        T: AsRef<[u8]> + 'static,
193    {
194        if cfg!(debug_assertions) {
195            match HeaderValue::from_maybe_shared(src) {
196                Ok(val) => val,
197                Err(_err) => {
198                    panic!("HeaderValue::from_maybe_shared_unchecked() with invalid bytes");
199                }
200            }
201        } else {
202            if_downcast_into!(T, Bytes, src, {
203                return HeaderValue {
204                    inner: src,
205                    is_sensitive: false,
206                };
207            });
208
209            let src = Bytes::copy_from_slice(src.as_ref());
210            HeaderValue {
211                inner: src,
212                is_sensitive: false,
213            }
214        }
215    }
216
217    fn from_shared(src: Bytes) -> Result<HeaderValue, InvalidHeaderValue> {
218        HeaderValue::try_from_generic(src, std::convert::identity, is_valid_ascii_or_opaque_byte)
219    }
220
221    fn try_from_generic<T: AsRef<[u8]>, F: FnOnce(T) -> Bytes, V: Fn(u8) -> bool>(
222        src: T,
223        into: F,
224        is_valid: V,
225    ) -> Result<HeaderValue, InvalidHeaderValue> {
226        // Avoid an early return so the loop vectorizes.
227        let mut bad = false;
228        for &b in src.as_ref() {
229            bad |= !is_valid(b);
230        }
231        if bad {
232            return Err(InvalidHeaderValue { _priv: () });
233        }
234        Ok(HeaderValue {
235            inner: into(src),
236            is_sensitive: false,
237        })
238    }
239
240    /// Yields a `&str` slice if the `HeaderValue` only contains visible ASCII
241    /// chars.
242    ///
243    /// This function will perform a scan of the header value, checking all the
244    /// characters.
245    ///
246    /// # Examples
247    ///
248    /// ```
249    /// # use rama_http_types::header::HeaderValue;
250    /// let val = HeaderValue::from_static("hello");
251    /// assert_eq!(val.to_str().unwrap(), "hello");
252    /// ```
253    pub fn to_str(&self) -> Result<&str, ToStrError> {
254        let bytes = self.as_ref();
255
256        // Avoid an early return so the loop vectorizes.
257        let mut bad = false;
258        for &b in bytes {
259            bad |= !is_valid_ascii(b);
260        }
261        if bad {
262            return Err(ToStrError { _priv: () });
263        }
264
265        unsafe { Ok(str::from_utf8_unchecked(bytes)) }
266    }
267
268    /// Returns the length of `self`.
269    ///
270    /// This length is in bytes.
271    ///
272    /// # Examples
273    ///
274    /// ```
275    /// # use rama_http_types::header::HeaderValue;
276    /// let val = HeaderValue::from_static("hello");
277    /// assert_eq!(val.len(), 5);
278    /// ```
279    #[inline]
280    pub fn len(&self) -> usize {
281        self.as_ref().len()
282    }
283
284    /// Returns true if the `HeaderValue` has a length of zero bytes.
285    ///
286    /// # Examples
287    ///
288    /// ```
289    /// # use rama_http_types::header::HeaderValue;
290    /// let val = HeaderValue::from_static("");
291    /// assert!(val.is_empty());
292    ///
293    /// let val = HeaderValue::from_static("hello");
294    /// assert!(!val.is_empty());
295    /// ```
296    #[inline]
297    pub fn is_empty(&self) -> bool {
298        self.len() == 0
299    }
300
301    /// Converts a `HeaderValue` to a byte slice.
302    ///
303    /// # Examples
304    ///
305    /// ```
306    /// # use rama_http_types::header::HeaderValue;
307    /// let val = HeaderValue::from_static("hello");
308    /// assert_eq!(val.as_bytes(), b"hello");
309    /// ```
310    #[inline]
311    pub fn as_bytes(&self) -> &[u8] {
312        self.as_ref()
313    }
314
315    /// Mark that the header value represents sensitive information.
316    ///
317    /// # Examples
318    ///
319    /// ```
320    /// # use rama_http_types::header::HeaderValue;
321    /// let mut val = HeaderValue::from_static("my secret");
322    ///
323    /// val.set_sensitive(true);
324    /// assert!(val.is_sensitive());
325    ///
326    /// val.set_sensitive(false);
327    /// assert!(!val.is_sensitive());
328    /// ```
329    #[inline]
330    pub fn set_sensitive(&mut self, val: bool) {
331        self.is_sensitive = val;
332    }
333
334    /// Returns `true` if the value represents sensitive data.
335    ///
336    /// Sensitive data could represent passwords or other data that should not
337    /// be stored on disk or in memory. By marking header values as sensitive,
338    /// components using this crate can be instructed to treat them with special
339    /// care for security reasons. For example, caches can avoid storing
340    /// sensitive values, and HPACK encoders used by HTTP/2.0 implementations
341    /// can choose not to compress them.
342    ///
343    /// Additionally, sensitive values will be masked by the `Debug`
344    /// implementation of `HeaderValue`.
345    ///
346    /// Note that sensitivity is not factored into equality or ordering.
347    ///
348    /// # Examples
349    ///
350    /// ```
351    /// # use rama_http_types::header::HeaderValue;
352    /// let mut val = HeaderValue::from_static("my secret");
353    ///
354    /// val.set_sensitive(true);
355    /// assert!(val.is_sensitive());
356    ///
357    /// val.set_sensitive(false);
358    /// assert!(!val.is_sensitive());
359    /// ```
360    #[inline]
361    pub fn is_sensitive(&self) -> bool {
362        self.is_sensitive
363    }
364}
365
366impl AsRef<[u8]> for HeaderValue {
367    #[inline]
368    fn as_ref(&self) -> &[u8] {
369        self.inner.as_ref()
370    }
371}
372
373impl fmt::Debug for HeaderValue {
374    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
375        if self.is_sensitive {
376            f.write_str("Sensitive")
377        } else {
378            f.write_str("\"")?;
379            let mut from = 0;
380            let bytes = self.as_bytes();
381            for (i, &b) in bytes.iter().enumerate() {
382                if !is_valid_ascii(b) || b == b'"' {
383                    if from != i {
384                        f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..i]) })?;
385                    }
386                    if b == b'"' {
387                        f.write_str("\\\"")?;
388                    } else {
389                        write!(f, "\\x{:x}", b)?;
390                    }
391                    from = i + 1;
392                }
393            }
394
395            f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..]) })?;
396            f.write_str("\"")
397        }
398    }
399}
400
401impl From<HeaderName> for HeaderValue {
402    #[inline]
403    fn from(h: HeaderName) -> HeaderValue {
404        HeaderValue {
405            inner: h.into_bytes(),
406            is_sensitive: false,
407        }
408    }
409}
410
411macro_rules! from_integers {
412    ($($name:ident: $t:ident => $max_len:expr),*) => {$(
413        impl From<$t> for HeaderValue {
414            fn from(num: $t) -> HeaderValue {
415                let mut buf = BytesMut::with_capacity($max_len);
416                let _ = buf.write_str(::itoa::Buffer::new().format(num));
417                HeaderValue {
418                    inner: buf.freeze(),
419                    is_sensitive: false,
420                }
421            }
422        }
423
424        #[test]
425        fn $name() {
426            let n: $t = 55;
427            let val = HeaderValue::from(n);
428            assert_eq!(val, &n.to_string());
429
430            let n = <$t>::MAX;
431            let val = HeaderValue::from(n);
432            assert_eq!(val, &n.to_string());
433        }
434    )*};
435}
436
437from_integers! {
438    // integer type => maximum decimal length
439
440    // u8 purposely left off... HeaderValue::from(b'3') could be confusing
441    from_u16: u16 => 5,
442    from_i16: i16 => 6,
443    from_u32: u32 => 10,
444    from_i32: i32 => 11,
445    from_u64: u64 => 20,
446    from_i64: i64 => 20
447}
448
449#[cfg(target_pointer_width = "16")]
450from_integers! {
451    from_usize: usize => 5,
452    from_isize: isize => 6
453}
454
455#[cfg(target_pointer_width = "32")]
456from_integers! {
457    from_usize: usize => 10,
458    from_isize: isize => 11
459}
460
461#[cfg(target_pointer_width = "64")]
462from_integers! {
463    from_usize: usize => 20,
464    from_isize: isize => 20
465}
466
467#[cfg(test)]
468mod from_header_name_tests {
469    use super::*;
470    use crate::header::map::HeaderMap;
471    use crate::header::name;
472
473    #[test]
474    fn it_can_insert_header_name_as_header_value() {
475        let mut map = HeaderMap::new();
476        map.insert(name::UPGRADE, name::SEC_WEBSOCKET_PROTOCOL.into());
477        map.insert(
478            name::ACCEPT,
479            name::HeaderName::from_bytes(b"hello-world").unwrap().into(),
480        );
481
482        assert_eq!(
483            map.get(name::UPGRADE).unwrap(),
484            HeaderValue::from_bytes(b"sec-websocket-protocol").unwrap()
485        );
486
487        assert_eq!(
488            map.get(name::ACCEPT).unwrap(),
489            HeaderValue::from_bytes(b"hello-world").unwrap()
490        );
491    }
492}
493
494impl FromStr for HeaderValue {
495    type Err = InvalidHeaderValue;
496
497    #[inline]
498    fn from_str(s: &str) -> Result<HeaderValue, Self::Err> {
499        HeaderValue::from_str(s)
500    }
501}
502
503impl From<&HeaderValue> for HeaderValue {
504    #[inline]
505    fn from(t: &HeaderValue) -> Self {
506        t.clone()
507    }
508}
509
510impl TryFrom<&str> for HeaderValue {
511    type Error = InvalidHeaderValue;
512
513    #[inline]
514    fn try_from(t: &str) -> Result<Self, Self::Error> {
515        t.parse()
516    }
517}
518
519impl TryFrom<&String> for HeaderValue {
520    type Error = InvalidHeaderValue;
521    #[inline]
522    fn try_from(s: &String) -> Result<Self, Self::Error> {
523        Self::from_str(s)
524    }
525}
526
527impl TryFrom<&[u8]> for HeaderValue {
528    type Error = InvalidHeaderValue;
529
530    #[inline]
531    fn try_from(t: &[u8]) -> Result<Self, Self::Error> {
532        HeaderValue::from_bytes(t)
533    }
534}
535
536impl TryFrom<String> for HeaderValue {
537    type Error = InvalidHeaderValue;
538
539    #[inline]
540    fn try_from(t: String) -> Result<Self, Self::Error> {
541        HeaderValue::try_from_generic(t, |s| s.into(), is_valid_ascii)
542    }
543}
544
545impl TryFrom<Vec<u8>> for HeaderValue {
546    type Error = InvalidHeaderValue;
547
548    #[inline]
549    fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
550        HeaderValue::from_shared(vec.into())
551    }
552}
553
554#[cfg(test)]
555mod try_from_header_name_tests {
556    use super::*;
557    use crate::header::name;
558
559    #[test]
560    fn it_converts_using_try_from() {
561        assert_eq!(
562            HeaderValue::try_from(name::UPGRADE).unwrap(),
563            HeaderValue::from_bytes(b"upgrade").unwrap()
564        );
565    }
566}
567
568const fn is_valid_ascii(b: u8) -> bool {
569    b >= 32 && b < 127 || b == b'\t'
570}
571
572// This validator is only for byte-oriented constructors. HTTP field values
573// may contain opaque bytes, even though those bytes cannot be exposed by
574// `HeaderValue::to_str`.
575#[inline]
576fn is_valid_ascii_or_opaque_byte(b: u8) -> bool {
577    b >= 32 && b != 127 || b == b'\t'
578}
579
580impl fmt::Debug for InvalidHeaderValue {
581    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
582        f.debug_struct("InvalidHeaderValue")
583            // skip _priv noise
584            .finish()
585    }
586}
587
588impl fmt::Display for InvalidHeaderValue {
589    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
590        f.write_str("failed to parse header value")
591    }
592}
593
594impl Error for InvalidHeaderValue {}
595
596impl fmt::Display for ToStrError {
597    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
598        f.write_str("failed to convert header to a str")
599    }
600}
601
602impl Error for ToStrError {}
603
604// ===== PartialEq / PartialOrd =====
605
606impl Hash for HeaderValue {
607    fn hash<H: Hasher>(&self, state: &mut H) {
608        self.inner.hash(state);
609    }
610}
611
612impl PartialEq for HeaderValue {
613    #[inline]
614    fn eq(&self, other: &HeaderValue) -> bool {
615        self.inner == other.inner
616    }
617}
618
619impl Eq for HeaderValue {}
620
621impl PartialOrd for HeaderValue {
622    #[inline]
623    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
624        Some(self.cmp(other))
625    }
626}
627
628impl Ord for HeaderValue {
629    #[inline]
630    fn cmp(&self, other: &Self) -> cmp::Ordering {
631        self.inner.cmp(&other.inner)
632    }
633}
634
635impl PartialEq<str> for HeaderValue {
636    #[inline]
637    fn eq(&self, other: &str) -> bool {
638        self.inner == other.as_bytes()
639    }
640}
641
642impl PartialEq<[u8]> for HeaderValue {
643    #[inline]
644    fn eq(&self, other: &[u8]) -> bool {
645        self.inner == other
646    }
647}
648
649impl PartialOrd<str> for HeaderValue {
650    #[inline]
651    fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
652        (*self.inner).partial_cmp(other.as_bytes())
653    }
654}
655
656impl PartialOrd<[u8]> for HeaderValue {
657    #[inline]
658    fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
659        (*self.inner).partial_cmp(other)
660    }
661}
662
663impl PartialEq<HeaderValue> for str {
664    #[inline]
665    fn eq(&self, other: &HeaderValue) -> bool {
666        *other == *self
667    }
668}
669
670impl PartialEq<HeaderValue> for [u8] {
671    #[inline]
672    fn eq(&self, other: &HeaderValue) -> bool {
673        *other == *self
674    }
675}
676
677impl PartialOrd<HeaderValue> for str {
678    #[inline]
679    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
680        self.as_bytes().partial_cmp(other.as_bytes())
681    }
682}
683
684impl PartialOrd<HeaderValue> for [u8] {
685    #[inline]
686    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
687        self.partial_cmp(other.as_bytes())
688    }
689}
690
691impl PartialEq<String> for HeaderValue {
692    #[inline]
693    fn eq(&self, other: &String) -> bool {
694        *self == other[..]
695    }
696}
697
698impl PartialOrd<String> for HeaderValue {
699    #[inline]
700    fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
701        self.inner.partial_cmp(other.as_bytes())
702    }
703}
704
705impl PartialEq<HeaderValue> for String {
706    #[inline]
707    fn eq(&self, other: &HeaderValue) -> bool {
708        *other == *self
709    }
710}
711
712impl PartialOrd<HeaderValue> for String {
713    #[inline]
714    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
715        self.as_bytes().partial_cmp(other.as_bytes())
716    }
717}
718
719impl PartialEq<HeaderValue> for &HeaderValue {
720    #[inline]
721    fn eq(&self, other: &HeaderValue) -> bool {
722        **self == *other
723    }
724}
725
726impl PartialOrd<HeaderValue> for &HeaderValue {
727    #[inline]
728    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
729        (**self).partial_cmp(other)
730    }
731}
732
733impl<T: ?Sized> PartialEq<&T> for HeaderValue
734where
735    HeaderValue: PartialEq<T>,
736{
737    #[inline]
738    fn eq(&self, other: &&T) -> bool {
739        *self == **other
740    }
741}
742
743impl<T: ?Sized> PartialOrd<&T> for HeaderValue
744where
745    HeaderValue: PartialOrd<T>,
746{
747    #[inline]
748    fn partial_cmp(&self, other: &&T) -> Option<cmp::Ordering> {
749        self.partial_cmp(*other)
750    }
751}
752
753impl serde::Serialize for HeaderValue {
754    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
755    where
756        S: serde::Serializer,
757    {
758        match self.to_str() {
759            Ok(value) if serializer.is_human_readable() => serializer.serialize_str(value),
760            _ => serializer.serialize_bytes(self.as_bytes()),
761        }
762    }
763}
764
765/// Human-readable formats must support `deserialize_any` because textual
766/// values deserialize from strings while opaque values deserialize from byte
767/// sequences. Formats that represent `serialize_bytes` as text cannot retain
768/// that distinction and are not suitable for lossless opaque header values.
769impl<'de> serde::Deserialize<'de> for HeaderValue {
770    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
771    where
772        D: serde::Deserializer<'de>,
773    {
774        struct HeaderValueVisitor;
775
776        impl<'de> serde::de::Visitor<'de> for HeaderValueVisitor {
777            type Value = HeaderValue;
778
779            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
780                formatter.write_str("a valid HTTP header value as text or bytes")
781            }
782
783            fn visit_borrowed_str<E>(self, value: &str) -> Result<Self::Value, E>
784            where
785                E: serde::de::Error,
786            {
787                HeaderValue::from_str(value).map_err(E::custom)
788            }
789
790            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
791            where
792                E: serde::de::Error,
793            {
794                self.visit_borrowed_str(value)
795            }
796
797            fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
798            where
799                E: serde::de::Error,
800            {
801                HeaderValue::try_from(value).map_err(E::custom)
802            }
803
804            fn visit_borrowed_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
805            where
806                E: serde::de::Error,
807            {
808                HeaderValue::from_bytes(value).map_err(E::custom)
809            }
810
811            fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
812            where
813                E: serde::de::Error,
814            {
815                self.visit_borrowed_bytes(value)
816            }
817
818            fn visit_byte_buf<E>(self, value: Vec<u8>) -> Result<Self::Value, E>
819            where
820                E: serde::de::Error,
821            {
822                HeaderValue::from_maybe_shared(value).map_err(E::custom)
823            }
824
825            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
826            where
827                A: serde::de::SeqAccess<'de>,
828            {
829                let mut bytes = Vec::new();
830                while let Some(byte) = seq.next_element()? {
831                    bytes.push(byte);
832                }
833                self.visit_byte_buf(bytes)
834            }
835        }
836
837        if deserializer.is_human_readable() {
838            deserializer.deserialize_any(HeaderValueVisitor)
839        } else {
840            deserializer.deserialize_bytes(HeaderValueVisitor)
841        }
842    }
843}
844
845impl PartialEq<HeaderValue> for &str {
846    #[inline]
847    fn eq(&self, other: &HeaderValue) -> bool {
848        *other == *self
849    }
850}
851
852impl PartialOrd<HeaderValue> for &str {
853    #[inline]
854    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
855        self.as_bytes().partial_cmp(other.as_bytes())
856    }
857}
858
859#[test]
860fn test_try_from() {
861    HeaderValue::try_from(vec![127]).unwrap_err();
862}
863
864#[test]
865fn test_string_constructors_reject_non_ascii() {
866    let value = String::from("hello \u{e9}");
867
868    assert!(HeaderValue::from_str(&value).is_err());
869    assert!(HeaderValue::try_from(value.as_str()).is_err());
870    assert!(HeaderValue::try_from(&value).is_err());
871    assert!(HeaderValue::try_from(value).is_err());
872}
873
874#[test]
875fn test_byte_constructors_allow_opaque_bytes_but_reject_del() {
876    assert!(HeaderValue::from_bytes(b"hello\xff").is_ok());
877    assert!(HeaderValue::try_from(&b"hello\xff"[..]).is_ok());
878    assert!(HeaderValue::try_from(b"hello\xff".to_vec()).is_ok());
879
880    assert!(HeaderValue::from_bytes(b"hello\x7f").is_err());
881}
882
883#[test]
884fn test_string_and_byte_constructors_allow_horizontal_tab() {
885    assert!(HeaderValue::from_str("hello\tworld").is_ok());
886    assert!(HeaderValue::from_bytes(b"hello\tworld").is_ok());
887}
888
889#[test]
890#[should_panic(expected = "HeaderValue::from_static with invalid bytes")]
891fn test_static_constructor_rejects_non_ascii() {
892    HeaderValue::from_static("hello \u{e9}");
893}
894
895#[test]
896fn test_debug() {
897    let cases = &[
898        ("hello", "\"hello\""),
899        ("hello \"world\"", "\"hello \\\"world\\\"\""),
900        ("\u{7FFF}hello", "\"\\xe7\\xbf\\xbfhello\""),
901    ];
902
903    for &(value, expected) in cases {
904        let val = HeaderValue::from_bytes(value.as_bytes()).unwrap();
905        let actual = format!("{:?}", val);
906        assert_eq!(expected, actual);
907    }
908
909    let mut sensitive = HeaderValue::from_static("password");
910    sensitive.set_sensitive(true);
911    assert_eq!("Sensitive", format!("{:?}", sensitive));
912}