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