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]
62 pub const fn from_static(src: &'static str) -> HeaderValue {
63 let bytes = src.as_bytes();
64 let mut i = 0;
65 while i < bytes.len() {
66 if !is_visible_ascii(bytes[i]) {
67 panic!("HeaderValue::from_static with invalid bytes")
68 }
69 i += 1;
70 }
71
72 HeaderValue {
73 inner: Bytes::from_static(bytes),
74 is_sensitive: false,
75 }
76 }
77
78 #[inline]
104 #[allow(clippy::should_implement_trait)]
105 pub fn from_str(src: &str) -> Result<HeaderValue, InvalidHeaderValue> {
106 HeaderValue::try_from_generic(src, |s| Bytes::copy_from_slice(s.as_bytes()))
107 }
108
109 #[inline]
122 pub fn from_name(name: HeaderName) -> HeaderValue {
123 name.into()
124 }
125
126 #[inline]
151 pub fn from_bytes(src: &[u8]) -> Result<HeaderValue, InvalidHeaderValue> {
152 HeaderValue::try_from_generic(src, Bytes::copy_from_slice)
153 }
154
155 pub fn from_maybe_shared<T>(src: T) -> Result<HeaderValue, InvalidHeaderValue>
160 where
161 T: AsRef<[u8]> + 'static,
162 {
163 if_downcast_into!(T, Bytes, src, {
164 return HeaderValue::from_shared(src);
165 });
166
167 HeaderValue::from_bytes(src.as_ref())
168 }
169
170 pub unsafe fn from_maybe_shared_unchecked<T>(src: T) -> HeaderValue
182 where
183 T: AsRef<[u8]> + 'static,
184 {
185 if cfg!(debug_assertions) {
186 match HeaderValue::from_maybe_shared(src) {
187 Ok(val) => val,
188 Err(_err) => {
189 panic!("HeaderValue::from_maybe_shared_unchecked() with invalid bytes");
190 }
191 }
192 } else {
193 if_downcast_into!(T, Bytes, src, {
194 return HeaderValue {
195 inner: src,
196 is_sensitive: false,
197 };
198 });
199
200 let src = Bytes::copy_from_slice(src.as_ref());
201 HeaderValue {
202 inner: src,
203 is_sensitive: false,
204 }
205 }
206 }
207
208 fn from_shared(src: Bytes) -> Result<HeaderValue, InvalidHeaderValue> {
209 HeaderValue::try_from_generic(src, std::convert::identity)
210 }
211
212 fn try_from_generic<T: AsRef<[u8]>, F: FnOnce(T) -> Bytes>(
213 src: T,
214 into: F,
215 ) -> Result<HeaderValue, InvalidHeaderValue> {
216 let mut bad = false;
218 for &b in src.as_ref() {
219 bad |= !is_valid(b);
220 }
221 if bad {
222 return Err(InvalidHeaderValue { _priv: () });
223 }
224 Ok(HeaderValue {
225 inner: into(src),
226 is_sensitive: false,
227 })
228 }
229
230 pub fn to_str(&self) -> Result<&str, ToStrError> {
244 let bytes = self.as_ref();
245
246 let mut bad = false;
248 for &b in bytes {
249 bad |= !is_visible_ascii(b);
250 }
251 if bad {
252 return Err(ToStrError { _priv: () });
253 }
254
255 unsafe { Ok(str::from_utf8_unchecked(bytes)) }
256 }
257
258 #[inline]
270 pub fn len(&self) -> usize {
271 self.as_ref().len()
272 }
273
274 #[inline]
287 pub fn is_empty(&self) -> bool {
288 self.len() == 0
289 }
290
291 #[inline]
301 pub fn as_bytes(&self) -> &[u8] {
302 self.as_ref()
303 }
304
305 #[inline]
320 pub fn set_sensitive(&mut self, val: bool) {
321 self.is_sensitive = val;
322 }
323
324 #[inline]
351 pub fn is_sensitive(&self) -> bool {
352 self.is_sensitive
353 }
354}
355
356impl AsRef<[u8]> for HeaderValue {
357 #[inline]
358 fn as_ref(&self) -> &[u8] {
359 self.inner.as_ref()
360 }
361}
362
363impl fmt::Debug for HeaderValue {
364 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
365 if self.is_sensitive {
366 f.write_str("Sensitive")
367 } else {
368 f.write_str("\"")?;
369 let mut from = 0;
370 let bytes = self.as_bytes();
371 for (i, &b) in bytes.iter().enumerate() {
372 if !is_visible_ascii(b) || b == b'"' {
373 if from != i {
374 f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..i]) })?;
375 }
376 if b == b'"' {
377 f.write_str("\\\"")?;
378 } else {
379 write!(f, "\\x{:x}", b)?;
380 }
381 from = i + 1;
382 }
383 }
384
385 f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..]) })?;
386 f.write_str("\"")
387 }
388 }
389}
390
391impl From<HeaderName> for HeaderValue {
392 #[inline]
393 fn from(h: HeaderName) -> HeaderValue {
394 HeaderValue {
395 inner: h.into_bytes(),
396 is_sensitive: false,
397 }
398 }
399}
400
401macro_rules! from_integers {
402 ($($name:ident: $t:ident => $max_len:expr),*) => {$(
403 impl From<$t> for HeaderValue {
404 fn from(num: $t) -> HeaderValue {
405 let mut buf = BytesMut::with_capacity($max_len);
406 let _ = buf.write_str(::itoa::Buffer::new().format(num));
407 HeaderValue {
408 inner: buf.freeze(),
409 is_sensitive: false,
410 }
411 }
412 }
413
414 #[test]
415 fn $name() {
416 let n: $t = 55;
417 let val = HeaderValue::from(n);
418 assert_eq!(val, &n.to_string());
419
420 let n = ::std::$t::MAX;
421 let val = HeaderValue::from(n);
422 assert_eq!(val, &n.to_string());
423 }
424 )*};
425}
426
427from_integers! {
428 from_u16: u16 => 5,
432 from_i16: i16 => 6,
433 from_u32: u32 => 10,
434 from_i32: i32 => 11,
435 from_u64: u64 => 20,
436 from_i64: i64 => 20
437}
438
439#[cfg(target_pointer_width = "16")]
440from_integers! {
441 from_usize: usize => 5,
442 from_isize: isize => 6
443}
444
445#[cfg(target_pointer_width = "32")]
446from_integers! {
447 from_usize: usize => 10,
448 from_isize: isize => 11
449}
450
451#[cfg(target_pointer_width = "64")]
452from_integers! {
453 from_usize: usize => 20,
454 from_isize: isize => 20
455}
456
457#[cfg(test)]
458mod from_header_name_tests {
459 use super::*;
460 use crate::header::map::HeaderMap;
461 use crate::header::name;
462
463 #[test]
464 fn it_can_insert_header_name_as_header_value() {
465 let mut map = HeaderMap::new();
466 map.insert(name::UPGRADE, name::SEC_WEBSOCKET_PROTOCOL.into());
467 map.insert(
468 name::ACCEPT,
469 name::HeaderName::from_bytes(b"hello-world").unwrap().into(),
470 );
471
472 assert_eq!(
473 map.get(name::UPGRADE).unwrap(),
474 HeaderValue::from_bytes(b"sec-websocket-protocol").unwrap()
475 );
476
477 assert_eq!(
478 map.get(name::ACCEPT).unwrap(),
479 HeaderValue::from_bytes(b"hello-world").unwrap()
480 );
481 }
482}
483
484impl FromStr for HeaderValue {
485 type Err = InvalidHeaderValue;
486
487 #[inline]
488 fn from_str(s: &str) -> Result<HeaderValue, Self::Err> {
489 HeaderValue::from_str(s)
490 }
491}
492
493impl From<&HeaderValue> for HeaderValue {
494 #[inline]
495 fn from(t: &HeaderValue) -> Self {
496 t.clone()
497 }
498}
499
500impl TryFrom<&str> for HeaderValue {
501 type Error = InvalidHeaderValue;
502
503 #[inline]
504 fn try_from(t: &str) -> Result<Self, Self::Error> {
505 t.parse()
506 }
507}
508
509impl TryFrom<&String> for HeaderValue {
510 type Error = InvalidHeaderValue;
511 #[inline]
512 fn try_from(s: &String) -> Result<Self, Self::Error> {
513 Self::from_bytes(s.as_bytes())
514 }
515}
516
517impl TryFrom<&[u8]> for HeaderValue {
518 type Error = InvalidHeaderValue;
519
520 #[inline]
521 fn try_from(t: &[u8]) -> Result<Self, Self::Error> {
522 HeaderValue::from_bytes(t)
523 }
524}
525
526impl TryFrom<String> for HeaderValue {
527 type Error = InvalidHeaderValue;
528
529 #[inline]
530 fn try_from(t: String) -> Result<Self, Self::Error> {
531 HeaderValue::from_shared(t.into())
532 }
533}
534
535impl TryFrom<Vec<u8>> for HeaderValue {
536 type Error = InvalidHeaderValue;
537
538 #[inline]
539 fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
540 HeaderValue::from_shared(vec.into())
541 }
542}
543
544#[cfg(test)]
545mod try_from_header_name_tests {
546 use super::*;
547 use crate::header::name;
548
549 #[test]
550 fn it_converts_using_try_from() {
551 assert_eq!(
552 HeaderValue::try_from(name::UPGRADE).unwrap(),
553 HeaderValue::from_bytes(b"upgrade").unwrap()
554 );
555 }
556}
557
558const fn is_visible_ascii(b: u8) -> bool {
559 b >= 32 && b < 127 || b == b'\t'
560}
561
562#[inline]
563fn is_valid(b: u8) -> bool {
564 b >= 32 && b != 127 || b == b'\t'
565}
566
567impl fmt::Debug for InvalidHeaderValue {
568 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
569 f.debug_struct("InvalidHeaderValue")
570 .finish()
572 }
573}
574
575impl fmt::Display for InvalidHeaderValue {
576 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
577 f.write_str("failed to parse header value")
578 }
579}
580
581impl Error for InvalidHeaderValue {}
582
583impl fmt::Display for ToStrError {
584 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
585 f.write_str("failed to convert header to a str")
586 }
587}
588
589impl Error for ToStrError {}
590
591impl Hash for HeaderValue {
594 fn hash<H: Hasher>(&self, state: &mut H) {
595 self.inner.hash(state);
596 }
597}
598
599impl PartialEq for HeaderValue {
600 #[inline]
601 fn eq(&self, other: &HeaderValue) -> bool {
602 self.inner == other.inner
603 }
604}
605
606impl Eq for HeaderValue {}
607
608impl PartialOrd for HeaderValue {
609 #[inline]
610 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
611 Some(self.cmp(other))
612 }
613}
614
615impl Ord for HeaderValue {
616 #[inline]
617 fn cmp(&self, other: &Self) -> cmp::Ordering {
618 self.inner.cmp(&other.inner)
619 }
620}
621
622impl PartialEq<str> for HeaderValue {
623 #[inline]
624 fn eq(&self, other: &str) -> bool {
625 self.inner == other.as_bytes()
626 }
627}
628
629impl PartialEq<[u8]> for HeaderValue {
630 #[inline]
631 fn eq(&self, other: &[u8]) -> bool {
632 self.inner == other
633 }
634}
635
636impl PartialOrd<str> for HeaderValue {
637 #[inline]
638 fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
639 (*self.inner).partial_cmp(other.as_bytes())
640 }
641}
642
643impl PartialOrd<[u8]> for HeaderValue {
644 #[inline]
645 fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
646 (*self.inner).partial_cmp(other)
647 }
648}
649
650impl PartialEq<HeaderValue> for str {
651 #[inline]
652 fn eq(&self, other: &HeaderValue) -> bool {
653 *other == *self
654 }
655}
656
657impl PartialEq<HeaderValue> for [u8] {
658 #[inline]
659 fn eq(&self, other: &HeaderValue) -> bool {
660 *other == *self
661 }
662}
663
664impl PartialOrd<HeaderValue> for str {
665 #[inline]
666 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
667 self.as_bytes().partial_cmp(other.as_bytes())
668 }
669}
670
671impl PartialOrd<HeaderValue> for [u8] {
672 #[inline]
673 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
674 self.partial_cmp(other.as_bytes())
675 }
676}
677
678impl PartialEq<String> for HeaderValue {
679 #[inline]
680 fn eq(&self, other: &String) -> bool {
681 *self == other[..]
682 }
683}
684
685impl PartialOrd<String> for HeaderValue {
686 #[inline]
687 fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
688 self.inner.partial_cmp(other.as_bytes())
689 }
690}
691
692impl PartialEq<HeaderValue> for String {
693 #[inline]
694 fn eq(&self, other: &HeaderValue) -> bool {
695 *other == *self
696 }
697}
698
699impl PartialOrd<HeaderValue> for String {
700 #[inline]
701 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
702 self.as_bytes().partial_cmp(other.as_bytes())
703 }
704}
705
706impl PartialEq<HeaderValue> for &HeaderValue {
707 #[inline]
708 fn eq(&self, other: &HeaderValue) -> bool {
709 **self == *other
710 }
711}
712
713impl PartialOrd<HeaderValue> for &HeaderValue {
714 #[inline]
715 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
716 (**self).partial_cmp(other)
717 }
718}
719
720impl<T: ?Sized> PartialEq<&T> for HeaderValue
721where
722 HeaderValue: PartialEq<T>,
723{
724 #[inline]
725 fn eq(&self, other: &&T) -> bool {
726 *self == **other
727 }
728}
729
730impl<T: ?Sized> PartialOrd<&T> for HeaderValue
731where
732 HeaderValue: PartialOrd<T>,
733{
734 #[inline]
735 fn partial_cmp(&self, other: &&T) -> Option<cmp::Ordering> {
736 self.partial_cmp(*other)
737 }
738}
739
740impl PartialEq<HeaderValue> for &str {
741 #[inline]
742 fn eq(&self, other: &HeaderValue) -> bool {
743 *other == *self
744 }
745}
746
747impl PartialOrd<HeaderValue> for &str {
748 #[inline]
749 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
750 self.as_bytes().partial_cmp(other.as_bytes())
751 }
752}
753
754#[test]
755fn test_try_from() {
756 HeaderValue::try_from(vec![127]).unwrap_err();
757}
758
759#[test]
760fn test_debug() {
761 let cases = &[
762 ("hello", "\"hello\""),
763 ("hello \"world\"", "\"hello \\\"world\\\"\""),
764 ("\u{7FFF}hello", "\"\\xe7\\xbf\\xbfhello\""),
765 ];
766
767 for &(value, expected) in cases {
768 let val = HeaderValue::from_bytes(value.as_bytes()).unwrap();
769 let actual = format!("{:?}", val);
770 assert_eq!(expected, actual);
771 }
772
773 let mut sensitive = HeaderValue::from_static("password");
774 sensitive.set_sensitive(true);
775 assert_eq!("Sensitive", format!("{:?}", sensitive));
776}