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