1use bytes::{Bytes, BytesMut};
2
3use std::convert::TryFrom;
4use std::error::Error;
5use std::fmt::Write;
6use std::str::FromStr;
7use std::{cmp, fmt, mem, str};
8
9use crate::header::name::HeaderName;
10
11#[derive(Clone, Hash)]
21pub struct HeaderValue {
22 inner: Bytes,
23 is_sensitive: bool,
24}
25
26pub struct InvalidHeaderValue {
29 _priv: (),
30}
31
32#[derive(Debug)]
37pub struct ToStrError {
38 _priv: (),
39}
40
41impl HeaderValue {
42 #[inline]
82 #[allow(unconditional_panic)] pub const fn from_static(src: &'static str) -> HeaderValue {
84 let bytes = src.as_bytes();
85 let mut i = 0;
86 while i < bytes.len() {
87 if !is_visible_ascii(bytes[i]) {
88 ([] as [u8; 0])[0]; }
90 i += 1;
91 }
92
93 HeaderValue {
94 inner: Bytes::from_static(bytes),
95 is_sensitive: false,
96 }
97 }
98
99 #[inline]
125 pub fn from_str(src: &str) -> Result<HeaderValue, InvalidHeaderValue> {
126 HeaderValue::try_from_generic(src, |s| Bytes::copy_from_slice(s.as_bytes()))
127 }
128
129 #[inline]
142 pub fn from_name(name: HeaderName) -> HeaderValue {
143 name.into()
144 }
145
146 #[inline]
171 pub fn from_bytes(src: &[u8]) -> Result<HeaderValue, InvalidHeaderValue> {
172 HeaderValue::try_from_generic(src, Bytes::copy_from_slice)
173 }
174
175 pub fn from_maybe_shared<T>(src: T) -> Result<HeaderValue, InvalidHeaderValue>
180 where
181 T: AsRef<[u8]> + 'static,
182 {
183 if_downcast_into!(T, Bytes, src, {
184 return HeaderValue::from_shared(src);
185 });
186
187 HeaderValue::from_bytes(src.as_ref())
188 }
189
190 pub unsafe fn from_maybe_shared_unchecked<T>(src: T) -> HeaderValue
195 where
196 T: AsRef<[u8]> + 'static,
197 {
198 if cfg!(debug_assertions) {
199 match HeaderValue::from_maybe_shared(src) {
200 Ok(val) => val,
201 Err(_err) => {
202 panic!("HeaderValue::from_maybe_shared_unchecked() with invalid bytes");
203 }
204 }
205 } else {
206
207 if_downcast_into!(T, Bytes, src, {
208 return HeaderValue {
209 inner: src,
210 is_sensitive: false,
211 };
212 });
213
214 let src = Bytes::copy_from_slice(src.as_ref());
215 HeaderValue {
216 inner: src,
217 is_sensitive: false,
218 }
219 }
220 }
221
222 fn from_shared(src: Bytes) -> Result<HeaderValue, InvalidHeaderValue> {
223 HeaderValue::try_from_generic(src, std::convert::identity)
224 }
225
226 fn try_from_generic<T: AsRef<[u8]>, F: FnOnce(T) -> Bytes>(src: T, into: F) -> Result<HeaderValue, InvalidHeaderValue> {
227 for &b in src.as_ref() {
228 if !is_valid(b) {
229 return Err(InvalidHeaderValue { _priv: () });
230 }
231 }
232 Ok(HeaderValue {
233 inner: into(src),
234 is_sensitive: false,
235 })
236 }
237
238 pub fn to_str(&self) -> Result<&str, ToStrError> {
252 let bytes = self.as_ref();
253
254 for &b in bytes {
255 if !is_visible_ascii(b) {
256 return Err(ToStrError { _priv: () });
257 }
258 }
259
260 unsafe { Ok(str::from_utf8_unchecked(bytes)) }
261 }
262
263 #[inline]
275 pub fn len(&self) -> usize {
276 self.as_ref().len()
277 }
278
279 #[inline]
292 pub fn is_empty(&self) -> bool {
293 self.len() == 0
294 }
295
296 #[inline]
306 pub fn as_bytes(&self) -> &[u8] {
307 self.as_ref()
308 }
309
310 #[inline]
325 pub fn set_sensitive(&mut self, val: bool) {
326 self.is_sensitive = val;
327 }
328
329 #[inline]
356 pub fn is_sensitive(&self) -> bool {
357 self.is_sensitive
358 }
359}
360
361impl AsRef<[u8]> for HeaderValue {
362 #[inline]
363 fn as_ref(&self) -> &[u8] {
364 self.inner.as_ref()
365 }
366}
367
368impl fmt::Debug for HeaderValue {
369 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
370 if self.is_sensitive {
371 f.write_str("Sensitive")
372 } else {
373 f.write_str("\"")?;
374 let mut from = 0;
375 let bytes = self.as_bytes();
376 for (i, &b) in bytes.iter().enumerate() {
377 if !is_visible_ascii(b) || b == b'"' {
378 if from != i {
379 f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..i]) })?;
380 }
381 if b == b'"' {
382 f.write_str("\\\"")?;
383 } else {
384 write!(f, "\\x{:x}", b)?;
385 }
386 from = i + 1;
387 }
388 }
389
390 f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..]) })?;
391 f.write_str("\"")
392 }
393 }
394}
395
396impl From<HeaderName> for HeaderValue {
397 #[inline]
398 fn from(h: HeaderName) -> HeaderValue {
399 HeaderValue {
400 inner: h.into_bytes(),
401 is_sensitive: false,
402 }
403 }
404}
405
406macro_rules! from_integers {
407 ($($name:ident: $t:ident => $max_len:expr),*) => {$(
408 impl From<$t> for HeaderValue {
409 fn from(num: $t) -> HeaderValue {
410 let mut buf = if mem::size_of::<BytesMut>() - 1 < $max_len {
411 if num as u64 > 999_999_999_999_999_999 {
422 BytesMut::with_capacity($max_len)
423 } else {
424 BytesMut::new()
426 }
427 } else {
428 BytesMut::new()
430 };
431 let _ = buf.write_str(::itoa::Buffer::new().format(num));
432 HeaderValue {
433 inner: buf.freeze(),
434 is_sensitive: false,
435 }
436 }
437 }
438
439 #[test]
440 fn $name() {
441 let n: $t = 55;
442 let val = HeaderValue::from(n);
443 assert_eq!(val, &n.to_string());
444
445 let n = ::std::$t::MAX;
446 let val = HeaderValue::from(n);
447 assert_eq!(val, &n.to_string());
448 }
449 )*};
450}
451
452from_integers! {
453 from_u16: u16 => 5,
457 from_i16: i16 => 6,
458 from_u32: u32 => 10,
459 from_i32: i32 => 11,
460 from_u64: u64 => 20,
461 from_i64: i64 => 20
462}
463
464#[cfg(target_pointer_width = "16")]
465from_integers! {
466 from_usize: usize => 5,
467 from_isize: isize => 6
468}
469
470#[cfg(target_pointer_width = "32")]
471from_integers! {
472 from_usize: usize => 10,
473 from_isize: isize => 11
474}
475
476#[cfg(target_pointer_width = "64")]
477from_integers! {
478 from_usize: usize => 20,
479 from_isize: isize => 20
480}
481
482#[cfg(test)]
483mod from_header_name_tests {
484 use super::*;
485 use crate::header::map::HeaderMap;
486 use crate::header::name;
487
488 #[test]
489 fn it_can_insert_header_name_as_header_value() {
490 let mut map = HeaderMap::new();
491 map.insert(name::UPGRADE, name::SEC_WEBSOCKET_PROTOCOL.into());
492 map.insert(
493 name::ACCEPT,
494 name::HeaderName::from_bytes(b"hello-world").unwrap().into(),
495 );
496
497 assert_eq!(
498 map.get(name::UPGRADE).unwrap(),
499 HeaderValue::from_bytes(b"sec-websocket-protocol").unwrap()
500 );
501
502 assert_eq!(
503 map.get(name::ACCEPT).unwrap(),
504 HeaderValue::from_bytes(b"hello-world").unwrap()
505 );
506 }
507}
508
509impl FromStr for HeaderValue {
510 type Err = InvalidHeaderValue;
511
512 #[inline]
513 fn from_str(s: &str) -> Result<HeaderValue, Self::Err> {
514 HeaderValue::from_str(s)
515 }
516}
517
518impl<'a> From<&'a HeaderValue> for HeaderValue {
519 #[inline]
520 fn from(t: &'a HeaderValue) -> Self {
521 t.clone()
522 }
523}
524
525impl<'a> TryFrom<&'a str> for HeaderValue {
526 type Error = InvalidHeaderValue;
527
528 #[inline]
529 fn try_from(t: &'a str) -> Result<Self, Self::Error> {
530 t.parse()
531 }
532}
533
534impl<'a> TryFrom<&'a String> for HeaderValue {
535 type Error = InvalidHeaderValue;
536 #[inline]
537 fn try_from(s: &'a String) -> Result<Self, Self::Error> {
538 Self::from_bytes(s.as_bytes())
539 }
540}
541
542impl<'a> TryFrom<&'a [u8]> for HeaderValue {
543 type Error = InvalidHeaderValue;
544
545 #[inline]
546 fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
547 HeaderValue::from_bytes(t)
548 }
549}
550
551impl TryFrom<String> for HeaderValue {
552 type Error = InvalidHeaderValue;
553
554 #[inline]
555 fn try_from(t: String) -> Result<Self, Self::Error> {
556 HeaderValue::from_shared(t.into())
557 }
558}
559
560impl TryFrom<Vec<u8>> for HeaderValue {
561 type Error = InvalidHeaderValue;
562
563 #[inline]
564 fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
565 HeaderValue::from_shared(vec.into())
566 }
567}
568
569#[cfg(test)]
570mod try_from_header_name_tests {
571 use super::*;
572 use crate::header::name;
573
574 #[test]
575 fn it_converts_using_try_from() {
576 assert_eq!(
577 HeaderValue::try_from(name::UPGRADE).unwrap(),
578 HeaderValue::from_bytes(b"upgrade").unwrap()
579 );
580 }
581}
582
583const fn is_visible_ascii(b: u8) -> bool {
584 b >= 32 && b < 127 || b == b'\t'
585}
586
587#[inline]
588fn is_valid(b: u8) -> bool {
589 b >= 32 && b != 127 || b == b'\t'
590}
591
592impl fmt::Debug for InvalidHeaderValue {
593 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
594 f.debug_struct("InvalidHeaderValue")
595 .finish()
597 }
598}
599
600impl fmt::Display for InvalidHeaderValue {
601 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
602 f.write_str("failed to parse header value")
603 }
604}
605
606impl Error for InvalidHeaderValue {}
607
608impl fmt::Display for ToStrError {
609 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
610 f.write_str("failed to convert header to a str")
611 }
612}
613
614impl Error for ToStrError {}
615
616impl PartialEq for HeaderValue {
619 #[inline]
620 fn eq(&self, other: &HeaderValue) -> bool {
621 self.inner == other.inner
622 }
623}
624
625impl Eq for HeaderValue {}
626
627impl PartialOrd for HeaderValue {
628 #[inline]
629 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
630 self.inner.partial_cmp(&other.inner)
631 }
632}
633
634impl Ord for HeaderValue {
635 #[inline]
636 fn cmp(&self, other: &Self) -> cmp::Ordering {
637 self.inner.cmp(&other.inner)
638 }
639}
640
641impl PartialEq<str> for HeaderValue {
642 #[inline]
643 fn eq(&self, other: &str) -> bool {
644 self.inner == other.as_bytes()
645 }
646}
647
648impl PartialEq<[u8]> for HeaderValue {
649 #[inline]
650 fn eq(&self, other: &[u8]) -> bool {
651 self.inner == other
652 }
653}
654
655impl PartialOrd<str> for HeaderValue {
656 #[inline]
657 fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
658 (*self.inner).partial_cmp(other.as_bytes())
659 }
660}
661
662impl PartialOrd<[u8]> for HeaderValue {
663 #[inline]
664 fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
665 (*self.inner).partial_cmp(other)
666 }
667}
668
669impl PartialEq<HeaderValue> for str {
670 #[inline]
671 fn eq(&self, other: &HeaderValue) -> bool {
672 *other == *self
673 }
674}
675
676impl PartialEq<HeaderValue> for [u8] {
677 #[inline]
678 fn eq(&self, other: &HeaderValue) -> bool {
679 *other == *self
680 }
681}
682
683impl PartialOrd<HeaderValue> for str {
684 #[inline]
685 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
686 self.as_bytes().partial_cmp(other.as_bytes())
687 }
688}
689
690impl PartialOrd<HeaderValue> for [u8] {
691 #[inline]
692 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
693 self.partial_cmp(other.as_bytes())
694 }
695}
696
697impl PartialEq<String> for HeaderValue {
698 #[inline]
699 fn eq(&self, other: &String) -> bool {
700 *self == &other[..]
701 }
702}
703
704impl PartialOrd<String> for HeaderValue {
705 #[inline]
706 fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
707 self.inner.partial_cmp(other.as_bytes())
708 }
709}
710
711impl PartialEq<HeaderValue> for String {
712 #[inline]
713 fn eq(&self, other: &HeaderValue) -> bool {
714 *other == *self
715 }
716}
717
718impl PartialOrd<HeaderValue> for String {
719 #[inline]
720 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
721 self.as_bytes().partial_cmp(other.as_bytes())
722 }
723}
724
725impl<'a> PartialEq<HeaderValue> for &'a HeaderValue {
726 #[inline]
727 fn eq(&self, other: &HeaderValue) -> bool {
728 **self == *other
729 }
730}
731
732impl<'a> PartialOrd<HeaderValue> for &'a HeaderValue {
733 #[inline]
734 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
735 (**self).partial_cmp(other)
736 }
737}
738
739impl<'a, T: ?Sized> PartialEq<&'a T> for HeaderValue
740where
741 HeaderValue: PartialEq<T>,
742{
743 #[inline]
744 fn eq(&self, other: &&'a T) -> bool {
745 *self == **other
746 }
747}
748
749impl<'a, T: ?Sized> PartialOrd<&'a T> for HeaderValue
750where
751 HeaderValue: PartialOrd<T>,
752{
753 #[inline]
754 fn partial_cmp(&self, other: &&'a T) -> Option<cmp::Ordering> {
755 self.partial_cmp(*other)
756 }
757}
758
759impl<'a> PartialEq<HeaderValue> for &'a str {
760 #[inline]
761 fn eq(&self, other: &HeaderValue) -> bool {
762 *other == *self
763 }
764}
765
766impl<'a> PartialOrd<HeaderValue> for &'a str {
767 #[inline]
768 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
769 self.as_bytes().partial_cmp(other.as_bytes())
770 }
771}
772
773#[test]
774fn test_try_from() {
775 HeaderValue::try_from(vec![127]).unwrap_err();
776}
777
778#[test]
779fn test_debug() {
780 let cases = &[
781 ("hello", "\"hello\""),
782 ("hello \"world\"", "\"hello \\\"world\\\"\""),
783 ("\u{7FFF}hello", "\"\\xe7\\xbf\\xbfhello\""),
784 ];
785
786 for &(value, expected) in cases {
787 let val = HeaderValue::from_bytes(value.as_bytes()).unwrap();
788 let actual = format!("{:?}", val);
789 assert_eq!(expected, actual);
790 }
791
792 let mut sensitive = HeaderValue::from_static("password");
793 sensitive.set_sensitive(true);
794 assert_eq!("Sensitive", format!("{:?}", sensitive));
795}