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