summaryrefslogtreecommitdiffstats
path: root/vendor/http/src/header/value.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/http/src/header/value.rs')
-rw-r--r--vendor/http/src/header/value.rs795
1 files changed, 795 insertions, 0 deletions
diff --git a/vendor/http/src/header/value.rs b/vendor/http/src/header/value.rs
new file mode 100644
index 000000000..bf05f16f4
--- /dev/null
+++ b/vendor/http/src/header/value.rs
@@ -0,0 +1,795 @@
+use bytes::{Bytes, BytesMut};
+
+use std::convert::TryFrom;
+use std::error::Error;
+use std::fmt::Write;
+use std::str::FromStr;
+use std::{cmp, fmt, mem, str};
+
+use crate::header::name::HeaderName;
+
+/// Represents an HTTP header field value.
+///
+/// In practice, HTTP header field values are usually valid ASCII. However, the
+/// HTTP spec allows for a header value to contain opaque bytes as well. In this
+/// case, the header field value is not able to be represented as a string.
+///
+/// To handle this, the `HeaderValue` is useable as a type and can be compared
+/// with strings and implements `Debug`. A `to_str` fn is provided that returns
+/// an `Err` if the header value contains non visible ascii characters.
+#[derive(Clone, Hash)]
+pub struct HeaderValue {
+ inner: Bytes,
+ is_sensitive: bool,
+}
+
+/// A possible error when converting a `HeaderValue` from a string or byte
+/// slice.
+pub struct InvalidHeaderValue {
+ _priv: (),
+}
+
+/// A possible error when converting a `HeaderValue` to a string representation.
+///
+/// Header field values may contain opaque bytes, in which case it is not
+/// possible to represent the value as a string.
+#[derive(Debug)]
+pub struct ToStrError {
+ _priv: (),
+}
+
+impl HeaderValue {
+ /// Convert a static string to a `HeaderValue`.
+ ///
+ /// This function will not perform any copying, however the string is
+ /// checked to ensure that no invalid characters are present. Only visible
+ /// ASCII characters (32-127) are permitted.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if the argument contains invalid header value
+ /// characters.
+ ///
+ /// Until [Allow panicking in constants](https://github.com/rust-lang/rfcs/pull/2345)
+ /// makes its way into stable, the panic message at compile-time is
+ /// going to look cryptic, but should at least point at your header value:
+ ///
+ /// ```text
+ /// error: any use of this value will cause an error
+ /// --> http/src/header/value.rs:67:17
+ /// |
+ /// 67 | ([] as [u8; 0])[0]; // Invalid header value
+ /// | ^^^^^^^^^^^^^^^^^^
+ /// | |
+ /// | index out of bounds: the length is 0 but the index is 0
+ /// | inside `HeaderValue::from_static` at http/src/header/value.rs:67:17
+ /// | inside `INVALID_HEADER` at src/main.rs:73:33
+ /// |
+ /// ::: src/main.rs:73:1
+ /// |
+ /// 73 | const INVALID_HEADER: HeaderValue = HeaderValue::from_static("жsome value");
+ /// | ----------------------------------------------------------------------------
+ /// ```
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::header::HeaderValue;
+ /// let val = HeaderValue::from_static("hello");
+ /// assert_eq!(val, "hello");
+ /// ```
+ #[inline]
+ #[allow(unconditional_panic)] // required for the panic circumvention
+ pub const fn from_static(src: &'static str) -> HeaderValue {
+ let bytes = src.as_bytes();
+ let mut i = 0;
+ while i < bytes.len() {
+ if !is_visible_ascii(bytes[i]) {
+ ([] as [u8; 0])[0]; // Invalid header value
+ }
+ i += 1;
+ }
+
+ HeaderValue {
+ inner: Bytes::from_static(bytes),
+ is_sensitive: false,
+ }
+ }
+
+ /// Attempt to convert a string to a `HeaderValue`.
+ ///
+ /// If the argument contains invalid header value characters, an error is
+ /// returned. Only visible ASCII characters (32-127) are permitted. Use
+ /// `from_bytes` to create a `HeaderValue` that includes opaque octets
+ /// (128-255).
+ ///
+ /// This function is intended to be replaced in the future by a `TryFrom`
+ /// implementation once the trait is stabilized in std.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::header::HeaderValue;
+ /// let val = HeaderValue::from_str("hello").unwrap();
+ /// assert_eq!(val, "hello");
+ /// ```
+ ///
+ /// An invalid value
+ ///
+ /// ```
+ /// # use http::header::HeaderValue;
+ /// let val = HeaderValue::from_str("\n");
+ /// assert!(val.is_err());
+ /// ```
+ #[inline]
+ pub fn from_str(src: &str) -> Result<HeaderValue, InvalidHeaderValue> {
+ HeaderValue::try_from_generic(src, |s| Bytes::copy_from_slice(s.as_bytes()))
+ }
+
+ /// Converts a HeaderName into a HeaderValue
+ ///
+ /// Since every valid HeaderName is a valid HeaderValue this is done infallibly.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::header::{HeaderValue, HeaderName};
+ /// # use http::header::ACCEPT;
+ /// let val = HeaderValue::from_name(ACCEPT);
+ /// assert_eq!(val, HeaderValue::from_bytes(b"accept").unwrap());
+ /// ```
+ #[inline]
+ pub fn from_name(name: HeaderName) -> HeaderValue {
+ name.into()
+ }
+
+ /// Attempt to convert a byte slice to a `HeaderValue`.
+ ///
+ /// If the argument contains invalid header value bytes, an error is
+ /// returned. Only byte values between 32 and 255 (inclusive) are permitted,
+ /// excluding byte 127 (DEL).
+ ///
+ /// This function is intended to be replaced in the future by a `TryFrom`
+ /// implementation once the trait is stabilized in std.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::header::HeaderValue;
+ /// let val = HeaderValue::from_bytes(b"hello\xfa").unwrap();
+ /// assert_eq!(val, &b"hello\xfa"[..]);
+ /// ```
+ ///
+ /// An invalid value
+ ///
+ /// ```
+ /// # use http::header::HeaderValue;
+ /// let val = HeaderValue::from_bytes(b"\n");
+ /// assert!(val.is_err());
+ /// ```
+ #[inline]
+ pub fn from_bytes(src: &[u8]) -> Result<HeaderValue, InvalidHeaderValue> {
+ HeaderValue::try_from_generic(src, Bytes::copy_from_slice)
+ }
+
+ /// Attempt to convert a `Bytes` buffer to a `HeaderValue`.
+ ///
+ /// This will try to prevent a copy if the type passed is the type used
+ /// internally, and will copy the data if it is not.
+ pub fn from_maybe_shared<T>(src: T) -> Result<HeaderValue, InvalidHeaderValue>
+ where
+ T: AsRef<[u8]> + 'static,
+ {
+ if_downcast_into!(T, Bytes, src, {
+ return HeaderValue::from_shared(src);
+ });
+
+ HeaderValue::from_bytes(src.as_ref())
+ }
+
+ /// Convert a `Bytes` directly into a `HeaderValue` without validating.
+ ///
+ /// This function does NOT validate that illegal bytes are not contained
+ /// within the buffer.
+ pub unsafe fn from_maybe_shared_unchecked<T>(src: T) -> HeaderValue
+ where
+ T: AsRef<[u8]> + 'static,
+ {
+ if cfg!(debug_assertions) {
+ match HeaderValue::from_maybe_shared(src) {
+ Ok(val) => val,
+ Err(_err) => {
+ panic!("HeaderValue::from_maybe_shared_unchecked() with invalid bytes");
+ }
+ }
+ } else {
+
+ if_downcast_into!(T, Bytes, src, {
+ return HeaderValue {
+ inner: src,
+ is_sensitive: false,
+ };
+ });
+
+ let src = Bytes::copy_from_slice(src.as_ref());
+ HeaderValue {
+ inner: src,
+ is_sensitive: false,
+ }
+ }
+ }
+
+ fn from_shared(src: Bytes) -> Result<HeaderValue, InvalidHeaderValue> {
+ HeaderValue::try_from_generic(src, std::convert::identity)
+ }
+
+ fn try_from_generic<T: AsRef<[u8]>, F: FnOnce(T) -> Bytes>(src: T, into: F) -> Result<HeaderValue, InvalidHeaderValue> {
+ for &b in src.as_ref() {
+ if !is_valid(b) {
+ return Err(InvalidHeaderValue { _priv: () });
+ }
+ }
+ Ok(HeaderValue {
+ inner: into(src),
+ is_sensitive: false,
+ })
+ }
+
+ /// Yields a `&str` slice if the `HeaderValue` only contains visible ASCII
+ /// chars.
+ ///
+ /// This function will perform a scan of the header value, checking all the
+ /// characters.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::header::HeaderValue;
+ /// let val = HeaderValue::from_static("hello");
+ /// assert_eq!(val.to_str().unwrap(), "hello");
+ /// ```
+ pub fn to_str(&self) -> Result<&str, ToStrError> {
+ let bytes = self.as_ref();
+
+ for &b in bytes {
+ if !is_visible_ascii(b) {
+ return Err(ToStrError { _priv: () });
+ }
+ }
+
+ unsafe { Ok(str::from_utf8_unchecked(bytes)) }
+ }
+
+ /// Returns the length of `self`.
+ ///
+ /// This length is in bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::header::HeaderValue;
+ /// let val = HeaderValue::from_static("hello");
+ /// assert_eq!(val.len(), 5);
+ /// ```
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.as_ref().len()
+ }
+
+ /// Returns true if the `HeaderValue` has a length of zero bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::header::HeaderValue;
+ /// let val = HeaderValue::from_static("");
+ /// assert!(val.is_empty());
+ ///
+ /// let val = HeaderValue::from_static("hello");
+ /// assert!(!val.is_empty());
+ /// ```
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.len() == 0
+ }
+
+ /// Converts a `HeaderValue` to a byte slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::header::HeaderValue;
+ /// let val = HeaderValue::from_static("hello");
+ /// assert_eq!(val.as_bytes(), b"hello");
+ /// ```
+ #[inline]
+ pub fn as_bytes(&self) -> &[u8] {
+ self.as_ref()
+ }
+
+ /// Mark that the header value represents sensitive information.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::header::HeaderValue;
+ /// let mut val = HeaderValue::from_static("my secret");
+ ///
+ /// val.set_sensitive(true);
+ /// assert!(val.is_sensitive());
+ ///
+ /// val.set_sensitive(false);
+ /// assert!(!val.is_sensitive());
+ /// ```
+ #[inline]
+ pub fn set_sensitive(&mut self, val: bool) {
+ self.is_sensitive = val;
+ }
+
+ /// Returns `true` if the value represents sensitive data.
+ ///
+ /// Sensitive data could represent passwords or other data that should not
+ /// be stored on disk or in memory. By marking header values as sensitive,
+ /// components using this crate can be instructed to treat them with special
+ /// care for security reasons. For example, caches can avoid storing
+ /// sensitive values, and HPACK encoders used by HTTP/2.0 implementations
+ /// can choose not to compress them.
+ ///
+ /// Additionally, sensitive values will be masked by the `Debug`
+ /// implementation of `HeaderValue`.
+ ///
+ /// Note that sensitivity is not factored into equality or ordering.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use http::header::HeaderValue;
+ /// let mut val = HeaderValue::from_static("my secret");
+ ///
+ /// val.set_sensitive(true);
+ /// assert!(val.is_sensitive());
+ ///
+ /// val.set_sensitive(false);
+ /// assert!(!val.is_sensitive());
+ /// ```
+ #[inline]
+ pub fn is_sensitive(&self) -> bool {
+ self.is_sensitive
+ }
+}
+
+impl AsRef<[u8]> for HeaderValue {
+ #[inline]
+ fn as_ref(&self) -> &[u8] {
+ self.inner.as_ref()
+ }
+}
+
+impl fmt::Debug for HeaderValue {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if self.is_sensitive {
+ f.write_str("Sensitive")
+ } else {
+ f.write_str("\"")?;
+ let mut from = 0;
+ let bytes = self.as_bytes();
+ for (i, &b) in bytes.iter().enumerate() {
+ if !is_visible_ascii(b) || b == b'"' {
+ if from != i {
+ f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..i]) })?;
+ }
+ if b == b'"' {
+ f.write_str("\\\"")?;
+ } else {
+ write!(f, "\\x{:x}", b)?;
+ }
+ from = i + 1;
+ }
+ }
+
+ f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..]) })?;
+ f.write_str("\"")
+ }
+ }
+}
+
+impl From<HeaderName> for HeaderValue {
+ #[inline]
+ fn from(h: HeaderName) -> HeaderValue {
+ HeaderValue {
+ inner: h.into_bytes(),
+ is_sensitive: false,
+ }
+ }
+}
+
+macro_rules! from_integers {
+ ($($name:ident: $t:ident => $max_len:expr),*) => {$(
+ impl From<$t> for HeaderValue {
+ fn from(num: $t) -> HeaderValue {
+ let mut buf = if mem::size_of::<BytesMut>() - 1 < $max_len {
+ // On 32bit platforms, BytesMut max inline size
+ // is 15 bytes, but the $max_len could be bigger.
+ //
+ // The likelihood of the number *actually* being
+ // that big is very small, so only allocate
+ // if the number needs that space.
+ //
+ // The largest decimal number in 15 digits:
+ // It wold be 10.pow(15) - 1, but this is a constant
+ // version.
+ if num as u64 > 999_999_999_999_999_999 {
+ BytesMut::with_capacity($max_len)
+ } else {
+ // fits inline...
+ BytesMut::new()
+ }
+ } else {
+ // full value fits inline, so don't allocate!
+ BytesMut::new()
+ };
+ let _ = buf.write_str(::itoa::Buffer::new().format(num));
+ HeaderValue {
+ inner: buf.freeze(),
+ is_sensitive: false,
+ }
+ }
+ }
+
+ #[test]
+ fn $name() {
+ let n: $t = 55;
+ let val = HeaderValue::from(n);
+ assert_eq!(val, &n.to_string());
+
+ let n = ::std::$t::MAX;
+ let val = HeaderValue::from(n);
+ assert_eq!(val, &n.to_string());
+ }
+ )*};
+}
+
+from_integers! {
+ // integer type => maximum decimal length
+
+ // u8 purposely left off... HeaderValue::from(b'3') could be confusing
+ from_u16: u16 => 5,
+ from_i16: i16 => 6,
+ from_u32: u32 => 10,
+ from_i32: i32 => 11,
+ from_u64: u64 => 20,
+ from_i64: i64 => 20
+}
+
+#[cfg(target_pointer_width = "16")]
+from_integers! {
+ from_usize: usize => 5,
+ from_isize: isize => 6
+}
+
+#[cfg(target_pointer_width = "32")]
+from_integers! {
+ from_usize: usize => 10,
+ from_isize: isize => 11
+}
+
+#[cfg(target_pointer_width = "64")]
+from_integers! {
+ from_usize: usize => 20,
+ from_isize: isize => 20
+}
+
+#[cfg(test)]
+mod from_header_name_tests {
+ use super::*;
+ use crate::header::map::HeaderMap;
+ use crate::header::name;
+
+ #[test]
+ fn it_can_insert_header_name_as_header_value() {
+ let mut map = HeaderMap::new();
+ map.insert(name::UPGRADE, name::SEC_WEBSOCKET_PROTOCOL.into());
+ map.insert(
+ name::ACCEPT,
+ name::HeaderName::from_bytes(b"hello-world").unwrap().into(),
+ );
+
+ assert_eq!(
+ map.get(name::UPGRADE).unwrap(),
+ HeaderValue::from_bytes(b"sec-websocket-protocol").unwrap()
+ );
+
+ assert_eq!(
+ map.get(name::ACCEPT).unwrap(),
+ HeaderValue::from_bytes(b"hello-world").unwrap()
+ );
+ }
+}
+
+impl FromStr for HeaderValue {
+ type Err = InvalidHeaderValue;
+
+ #[inline]
+ fn from_str(s: &str) -> Result<HeaderValue, Self::Err> {
+ HeaderValue::from_str(s)
+ }
+}
+
+impl<'a> From<&'a HeaderValue> for HeaderValue {
+ #[inline]
+ fn from(t: &'a HeaderValue) -> Self {
+ t.clone()
+ }
+}
+
+impl<'a> TryFrom<&'a str> for HeaderValue {
+ type Error = InvalidHeaderValue;
+
+ #[inline]
+ fn try_from(t: &'a str) -> Result<Self, Self::Error> {
+ t.parse()
+ }
+}
+
+impl<'a> TryFrom<&'a String> for HeaderValue {
+ type Error = InvalidHeaderValue;
+ #[inline]
+ fn try_from(s: &'a String) -> Result<Self, Self::Error> {
+ Self::from_bytes(s.as_bytes())
+ }
+}
+
+impl<'a> TryFrom<&'a [u8]> for HeaderValue {
+ type Error = InvalidHeaderValue;
+
+ #[inline]
+ fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
+ HeaderValue::from_bytes(t)
+ }
+}
+
+impl TryFrom<String> for HeaderValue {
+ type Error = InvalidHeaderValue;
+
+ #[inline]
+ fn try_from(t: String) -> Result<Self, Self::Error> {
+ HeaderValue::from_shared(t.into())
+ }
+}
+
+impl TryFrom<Vec<u8>> for HeaderValue {
+ type Error = InvalidHeaderValue;
+
+ #[inline]
+ fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
+ HeaderValue::from_shared(vec.into())
+ }
+}
+
+#[cfg(test)]
+mod try_from_header_name_tests {
+ use super::*;
+ use crate::header::name;
+
+ #[test]
+ fn it_converts_using_try_from() {
+ assert_eq!(
+ HeaderValue::try_from(name::UPGRADE).unwrap(),
+ HeaderValue::from_bytes(b"upgrade").unwrap()
+ );
+ }
+}
+
+const fn is_visible_ascii(b: u8) -> bool {
+ b >= 32 && b < 127 || b == b'\t'
+}
+
+#[inline]
+fn is_valid(b: u8) -> bool {
+ b >= 32 && b != 127 || b == b'\t'
+}
+
+impl fmt::Debug for InvalidHeaderValue {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("InvalidHeaderValue")
+ // skip _priv noise
+ .finish()
+ }
+}
+
+impl fmt::Display for InvalidHeaderValue {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("failed to parse header value")
+ }
+}
+
+impl Error for InvalidHeaderValue {}
+
+impl fmt::Display for ToStrError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("failed to convert header to a str")
+ }
+}
+
+impl Error for ToStrError {}
+
+// ===== PartialEq / PartialOrd =====
+
+impl PartialEq for HeaderValue {
+ #[inline]
+ fn eq(&self, other: &HeaderValue) -> bool {
+ self.inner == other.inner
+ }
+}
+
+impl Eq for HeaderValue {}
+
+impl PartialOrd for HeaderValue {
+ #[inline]
+ fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
+ self.inner.partial_cmp(&other.inner)
+ }
+}
+
+impl Ord for HeaderValue {
+ #[inline]
+ fn cmp(&self, other: &Self) -> cmp::Ordering {
+ self.inner.cmp(&other.inner)
+ }
+}
+
+impl PartialEq<str> for HeaderValue {
+ #[inline]
+ fn eq(&self, other: &str) -> bool {
+ self.inner == other.as_bytes()
+ }
+}
+
+impl PartialEq<[u8]> for HeaderValue {
+ #[inline]
+ fn eq(&self, other: &[u8]) -> bool {
+ self.inner == other
+ }
+}
+
+impl PartialOrd<str> for HeaderValue {
+ #[inline]
+ fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
+ (*self.inner).partial_cmp(other.as_bytes())
+ }
+}
+
+impl PartialOrd<[u8]> for HeaderValue {
+ #[inline]
+ fn partial_cmp(&self, other: &[u8]) -> Option<cmp::Ordering> {
+ (*self.inner).partial_cmp(other)
+ }
+}
+
+impl PartialEq<HeaderValue> for str {
+ #[inline]
+ fn eq(&self, other: &HeaderValue) -> bool {
+ *other == *self
+ }
+}
+
+impl PartialEq<HeaderValue> for [u8] {
+ #[inline]
+ fn eq(&self, other: &HeaderValue) -> bool {
+ *other == *self
+ }
+}
+
+impl PartialOrd<HeaderValue> for str {
+ #[inline]
+ fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
+ self.as_bytes().partial_cmp(other.as_bytes())
+ }
+}
+
+impl PartialOrd<HeaderValue> for [u8] {
+ #[inline]
+ fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
+ self.partial_cmp(other.as_bytes())
+ }
+}
+
+impl PartialEq<String> for HeaderValue {
+ #[inline]
+ fn eq(&self, other: &String) -> bool {
+ *self == &other[..]
+ }
+}
+
+impl PartialOrd<String> for HeaderValue {
+ #[inline]
+ fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
+ self.inner.partial_cmp(other.as_bytes())
+ }
+}
+
+impl PartialEq<HeaderValue> for String {
+ #[inline]
+ fn eq(&self, other: &HeaderValue) -> bool {
+ *other == *self
+ }
+}
+
+impl PartialOrd<HeaderValue> for String {
+ #[inline]
+ fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
+ self.as_bytes().partial_cmp(other.as_bytes())
+ }
+}
+
+impl<'a> PartialEq<HeaderValue> for &'a HeaderValue {
+ #[inline]
+ fn eq(&self, other: &HeaderValue) -> bool {
+ **self == *other
+ }
+}
+
+impl<'a> PartialOrd<HeaderValue> for &'a HeaderValue {
+ #[inline]
+ fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
+ (**self).partial_cmp(other)
+ }
+}
+
+impl<'a, T: ?Sized> PartialEq<&'a T> for HeaderValue
+where
+ HeaderValue: PartialEq<T>,
+{
+ #[inline]
+ fn eq(&self, other: &&'a T) -> bool {
+ *self == **other
+ }
+}
+
+impl<'a, T: ?Sized> PartialOrd<&'a T> for HeaderValue
+where
+ HeaderValue: PartialOrd<T>,
+{
+ #[inline]
+ fn partial_cmp(&self, other: &&'a T) -> Option<cmp::Ordering> {
+ self.partial_cmp(*other)
+ }
+}
+
+impl<'a> PartialEq<HeaderValue> for &'a str {
+ #[inline]
+ fn eq(&self, other: &HeaderValue) -> bool {
+ *other == *self
+ }
+}
+
+impl<'a> PartialOrd<HeaderValue> for &'a str {
+ #[inline]
+ fn partial_cmp(&self, other: &HeaderValue) -> Option<cmp::Ordering> {
+ self.as_bytes().partial_cmp(other.as_bytes())
+ }
+}
+
+#[test]
+fn test_try_from() {
+ HeaderValue::try_from(vec![127]).unwrap_err();
+}
+
+#[test]
+fn test_debug() {
+ let cases = &[
+ ("hello", "\"hello\""),
+ ("hello \"world\"", "\"hello \\\"world\\\"\""),
+ ("\u{7FFF}hello", "\"\\xe7\\xbf\\xbfhello\""),
+ ];
+
+ for &(value, expected) in cases {
+ let val = HeaderValue::from_bytes(value.as_bytes()).unwrap();
+ let actual = format!("{:?}", val);
+ assert_eq!(expected, actual);
+ }
+
+ let mut sensitive = HeaderValue::from_static("password");
+ sensitive.set_sensitive(true);
+ assert_eq!("Sensitive", format!("{:?}", sensitive));
+}