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, mem, 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 = if mem::size_of::<BytesMut>() - 1 < $max_len {
428 if num as u64 > 999_999_999_999_999_999 {
439 BytesMut::with_capacity($max_len)
440 } else {
441 BytesMut::new()
443 }
444 } else {
445 BytesMut::new()
447 };
448 let _ = buf.write_str(::itoa::Buffer::new().format(num));
449 HeaderValue {
450 inner: buf.freeze(),
451 is_sensitive: false,
452 }
453 }
454 }
455
456 #[test]
457 fn $name() {
458 let n: $t = 55;
459 let val = HeaderValue::from(n);
460 assert_eq!(val, &n.to_string());
461
462 let n = ::std::$t::MAX;
463 let val = HeaderValue::from(n);
464 assert_eq!(val, &n.to_string());
465 }
466 )*};
467}
468
469from_integers! {
470 from_u16: u16 => 5,
474 from_i16: i16 => 6,
475 from_u32: u32 => 10,
476 from_i32: i32 => 11,
477 from_u64: u64 => 20,
478 from_i64: i64 => 20
479}
480
481#[cfg(target_pointer_width = "16")]
482from_integers! {
483 from_usize: usize => 5,
484 from_isize: isize => 6
485}
486
487#[cfg(target_pointer_width = "32")]
488from_integers! {
489 from_usize: usize => 10,
490 from_isize: isize => 11
491}
492
493#[cfg(target_pointer_width = "64")]
494from_integers! {
495 from_usize: usize => 20,
496 from_isize: isize => 20
497}
498
499#[cfg(test)]
500mod from_header_name_tests {
501 use super::*;
502 use crate::header::map::HeaderMap;
503 use crate::header::name;
504
505 #[test]
506 fn it_can_insert_header_name_as_header_value() {
507 let mut map = HeaderMap::new();
508 map.insert(name::UPGRADE, name::SEC_WEBSOCKET_PROTOCOL.into());
509 map.insert(
510 name::ACCEPT,
511 name::HeaderName::from_bytes(b"hello-world").unwrap().into(),
512 );
513
514 assert_eq!(
515 map.get(name::UPGRADE).unwrap(),
516 HeaderValue::from_bytes(b"sec-websocket-protocol").unwrap()
517 );
518
519 assert_eq!(
520 map.get(name::ACCEPT).unwrap(),
521 HeaderValue::from_bytes(b"hello-world").unwrap()
522 );
523 }
524}
525
526impl FromStr for HeaderValue {
527 type Err = InvalidHeaderValue;
528
529 #[inline]
530 fn from_str(s: &str) -> Result<HeaderValue, Self::Err> {
531 HeaderValue::from_str(s)
532 }
533}
534
535impl<'a> From<&'a HeaderValue> for HeaderValue {
536 #[inline]
537 fn from(t: &'a HeaderValue) -> Self {
538 t.clone()
539 }
540}
541
542impl<'a> TryFrom<&'a str> for HeaderValue {
543 type Error = InvalidHeaderValue;
544
545 #[inline]
546 fn try_from(t: &'a str) -> Result<Self, Self::Error> {
547 t.parse()
548 }
549}
550
551impl<'a> TryFrom<&'a String> for HeaderValue {
552 type Error = InvalidHeaderValue;
553 #[inline]
554 fn try_from(s: &'a String) -> Result<Self, Self::Error> {
555 Self::from_bytes(s.as_bytes())
556 }
557}
558
559impl<'a> TryFrom<&'a [u8]> for HeaderValue {
560 type Error = InvalidHeaderValue;
561
562 #[inline]
563 fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
564 HeaderValue::from_bytes(t)
565 }
566}
567
568impl TryFrom<String> for HeaderValue {
569 type Error = InvalidHeaderValue;
570
571 #[inline]
572 fn try_from(t: String) -> Result<Self, Self::Error> {
573 HeaderValue::from_shared(t.into())
574 }
575}
576
577impl TryFrom<Vec<u8>> for HeaderValue {
578 type Error = InvalidHeaderValue;
579
580 #[inline]
581 fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
582 HeaderValue::from_shared(vec.into())
583 }
584}
585
586#[cfg(test)]
587mod try_from_header_name_tests {
588 use super::*;
589 use crate::header::name;
590
591 #[test]
592 fn it_converts_using_try_from() {
593 assert_eq!(
594 HeaderValue::try_from(name::UPGRADE).unwrap(),
595 HeaderValue::from_bytes(b"upgrade").unwrap()
596 );
597 }
598}
599
600const fn is_visible_ascii(b: u8) -> bool {
601 b >= 32 && b < 127 || b == b'\t'
602}
603
604#[inline]
605fn is_valid(b: u8) -> bool {
606 b >= 32 && b != 127 || b == b'\t'
607}
608
609impl fmt::Debug for InvalidHeaderValue {
610 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
611 f.debug_struct("InvalidHeaderValue")
612 .finish()
614 }
615}
616
617impl fmt::Display for InvalidHeaderValue {
618 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
619 f.write_str("failed to parse header value")
620 }
621}
622
623impl Error for InvalidHeaderValue {}
624
625impl fmt::Display for ToStrError {
626 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
627 f.write_str("failed to convert header to a str")
628 }
629}
630
631impl Error for ToStrError {}
632
633impl Hash for HeaderValue {
636 fn hash<H: Hasher>(&self, state: &mut H) {
637 self.inner.hash(state);
638 }
639}
640
641impl PartialEq for HeaderValue {
642 #[inline]
643 fn eq(&self, other: &HeaderValue) -> bool {
644 self.inner == other.inner
645 }
646}
647
648impl Eq for HeaderValue {}
649
650impl PartialOrd for HeaderValue {
651 #[inline]
652 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
653 Some(self.cmp(other))
654 }
655}
656
657impl Ord for HeaderValue {
658 #[inline]
659 fn cmp(&self, other: &Self) -> cmp::Ordering {
660 self.inner.cmp(&other.inner)
661 }
662}
663
664impl PartialEq<str> for HeaderValue {
665 #[inline]
666 fn eq(&self, other: &str) -> bool {
667 self.inner == other.as_bytes()
668 }
669}
670
671impl PartialEq<[u8]> for HeaderValue {
672 #[inline]
673 fn eq(&self, other: &[u8]) -> bool {
674 self.inner == other
675 }
676}
677
678impl PartialOrd<str> for HeaderValue {
679 #[inline]
680 fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
681 (*self.inner).partial_cmp(other.as_bytes())
682 }
683}
684
685impl PartialOrd<[u8]> for HeaderValue {
686 #[inline]
687 fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
688 (*self.inner).partial_cmp(other)
689 }
690}
691
692impl PartialEq<HeaderValue> for str {
693 #[inline]
694 fn eq(&self, other: &HeaderValue) -> bool {
695 *other == *self
696 }
697}
698
699impl PartialEq<HeaderValue> for [u8] {
700 #[inline]
701 fn eq(&self, other: &HeaderValue) -> bool {
702 *other == *self
703 }
704}
705
706impl PartialOrd<HeaderValue> for str {
707 #[inline]
708 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
709 self.as_bytes().partial_cmp(other.as_bytes())
710 }
711}
712
713impl PartialOrd<HeaderValue> for [u8] {
714 #[inline]
715 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
716 self.partial_cmp(other.as_bytes())
717 }
718}
719
720impl PartialEq<String> for HeaderValue {
721 #[inline]
722 fn eq(&self, other: &String) -> bool {
723 *self == other[..]
724 }
725}
726
727impl PartialOrd<String> for HeaderValue {
728 #[inline]
729 fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
730 self.inner.partial_cmp(other.as_bytes())
731 }
732}
733
734impl PartialEq<HeaderValue> for String {
735 #[inline]
736 fn eq(&self, other: &HeaderValue) -> bool {
737 *other == *self
738 }
739}
740
741impl PartialOrd<HeaderValue> for String {
742 #[inline]
743 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
744 self.as_bytes().partial_cmp(other.as_bytes())
745 }
746}
747
748impl<'a> PartialEq<HeaderValue> for &'a HeaderValue {
749 #[inline]
750 fn eq(&self, other: &HeaderValue) -> bool {
751 **self == *other
752 }
753}
754
755impl<'a> PartialOrd<HeaderValue> for &'a HeaderValue {
756 #[inline]
757 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
758 (**self).partial_cmp(other)
759 }
760}
761
762impl<'a, T: ?Sized> PartialEq<&'a T> for HeaderValue
763where
764 HeaderValue: PartialEq<T>,
765{
766 #[inline]
767 fn eq(&self, other: &&'a T) -> bool {
768 *self == **other
769 }
770}
771
772impl<'a, T: ?Sized> PartialOrd<&'a T> for HeaderValue
773where
774 HeaderValue: PartialOrd<T>,
775{
776 #[inline]
777 fn partial_cmp(&self, other: &&'a T) -> Option<cmp::Ordering> {
778 self.partial_cmp(*other)
779 }
780}
781
782impl<'a> PartialEq<HeaderValue> for &'a str {
783 #[inline]
784 fn eq(&self, other: &HeaderValue) -> bool {
785 *other == *self
786 }
787}
788
789impl<'a> PartialOrd<HeaderValue> for &'a str {
790 #[inline]
791 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
792 self.as_bytes().partial_cmp(other.as_bytes())
793 }
794}
795
796#[test]
797fn test_try_from() {
798 HeaderValue::try_from(vec![127]).unwrap_err();
799}
800
801#[test]
802fn test_debug() {
803 let cases = &[
804 ("hello", "\"hello\""),
805 ("hello \"world\"", "\"hello \\\"world\\\"\""),
806 ("\u{7FFF}hello", "\"\\xe7\\xbf\\xbfhello\""),
807 ];
808
809 for &(value, expected) in cases {
810 let val = HeaderValue::from_bytes(value.as_bytes()).unwrap();
811 let actual = format!("{:?}", val);
812 assert_eq!(expected, actual);
813 }
814
815 let mut sensitive = HeaderValue::from_static("password");
816 sensitive.set_sensitive(true);
817 assert_eq!("Sensitive", format!("{:?}", sensitive));
818}