summaryrefslogtreecommitdiff
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.rs798
1 files changed, 0 insertions, 798 deletions
diff --git a/vendor/http/src/header/value.rs b/vendor/http/src/header/value.rs
deleted file mode 100644
index 99d1e155..00000000
--- a/vendor/http/src/header/value.rs
+++ /dev/null
@@ -1,798 +0,0 @@
-use bytes::{Bytes, BytesMut};
-
-use std::convert::TryFrom;
-use std::error::Error;
-use std::fmt::Write;
-use std::hash::{Hash, Hasher};
-use std::str::FromStr;
-use std::{cmp, fmt, 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)]
-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]) {
- // TODO: When msrv is bumped to larger than 1.57, this should be
- // replaced with `panic!` macro.
- // https://blog.rust-lang.org/2021/12/02/Rust-1.57.0.html#panic-in-const-contexts
- //
- // See the panics section of this method's document for details.
- #[allow(clippy::no_effect, clippy::out_of_bounds_indexing)]
- ([] 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]
- #[allow(clippy::should_implement_trait)]
- 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.
- ///
- /// ## Panics
- /// In a debug build this will panic if `src` is not valid UTF-8.
- ///
- /// ## Safety
- /// `src` must contain valid UTF-8. In a release build it is undefined
- /// behaviour to call this with `src` that is not valid UTF-8.
- 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 = BytesMut::with_capacity($max_len);
- 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 Hash for HeaderValue {
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.inner.hash(state);
- }
-}
-
-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> {
- Some(self.cmp(other))
- }
-}
-
-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));
-}