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}