http_with_url/header/
value.rs1use bytes::Bytes;
2
3use std::{cmp, fmt, str};
4use std::error::Error;
5use std::str::FromStr;
6
7use ::convert::HttpTryFrom;
8use header::name::HeaderName;
9
10#[derive(Clone, Hash)]
20pub struct HeaderValue {
21    inner: Bytes,
22    is_sensitive: bool,
23}
24
25#[derive(Debug)]
28pub struct InvalidHeaderValue {
29    _priv: (),
30}
31
32#[derive(Debug)]
35pub struct InvalidHeaderValueBytes(InvalidHeaderValue);
36
37#[derive(Debug)]
42pub struct ToStrError {
43    _priv: (),
44}
45
46impl HeaderValue {
47    #[inline]
66    pub fn from_static(src: &'static str) -> HeaderValue {
67        let bytes = src.as_bytes();
68        for &b in bytes {
69            if !is_visible_ascii(b) {
70                panic!("invalid header value");
71            }
72        }
73
74        HeaderValue {
75            inner: Bytes::from_static(bytes),
76            is_sensitive: false,
77        }
78    }
79
80    #[inline]
106    pub fn from_str(src: &str) -> Result<HeaderValue, InvalidHeaderValue> {
107        HeaderValue::try_from(src)
108    }
109
110    #[inline]
123    pub fn from_name(name: HeaderName) -> HeaderValue {
124        name.into()
125    }
126
127    #[inline]
152    pub fn from_bytes(src: &[u8]) -> Result<HeaderValue, InvalidHeaderValue> {
153        HeaderValue::try_from(src)
154    }
155
156    #[inline]
165    pub fn from_shared(src: Bytes) -> Result<HeaderValue, InvalidHeaderValueBytes> {
166        HeaderValue::try_from(src).map_err(InvalidHeaderValueBytes)
167    }
168
169    #[inline]
174    pub unsafe fn from_shared_unchecked(src: Bytes) -> HeaderValue {
175        HeaderValue {
176            inner: src,
177            is_sensitive: false,
178        }
179    }
180
181    fn try_from<T: AsRef<[u8]> + Into<Bytes>>(src: T) -> Result<HeaderValue, InvalidHeaderValue> {
182        for &b in src.as_ref() {
183            if !is_valid(b) {
184                return Err(InvalidHeaderValue {
185                    _priv: (),
186                });
187            }
188        }
189        Ok(HeaderValue {
190            inner: src.into(),
191            is_sensitive: false,
192        })
193    }
194
195    pub fn to_str(&self) -> Result<&str, ToStrError> {
209        let bytes = self.as_ref();
210
211        for &b in bytes {
212            if !is_visible_ascii(b) {
213                return Err(ToStrError { _priv: () });
214            }
215        }
216
217        unsafe { Ok(str::from_utf8_unchecked(bytes)) }
218    }
219
220    #[inline]
232    pub fn len(&self) -> usize {
233        self.as_ref().len()
234    }
235
236    #[inline]
249    pub fn is_empty(&self) -> bool {
250        self.len() == 0
251    }
252
253    #[inline]
263    pub fn as_bytes(&self) -> &[u8] {
264        self.as_ref()
265    }
266
267    #[inline]
282    pub fn set_sensitive(&mut self, val: bool) {
283        self.is_sensitive = val;
284    }
285
286    #[inline]
308    pub fn is_sensitive(&self) -> bool {
309        self.is_sensitive
310    }
311}
312
313impl AsRef<[u8]> for HeaderValue {
314    #[inline]
315    fn as_ref(&self) -> &[u8] {
316        self.inner.as_ref()
317    }
318}
319
320impl fmt::Debug for HeaderValue {
321    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
322        if self.is_sensitive {
323            f.write_str("Sensitive")
324        } else {
325            f.write_str("\"")?;
326            let mut from = 0;
327            let bytes = self.as_bytes();
328            for (i, &b) in bytes.iter().enumerate() {
329                if !is_visible_ascii(b) || b == b'"' {
330                    if from != i {
331                        f.write_str(unsafe {
332                            str::from_utf8_unchecked(&bytes[from..i])
333                        })?;
334                    }
335                    if b == b'"' {
336                        f.write_str("\\\"")?;
337                    } else {
338                        write!(f, "\\x{:x}", b)?;
339                    }
340                    from = i + 1;
341                }
342            }
343
344            f.write_str(unsafe {
345                str::from_utf8_unchecked(&bytes[from..])
346            })?;
347            f.write_str("\"")
348        }
349    }
350}
351
352impl From<HeaderName> for HeaderValue {
353    #[inline]
354    fn from(h: HeaderName) -> HeaderValue {
355        HeaderValue {
356            inner: h.into(),
357            is_sensitive: false,
358        }
359    }
360}
361
362#[cfg(test)]
363mod from_header_name_tests {
364    use super::*;
365    use header::map::HeaderMap;
366    use header::name;
367
368    #[test]
369    fn it_can_insert_header_name_as_header_value() {
370        let mut map = HeaderMap::new();
371        map.insert(name::UPGRADE, name::SEC_WEBSOCKET_PROTOCOL.into());
372        map.insert(name::ACCEPT, name::HeaderName::from_bytes(b"hello-world").unwrap().into());
373
374        assert_eq!(
375            map.get(name::UPGRADE).unwrap(),
376            HeaderValue::from_bytes(b"sec-websocket-protocol").unwrap()
377        );
378
379        assert_eq!(
380            map.get(name::ACCEPT).unwrap(),
381            HeaderValue::from_bytes(b"hello-world").unwrap()
382        );
383    }
384}
385
386impl FromStr for HeaderValue {
387    type Err = InvalidHeaderValue;
388
389    #[inline]
390    fn from_str(s: &str) -> Result<HeaderValue, Self::Err> {
391        HeaderValue::from_str(s)
392    }
393}
394
395impl From<HeaderValue> for Bytes {
396    #[inline]
397    fn from(value: HeaderValue) -> Bytes {
398        value.inner
399    }
400}
401
402impl<'a> HttpTryFrom<&'a str> for HeaderValue {
403    type Error = InvalidHeaderValue;
404
405    #[inline]
406    fn try_from(t: &'a str) -> Result<Self, Self::Error> {
407        t.parse()
408    }
409}
410
411impl<'a> HttpTryFrom<&'a [u8]> for HeaderValue {
412    type Error = InvalidHeaderValue;
413
414    #[inline]
415    fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
416        HeaderValue::from_bytes(t)
417    }
418}
419
420impl HttpTryFrom<Bytes> for HeaderValue {
421    type Error = InvalidHeaderValueBytes;
422
423    #[inline]
424    fn try_from(bytes: Bytes) -> Result<Self, Self::Error> {
425        HeaderValue::from_shared(bytes)
426    }
427}
428
429impl HttpTryFrom<HeaderName> for HeaderValue {
430    type Error = InvalidHeaderValue;
431
432    #[inline]
433    fn try_from(name: HeaderName) -> Result<Self, Self::Error> {
434        Ok(name.into())
436    }
437}
438
439#[cfg(test)]
440mod try_from_header_name_tests {
441    use super::*;
442    use header::name;
443
444    #[test]
445    fn it_converts_using_try_from() {
446        assert_eq!(
447            HeaderValue::try_from(name::UPGRADE).unwrap(),
448            HeaderValue::from_bytes(b"upgrade").unwrap()
449        );
450    }
451}
452
453fn is_visible_ascii(b: u8) -> bool {
454    b >= 32 && b < 127
455}
456
457#[inline]
458fn is_valid(b: u8) -> bool {
459    b >= 32 && b != 127
460}
461
462impl fmt::Display for InvalidHeaderValue {
463    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
464        self.description().fmt(f)
465    }
466}
467
468impl Error for InvalidHeaderValue {
469    fn description(&self) -> &str {
470        "failed to parse header value"
471    }
472}
473
474impl fmt::Display for InvalidHeaderValueBytes {
475    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
476        self.0.fmt(f)
477    }
478}
479
480impl Error for InvalidHeaderValueBytes {
481    fn description(&self) -> &str {
482        self.0.description()
483    }
484}
485
486impl fmt::Display for ToStrError {
487    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
488        self.description().fmt(f)
489    }
490}
491
492impl Error for ToStrError {
493    fn description(&self) -> &str {
494        "failed to convert header to a str"
495    }
496}
497
498impl PartialEq for HeaderValue {
501    #[inline]
502    fn eq(&self, other: &HeaderValue) -> bool {
503        self.inner == other.inner
504    }
505}
506
507impl Eq for HeaderValue {}
508
509impl PartialOrd for HeaderValue {
510    #[inline]
511    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
512        self.inner.partial_cmp(&other.inner)
513    }
514}
515
516impl Ord for HeaderValue {
517    #[inline]
518    fn cmp(&self, other: &Self) -> cmp::Ordering {
519        self.inner.cmp(&other.inner)
520    }
521}
522
523impl PartialEq<str> for HeaderValue {
524    #[inline]
525    fn eq(&self, other: &str) -> bool {
526        self.inner == other.as_bytes()
527    }
528}
529
530impl PartialEq<[u8]> for HeaderValue {
531    #[inline]
532    fn eq(&self, other: &[u8]) -> bool {
533        self.inner == other
534    }
535}
536
537impl PartialOrd<str> for HeaderValue {
538    #[inline]
539    fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
540        (*self.inner).partial_cmp(other.as_bytes())
541    }
542}
543
544impl PartialOrd<[u8]> for HeaderValue {
545    #[inline]
546    fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
547        (*self.inner).partial_cmp(other)
548    }
549}
550
551impl PartialEq<HeaderValue> for str {
552    #[inline]
553    fn eq(&self, other: &HeaderValue) -> bool {
554        *other == *self
555    }
556}
557
558impl PartialEq<HeaderValue> for [u8] {
559    #[inline]
560    fn eq(&self, other: &HeaderValue) -> bool {
561        *other == *self
562    }
563}
564
565impl PartialOrd<HeaderValue> for str {
566    #[inline]
567    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
568        self.as_bytes().partial_cmp(other.as_bytes())
569    }
570}
571
572impl PartialOrd<HeaderValue> for [u8] {
573    #[inline]
574    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
575        self.partial_cmp(other.as_bytes())
576    }
577}
578
579impl PartialEq<String> for HeaderValue {
580    #[inline]
581    fn eq(&self, other: &String) -> bool {
582        *self == &other[..]
583    }
584}
585
586impl PartialOrd<String> for HeaderValue {
587    #[inline]
588    fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
589        self.inner.partial_cmp(other.as_bytes())
590    }
591}
592
593impl PartialEq<HeaderValue> for String {
594    #[inline]
595    fn eq(&self, other: &HeaderValue) -> bool {
596        *other == *self
597    }
598}
599
600impl PartialOrd<HeaderValue> for String {
601    #[inline]
602    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
603        self.as_bytes().partial_cmp(other.as_bytes())
604    }
605}
606
607impl<'a> PartialEq<HeaderValue> for &'a HeaderValue {
608    #[inline]
609    fn eq(&self, other: &HeaderValue) -> bool {
610        **self == *other
611    }
612}
613
614impl<'a> PartialOrd<HeaderValue> for &'a HeaderValue {
615    #[inline]
616    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
617        (**self).partial_cmp(other)
618    }
619}
620
621impl<'a, T: ?Sized> PartialEq<&'a T> for HeaderValue
622    where HeaderValue: PartialEq<T>
623{
624    #[inline]
625    fn eq(&self, other: &&'a T) -> bool {
626        *self == **other
627    }
628}
629
630impl<'a, T: ?Sized> PartialOrd<&'a T> for HeaderValue
631    where HeaderValue: PartialOrd<T>
632{
633    #[inline]
634    fn partial_cmp(&self, other: &&'a T) -> Option<cmp::Ordering> {
635        self.partial_cmp(*other)
636    }
637}
638
639impl<'a> PartialEq<HeaderValue> for &'a str {
640    #[inline]
641    fn eq(&self, other: &HeaderValue) -> bool {
642        *other == *self
643    }
644}
645
646impl<'a> PartialOrd<HeaderValue> for &'a str {
647    #[inline]
648    fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
649        self.as_bytes().partial_cmp(other.as_bytes())
650    }
651}
652
653#[test]
654fn test_try_from() {
655    HeaderValue::try_from(vec![127]).unwrap_err();
656}
657
658#[test]
659fn test_debug() {
660    let cases = &[
661        ("hello", "\"hello\""),
662        ("hello \"world\"", "\"hello \\\"world\\\"\""),
663        ("\u{7FFF}hello", "\"\\xe7\\xbf\\xbfhello\""),
664    ];
665
666    for &(value, expected) in cases {
667        let val = HeaderValue::from_bytes(value.as_bytes()).unwrap();
668        let actual = format!("{:?}", val);
669        assert_eq!(expected, actual);
670    }
671
672    let mut sensitive = HeaderValue::from_static("password");
673    sensitive.set_sensitive(true);
674    assert_eq!("Sensitive", format!("{:?}", sensitive));
675}