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 for &b in src.as_ref() {
217 if !is_valid(b) {
218 return Err(InvalidHeaderValue { _priv: () });
219 }
220 }
221 Ok(HeaderValue {
222 inner: into(src),
223 is_sensitive: false,
224 })
225 }
226
227 pub fn to_str(&self) -> Result<&str, ToStrError> {
241 let bytes = self.as_ref();
242
243 for &b in bytes {
244 if !is_visible_ascii(b) {
245 return Err(ToStrError { _priv: () });
246 }
247 }
248
249 unsafe { Ok(str::from_utf8_unchecked(bytes)) }
250 }
251
252 #[inline]
264 pub fn len(&self) -> usize {
265 self.as_ref().len()
266 }
267
268 #[inline]
281 pub fn is_empty(&self) -> bool {
282 self.len() == 0
283 }
284
285 #[inline]
295 pub fn as_bytes(&self) -> &[u8] {
296 self.as_ref()
297 }
298
299 #[inline]
314 pub fn set_sensitive(&mut self, val: bool) {
315 self.is_sensitive = val;
316 }
317
318 #[inline]
345 pub fn is_sensitive(&self) -> bool {
346 self.is_sensitive
347 }
348}
349
350impl AsRef<[u8]> for HeaderValue {
351 #[inline]
352 fn as_ref(&self) -> &[u8] {
353 self.inner.as_ref()
354 }
355}
356
357impl fmt::Debug for HeaderValue {
358 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
359 if self.is_sensitive {
360 f.write_str("Sensitive")
361 } else {
362 f.write_str("\"")?;
363 let mut from = 0;
364 let bytes = self.as_bytes();
365 for (i, &b) in bytes.iter().enumerate() {
366 if !is_visible_ascii(b) || b == b'"' {
367 if from != i {
368 f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..i]) })?;
369 }
370 if b == b'"' {
371 f.write_str("\\\"")?;
372 } else {
373 write!(f, "\\x{:x}", b)?;
374 }
375 from = i + 1;
376 }
377 }
378
379 f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..]) })?;
380 f.write_str("\"")
381 }
382 }
383}
384
385impl From<HeaderName> for HeaderValue {
386 #[inline]
387 fn from(h: HeaderName) -> HeaderValue {
388 HeaderValue {
389 inner: h.into_bytes(),
390 is_sensitive: false,
391 }
392 }
393}
394
395macro_rules! from_integers {
396 ($($name:ident: $t:ident => $max_len:expr),*) => {$(
397 impl From<$t> for HeaderValue {
398 fn from(num: $t) -> HeaderValue {
399 let mut buf = BytesMut::with_capacity($max_len);
400 let _ = buf.write_str(::itoa::Buffer::new().format(num));
401 HeaderValue {
402 inner: buf.freeze(),
403 is_sensitive: false,
404 }
405 }
406 }
407
408 #[test]
409 fn $name() {
410 let n: $t = 55;
411 let val = HeaderValue::from(n);
412 assert_eq!(val, &n.to_string());
413
414 let n = ::std::$t::MAX;
415 let val = HeaderValue::from(n);
416 assert_eq!(val, &n.to_string());
417 }
418 )*};
419}
420
421from_integers! {
422 from_u16: u16 => 5,
426 from_i16: i16 => 6,
427 from_u32: u32 => 10,
428 from_i32: i32 => 11,
429 from_u64: u64 => 20,
430 from_i64: i64 => 20
431}
432
433#[cfg(target_pointer_width = "16")]
434from_integers! {
435 from_usize: usize => 5,
436 from_isize: isize => 6
437}
438
439#[cfg(target_pointer_width = "32")]
440from_integers! {
441 from_usize: usize => 10,
442 from_isize: isize => 11
443}
444
445#[cfg(target_pointer_width = "64")]
446from_integers! {
447 from_usize: usize => 20,
448 from_isize: isize => 20
449}
450
451#[cfg(test)]
452mod from_header_name_tests {
453 use super::*;
454 use crate::header::map::HeaderMap;
455 use crate::header::name;
456
457 #[test]
458 fn it_can_insert_header_name_as_header_value() {
459 let mut map = HeaderMap::new();
460 map.insert(name::UPGRADE, name::SEC_WEBSOCKET_PROTOCOL.into());
461 map.insert(
462 name::ACCEPT,
463 name::HeaderName::from_bytes(b"hello-world").unwrap().into(),
464 );
465
466 assert_eq!(
467 map.get(name::UPGRADE).unwrap(),
468 HeaderValue::from_bytes(b"sec-websocket-protocol").unwrap()
469 );
470
471 assert_eq!(
472 map.get(name::ACCEPT).unwrap(),
473 HeaderValue::from_bytes(b"hello-world").unwrap()
474 );
475 }
476}
477
478impl FromStr for HeaderValue {
479 type Err = InvalidHeaderValue;
480
481 #[inline]
482 fn from_str(s: &str) -> Result<HeaderValue, Self::Err> {
483 HeaderValue::from_str(s)
484 }
485}
486
487impl<'a> From<&'a HeaderValue> for HeaderValue {
488 #[inline]
489 fn from(t: &'a HeaderValue) -> Self {
490 t.clone()
491 }
492}
493
494impl<'a> TryFrom<&'a str> for HeaderValue {
495 type Error = InvalidHeaderValue;
496
497 #[inline]
498 fn try_from(t: &'a str) -> Result<Self, Self::Error> {
499 t.parse()
500 }
501}
502
503impl<'a> TryFrom<&'a String> for HeaderValue {
504 type Error = InvalidHeaderValue;
505 #[inline]
506 fn try_from(s: &'a String) -> Result<Self, Self::Error> {
507 Self::from_bytes(s.as_bytes())
508 }
509}
510
511impl<'a> TryFrom<&'a [u8]> for HeaderValue {
512 type Error = InvalidHeaderValue;
513
514 #[inline]
515 fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
516 HeaderValue::from_bytes(t)
517 }
518}
519
520impl TryFrom<String> for HeaderValue {
521 type Error = InvalidHeaderValue;
522
523 #[inline]
524 fn try_from(t: String) -> Result<Self, Self::Error> {
525 HeaderValue::from_shared(t.into())
526 }
527}
528
529impl TryFrom<Vec<u8>> for HeaderValue {
530 type Error = InvalidHeaderValue;
531
532 #[inline]
533 fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
534 HeaderValue::from_shared(vec.into())
535 }
536}
537
538#[cfg(test)]
539mod try_from_header_name_tests {
540 use super::*;
541 use crate::header::name;
542
543 #[test]
544 fn it_converts_using_try_from() {
545 assert_eq!(
546 HeaderValue::try_from(name::UPGRADE).unwrap(),
547 HeaderValue::from_bytes(b"upgrade").unwrap()
548 );
549 }
550}
551
552const fn is_visible_ascii(b: u8) -> bool {
553 b >= 32 && b < 127 || b == b'\t'
554}
555
556#[inline]
557fn is_valid(b: u8) -> bool {
558 b >= 32 && b != 127 || b == b'\t'
559}
560
561impl fmt::Debug for InvalidHeaderValue {
562 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
563 f.debug_struct("InvalidHeaderValue")
564 .finish()
566 }
567}
568
569impl fmt::Display for InvalidHeaderValue {
570 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
571 f.write_str("failed to parse header value")
572 }
573}
574
575impl Error for InvalidHeaderValue {}
576
577impl fmt::Display for ToStrError {
578 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
579 f.write_str("failed to convert header to a str")
580 }
581}
582
583impl Error for ToStrError {}
584
585impl Hash for HeaderValue {
588 fn hash<H: Hasher>(&self, state: &mut H) {
589 self.inner.hash(state);
590 }
591}
592
593impl PartialEq for HeaderValue {
594 #[inline]
595 fn eq(&self, other: &HeaderValue) -> bool {
596 self.inner == other.inner
597 }
598}
599
600impl Eq for HeaderValue {}
601
602impl PartialOrd for HeaderValue {
603 #[inline]
604 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
605 Some(self.cmp(other))
606 }
607}
608
609impl Ord for HeaderValue {
610 #[inline]
611 fn cmp(&self, other: &Self) -> cmp::Ordering {
612 self.inner.cmp(&other.inner)
613 }
614}
615
616impl PartialEq<str> for HeaderValue {
617 #[inline]
618 fn eq(&self, other: &str) -> bool {
619 self.inner == other.as_bytes()
620 }
621}
622
623impl PartialEq<[u8]> for HeaderValue {
624 #[inline]
625 fn eq(&self, other: &[u8]) -> bool {
626 self.inner == other
627 }
628}
629
630impl PartialOrd<str> for HeaderValue {
631 #[inline]
632 fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
633 (*self.inner).partial_cmp(other.as_bytes())
634 }
635}
636
637impl PartialOrd<[u8]> for HeaderValue {
638 #[inline]
639 fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
640 (*self.inner).partial_cmp(other)
641 }
642}
643
644impl PartialEq<HeaderValue> for str {
645 #[inline]
646 fn eq(&self, other: &HeaderValue) -> bool {
647 *other == *self
648 }
649}
650
651impl PartialEq<HeaderValue> for [u8] {
652 #[inline]
653 fn eq(&self, other: &HeaderValue) -> bool {
654 *other == *self
655 }
656}
657
658impl PartialOrd<HeaderValue> for str {
659 #[inline]
660 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
661 self.as_bytes().partial_cmp(other.as_bytes())
662 }
663}
664
665impl PartialOrd<HeaderValue> for [u8] {
666 #[inline]
667 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
668 self.partial_cmp(other.as_bytes())
669 }
670}
671
672impl PartialEq<String> for HeaderValue {
673 #[inline]
674 fn eq(&self, other: &String) -> bool {
675 *self == other[..]
676 }
677}
678
679impl PartialOrd<String> for HeaderValue {
680 #[inline]
681 fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
682 self.inner.partial_cmp(other.as_bytes())
683 }
684}
685
686impl PartialEq<HeaderValue> for String {
687 #[inline]
688 fn eq(&self, other: &HeaderValue) -> bool {
689 *other == *self
690 }
691}
692
693impl PartialOrd<HeaderValue> for String {
694 #[inline]
695 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
696 self.as_bytes().partial_cmp(other.as_bytes())
697 }
698}
699
700impl<'a> PartialEq<HeaderValue> for &'a HeaderValue {
701 #[inline]
702 fn eq(&self, other: &HeaderValue) -> bool {
703 **self == *other
704 }
705}
706
707impl<'a> PartialOrd<HeaderValue> for &'a HeaderValue {
708 #[inline]
709 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
710 (**self).partial_cmp(other)
711 }
712}
713
714impl<'a, T: ?Sized> PartialEq<&'a T> for HeaderValue
715where
716 HeaderValue: PartialEq<T>,
717{
718 #[inline]
719 fn eq(&self, other: &&'a T) -> bool {
720 *self == **other
721 }
722}
723
724impl<'a, T: ?Sized> PartialOrd<&'a T> for HeaderValue
725where
726 HeaderValue: PartialOrd<T>,
727{
728 #[inline]
729 fn partial_cmp(&self, other: &&'a T) -> Option<cmp::Ordering> {
730 self.partial_cmp(*other)
731 }
732}
733
734impl<'a> PartialEq<HeaderValue> for &'a str {
735 #[inline]
736 fn eq(&self, other: &HeaderValue) -> bool {
737 *other == *self
738 }
739}
740
741impl<'a> PartialOrd<HeaderValue> for &'a str {
742 #[inline]
743 fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
744 self.as_bytes().partial_cmp(other.as_bytes())
745 }
746}
747
748#[test]
749fn test_try_from() {
750 HeaderValue::try_from(vec![127]).unwrap_err();
751}
752
753#[test]
754fn test_debug() {
755 let cases = &[
756 ("hello", "\"hello\""),
757 ("hello \"world\"", "\"hello \\\"world\\\"\""),
758 ("\u{7FFF}hello", "\"\\xe7\\xbf\\xbfhello\""),
759 ];
760
761 for &(value, expected) in cases {
762 let val = HeaderValue::from_bytes(value.as_bytes()).unwrap();
763 let actual = format!("{:?}", val);
764 assert_eq!(expected, actual);
765 }
766
767 let mut sensitive = HeaderValue::from_static("password");
768 sensitive.set_sensitive(true);
769 assert_eq!("Sensitive", format!("{:?}", sensitive));
770}