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)]
26pub struct HeaderValue {
27 inner: Bytes,
28 is_sensitive: bool,
29}
30
31pub struct InvalidHeaderValue {
34 _priv: (),
35}
36
37#[derive(Debug)]
42pub struct ToStrError {
43 _priv: (),
44}
45
46impl HeaderValue {
47 #[inline]
66 pub const fn from_static(src: &'static str) -> HeaderValue {
67 let bytes = src.as_bytes();
68 let mut i = 0;
69 while i < bytes.len() {
70 if !is_valid_ascii(bytes[i]) {
71 panic!("HeaderValue::from_static with invalid bytes")
72 }
73 i += 1;
74 }
75
76 HeaderValue {
77 inner: Bytes::from_static(bytes),
78 is_sensitive: false,
79 }
80 }
81
82 #[inline]
109 #[allow(clippy::should_implement_trait)]
110 pub fn from_str(src: &str) -> Result<HeaderValue, InvalidHeaderValue> {
111 HeaderValue::try_from_generic(
112 src,
113 |s| Bytes::copy_from_slice(s.as_bytes()),
114 is_valid_ascii,
115 )
116 }
117
118 #[inline]
131 pub fn from_name(name: HeaderName) -> HeaderValue {
132 name.into()
133 }
134
135 #[inline]
160 pub fn from_bytes(src: &[u8]) -> Result<HeaderValue, InvalidHeaderValue> {
161 HeaderValue::try_from_generic(src, Bytes::copy_from_slice, is_valid_ascii_or_opaque_byte)
162 }
163
164 pub fn from_maybe_shared<T>(src: T) -> Result<HeaderValue, InvalidHeaderValue>
169 where
170 T: AsRef<[u8]> + 'static,
171 {
172 if_downcast_into!(T, Bytes, src, {
173 return HeaderValue::from_shared(src);
174 });
175
176 HeaderValue::from_bytes(src.as_ref())
177 }
178
179 pub unsafe fn from_maybe_shared_unchecked<T>(src: T) -> HeaderValue
191 where
192 T: AsRef<[u8]> + 'static,
193 {
194 if cfg!(debug_assertions) {
195 match HeaderValue::from_maybe_shared(src) {
196 Ok(val) => val,
197 Err(_err) => {
198 panic!("HeaderValue::from_maybe_shared_unchecked() with invalid bytes");
199 }
200 }
201 } else {
202 if_downcast_into!(T, Bytes, src, {
203 return HeaderValue {
204 inner: src,
205 is_sensitive: false,
206 };
207 });
208
209 let src = Bytes::copy_from_slice(src.as_ref());
210 HeaderValue {
211 inner: src,
212 is_sensitive: false,
213 }
214 }
215 }
216
217 fn from_shared(src: Bytes) -> Result<HeaderValue, InvalidHeaderValue> {
218 HeaderValue::try_from_generic(src, std::convert::identity, is_valid_ascii_or_opaque_byte)
219 }
220
221 fn try_from_generic<T: AsRef<[u8]>, F: FnOnce(T) -> Bytes, V: Fn(u8) -> bool>(
222 src: T,
223 into: F,
224 is_valid: V,
225 ) -> Result<HeaderValue, InvalidHeaderValue> {
226 let mut bad = false;
228 for &b in src.as_ref() {
229 bad |= !is_valid(b);
230 }
231 if bad {
232 return Err(InvalidHeaderValue { _priv: () });
233 }
234 Ok(HeaderValue {
235 inner: into(src),
236 is_sensitive: false,
237 })
238 }
239
240 pub fn to_str(&self) -> Result<&str, ToStrError> {
254 let bytes = self.as_ref();
255
256 let mut bad = false;
258 for &b in bytes {
259 bad |= !is_valid_ascii(b);
260 }
261 if bad {
262 return Err(ToStrError { _priv: () });
263 }
264
265 unsafe { Ok(str::from_utf8_unchecked(bytes)) }
266 }
267
268 #[inline]
280 pub fn len(&self) -> usize {
281 self.as_ref().len()
282 }
283
284 #[inline]
297 pub fn is_empty(&self) -> bool {
298 self.len() == 0
299 }
300
301 #[inline]
311 pub fn as_bytes(&self) -> &[u8] {
312 self.as_ref()
313 }
314
315 #[inline]
330 pub fn set_sensitive(&mut self, val: bool) {
331 self.is_sensitive = val;
332 }
333
334 #[inline]
361 pub fn is_sensitive(&self) -> bool {
362 self.is_sensitive
363 }
364}
365
366impl AsRef<[u8]> for HeaderValue {
367 #[inline]
368 fn as_ref(&self) -> &[u8] {
369 self.inner.as_ref()
370 }
371}
372
373impl fmt::Debug for HeaderValue {
374 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
375 if self.is_sensitive {
376 f.write_str("Sensitive")
377 } else {
378 f.write_str("\"")?;
379 let mut from = 0;
380 let bytes = self.as_bytes();
381 for (i, &b) in bytes.iter().enumerate() {
382 if !is_valid_ascii(b) || b == b'"' {
383 if from != i {
384 f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..i]) })?;
385 }
386 if b == b'"' {
387 f.write_str("\\\"")?;
388 } else {
389 write!(f, "\\x{:x}", b)?;
390 }
391 from = i + 1;
392 }
393 }
394
395 f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..]) })?;
396 f.write_str("\"")
397 }
398 }
399}
400
401impl From<HeaderName> for HeaderValue {
402 #[inline]
403 fn from(h: HeaderName) -> HeaderValue {
404 HeaderValue {
405 inner: h.into_bytes(),
406 is_sensitive: false,
407 }
408 }
409}
410
411macro_rules! from_integers {
412 ($($name:ident: $t:ident => $max_len:expr),*) => {$(
413 impl From<$t> for HeaderValue {
414 fn from(num: $t) -> HeaderValue {
415 let mut buf = BytesMut::with_capacity($max_len);
416 let _ = buf.write_str(::itoa::Buffer::new().format(num));
417 HeaderValue {
418 inner: buf.freeze(),
419 is_sensitive: false,
420 }
421 }
422 }
423
424 #[test]
425 fn $name() {
426 let n: $t = 55;
427 let val = HeaderValue::from(n);
428 assert_eq!(val, &n.to_string());
429
430 let n = <$t>::MAX;
431 let val = HeaderValue::from(n);
432 assert_eq!(val, &n.to_string());
433 }
434 )*};
435}
436
437from_integers! {
438 from_u16: u16 => 5,
442 from_i16: i16 => 6,
443 from_u32: u32 => 10,
444 from_i32: i32 => 11,
445 from_u64: u64 => 20,
446 from_i64: i64 => 20
447}
448
449#[cfg(target_pointer_width = "16")]
450from_integers! {
451 from_usize: usize => 5,
452 from_isize: isize => 6
453}
454
455#[cfg(target_pointer_width = "32")]
456from_integers! {
457 from_usize: usize => 10,
458 from_isize: isize => 11
459}
460
461#[cfg(target_pointer_width = "64")]
462from_integers! {
463 from_usize: usize => 20,
464 from_isize: isize => 20
465}
466
467#[cfg(test)]
468mod from_header_name_tests {
469 use super::*;
470 use crate::header::map::HeaderMap;
471 use crate::header::name;
472
473 #[test]
474 fn it_can_insert_header_name_as_header_value() {
475 let mut map = HeaderMap::new();
476 map.insert(name::UPGRADE, name::SEC_WEBSOCKET_PROTOCOL.into());
477 map.insert(
478 name::ACCEPT,
479 name::HeaderName::from_bytes(b"hello-world").unwrap().into(),
480 );
481
482 assert_eq!(
483 map.get(name::UPGRADE).unwrap(),
484 HeaderValue::from_bytes(b"sec-websocket-protocol").unwrap()
485 );
486
487 assert_eq!(
488 map.get(name::ACCEPT).unwrap(),
489 HeaderValue::from_bytes(b"hello-world").unwrap()
490 );
491 }
492}
493
494impl FromStr for HeaderValue {
495 type Err = InvalidHeaderValue;
496
497 #[inline]
498 fn from_str(s: &str) -> Result<HeaderValue, Self::Err> {
499 HeaderValue::from_str(s)
500 }
501}
502
503impl From<&HeaderValue> for HeaderValue {
504 #[inline]
505 fn from(t: &HeaderValue) -> Self {
506 t.clone()
507 }
508}
509
510impl TryFrom<&str> for HeaderValue {
511 type Error = InvalidHeaderValue;
512
513 #[inline]
514 fn try_from(t: &str) -> Result<Self, Self::Error> {
515 t.parse()
516 }
517}
518
519impl TryFrom<&String> for HeaderValue {
520 type Error = InvalidHeaderValue;
521 #[inline]
522 fn try_from(s: &String) -> Result<Self, Self::Error> {
523 Self::from_str(s)
524 }
525}
526
527impl TryFrom<&[u8]> for HeaderValue {
528 type Error = InvalidHeaderValue;
529
530 #[inline]
531 fn try_from(t: &[u8]) -> Result<Self, Self::Error> {
532 HeaderValue::from_bytes(t)
533 }
534}
535
536impl TryFrom<String> for HeaderValue {
537 type Error = InvalidHeaderValue;
538
539 #[inline]
540 fn try_from(t: String) -> Result<Self, Self::Error> {
541 HeaderValue::try_from_generic(t, |s| s.into(), is_valid_ascii)
542 }
543}
544
545impl TryFrom<Vec<u8>> for HeaderValue {
546 type Error = InvalidHeaderValue;
547
548 #[inline]
549 fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
550 HeaderValue::from_shared(vec.into())
551 }
552}
553
554#[cfg(test)]
555mod try_from_header_name_tests {
556 use super::*;
557 use crate::header::name;
558
559 #[test]
560 fn it_converts_using_try_from() {
561 assert_eq!(
562 HeaderValue::try_from(name::UPGRADE).unwrap(),
563 HeaderValue::from_bytes(b"upgrade").unwrap()
564 );
565 }
566}
567
568const fn is_valid_ascii(b: u8) -> bool {
569 b >= 32 && b < 127 || b == b'\t'
570}
571
572#[inline]
576fn is_valid_ascii_or_opaque_byte(b: u8) -> bool {
577 b >= 32 && b != 127 || b == b'\t'
578}
579
580impl fmt::Debug for InvalidHeaderValue {
581 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
582 f.debug_struct("InvalidHeaderValue")
583 .finish()
585 }
586}
587
588impl fmt::Display for InvalidHeaderValue {
589 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
590 f.write_str("failed to parse header value")
591 }
592}
593
594impl Error for InvalidHeaderValue {}
595
596impl fmt::Display for ToStrError {
597 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
598 f.write_str("failed to convert header to a str")
599 }
600}
601
602impl Error for ToStrError {}
603
604impl Hash for HeaderValue {
607 fn hash<H: Hasher>(&self, state: &mut H) {
608 self.inner.hash(state);
609 }
610}
611
612impl PartialEq for HeaderValue {
613 #[inline]
614 fn eq(&self, other: &HeaderValue) -> bool {
615 self.inner == other.inner
616 }
617}
618
619impl Eq for HeaderValue {}
620
621impl PartialOrd for HeaderValue {
622 #[inline]
623 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
624 Some(self.cmp(other))
625 }
626}
627
628impl Ord for HeaderValue {
629 #[inline]
630 fn cmp(&self, other: &Self) -> cmp::Ordering {
631 self.inner.cmp(&other.inner)
632 }
633}
634
635impl PartialEq<str> for HeaderValue {
636 #[inline]
637 fn eq(&self, other: &str) -> bool {
638 self.inner == other.as_bytes()
639 }
640}
641
642impl PartialEq<[u8]> for HeaderValue {
643 #[inline]
644 fn eq(&self, other: &[u8]) -> bool {
645 self.inner == other
646 }
647}
648
649impl PartialOrd<str> for HeaderValue {
650 #[inline]
651 fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
652 (*self.inner).partial_cmp(other.as_bytes())
653 }
654}
655
656impl PartialOrd<[u8]> for HeaderValue {
657 #[inline]
658 fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
659 (*self.inner).partial_cmp(other)
660 }
661}
662
663impl PartialEq<HeaderValue> for str {
664 #[inline]
665 fn eq(&self, other: &HeaderValue) -> bool {
666 *other == *self
667 }
668}
669
670impl PartialEq<HeaderValue> for [u8] {
671 #[inline]
672 fn eq(&self, other: &HeaderValue) -> bool {
673 *other == *self
674 }
675}
676
677impl PartialOrd<HeaderValue> for str {
678 #[inline]
679 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
680 self.as_bytes().partial_cmp(other.as_bytes())
681 }
682}
683
684impl PartialOrd<HeaderValue> for [u8] {
685 #[inline]
686 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
687 self.partial_cmp(other.as_bytes())
688 }
689}
690
691impl PartialEq<String> for HeaderValue {
692 #[inline]
693 fn eq(&self, other: &String) -> bool {
694 *self == other[..]
695 }
696}
697
698impl PartialOrd<String> for HeaderValue {
699 #[inline]
700 fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
701 self.inner.partial_cmp(other.as_bytes())
702 }
703}
704
705impl PartialEq<HeaderValue> for String {
706 #[inline]
707 fn eq(&self, other: &HeaderValue) -> bool {
708 *other == *self
709 }
710}
711
712impl PartialOrd<HeaderValue> for String {
713 #[inline]
714 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
715 self.as_bytes().partial_cmp(other.as_bytes())
716 }
717}
718
719impl PartialEq<HeaderValue> for &HeaderValue {
720 #[inline]
721 fn eq(&self, other: &HeaderValue) -> bool {
722 **self == *other
723 }
724}
725
726impl PartialOrd<HeaderValue> for &HeaderValue {
727 #[inline]
728 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
729 (**self).partial_cmp(other)
730 }
731}
732
733impl<T: ?Sized> PartialEq<&T> for HeaderValue
734where
735 HeaderValue: PartialEq<T>,
736{
737 #[inline]
738 fn eq(&self, other: &&T) -> bool {
739 *self == **other
740 }
741}
742
743impl<T: ?Sized> PartialOrd<&T> for HeaderValue
744where
745 HeaderValue: PartialOrd<T>,
746{
747 #[inline]
748 fn partial_cmp(&self, other: &&T) -> Option<cmp::Ordering> {
749 self.partial_cmp(*other)
750 }
751}
752
753impl serde::Serialize for HeaderValue {
754 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
755 where
756 S: serde::Serializer,
757 {
758 match self.to_str() {
759 Ok(value) if serializer.is_human_readable() => serializer.serialize_str(value),
760 _ => serializer.serialize_bytes(self.as_bytes()),
761 }
762 }
763}
764
765impl<'de> serde::Deserialize<'de> for HeaderValue {
770 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
771 where
772 D: serde::Deserializer<'de>,
773 {
774 struct HeaderValueVisitor;
775
776 impl<'de> serde::de::Visitor<'de> for HeaderValueVisitor {
777 type Value = HeaderValue;
778
779 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
780 formatter.write_str("a valid HTTP header value as text or bytes")
781 }
782
783 fn visit_borrowed_str<E>(self, value: &str) -> Result<Self::Value, E>
784 where
785 E: serde::de::Error,
786 {
787 HeaderValue::from_str(value).map_err(E::custom)
788 }
789
790 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
791 where
792 E: serde::de::Error,
793 {
794 self.visit_borrowed_str(value)
795 }
796
797 fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
798 where
799 E: serde::de::Error,
800 {
801 HeaderValue::try_from(value).map_err(E::custom)
802 }
803
804 fn visit_borrowed_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
805 where
806 E: serde::de::Error,
807 {
808 HeaderValue::from_bytes(value).map_err(E::custom)
809 }
810
811 fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
812 where
813 E: serde::de::Error,
814 {
815 self.visit_borrowed_bytes(value)
816 }
817
818 fn visit_byte_buf<E>(self, value: Vec<u8>) -> Result<Self::Value, E>
819 where
820 E: serde::de::Error,
821 {
822 HeaderValue::from_maybe_shared(value).map_err(E::custom)
823 }
824
825 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
826 where
827 A: serde::de::SeqAccess<'de>,
828 {
829 let mut bytes = Vec::new();
830 while let Some(byte) = seq.next_element()? {
831 bytes.push(byte);
832 }
833 self.visit_byte_buf(bytes)
834 }
835 }
836
837 if deserializer.is_human_readable() {
838 deserializer.deserialize_any(HeaderValueVisitor)
839 } else {
840 deserializer.deserialize_bytes(HeaderValueVisitor)
841 }
842 }
843}
844
845impl PartialEq<HeaderValue> for &str {
846 #[inline]
847 fn eq(&self, other: &HeaderValue) -> bool {
848 *other == *self
849 }
850}
851
852impl PartialOrd<HeaderValue> for &str {
853 #[inline]
854 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
855 self.as_bytes().partial_cmp(other.as_bytes())
856 }
857}
858
859#[test]
860fn test_try_from() {
861 HeaderValue::try_from(vec![127]).unwrap_err();
862}
863
864#[test]
865fn test_string_constructors_reject_non_ascii() {
866 let value = String::from("hello \u{e9}");
867
868 assert!(HeaderValue::from_str(&value).is_err());
869 assert!(HeaderValue::try_from(value.as_str()).is_err());
870 assert!(HeaderValue::try_from(&value).is_err());
871 assert!(HeaderValue::try_from(value).is_err());
872}
873
874#[test]
875fn test_byte_constructors_allow_opaque_bytes_but_reject_del() {
876 assert!(HeaderValue::from_bytes(b"hello\xff").is_ok());
877 assert!(HeaderValue::try_from(&b"hello\xff"[..]).is_ok());
878 assert!(HeaderValue::try_from(b"hello\xff".to_vec()).is_ok());
879
880 assert!(HeaderValue::from_bytes(b"hello\x7f").is_err());
881}
882
883#[test]
884fn test_string_and_byte_constructors_allow_horizontal_tab() {
885 assert!(HeaderValue::from_str("hello\tworld").is_ok());
886 assert!(HeaderValue::from_bytes(b"hello\tworld").is_ok());
887}
888
889#[test]
890#[should_panic(expected = "HeaderValue::from_static with invalid bytes")]
891fn test_static_constructor_rejects_non_ascii() {
892 HeaderValue::from_static("hello \u{e9}");
893}
894
895#[test]
896fn test_debug() {
897 let cases = &[
898 ("hello", "\"hello\""),
899 ("hello \"world\"", "\"hello \\\"world\\\"\""),
900 ("\u{7FFF}hello", "\"\\xe7\\xbf\\xbfhello\""),
901 ];
902
903 for &(value, expected) in cases {
904 let val = HeaderValue::from_bytes(value.as_bytes()).unwrap();
905 let actual = format!("{:?}", val);
906 assert_eq!(expected, actual);
907 }
908
909 let mut sensitive = HeaderValue::from_static("password");
910 sensitive.set_sensitive(true);
911 assert_eq!("Sensitive", format!("{:?}", sensitive));
912}