http/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, mem, 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 useable 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#[derive(Clone)]
22pub struct HeaderValue {
23    inner: Bytes,
24    is_sensitive: bool,
25}
26
27/// A possible error when converting a `HeaderValue` from a string or byte
28/// slice.
29pub struct InvalidHeaderValue {
30    _priv: (),
31}
32
33/// A possible error when converting a `HeaderValue` to a string representation.
34///
35/// Header field values may contain opaque bytes, in which case it is not
36/// possible to represent the value as a string.
37#[derive(Debug)]
38pub struct ToStrError {
39    _priv: (),
40}
41
42impl HeaderValue {
43    /// Convert a static string to a `HeaderValue`.
44    ///
45    /// This function will not perform any copying, however the string is
46    /// checked to ensure that no invalid characters are present. Only visible
47    /// ASCII characters (32-127) are permitted.
48    ///
49    /// # Panics
50    ///
51    /// This function panics if the argument contains invalid header value
52    /// characters.
53    ///
54    /// Until [Allow panicking in constants](https://github.com/rust-lang/rfcs/pull/2345)
55    /// makes its way into stable, the panic message at compile-time is
56    /// going to look cryptic, but should at least point at your header value:
57    ///
58    /// ```text
59    /// error: any use of this value will cause an error
60    ///   --> http/src/header/value.rs:67:17
61    ///    |
62    /// 67 |                 ([] as [u8; 0])[0]; // Invalid header value
63    ///    |                 ^^^^^^^^^^^^^^^^^^
64    ///    |                 |
65    ///    |                 index out of bounds: the length is 0 but the index is 0
66    ///    |                 inside `HeaderValue::from_static` at http/src/header/value.rs:67:17
67    ///    |                 inside `INVALID_HEADER` at src/main.rs:73:33
68    ///    |
69    ///   ::: src/main.rs:73:1
70    ///    |
71    /// 73 | const INVALID_HEADER: HeaderValue = HeaderValue::from_static("жsome value");
72    ///    | ----------------------------------------------------------------------------
73    /// ```
74    ///
75    /// # Examples
76    ///
77    /// ```
78    /// # use http::header::HeaderValue;
79    /// let val = HeaderValue::from_static("hello");
80    /// assert_eq!(val, "hello");
81    /// ```
82    #[inline]
83    #[allow(unconditional_panic)] // required for the panic circumvention
84    pub const fn from_static(src: &'static str) -> HeaderValue {
85        let bytes = src.as_bytes();
86        let mut i = 0;
87        while i < bytes.len() {
88            if !is_visible_ascii(bytes[i]) {
89                // TODO: When msrv is bumped to larger than 1.57, this should be
90                // replaced with `panic!` macro.
91                // https://blog.rust-lang.org/2021/12/02/Rust-1.57.0.html#panic-in-const-contexts
92                //
93                // See the panics section of this method's document for details.
94                #[allow(clippy::no_effect, clippy::out_of_bounds_indexing)]
95                ([] as [u8; 0])[0]; // Invalid header value
96            }
97            i += 1;
98        }
99
100        HeaderValue {
101            inner: Bytes::from_static(bytes),
102            is_sensitive: false,
103        }
104    }
105
106    /// Attempt to convert a string to a `HeaderValue`.
107    ///
108    /// If the argument contains invalid header value characters, an error is
109    /// returned. Only visible ASCII characters (32-127) are permitted. Use
110    /// `from_bytes` to create a `HeaderValue` that includes opaque octets
111    /// (128-255).
112    ///
113    /// This function is intended to be replaced in the future by a `TryFrom`
114    /// implementation once the trait is stabilized in std.
115    ///
116    /// # Examples
117    ///
118    /// ```
119    /// # use http::header::HeaderValue;
120    /// let val = HeaderValue::from_str("hello").unwrap();
121    /// assert_eq!(val, "hello");
122    /// ```
123    ///
124    /// An invalid value
125    ///
126    /// ```
127    /// # use http::header::HeaderValue;
128    /// let val = HeaderValue::from_str("\n");
129    /// assert!(val.is_err());
130    /// ```
131    #[inline]
132    #[allow(clippy::should_implement_trait)]
133    pub fn from_str(src: &str) -> Result<HeaderValue, InvalidHeaderValue> {
134        HeaderValue::try_from_generic(src, |s| Bytes::copy_from_slice(s.as_bytes()))
135    }
136
137    /// Converts a HeaderName into a HeaderValue
138    ///
139    /// Since every valid HeaderName is a valid HeaderValue this is done infallibly.
140    ///
141    /// # Examples
142    ///
143    /// ```
144    /// # use http::header::{HeaderValue, HeaderName};
145    /// # use http::header::ACCEPT;
146    /// let val = HeaderValue::from_name(ACCEPT);
147    /// assert_eq!(val, HeaderValue::from_bytes(b"accept").unwrap());
148    /// ```
149    #[inline]
150    pub fn from_name(name: HeaderName) -> HeaderValue {
151        name.into()
152    }
153
154    /// Attempt to convert a byte slice to a `HeaderValue`.
155    ///
156    /// If the argument contains invalid header value bytes, an error is
157    /// returned. Only byte values between 32 and 255 (inclusive) are permitted,
158    /// excluding byte 127 (DEL).
159    ///
160    /// This function is intended to be replaced in the future by a `TryFrom`
161    /// implementation once the trait is stabilized in std.
162    ///
163    /// # Examples
164    ///
165    /// ```
166    /// # use http::header::HeaderValue;
167    /// let val = HeaderValue::from_bytes(b"hello\xfa").unwrap();
168    /// assert_eq!(val, &b"hello\xfa"[..]);
169    /// ```
170    ///
171    /// An invalid value
172    ///
173    /// ```
174    /// # use http::header::HeaderValue;
175    /// let val = HeaderValue::from_bytes(b"\n");
176    /// assert!(val.is_err());
177    /// ```
178    #[inline]
179    pub fn from_bytes(src: &[u8]) -> Result<HeaderValue, InvalidHeaderValue> {
180        HeaderValue::try_from_generic(src, Bytes::copy_from_slice)
181    }
182
183    /// Attempt to convert a `Bytes` buffer to a `HeaderValue`.
184    ///
185    /// This will try to prevent a copy if the type passed is the type used
186    /// internally, and will copy the data if it is not.
187    pub fn from_maybe_shared<T>(src: T) -> Result<HeaderValue, InvalidHeaderValue>
188    where
189        T: AsRef<[u8]> + 'static,
190    {
191        if_downcast_into!(T, Bytes, src, {
192            return HeaderValue::from_shared(src);
193        });
194
195        HeaderValue::from_bytes(src.as_ref())
196    }
197
198    /// Convert a `Bytes` directly into a `HeaderValue` without validating.
199    ///
200    /// This function does NOT validate that illegal bytes are not contained
201    /// within the buffer.
202    ///
203    /// ## Panics
204    /// In a debug build this will panic if `src` is not valid UTF-8.
205    ///
206    /// ## Safety
207    /// `src` must contain valid UTF-8. In a release build it is undefined
208    /// behaviour to call this with `src` that is not valid UTF-8.
209    pub unsafe fn from_maybe_shared_unchecked<T>(src: T) -> HeaderValue
210    where
211        T: AsRef<[u8]> + 'static,
212    {
213        if cfg!(debug_assertions) {
214            match HeaderValue::from_maybe_shared(src) {
215                Ok(val) => val,
216                Err(_err) => {
217                    panic!("HeaderValue::from_maybe_shared_unchecked() with invalid bytes");
218                }
219            }
220        } else {
221            if_downcast_into!(T, Bytes, src, {
222                return HeaderValue {
223                    inner: src,
224                    is_sensitive: false,
225                };
226            });
227
228            let src = Bytes::copy_from_slice(src.as_ref());
229            HeaderValue {
230                inner: src,
231                is_sensitive: false,
232            }
233        }
234    }
235
236    fn from_shared(src: Bytes) -> Result<HeaderValue, InvalidHeaderValue> {
237        HeaderValue::try_from_generic(src, std::convert::identity)
238    }
239
240    fn try_from_generic<T: AsRef<[u8]>, F: FnOnce(T) -> Bytes>(
241        src: T,
242        into: F,
243    ) -> Result<HeaderValue, InvalidHeaderValue> {
244        for &b in src.as_ref() {
245            if !is_valid(b) {
246                return Err(InvalidHeaderValue { _priv: () });
247            }
248        }
249        Ok(HeaderValue {
250            inner: into(src),
251            is_sensitive: false,
252        })
253    }
254
255    /// Yields a `&str` slice if the `HeaderValue` only contains visible ASCII
256    /// chars.
257    ///
258    /// This function will perform a scan of the header value, checking all the
259    /// characters.
260    ///
261    /// # Examples
262    ///
263    /// ```
264    /// # use http::header::HeaderValue;
265    /// let val = HeaderValue::from_static("hello");
266    /// assert_eq!(val.to_str().unwrap(), "hello");
267    /// ```
268    pub fn to_str(&self) -> Result<&str, ToStrError> {
269        let bytes = self.as_ref();
270
271        for &b in bytes {
272            if !is_visible_ascii(b) {
273                return Err(ToStrError { _priv: () });
274            }
275        }
276
277        unsafe { Ok(str::from_utf8_unchecked(bytes)) }
278    }
279
280    /// Returns the length of `self`.
281    ///
282    /// This length is in bytes.
283    ///
284    /// # Examples
285    ///
286    /// ```
287    /// # use http::header::HeaderValue;
288    /// let val = HeaderValue::from_static("hello");
289    /// assert_eq!(val.len(), 5);
290    /// ```
291    #[inline]
292    pub fn len(&self) -> usize {
293        self.as_ref().len()
294    }
295
296    /// Returns true if the `HeaderValue` has a length of zero bytes.
297    ///
298    /// # Examples
299    ///
300    /// ```
301    /// # use http::header::HeaderValue;
302    /// let val = HeaderValue::from_static("");
303    /// assert!(val.is_empty());
304    ///
305    /// let val = HeaderValue::from_static("hello");
306    /// assert!(!val.is_empty());
307    /// ```
308    #[inline]
309    pub fn is_empty(&self) -> bool {
310        self.len() == 0
311    }
312
313    /// Converts a `HeaderValue` to a byte slice.
314    ///
315    /// # Examples
316    ///
317    /// ```
318    /// # use http::header::HeaderValue;
319    /// let val = HeaderValue::from_static("hello");
320    /// assert_eq!(val.as_bytes(), b"hello");
321    /// ```
322    #[inline]
323    pub fn as_bytes(&self) -> &[u8] {
324        self.as_ref()
325    }
326
327    /// Mark that the header value represents sensitive information.
328    ///
329    /// # Examples
330    ///
331    /// ```
332    /// # use http::header::HeaderValue;
333    /// let mut val = HeaderValue::from_static("my secret");
334    ///
335    /// val.set_sensitive(true);
336    /// assert!(val.is_sensitive());
337    ///
338    /// val.set_sensitive(false);
339    /// assert!(!val.is_sensitive());
340    /// ```
341    #[inline]
342    pub fn set_sensitive(&mut self, val: bool) {
343        self.is_sensitive = val;
344    }
345
346    /// Returns `true` if the value represents sensitive data.
347    ///
348    /// Sensitive data could represent passwords or other data that should not
349    /// be stored on disk or in memory. By marking header values as sensitive,
350    /// components using this crate can be instructed to treat them with special
351    /// care for security reasons. For example, caches can avoid storing
352    /// sensitive values, and HPACK encoders used by HTTP/2.0 implementations
353    /// can choose not to compress them.
354    ///
355    /// Additionally, sensitive values will be masked by the `Debug`
356    /// implementation of `HeaderValue`.
357    ///
358    /// Note that sensitivity is not factored into equality or ordering.
359    ///
360    /// # Examples
361    ///
362    /// ```
363    /// # use http::header::HeaderValue;
364    /// let mut val = HeaderValue::from_static("my secret");
365    ///
366    /// val.set_sensitive(true);
367    /// assert!(val.is_sensitive());
368    ///
369    /// val.set_sensitive(false);
370    /// assert!(!val.is_sensitive());
371    /// ```
372    #[inline]
373    pub fn is_sensitive(&self) -> bool {
374        self.is_sensitive
375    }
376}
377
378impl AsRef<[u8]> for HeaderValue {
379    #[inline]
380    fn as_ref(&self) -> &[u8] {
381        self.inner.as_ref()
382    }
383}
384
385impl fmt::Debug for HeaderValue {
386    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
387        if self.is_sensitive {
388            f.write_str("Sensitive")
389        } else {
390            f.write_str("\"")?;
391            let mut from = 0;
392            let bytes = self.as_bytes();
393            for (i, &b) in bytes.iter().enumerate() {
394                if !is_visible_ascii(b) || b == b'"' {
395                    if from != i {
396                        f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..i]) })?;
397                    }
398                    if b == b'"' {
399                        f.write_str("\\\"")?;
400                    } else {
401                        write!(f, "\\x{:x}", b)?;
402                    }
403                    from = i + 1;
404                }
405            }
406
407            f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..]) })?;
408            f.write_str("\"")
409        }
410    }
411}
412
413impl From<HeaderName> for HeaderValue {
414    #[inline]
415    fn from(h: HeaderName) -> HeaderValue {
416        HeaderValue {
417            inner: h.into_bytes(),
418            is_sensitive: false,
419        }
420    }
421}
422
423macro_rules! from_integers {
424    ($($name:ident: $t:ident => $max_len:expr),*) => {$(
425        impl From<$t> for HeaderValue {
426            fn from(num: $t) -> HeaderValue {
427                let mut buf = if mem::size_of::<BytesMut>() - 1 < $max_len {
428                    // On 32bit platforms, BytesMut max inline size
429                    // is 15 bytes, but the $max_len could be bigger.
430                    //
431                    // The likelihood of the number *actually* being
432                    // that big is very small, so only allocate
433                    // if the number needs that space.
434                    //
435                    // The largest decimal number in 15 digits:
436                    // It wold be 10.pow(15) - 1, but this is a constant
437                    // version.
438                    if num as u64 > 999_999_999_999_999_999 {
439                        BytesMut::with_capacity($max_len)
440                    } else {
441                        // fits inline...
442                        BytesMut::new()
443                    }
444                } else {
445                    // full value fits inline, so don't allocate!
446                    BytesMut::new()
447                };
448                let _ = buf.write_str(::itoa::Buffer::new().format(num));
449                HeaderValue {
450                    inner: buf.freeze(),
451                    is_sensitive: false,
452                }
453            }
454        }
455
456        #[test]
457        fn $name() {
458            let n: $t = 55;
459            let val = HeaderValue::from(n);
460            assert_eq!(val, &n.to_string());
461
462            let n = ::std::$t::MAX;
463            let val = HeaderValue::from(n);
464            assert_eq!(val, &n.to_string());
465        }
466    )*};
467}
468
469from_integers! {
470    // integer type => maximum decimal length
471
472    // u8 purposely left off... HeaderValue::from(b'3') could be confusing
473    from_u16: u16 => 5,
474    from_i16: i16 => 6,
475    from_u32: u32 => 10,
476    from_i32: i32 => 11,
477    from_u64: u64 => 20,
478    from_i64: i64 => 20
479}
480
481#[cfg(target_pointer_width = "16")]
482from_integers! {
483    from_usize: usize => 5,
484    from_isize: isize => 6
485}
486
487#[cfg(target_pointer_width = "32")]
488from_integers! {
489    from_usize: usize => 10,
490    from_isize: isize => 11
491}
492
493#[cfg(target_pointer_width = "64")]
494from_integers! {
495    from_usize: usize => 20,
496    from_isize: isize => 20
497}
498
499#[cfg(test)]
500mod from_header_name_tests {
501    use super::*;
502    use crate::header::map::HeaderMap;
503    use crate::header::name;
504
505    #[test]
506    fn it_can_insert_header_name_as_header_value() {
507        let mut map = HeaderMap::new();
508        map.insert(name::UPGRADE, name::SEC_WEBSOCKET_PROTOCOL.into());
509        map.insert(
510            name::ACCEPT,
511            name::HeaderName::from_bytes(b"hello-world").unwrap().into(),
512        );
513
514        assert_eq!(
515            map.get(name::UPGRADE).unwrap(),
516            HeaderValue::from_bytes(b"sec-websocket-protocol").unwrap()
517        );
518
519        assert_eq!(
520            map.get(name::ACCEPT).unwrap(),
521            HeaderValue::from_bytes(b"hello-world").unwrap()
522        );
523    }
524}
525
526impl FromStr for HeaderValue {
527    type Err = InvalidHeaderValue;
528
529    #[inline]
530    fn from_str(s: &str) -> Result<HeaderValue, Self::Err> {
531        HeaderValue::from_str(s)
532    }
533}
534
535impl<'a> From<&'a HeaderValue> for HeaderValue {
536    #[inline]
537    fn from(t: &'a HeaderValue) -> Self {
538        t.clone()
539    }
540}
541
542impl<'a> TryFrom<&'a str> for HeaderValue {
543    type Error = InvalidHeaderValue;
544
545    #[inline]
546    fn try_from(t: &'a str) -> Result<Self, Self::Error> {
547        t.parse()
548    }
549}
550
551impl<'a> TryFrom<&'a String> for HeaderValue {
552    type Error = InvalidHeaderValue;
553    #[inline]
554    fn try_from(s: &'a String) -> Result<Self, Self::Error> {
555        Self::from_bytes(s.as_bytes())
556    }
557}
558
559impl<'a> TryFrom<&'a [u8]> for HeaderValue {
560    type Error = InvalidHeaderValue;
561
562    #[inline]
563    fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
564        HeaderValue::from_bytes(t)
565    }
566}
567
568impl TryFrom<String> for HeaderValue {
569    type Error = InvalidHeaderValue;
570
571    #[inline]
572    fn try_from(t: String) -> Result<Self, Self::Error> {
573        HeaderValue::from_shared(t.into())
574    }
575}
576
577impl TryFrom<Vec<u8>> for HeaderValue {
578    type Error = InvalidHeaderValue;
579
580    #[inline]
581    fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
582        HeaderValue::from_shared(vec.into())
583    }
584}
585
586#[cfg(test)]
587mod try_from_header_name_tests {
588    use super::*;
589    use crate::header::name;
590
591    #[test]
592    fn it_converts_using_try_from() {
593        assert_eq!(
594            HeaderValue::try_from(name::UPGRADE).unwrap(),
595            HeaderValue::from_bytes(b"upgrade").unwrap()
596        );
597    }
598}
599
600const fn is_visible_ascii(b: u8) -> bool {
601    b >= 32 && b < 127 || b == b'\t'
602}
603
604#[inline]
605fn is_valid(b: u8) -> bool {
606    b >= 32 && b != 127 || b == b'\t'
607}
608
609impl fmt::Debug for InvalidHeaderValue {
610    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
611        f.debug_struct("InvalidHeaderValue")
612            // skip _priv noise
613            .finish()
614    }
615}
616
617impl fmt::Display for InvalidHeaderValue {
618    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
619        f.write_str("failed to parse header value")
620    }
621}
622
623impl Error for InvalidHeaderValue {}
624
625impl fmt::Display for ToStrError {
626    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
627        f.write_str("failed to convert header to a str")
628    }
629}
630
631impl Error for ToStrError {}
632
633// ===== PartialEq / PartialOrd =====
634
635impl Hash for HeaderValue {
636    fn hash<H: Hasher>(&self, state: &mut H) {
637        self.inner.hash(state);
638    }
639}
640
641impl PartialEq for HeaderValue {
642    #[inline]
643    fn eq(&self, other: &HeaderValue) -> bool {
644        self.inner == other.inner
645    }
646}
647
648impl Eq for HeaderValue {}
649
650impl PartialOrd for HeaderValue {
651    #[inline]
652    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
653        Some(self.cmp(other))
654    }
655}
656
657impl Ord for HeaderValue {
658    #[inline]
659    fn cmp(&self, other: &Self) -> cmp::Ordering {
660        self.inner.cmp(&other.inner)
661    }
662}
663
664impl PartialEq<str> for HeaderValue {
665    #[inline]
666    fn eq(&self, other: &str) -> bool {
667        self.inner == other.as_bytes()
668    }
669}
670
671impl PartialEq<[u8]> for HeaderValue {
672    #[inline]
673    fn eq(&self, other: &[u8]) -> bool {
674        self.inner == other
675    }
676}
677
678impl PartialOrd<str> for HeaderValue {
679    #[inline]
680    fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
681        (*self.inner).partial_cmp(other.as_bytes())
682    }
683}
684
685impl PartialOrd<[u8]> for HeaderValue {
686    #[inline]
687    fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
688        (*self.inner).partial_cmp(other)
689    }
690}
691
692impl PartialEq<HeaderValue> for str {
693    #[inline]
694    fn eq(&self, other: &HeaderValue) -> bool {
695        *other == *self
696    }
697}
698
699impl PartialEq<HeaderValue> for [u8] {
700    #[inline]
701    fn eq(&self, other: &HeaderValue) -> bool {
702        *other == *self
703    }
704}
705
706impl PartialOrd<HeaderValue> for str {
707    #[inline]
708    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
709        self.as_bytes().partial_cmp(other.as_bytes())
710    }
711}
712
713impl PartialOrd<HeaderValue> for [u8] {
714    #[inline]
715    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
716        self.partial_cmp(other.as_bytes())
717    }
718}
719
720impl PartialEq<String> for HeaderValue {
721    #[inline]
722    fn eq(&self, other: &String) -> bool {
723        *self == other[..]
724    }
725}
726
727impl PartialOrd<String> for HeaderValue {
728    #[inline]
729    fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
730        self.inner.partial_cmp(other.as_bytes())
731    }
732}
733
734impl PartialEq<HeaderValue> for String {
735    #[inline]
736    fn eq(&self, other: &HeaderValue) -> bool {
737        *other == *self
738    }
739}
740
741impl PartialOrd<HeaderValue> for String {
742    #[inline]
743    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
744        self.as_bytes().partial_cmp(other.as_bytes())
745    }
746}
747
748impl<'a> PartialEq<HeaderValue> for &'a HeaderValue {
749    #[inline]
750    fn eq(&self, other: &HeaderValue) -> bool {
751        **self == *other
752    }
753}
754
755impl<'a> PartialOrd<HeaderValue> for &'a HeaderValue {
756    #[inline]
757    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
758        (**self).partial_cmp(other)
759    }
760}
761
762impl<'a, T: ?Sized> PartialEq<&'a T> for HeaderValue
763where
764    HeaderValue: PartialEq<T>,
765{
766    #[inline]
767    fn eq(&self, other: &&'a T) -> bool {
768        *self == **other
769    }
770}
771
772impl<'a, T: ?Sized> PartialOrd<&'a T> for HeaderValue
773where
774    HeaderValue: PartialOrd<T>,
775{
776    #[inline]
777    fn partial_cmp(&self, other: &&'a T) -> Option<cmp::Ordering> {
778        self.partial_cmp(*other)
779    }
780}
781
782impl<'a> PartialEq<HeaderValue> for &'a str {
783    #[inline]
784    fn eq(&self, other: &HeaderValue) -> bool {
785        *other == *self
786    }
787}
788
789impl<'a> PartialOrd<HeaderValue> for &'a str {
790    #[inline]
791    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
792        self.as_bytes().partial_cmp(other.as_bytes())
793    }
794}
795
796#[test]
797fn test_try_from() {
798    HeaderValue::try_from(vec![127]).unwrap_err();
799}
800
801#[test]
802fn test_debug() {
803    let cases = &[
804        ("hello", "\"hello\""),
805        ("hello \"world\"", "\"hello \\\"world\\\"\""),
806        ("\u{7FFF}hello", "\"\\xe7\\xbf\\xbfhello\""),
807    ];
808
809    for &(value, expected) in cases {
810        let val = HeaderValue::from_bytes(value.as_bytes()).unwrap();
811        let actual = format!("{:?}", val);
812        assert_eq!(expected, actual);
813    }
814
815    let mut sensitive = HeaderValue::from_static("password");
816    sensitive.set_sensitive(true);
817    assert_eq!("Sensitive", format!("{:?}", sensitive));
818}