1use bytes::{Bytes, BytesMut};
2
3use std::convert::TryFrom;
4use std::error::Error;
5use std::str::FromStr;
6use std::{cmp, fmt, mem, str};
7
8use crate::header::name::HeaderName;
9
10#[derive(Clone, Hash)]
20pub struct HeaderValue {
21 inner: Bytes,
22 is_sensitive: bool,
23}
24
25pub struct InvalidHeaderValue {
28 _priv: (),
29}
30
31#[derive(Debug)]
36pub struct ToStrError {
37 _priv: (),
38}
39
40impl HeaderValue {
41 #[inline]
60 pub fn from_static(src: &'static str) -> HeaderValue {
61 let bytes = src.as_bytes();
62 for &b in bytes {
63 if !is_visible_ascii(b) {
64 panic!("invalid header value");
65 }
66 }
67
68 HeaderValue {
69 inner: Bytes::from_static(bytes),
70 is_sensitive: false,
71 }
72 }
73
74 #[inline]
100 pub fn from_str(src: &str) -> Result<HeaderValue, InvalidHeaderValue> {
101 HeaderValue::try_from_generic(src, |s| Bytes::copy_from_slice(s.as_bytes()))
102 }
103
104 #[inline]
117 pub fn from_name(name: HeaderName) -> HeaderValue {
118 name.into()
119 }
120
121 #[inline]
146 pub fn from_bytes(src: &[u8]) -> Result<HeaderValue, InvalidHeaderValue> {
147 HeaderValue::try_from_generic(src, Bytes::copy_from_slice)
148 }
149
150 pub fn from_maybe_shared<T>(src: T) -> Result<HeaderValue, InvalidHeaderValue>
155 where
156 T: AsRef<[u8]> + 'static,
157 {
158 if_downcast_into!(T, Bytes, src, {
159 return HeaderValue::from_shared(src);
160 });
161
162 HeaderValue::from_bytes(src.as_ref())
163 }
164
165 pub unsafe fn from_maybe_shared_unchecked<T>(src: T) -> HeaderValue
170 where
171 T: AsRef<[u8]> + 'static,
172 {
173 if cfg!(debug_assertions) {
174 match HeaderValue::from_maybe_shared(src) {
175 Ok(val) => val,
176 Err(_err) => {
177 panic!("HeaderValue::from_maybe_shared_unchecked() with invalid bytes");
178 }
179 }
180 } else {
181
182 if_downcast_into!(T, Bytes, src, {
183 return HeaderValue {
184 inner: src,
185 is_sensitive: false,
186 };
187 });
188
189 let src = Bytes::copy_from_slice(src.as_ref());
190 HeaderValue {
191 inner: src,
192 is_sensitive: false,
193 }
194 }
195 }
196
197 fn from_shared(src: Bytes) -> Result<HeaderValue, InvalidHeaderValue> {
198 HeaderValue::try_from_generic(src, std::convert::identity)
199 }
200
201 fn try_from_generic<T: AsRef<[u8]>, F: FnOnce(T) -> Bytes>(src: T, into: F) -> Result<HeaderValue, InvalidHeaderValue> {
202 for &b in src.as_ref() {
203 if !is_valid(b) {
204 return Err(InvalidHeaderValue { _priv: () });
205 }
206 }
207 Ok(HeaderValue {
208 inner: into(src),
209 is_sensitive: false,
210 })
211 }
212
213 pub fn to_str(&self) -> Result<&str, ToStrError> {
227 let bytes = self.as_ref();
228
229 for &b in bytes {
230 if !is_visible_ascii(b) {
231 return Err(ToStrError { _priv: () });
232 }
233 }
234
235 unsafe { Ok(str::from_utf8_unchecked(bytes)) }
236 }
237
238 #[inline]
250 pub fn len(&self) -> usize {
251 self.as_ref().len()
252 }
253
254 #[inline]
267 pub fn is_empty(&self) -> bool {
268 self.len() == 0
269 }
270
271 #[inline]
281 pub fn as_bytes(&self) -> &[u8] {
282 self.as_ref()
283 }
284
285 #[inline]
300 pub fn set_sensitive(&mut self, val: bool) {
301 self.is_sensitive = val;
302 }
303
304 #[inline]
331 pub fn is_sensitive(&self) -> bool {
332 self.is_sensitive
333 }
334}
335
336impl AsRef<[u8]> for HeaderValue {
337 #[inline]
338 fn as_ref(&self) -> &[u8] {
339 self.inner.as_ref()
340 }
341}
342
343impl fmt::Debug for HeaderValue {
344 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
345 if self.is_sensitive {
346 f.write_str("Sensitive")
347 } else {
348 f.write_str("\"")?;
349 let mut from = 0;
350 let bytes = self.as_bytes();
351 for (i, &b) in bytes.iter().enumerate() {
352 if !is_visible_ascii(b) || b == b'"' {
353 if from != i {
354 f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..i]) })?;
355 }
356 if b == b'"' {
357 f.write_str("\\\"")?;
358 } else {
359 write!(f, "\\x{:x}", b)?;
360 }
361 from = i + 1;
362 }
363 }
364
365 f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..]) })?;
366 f.write_str("\"")
367 }
368 }
369}
370
371impl From<HeaderName> for HeaderValue {
372 #[inline]
373 fn from(h: HeaderName) -> HeaderValue {
374 HeaderValue {
375 inner: h.into_bytes(),
376 is_sensitive: false,
377 }
378 }
379}
380
381macro_rules! from_integers {
382 ($($name:ident: $t:ident => $max_len:expr),*) => {$(
383 impl From<$t> for HeaderValue {
384 fn from(num: $t) -> HeaderValue {
385 let mut buf = if mem::size_of::<BytesMut>() - 1 < $max_len {
386 if num as u64 > 999_999_999_999_999_999 {
397 BytesMut::with_capacity($max_len)
398 } else {
399 BytesMut::new()
401 }
402 } else {
403 BytesMut::new()
405 };
406 let _ = ::itoa::fmt(&mut buf, 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<'a> From<&'a HeaderValue> for HeaderValue {
494 #[inline]
495 fn from(t: &'a HeaderValue) -> Self {
496 t.clone()
497 }
498}
499
500impl<'a> TryFrom<&'a str> for HeaderValue {
501 type Error = InvalidHeaderValue;
502
503 #[inline]
504 fn try_from(t: &'a str) -> Result<Self, Self::Error> {
505 t.parse()
506 }
507}
508
509impl<'a> TryFrom<&'a String> for HeaderValue {
510 type Error = InvalidHeaderValue;
511 #[inline]
512 fn try_from(s: &'a String) -> Result<Self, Self::Error> {
513 Self::from_bytes(s.as_bytes())
514 }
515}
516
517impl<'a> TryFrom<&'a [u8]> for HeaderValue {
518 type Error = InvalidHeaderValue;
519
520 #[inline]
521 fn try_from(t: &'a [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
558fn 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 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 self.inner.partial_cmp(&other.inner)
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}