1use bytes::{Bytes, BytesMut};
2
3use std::convert::TryFrom;
4use std::error::Error;
5use std::fmt::Write;
6use std::hash::{Hash, Hasher};
7use std::str::FromStr;
8use std::{cmp, fmt, str};
9
10use crate::header::name::HeaderName;
11
12#[derive(Clone)]
22pub struct HeaderValue {
23 inner: Bytes,
24 is_sensitive: bool,
25}
26
27pub struct InvalidHeaderValue {
30 _priv: (),
31}
32
33#[derive(Debug)]
38pub struct ToStrError {
39 _priv: (),
40}
41
42impl HeaderValue {
43 #[inline]
83 #[allow(unconditional_panic)] 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 #[allow(clippy::no_effect, clippy::out_of_bounds_indexing)]
95 ([] as [u8; 0])[0]; }
97 i += 1;
98 }
99
100 HeaderValue {
101 inner: Bytes::from_static(bytes),
102 is_sensitive: false,
103 }
104 }
105
106 #[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 #[inline]
150 pub fn from_name(name: HeaderName) -> HeaderValue {
151 name.into()
152 }
153
154 #[inline]
179 pub fn from_bytes(src: &[u8]) -> Result<HeaderValue, InvalidHeaderValue> {
180 HeaderValue::try_from_generic(src, Bytes::copy_from_slice)
181 }
182
183 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 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 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 #[inline]
292 pub fn len(&self) -> usize {
293 self.as_ref().len()
294 }
295
296 #[inline]
309 pub fn is_empty(&self) -> bool {
310 self.len() == 0
311 }
312
313 #[inline]
323 pub fn as_bytes(&self) -> &[u8] {
324 self.as_ref()
325 }
326
327 #[inline]
342 pub fn set_sensitive(&mut self, val: bool) {
343 self.is_sensitive = val;
344 }
345
346 #[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 = BytesMut::with_capacity($max_len);
428 let _ = buf.write_str(::itoa::Buffer::new().format(num));
429 HeaderValue {
430 inner: buf.freeze(),
431 is_sensitive: false,
432 }
433 }
434 }
435
436 #[test]
437 fn $name() {
438 let n: $t = 55;
439 let val = HeaderValue::from(n);
440 assert_eq!(val, &n.to_string());
441
442 let n = ::std::$t::MAX;
443 let val = HeaderValue::from(n);
444 assert_eq!(val, &n.to_string());
445 }
446 )*};
447}
448
449from_integers! {
450 from_u16: u16 => 5,
454 from_i16: i16 => 6,
455 from_u32: u32 => 10,
456 from_i32: i32 => 11,
457 from_u64: u64 => 20,
458 from_i64: i64 => 20
459}
460
461#[cfg(target_pointer_width = "16")]
462from_integers! {
463 from_usize: usize => 5,
464 from_isize: isize => 6
465}
466
467#[cfg(target_pointer_width = "32")]
468from_integers! {
469 from_usize: usize => 10,
470 from_isize: isize => 11
471}
472
473#[cfg(target_pointer_width = "64")]
474from_integers! {
475 from_usize: usize => 20,
476 from_isize: isize => 20
477}
478
479#[cfg(test)]
480mod from_header_name_tests {
481 use super::*;
482 use crate::header::map::HeaderMap;
483 use crate::header::name;
484
485 #[test]
486 fn it_can_insert_header_name_as_header_value() {
487 let mut map = HeaderMap::new();
488 map.insert(name::UPGRADE, name::SEC_WEBSOCKET_PROTOCOL.into());
489 map.insert(
490 name::ACCEPT,
491 name::HeaderName::from_bytes(b"hello-world").unwrap().into(),
492 );
493
494 assert_eq!(
495 map.get(name::UPGRADE).unwrap(),
496 HeaderValue::from_bytes(b"sec-websocket-protocol").unwrap()
497 );
498
499 assert_eq!(
500 map.get(name::ACCEPT).unwrap(),
501 HeaderValue::from_bytes(b"hello-world").unwrap()
502 );
503 }
504}
505
506impl FromStr for HeaderValue {
507 type Err = InvalidHeaderValue;
508
509 #[inline]
510 fn from_str(s: &str) -> Result<HeaderValue, Self::Err> {
511 HeaderValue::from_str(s)
512 }
513}
514
515impl<'a> From<&'a HeaderValue> for HeaderValue {
516 #[inline]
517 fn from(t: &'a HeaderValue) -> Self {
518 t.clone()
519 }
520}
521
522impl<'a> TryFrom<&'a str> for HeaderValue {
523 type Error = InvalidHeaderValue;
524
525 #[inline]
526 fn try_from(t: &'a str) -> Result<Self, Self::Error> {
527 t.parse()
528 }
529}
530
531impl<'a> TryFrom<&'a String> for HeaderValue {
532 type Error = InvalidHeaderValue;
533 #[inline]
534 fn try_from(s: &'a String) -> Result<Self, Self::Error> {
535 Self::from_bytes(s.as_bytes())
536 }
537}
538
539impl<'a> TryFrom<&'a [u8]> for HeaderValue {
540 type Error = InvalidHeaderValue;
541
542 #[inline]
543 fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
544 HeaderValue::from_bytes(t)
545 }
546}
547
548impl TryFrom<String> for HeaderValue {
549 type Error = InvalidHeaderValue;
550
551 #[inline]
552 fn try_from(t: String) -> Result<Self, Self::Error> {
553 HeaderValue::from_shared(t.into())
554 }
555}
556
557impl TryFrom<Vec<u8>> for HeaderValue {
558 type Error = InvalidHeaderValue;
559
560 #[inline]
561 fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
562 HeaderValue::from_shared(vec.into())
563 }
564}
565
566#[cfg(test)]
567mod try_from_header_name_tests {
568 use super::*;
569 use crate::header::name;
570
571 #[test]
572 fn it_converts_using_try_from() {
573 assert_eq!(
574 HeaderValue::try_from(name::UPGRADE).unwrap(),
575 HeaderValue::from_bytes(b"upgrade").unwrap()
576 );
577 }
578}
579
580const fn is_visible_ascii(b: u8) -> bool {
581 b >= 32 && b < 127 || b == b'\t'
582}
583
584#[inline]
585fn is_valid(b: u8) -> bool {
586 b >= 32 && b != 127 || b == b'\t'
587}
588
589impl fmt::Debug for InvalidHeaderValue {
590 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
591 f.debug_struct("InvalidHeaderValue")
592 .finish()
594 }
595}
596
597impl fmt::Display for InvalidHeaderValue {
598 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
599 f.write_str("failed to parse header value")
600 }
601}
602
603impl Error for InvalidHeaderValue {}
604
605impl fmt::Display for ToStrError {
606 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
607 f.write_str("failed to convert header to a str")
608 }
609}
610
611impl Error for ToStrError {}
612
613impl Hash for HeaderValue {
616 fn hash<H: Hasher>(&self, state: &mut H) {
617 self.inner.hash(state);
618 }
619}
620
621impl PartialEq for HeaderValue {
622 #[inline]
623 fn eq(&self, other: &HeaderValue) -> bool {
624 self.inner == other.inner
625 }
626}
627
628impl Eq for HeaderValue {}
629
630impl PartialOrd for HeaderValue {
631 #[inline]
632 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
633 Some(self.cmp(other))
634 }
635}
636
637impl Ord for HeaderValue {
638 #[inline]
639 fn cmp(&self, other: &Self) -> cmp::Ordering {
640 self.inner.cmp(&other.inner)
641 }
642}
643
644impl PartialEq<str> for HeaderValue {
645 #[inline]
646 fn eq(&self, other: &str) -> bool {
647 self.inner == other.as_bytes()
648 }
649}
650
651impl PartialEq<[u8]> for HeaderValue {
652 #[inline]
653 fn eq(&self, other: &[u8]) -> bool {
654 self.inner == other
655 }
656}
657
658impl PartialOrd<str> for HeaderValue {
659 #[inline]
660 fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
661 (*self.inner).partial_cmp(other.as_bytes())
662 }
663}
664
665impl PartialOrd<[u8]> for HeaderValue {
666 #[inline]
667 fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
668 (*self.inner).partial_cmp(other)
669 }
670}
671
672impl PartialEq<HeaderValue> for str {
673 #[inline]
674 fn eq(&self, other: &HeaderValue) -> bool {
675 *other == *self
676 }
677}
678
679impl PartialEq<HeaderValue> for [u8] {
680 #[inline]
681 fn eq(&self, other: &HeaderValue) -> bool {
682 *other == *self
683 }
684}
685
686impl PartialOrd<HeaderValue> for str {
687 #[inline]
688 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
689 self.as_bytes().partial_cmp(other.as_bytes())
690 }
691}
692
693impl PartialOrd<HeaderValue> for [u8] {
694 #[inline]
695 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
696 self.partial_cmp(other.as_bytes())
697 }
698}
699
700impl PartialEq<String> for HeaderValue {
701 #[inline]
702 fn eq(&self, other: &String) -> bool {
703 *self == other[..]
704 }
705}
706
707impl PartialOrd<String> for HeaderValue {
708 #[inline]
709 fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
710 self.inner.partial_cmp(other.as_bytes())
711 }
712}
713
714impl PartialEq<HeaderValue> for String {
715 #[inline]
716 fn eq(&self, other: &HeaderValue) -> bool {
717 *other == *self
718 }
719}
720
721impl PartialOrd<HeaderValue> for String {
722 #[inline]
723 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
724 self.as_bytes().partial_cmp(other.as_bytes())
725 }
726}
727
728impl<'a> PartialEq<HeaderValue> for &'a HeaderValue {
729 #[inline]
730 fn eq(&self, other: &HeaderValue) -> bool {
731 **self == *other
732 }
733}
734
735impl<'a> PartialOrd<HeaderValue> for &'a HeaderValue {
736 #[inline]
737 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
738 (**self).partial_cmp(other)
739 }
740}
741
742impl<'a, T: ?Sized> PartialEq<&'a T> for HeaderValue
743where
744 HeaderValue: PartialEq<T>,
745{
746 #[inline]
747 fn eq(&self, other: &&'a T) -> bool {
748 *self == **other
749 }
750}
751
752impl<'a, T: ?Sized> PartialOrd<&'a T> for HeaderValue
753where
754 HeaderValue: PartialOrd<T>,
755{
756 #[inline]
757 fn partial_cmp(&self, other: &&'a T) -> Option<cmp::Ordering> {
758 self.partial_cmp(*other)
759 }
760}
761
762impl<'a> PartialEq<HeaderValue> for &'a str {
763 #[inline]
764 fn eq(&self, other: &HeaderValue) -> bool {
765 *other == *self
766 }
767}
768
769impl<'a> PartialOrd<HeaderValue> for &'a str {
770 #[inline]
771 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
772 self.as_bytes().partial_cmp(other.as_bytes())
773 }
774}
775
776#[test]
777fn test_try_from() {
778 HeaderValue::try_from(vec![127]).unwrap_err();
779}
780
781#[test]
782fn test_debug() {
783 let cases = &[
784 ("hello", "\"hello\""),
785 ("hello \"world\"", "\"hello \\\"world\\\"\""),
786 ("\u{7FFF}hello", "\"\\xe7\\xbf\\xbfhello\""),
787 ];
788
789 for &(value, expected) in cases {
790 let val = HeaderValue::from_bytes(value.as_bytes()).unwrap();
791 let actual = format!("{:?}", val);
792 assert_eq!(expected, actual);
793 }
794
795 let mut sensitive = HeaderValue::from_static("password");
796 sensitive.set_sensitive(true);
797 assert_eq!("Sensitive", format!("{:?}", sensitive));
798}