RPM build fix (reverted CI changes which will need to be un-reverted or made conditional) and vendor Rust dependencies to make builds much faster in any CI system.

This commit is contained in:
Adam Ierymenko
2022-06-08 07:32:16 -04:00
parent 373ca30269
commit d5ca4e5f52
12611 changed files with 2898014 additions and 284 deletions

85
zeroidc/vendor/http/src/byte_str.rs vendored Normal file
View File

@@ -0,0 +1,85 @@
use bytes::Bytes;
use std::{ops, str};
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub(crate) struct ByteStr {
// Invariant: bytes contains valid UTF-8
bytes: Bytes,
}
impl ByteStr {
#[inline]
pub fn new() -> ByteStr {
ByteStr {
// Invariant: the empty slice is trivially valid UTF-8.
bytes: Bytes::new(),
}
}
#[inline]
pub const fn from_static(val: &'static str) -> ByteStr {
ByteStr {
// Invariant: val is a str so contains vaid UTF-8.
bytes: Bytes::from_static(val.as_bytes()),
}
}
#[inline]
/// ## Panics
/// In a debug build this will panic if `bytes` is not valid UTF-8.
///
/// ## Safety
/// `bytes` must contain valid UTF-8. In a release build it is undefined
/// behaviour to call this with `bytes` that is not valid UTF-8.
pub unsafe fn from_utf8_unchecked(bytes: Bytes) -> ByteStr {
if cfg!(debug_assertions) {
match str::from_utf8(&bytes) {
Ok(_) => (),
Err(err) => panic!(
"ByteStr::from_utf8_unchecked() with invalid bytes; error = {}, bytes = {:?}",
err, bytes
),
}
}
// Invariant: assumed by the safety requirements of this function.
ByteStr { bytes: bytes }
}
}
impl ops::Deref for ByteStr {
type Target = str;
#[inline]
fn deref(&self) -> &str {
let b: &[u8] = self.bytes.as_ref();
// Safety: the invariant of `bytes` is that it contains valid UTF-8.
unsafe { str::from_utf8_unchecked(b) }
}
}
impl From<String> for ByteStr {
#[inline]
fn from(src: String) -> ByteStr {
ByteStr {
// Invariant: src is a String so contains valid UTF-8.
bytes: Bytes::from(src),
}
}
}
impl<'a> From<&'a str> for ByteStr {
#[inline]
fn from(src: &'a str) -> ByteStr {
ByteStr {
// Invariant: src is a str so contains valid UTF-8.
bytes: Bytes::copy_from_slice(src.as_bytes()),
}
}
}
impl From<ByteStr> for Bytes {
fn from(src: ByteStr) -> Self {
src.bytes
}
}

17
zeroidc/vendor/http/src/convert.rs vendored Normal file
View File

@@ -0,0 +1,17 @@
macro_rules! if_downcast_into {
($in_ty:ty, $out_ty:ty, $val:ident, $body:expr) => ({
if std::any::TypeId::of::<$in_ty>() == std::any::TypeId::of::<$out_ty>() {
// Store the value in an `Option` so we can `take`
// it after casting to `&mut dyn Any`.
let mut slot = Some($val);
// Re-write the `$val` ident with the downcasted value.
let $val = (&mut slot as &mut dyn std::any::Any)
.downcast_mut::<Option<$out_ty>>()
.unwrap()
.take()
.unwrap();
// Run the $body in scope of the replaced val.
$body
}
})
}

149
zeroidc/vendor/http/src/error.rs vendored Normal file
View File

@@ -0,0 +1,149 @@
use std::error;
use std::fmt;
use std::result;
use crate::header;
use crate::method;
use crate::status;
use crate::uri;
/// A generic "error" for HTTP connections
///
/// This error type is less specific than the error returned from other
/// functions in this crate, but all other errors can be converted to this
/// error. Consumers of this crate can typically consume and work with this form
/// of error for conversions with the `?` operator.
pub struct Error {
inner: ErrorKind,
}
/// A `Result` typedef to use with the `http::Error` type
pub type Result<T> = result::Result<T, Error>;
enum ErrorKind {
StatusCode(status::InvalidStatusCode),
Method(method::InvalidMethod),
Uri(uri::InvalidUri),
UriParts(uri::InvalidUriParts),
HeaderName(header::InvalidHeaderName),
HeaderValue(header::InvalidHeaderValue),
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("http::Error")
// Skip the noise of the ErrorKind enum
.field(&self.get_ref())
.finish()
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.get_ref(), f)
}
}
impl Error {
/// Return true if the underlying error has the same type as T.
pub fn is<T: error::Error + 'static>(&self) -> bool {
self.get_ref().is::<T>()
}
/// Return a reference to the lower level, inner error.
pub fn get_ref(&self) -> &(dyn error::Error + 'static) {
use self::ErrorKind::*;
match self.inner {
StatusCode(ref e) => e,
Method(ref e) => e,
Uri(ref e) => e,
UriParts(ref e) => e,
HeaderName(ref e) => e,
HeaderValue(ref e) => e,
}
}
}
impl error::Error for Error {
// Return any available cause from the inner error. Note the inner error is
// not itself the cause.
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
self.get_ref().source()
}
}
impl From<status::InvalidStatusCode> for Error {
fn from(err: status::InvalidStatusCode) -> Error {
Error {
inner: ErrorKind::StatusCode(err),
}
}
}
impl From<method::InvalidMethod> for Error {
fn from(err: method::InvalidMethod) -> Error {
Error {
inner: ErrorKind::Method(err),
}
}
}
impl From<uri::InvalidUri> for Error {
fn from(err: uri::InvalidUri) -> Error {
Error {
inner: ErrorKind::Uri(err),
}
}
}
impl From<uri::InvalidUriParts> for Error {
fn from(err: uri::InvalidUriParts) -> Error {
Error {
inner: ErrorKind::UriParts(err),
}
}
}
impl From<header::InvalidHeaderName> for Error {
fn from(err: header::InvalidHeaderName) -> Error {
Error {
inner: ErrorKind::HeaderName(err),
}
}
}
impl From<header::InvalidHeaderValue> for Error {
fn from(err: header::InvalidHeaderValue) -> Error {
Error {
inner: ErrorKind::HeaderValue(err),
}
}
}
impl From<std::convert::Infallible> for Error {
fn from(err: std::convert::Infallible) -> Error {
match err {}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn inner_error_is_invalid_status_code() {
if let Err(e) = status::StatusCode::from_u16(6666) {
let err: Error = e.into();
let ie = err.get_ref();
assert!(!ie.is::<header::InvalidHeaderValue>());
assert!(ie.is::<status::InvalidStatusCode>());
ie.downcast_ref::<status::InvalidStatusCode>().unwrap();
assert!(!err.is::<header::InvalidHeaderValue>());
assert!(err.is::<status::InvalidStatusCode>());
} else {
panic!("Bad status allowed!");
}
}
}

250
zeroidc/vendor/http/src/extensions.rs vendored Normal file
View File

@@ -0,0 +1,250 @@
use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::fmt;
use std::hash::{BuildHasherDefault, Hasher};
type AnyMap = HashMap<TypeId, Box<dyn Any + Send + Sync>, BuildHasherDefault<IdHasher>>;
// With TypeIds as keys, there's no need to hash them. They are already hashes
// themselves, coming from the compiler. The IdHasher just holds the u64 of
// the TypeId, and then returns it, instead of doing any bit fiddling.
#[derive(Default)]
struct IdHasher(u64);
impl Hasher for IdHasher {
fn write(&mut self, _: &[u8]) {
unreachable!("TypeId calls write_u64");
}
#[inline]
fn write_u64(&mut self, id: u64) {
self.0 = id;
}
#[inline]
fn finish(&self) -> u64 {
self.0
}
}
/// A type map of protocol extensions.
///
/// `Extensions` can be used by `Request` and `Response` to store
/// extra data derived from the underlying protocol.
#[derive(Default)]
pub struct Extensions {
// If extensions are never used, no need to carry around an empty HashMap.
// That's 3 words. Instead, this is only 1 word.
map: Option<Box<AnyMap>>,
}
impl Extensions {
/// Create an empty `Extensions`.
#[inline]
pub fn new() -> Extensions {
Extensions { map: None }
}
/// Insert a type into this `Extensions`.
///
/// If a extension of this type already existed, it will
/// be returned.
///
/// # Example
///
/// ```
/// # use http::Extensions;
/// let mut ext = Extensions::new();
/// assert!(ext.insert(5i32).is_none());
/// assert!(ext.insert(4u8).is_none());
/// assert_eq!(ext.insert(9i32), Some(5i32));
/// ```
pub fn insert<T: Send + Sync + 'static>(&mut self, val: T) -> Option<T> {
self.map
.get_or_insert_with(|| Box::new(HashMap::default()))
.insert(TypeId::of::<T>(), Box::new(val))
.and_then(|boxed| {
(boxed as Box<dyn Any + 'static>)
.downcast()
.ok()
.map(|boxed| *boxed)
})
}
/// Get a reference to a type previously inserted on this `Extensions`.
///
/// # Example
///
/// ```
/// # use http::Extensions;
/// let mut ext = Extensions::new();
/// assert!(ext.get::<i32>().is_none());
/// ext.insert(5i32);
///
/// assert_eq!(ext.get::<i32>(), Some(&5i32));
/// ```
pub fn get<T: Send + Sync + 'static>(&self) -> Option<&T> {
self.map
.as_ref()
.and_then(|map| map.get(&TypeId::of::<T>()))
.and_then(|boxed| (&**boxed as &(dyn Any + 'static)).downcast_ref())
}
/// Get a mutable reference to a type previously inserted on this `Extensions`.
///
/// # Example
///
/// ```
/// # use http::Extensions;
/// let mut ext = Extensions::new();
/// ext.insert(String::from("Hello"));
/// ext.get_mut::<String>().unwrap().push_str(" World");
///
/// assert_eq!(ext.get::<String>().unwrap(), "Hello World");
/// ```
pub fn get_mut<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
self.map
.as_mut()
.and_then(|map| map.get_mut(&TypeId::of::<T>()))
.and_then(|boxed| (&mut **boxed as &mut (dyn Any + 'static)).downcast_mut())
}
/// Remove a type from this `Extensions`.
///
/// If a extension of this type existed, it will be returned.
///
/// # Example
///
/// ```
/// # use http::Extensions;
/// let mut ext = Extensions::new();
/// ext.insert(5i32);
/// assert_eq!(ext.remove::<i32>(), Some(5i32));
/// assert!(ext.get::<i32>().is_none());
/// ```
pub fn remove<T: Send + Sync + 'static>(&mut self) -> Option<T> {
self.map
.as_mut()
.and_then(|map| map.remove(&TypeId::of::<T>()))
.and_then(|boxed| {
(boxed as Box<dyn Any + 'static>)
.downcast()
.ok()
.map(|boxed| *boxed)
})
}
/// Clear the `Extensions` of all inserted extensions.
///
/// # Example
///
/// ```
/// # use http::Extensions;
/// let mut ext = Extensions::new();
/// ext.insert(5i32);
/// ext.clear();
///
/// assert!(ext.get::<i32>().is_none());
/// ```
#[inline]
pub fn clear(&mut self) {
if let Some(ref mut map) = self.map {
map.clear();
}
}
/// Check whether the extension set is empty or not.
///
/// # Example
///
/// ```
/// # use http::Extensions;
/// let mut ext = Extensions::new();
/// assert!(ext.is_empty());
/// ext.insert(5i32);
/// assert!(!ext.is_empty());
/// ```
#[inline]
pub fn is_empty(&self) -> bool {
self.map
.as_ref()
.map_or(true, |map| map.is_empty())
}
/// Get the numer of extensions available.
///
/// # Example
///
/// ```
/// # use http::Extensions;
/// let mut ext = Extensions::new();
/// assert_eq!(ext.len(), 0);
/// ext.insert(5i32);
/// assert_eq!(ext.len(), 1);
/// ```
#[inline]
pub fn len(&self) -> usize {
self.map
.as_ref()
.map_or(0, |map| map.len())
}
/// Extends `self` with another `Extensions`.
///
/// If an instance of a specific type exists in both, the one in `self` is overwritten with the
/// one from `other`.
///
/// # Example
///
/// ```
/// # use http::Extensions;
/// let mut ext_a = Extensions::new();
/// ext_a.insert(8u8);
/// ext_a.insert(16u16);
///
/// let mut ext_b = Extensions::new();
/// ext_b.insert(4u8);
/// ext_b.insert("hello");
///
/// ext_a.extend(ext_b);
/// assert_eq!(ext_a.len(), 3);
/// assert_eq!(ext_a.get::<u8>(), Some(&4u8));
/// assert_eq!(ext_a.get::<u16>(), Some(&16u16));
/// assert_eq!(ext_a.get::<&'static str>().copied(), Some("hello"));
/// ```
pub fn extend(&mut self, other: Self) {
if let Some(other) = other.map {
if let Some(map) = &mut self.map {
map.extend(*other);
} else {
self.map = Some(other);
}
}
}
}
impl fmt::Debug for Extensions {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Extensions").finish()
}
}
#[test]
fn test_extensions() {
#[derive(Debug, PartialEq)]
struct MyType(i32);
let mut extensions = Extensions::new();
extensions.insert(5i32);
extensions.insert(MyType(10));
assert_eq!(extensions.get(), Some(&5i32));
assert_eq!(extensions.get_mut(), Some(&mut 5i32));
assert_eq!(extensions.remove::<i32>(), Some(5i32));
assert!(extensions.get::<i32>().is_none());
assert_eq!(extensions.get::<bool>(), None);
assert_eq!(extensions.get(), Some(&MyType(10)));
}

3496
zeroidc/vendor/http/src/header/map.rs vendored Normal file

File diff suppressed because it is too large Load Diff

172
zeroidc/vendor/http/src/header/mod.rs vendored Normal file
View File

@@ -0,0 +1,172 @@
//! HTTP header types
//!
//! The module provides [`HeaderName`], [`HeaderMap`], and a number of types
//! used for interacting with `HeaderMap`. These types allow representing both
//! HTTP/1 and HTTP/2 headers.
//!
//! # `HeaderName`
//!
//! The `HeaderName` type represents both standard header names as well as
//! custom header names. The type handles the case insensitive nature of header
//! names and is used as the key portion of `HeaderMap`. Header names are
//! normalized to lower case. In other words, when creating a `HeaderName` with
//! a string, even if upper case characters are included, when getting a string
//! representation of the `HeaderName`, it will be all lower case. This allows
//! for faster `HeaderMap` comparison operations.
//!
//! The internal representation is optimized to efficiently handle the cases
//! most commonly encountered when working with HTTP. Standard header names are
//! special cased and are represented internally as an enum. Short custom
//! headers will be stored directly in the `HeaderName` struct and will not
//! incur any allocation overhead, however longer strings will require an
//! allocation for storage.
//!
//! ## Limitations
//!
//! `HeaderName` has a max length of 32,768 for header names. Attempting to
//! parse longer names will result in a panic.
//!
//! # `HeaderMap`
//!
//! `HeaderMap` is a map structure of header names highly optimized for use
//! cases common with HTTP. It is a [multimap] structure, where each header name
//! may have multiple associated header values. Given this, some of the APIs
//! diverge from [`HashMap`].
//!
//! ## Overview
//!
//! Just like `HashMap` in Rust's stdlib, `HeaderMap` is based on [Robin Hood
//! hashing]. This algorithm tends to reduce the worst case search times in the
//! table and enables high load factors without seriously affecting performance.
//! Internally, keys and values are stored in vectors. As such, each insertion
//! will not incur allocation overhead. However, once the underlying vector
//! storage is full, a larger vector must be allocated and all values copied.
//!
//! ## Deterministic ordering
//!
//! Unlike Rust's `HashMap`, values in `HeaderMap` are deterministically
//! ordered. Roughly, values are ordered by insertion. This means that a
//! function that deterministically operates on a header map can rely on the
//! iteration order to remain consistent across processes and platforms.
//!
//! ## Adaptive hashing
//!
//! `HeaderMap` uses an adaptive hashing strategy in order to efficiently handle
//! most common cases. All standard headers have statically computed hash values
//! which removes the need to perform any hashing of these headers at runtime.
//! The default hash function emphasizes performance over robustness. However,
//! `HeaderMap` detects high collision rates and switches to a secure hash
//! function in those events. The threshold is set such that only denial of
//! service attacks should trigger it.
//!
//! ## Limitations
//!
//! `HeaderMap` can store a maximum of 32,768 headers (header name / value
//! pairs). Attempting to insert more will result in a panic.
//!
//! [`HeaderName`]: struct.HeaderName.html
//! [`HeaderMap`]: struct.HeaderMap.html
//! [multimap]: https://en.wikipedia.org/wiki/Multimap
//! [`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html
//! [Robin Hood hashing]: https://en.wikipedia.org/wiki/Hash_table#Robin_Hood_hashing
mod map;
mod name;
mod value;
pub use self::map::{
AsHeaderName, Drain, Entry, GetAll, HeaderMap, IntoHeaderName, IntoIter, Iter, IterMut, Keys,
OccupiedEntry, VacantEntry, ValueDrain, ValueIter, ValueIterMut, Values, ValuesMut,
};
pub use self::name::{HeaderName, InvalidHeaderName};
pub use self::value::{HeaderValue, InvalidHeaderValue, ToStrError};
// Use header name constants
pub use self::name::{
ACCEPT,
ACCEPT_CHARSET,
ACCEPT_ENCODING,
ACCEPT_LANGUAGE,
ACCEPT_RANGES,
ACCESS_CONTROL_ALLOW_CREDENTIALS,
ACCESS_CONTROL_ALLOW_HEADERS,
ACCESS_CONTROL_ALLOW_METHODS,
ACCESS_CONTROL_ALLOW_ORIGIN,
ACCESS_CONTROL_EXPOSE_HEADERS,
ACCESS_CONTROL_MAX_AGE,
ACCESS_CONTROL_REQUEST_HEADERS,
ACCESS_CONTROL_REQUEST_METHOD,
AGE,
ALLOW,
ALT_SVC,
AUTHORIZATION,
CACHE_CONTROL,
CONNECTION,
CONTENT_DISPOSITION,
CONTENT_ENCODING,
CONTENT_LANGUAGE,
CONTENT_LENGTH,
CONTENT_LOCATION,
CONTENT_RANGE,
CONTENT_SECURITY_POLICY,
CONTENT_SECURITY_POLICY_REPORT_ONLY,
CONTENT_TYPE,
COOKIE,
DNT,
DATE,
ETAG,
EXPECT,
EXPIRES,
FORWARDED,
FROM,
HOST,
IF_MATCH,
IF_MODIFIED_SINCE,
IF_NONE_MATCH,
IF_RANGE,
IF_UNMODIFIED_SINCE,
LAST_MODIFIED,
LINK,
LOCATION,
MAX_FORWARDS,
ORIGIN,
PRAGMA,
PROXY_AUTHENTICATE,
PROXY_AUTHORIZATION,
PUBLIC_KEY_PINS,
PUBLIC_KEY_PINS_REPORT_ONLY,
RANGE,
REFERER,
REFERRER_POLICY,
REFRESH,
RETRY_AFTER,
SEC_WEBSOCKET_ACCEPT,
SEC_WEBSOCKET_EXTENSIONS,
SEC_WEBSOCKET_KEY,
SEC_WEBSOCKET_PROTOCOL,
SEC_WEBSOCKET_VERSION,
SERVER,
SET_COOKIE,
STRICT_TRANSPORT_SECURITY,
TE,
TRAILER,
TRANSFER_ENCODING,
UPGRADE,
UPGRADE_INSECURE_REQUESTS,
USER_AGENT,
VARY,
VIA,
WARNING,
WWW_AUTHENTICATE,
X_CONTENT_TYPE_OPTIONS,
X_DNS_PREFETCH_CONTROL,
X_FRAME_OPTIONS,
X_XSS_PROTECTION,
};
/// Maximum length of a header name
///
/// Generally, 64kb for a header name is WAY too much than would ever be needed
/// in practice. Restricting it to this size enables using `u16` values to
/// represent offsets when dealing with header names.
const MAX_HEADER_NAME_LEN: usize = (1 << 16) - 1;

1856
zeroidc/vendor/http/src/header/name.rs vendored Normal file

File diff suppressed because it is too large Load Diff

795
zeroidc/vendor/http/src/header/value.rs vendored Normal file
View File

@@ -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));
}

211
zeroidc/vendor/http/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,211 @@
#![doc(html_root_url = "https://docs.rs/http/0.2.8")]
//! A general purpose library of common HTTP types
//!
//! This crate is a general purpose library for common types found when working
//! with the HTTP protocol. You'll find `Request` and `Response` types for
//! working as either a client or a server as well as all of their components.
//! Notably you'll find `Uri` for what a `Request` is requesting, a `Method`
//! for how it's being requested, a `StatusCode` for what sort of response came
//! back, a `Version` for how this was communicated, and
//! `HeaderName`/`HeaderValue` definitions to get grouped in a `HeaderMap` to
//! work with request/response headers.
//!
//! You will notably *not* find an implementation of sending requests or
//! spinning up a server in this crate. It's intended that this crate is the
//! "standard library" for HTTP clients and servers without dictating any
//! particular implementation. Note that this crate is still early on in its
//! lifecycle so the support libraries that integrate with the `http` crate are
//! a work in progress! Stay tuned and we'll be sure to highlight crates here
//! in the future.
//!
//! ## Requests and Responses
//!
//! Perhaps the main two types in this crate are the `Request` and `Response`
//! types. A `Request` could either be constructed to get sent off as a client
//! or it can also be received to generate a `Response` for a server. Similarly
//! as a client a `Response` is what you get after sending a `Request`, whereas
//! on a server you'll be manufacturing a `Response` to send back to the client.
//!
//! Each type has a number of accessors for the component fields. For as a
//! server you might want to inspect a requests URI to dispatch it:
//!
//! ```
//! use http::{Request, Response};
//!
//! fn response(req: Request<()>) -> http::Result<Response<()>> {
//! match req.uri().path() {
//! "/" => index(req),
//! "/foo" => foo(req),
//! "/bar" => bar(req),
//! _ => not_found(req),
//! }
//! }
//! # fn index(_req: Request<()>) -> http::Result<Response<()>> { panic!() }
//! # fn foo(_req: Request<()>) -> http::Result<Response<()>> { panic!() }
//! # fn bar(_req: Request<()>) -> http::Result<Response<()>> { panic!() }
//! # fn not_found(_req: Request<()>) -> http::Result<Response<()>> { panic!() }
//! ```
//!
//! On a `Request` you'll also find accessors like `method` to return a
//! `Method` and `headers` to inspect the various headers. A `Response`
//! has similar methods for headers, the status code, etc.
//!
//! In addition to getters, request/response types also have mutable accessors
//! to edit the request/response:
//!
//! ```
//! use http::{HeaderValue, Response, StatusCode};
//! use http::header::CONTENT_TYPE;
//!
//! fn add_server_headers<T>(response: &mut Response<T>) {
//! response.headers_mut()
//! .insert(CONTENT_TYPE, HeaderValue::from_static("text/html"));
//! *response.status_mut() = StatusCode::OK;
//! }
//! ```
//!
//! And finally, one of the most important aspects of requests/responses, the
//! body! The `Request` and `Response` types in this crate are *generic* in
//! what their body is. This allows downstream libraries to use different
//! representations such as `Request<Vec<u8>>`, `Response<impl Read>`,
//! `Request<impl Stream<Item = Vec<u8>, Error = _>>`, or even
//! `Response<MyCustomType>` where the custom type was deserialized from JSON.
//!
//! The body representation is intentionally flexible to give downstream
//! libraries maximal flexibility in implementing the body as appropriate.
//!
//! ## HTTP Headers
//!
//! Another major piece of functionality in this library is HTTP header
//! interpretation and generation. The `HeaderName` type serves as a way to
//! define header *names*, or what's to the left of the colon. A `HeaderValue`
//! conversely is the header *value*, or what's to the right of a colon.
//!
//! For example, if you have an HTTP request that looks like:
//!
//! ```http
//! GET /foo HTTP/1.1
//! Accept: text/html
//! ```
//!
//! Then `"Accept"` is a `HeaderName` while `"text/html"` is a `HeaderValue`.
//! Each of these is a dedicated type to allow for a number of interesting
//! optimizations and to also encode the static guarantees of each type. For
//! example a `HeaderName` is always a valid `&str`, but a `HeaderValue` may
//! not be valid UTF-8.
//!
//! The most common header names are already defined for you as constant values
//! in the `header` module of this crate. For example:
//!
//! ```
//! use http::header::{self, HeaderName};
//!
//! let name: HeaderName = header::ACCEPT;
//! assert_eq!(name.as_str(), "accept");
//! ```
//!
//! You can, however, also parse header names from strings:
//!
//! ```
//! use http::header::{self, HeaderName};
//!
//! let name = "Accept".parse::<HeaderName>().unwrap();
//! assert_eq!(name, header::ACCEPT);
//! ```
//!
//! Header values can be created from string literals through the `from_static`
//! function:
//!
//! ```
//! use http::HeaderValue;
//!
//! let value = HeaderValue::from_static("text/html");
//! assert_eq!(value.as_bytes(), b"text/html");
//! ```
//!
//! And header values can also be parsed like names:
//!
//! ```
//! use http::HeaderValue;
//!
//! let value = "text/html";
//! let value = value.parse::<HeaderValue>().unwrap();
//! ```
//!
//! Most HTTP requests and responses tend to come with more than one header, so
//! it's not too useful to just work with names and values only! This crate also
//! provides a `HeaderMap` type which is a specialized hash map for keys as
//! `HeaderName` and generic values. This type, like header names, is optimized
//! for common usage but should continue to scale with your needs over time.
//!
//! # URIs
//!
//! Each HTTP `Request` has an associated URI with it. This may just be a path
//! like `/index.html` but it could also be an absolute URL such as
//! `https://www.rust-lang.org/index.html`. A `URI` has a number of accessors to
//! interpret it:
//!
//! ```
//! use http::Uri;
//! use http::uri::Scheme;
//!
//! let uri = "https://www.rust-lang.org/index.html".parse::<Uri>().unwrap();
//!
//! assert_eq!(uri.scheme(), Some(&Scheme::HTTPS));
//! assert_eq!(uri.host(), Some("www.rust-lang.org"));
//! assert_eq!(uri.path(), "/index.html");
//! assert_eq!(uri.query(), None);
//! ```
#![deny(warnings, missing_docs, missing_debug_implementations)]
#[cfg(test)]
#[macro_use]
extern crate doc_comment;
#[cfg(test)]
doctest!("../README.md");
#[macro_use]
mod convert;
pub mod header;
pub mod method;
pub mod request;
pub mod response;
pub mod status;
pub mod uri;
pub mod version;
mod byte_str;
mod error;
mod extensions;
pub use crate::error::{Error, Result};
pub use crate::extensions::Extensions;
#[doc(no_inline)]
pub use crate::header::{HeaderMap, HeaderValue};
pub use crate::method::Method;
pub use crate::request::Request;
pub use crate::response::Response;
pub use crate::status::StatusCode;
pub use crate::uri::Uri;
pub use crate::version::Version;
fn _assert_types() {
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}
assert_send::<Request<()>>();
assert_send::<Response<()>>();
assert_sync::<Request<()>>();
assert_sync::<Response<()>>();
}
mod sealed {
/// Private trait to this crate to prevent traits from being implemented in
/// downstream crates.
pub trait Sealed {}
}

473
zeroidc/vendor/http/src/method.rs vendored Normal file
View File

@@ -0,0 +1,473 @@
//! The HTTP request method
//!
//! This module contains HTTP-method related structs and errors and such. The
//! main type of this module, `Method`, is also reexported at the root of the
//! crate as `http::Method` and is intended for import through that location
//! primarily.
//!
//! # Examples
//!
//! ```
//! use http::Method;
//!
//! assert_eq!(Method::GET, Method::from_bytes(b"GET").unwrap());
//! assert!(Method::GET.is_idempotent());
//! assert_eq!(Method::POST.as_str(), "POST");
//! ```
use self::Inner::*;
use self::extension::{InlineExtension, AllocatedExtension};
use std::convert::AsRef;
use std::error::Error;
use std::str::FromStr;
use std::convert::TryFrom;
use std::{fmt, str};
/// The Request Method (VERB)
///
/// This type also contains constants for a number of common HTTP methods such
/// as GET, POST, etc.
///
/// Currently includes 8 variants representing the 8 methods defined in
/// [RFC 7230](https://tools.ietf.org/html/rfc7231#section-4.1), plus PATCH,
/// and an Extension variant for all extensions.
///
/// # Examples
///
/// ```
/// use http::Method;
///
/// assert_eq!(Method::GET, Method::from_bytes(b"GET").unwrap());
/// assert!(Method::GET.is_idempotent());
/// assert_eq!(Method::POST.as_str(), "POST");
/// ```
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Method(Inner);
/// A possible error value when converting `Method` from bytes.
pub struct InvalidMethod {
_priv: (),
}
#[derive(Clone, PartialEq, Eq, Hash)]
enum Inner {
Options,
Get,
Post,
Put,
Delete,
Head,
Trace,
Connect,
Patch,
// If the extension is short enough, store it inline
ExtensionInline(InlineExtension),
// Otherwise, allocate it
ExtensionAllocated(AllocatedExtension),
}
impl Method {
/// GET
pub const GET: Method = Method(Get);
/// POST
pub const POST: Method = Method(Post);
/// PUT
pub const PUT: Method = Method(Put);
/// DELETE
pub const DELETE: Method = Method(Delete);
/// HEAD
pub const HEAD: Method = Method(Head);
/// OPTIONS
pub const OPTIONS: Method = Method(Options);
/// CONNECT
pub const CONNECT: Method = Method(Connect);
/// PATCH
pub const PATCH: Method = Method(Patch);
/// TRACE
pub const TRACE: Method = Method(Trace);
/// Converts a slice of bytes to an HTTP method.
pub fn from_bytes(src: &[u8]) -> Result<Method, InvalidMethod> {
match src.len() {
0 => Err(InvalidMethod::new()),
3 => match src {
b"GET" => Ok(Method(Get)),
b"PUT" => Ok(Method(Put)),
_ => Method::extension_inline(src),
},
4 => match src {
b"POST" => Ok(Method(Post)),
b"HEAD" => Ok(Method(Head)),
_ => Method::extension_inline(src),
},
5 => match src {
b"PATCH" => Ok(Method(Patch)),
b"TRACE" => Ok(Method(Trace)),
_ => Method::extension_inline(src),
},
6 => match src {
b"DELETE" => Ok(Method(Delete)),
_ => Method::extension_inline(src),
},
7 => match src {
b"OPTIONS" => Ok(Method(Options)),
b"CONNECT" => Ok(Method(Connect)),
_ => Method::extension_inline(src),
},
_ => {
if src.len() < InlineExtension::MAX {
Method::extension_inline(src)
} else {
let allocated = AllocatedExtension::new(src)?;
Ok(Method(ExtensionAllocated(allocated)))
}
}
}
}
fn extension_inline(src: &[u8]) -> Result<Method, InvalidMethod> {
let inline = InlineExtension::new(src)?;
Ok(Method(ExtensionInline(inline)))
}
/// Whether a method is considered "safe", meaning the request is
/// essentially read-only.
///
/// See [the spec](https://tools.ietf.org/html/rfc7231#section-4.2.1)
/// for more words.
pub fn is_safe(&self) -> bool {
match self.0 {
Get | Head | Options | Trace => true,
_ => false,
}
}
/// Whether a method is considered "idempotent", meaning the request has
/// the same result if executed multiple times.
///
/// See [the spec](https://tools.ietf.org/html/rfc7231#section-4.2.2) for
/// more words.
pub fn is_idempotent(&self) -> bool {
match self.0 {
Put | Delete => true,
_ => self.is_safe(),
}
}
/// Return a &str representation of the HTTP method
#[inline]
pub fn as_str(&self) -> &str {
match self.0 {
Options => "OPTIONS",
Get => "GET",
Post => "POST",
Put => "PUT",
Delete => "DELETE",
Head => "HEAD",
Trace => "TRACE",
Connect => "CONNECT",
Patch => "PATCH",
ExtensionInline(ref inline) => inline.as_str(),
ExtensionAllocated(ref allocated) => allocated.as_str(),
}
}
}
impl AsRef<str> for Method {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl<'a> PartialEq<&'a Method> for Method {
#[inline]
fn eq(&self, other: &&'a Method) -> bool {
self == *other
}
}
impl<'a> PartialEq<Method> for &'a Method {
#[inline]
fn eq(&self, other: &Method) -> bool {
*self == other
}
}
impl PartialEq<str> for Method {
#[inline]
fn eq(&self, other: &str) -> bool {
self.as_ref() == other
}
}
impl PartialEq<Method> for str {
#[inline]
fn eq(&self, other: &Method) -> bool {
self == other.as_ref()
}
}
impl<'a> PartialEq<&'a str> for Method {
#[inline]
fn eq(&self, other: &&'a str) -> bool {
self.as_ref() == *other
}
}
impl<'a> PartialEq<Method> for &'a str {
#[inline]
fn eq(&self, other: &Method) -> bool {
*self == other.as_ref()
}
}
impl fmt::Debug for Method {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_ref())
}
}
impl fmt::Display for Method {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str(self.as_ref())
}
}
impl Default for Method {
#[inline]
fn default() -> Method {
Method::GET
}
}
impl<'a> From<&'a Method> for Method {
#[inline]
fn from(t: &'a Method) -> Self {
t.clone()
}
}
impl<'a> TryFrom<&'a [u8]> for Method {
type Error = InvalidMethod;
#[inline]
fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
Method::from_bytes(t)
}
}
impl<'a> TryFrom<&'a str> for Method {
type Error = InvalidMethod;
#[inline]
fn try_from(t: &'a str) -> Result<Self, Self::Error> {
TryFrom::try_from(t.as_bytes())
}
}
impl FromStr for Method {
type Err = InvalidMethod;
#[inline]
fn from_str(t: &str) -> Result<Self, Self::Err> {
TryFrom::try_from(t)
}
}
impl InvalidMethod {
fn new() -> InvalidMethod {
InvalidMethod { _priv: () }
}
}
impl fmt::Debug for InvalidMethod {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("InvalidMethod")
// skip _priv noise
.finish()
}
}
impl fmt::Display for InvalidMethod {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("invalid HTTP method")
}
}
impl Error for InvalidMethod {}
mod extension {
use super::InvalidMethod;
use std::str;
#[derive(Clone, PartialEq, Eq, Hash)]
// Invariant: the first self.1 bytes of self.0 are valid UTF-8.
pub struct InlineExtension([u8; InlineExtension::MAX], u8);
#[derive(Clone, PartialEq, Eq, Hash)]
// Invariant: self.0 contains valid UTF-8.
pub struct AllocatedExtension(Box<[u8]>);
impl InlineExtension {
// Method::from_bytes() assumes this is at least 7
pub const MAX: usize = 15;
pub fn new(src: &[u8]) -> Result<InlineExtension, InvalidMethod> {
let mut data: [u8; InlineExtension::MAX] = Default::default();
write_checked(src, &mut data)?;
// Invariant: write_checked ensures that the first src.len() bytes
// of data are valid UTF-8.
Ok(InlineExtension(data, src.len() as u8))
}
pub fn as_str(&self) -> &str {
let InlineExtension(ref data, len) = self;
// Safety: the invariant of InlineExtension ensures that the first
// len bytes of data contain valid UTF-8.
unsafe {str::from_utf8_unchecked(&data[..*len as usize])}
}
}
impl AllocatedExtension {
pub fn new(src: &[u8]) -> Result<AllocatedExtension, InvalidMethod> {
let mut data: Vec<u8> = vec![0; src.len()];
write_checked(src, &mut data)?;
// Invariant: data is exactly src.len() long and write_checked
// ensures that the first src.len() bytes of data are valid UTF-8.
Ok(AllocatedExtension(data.into_boxed_slice()))
}
pub fn as_str(&self) -> &str {
// Safety: the invariant of AllocatedExtension ensures that self.0
// contains valid UTF-8.
unsafe {str::from_utf8_unchecked(&self.0)}
}
}
// From the HTTP spec section 5.1.1, the HTTP method is case-sensitive and can
// contain the following characters:
//
// ```
// method = token
// token = 1*tchar
// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
// ```
//
// https://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01#Method
//
// Note that this definition means that any &[u8] that consists solely of valid
// characters is also valid UTF-8 because the valid method characters are a
// subset of the valid 1 byte UTF-8 encoding.
const METHOD_CHARS: [u8; 256] = [
// 0 1 2 3 4 5 6 7 8 9
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 1x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 2x
b'\0', b'\0', b'\0', b'!', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 3x
b'\0', b'\0', b'*', b'+', b'\0', b'-', b'.', b'\0', b'0', b'1', // 4x
b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'\0', b'\0', // 5x
b'\0', b'\0', b'\0', b'\0', b'\0', b'A', b'B', b'C', b'D', b'E', // 6x
b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', // 7x
b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', // 8x
b'Z', b'\0', b'\0', b'\0', b'^', b'_', b'`', b'a', b'b', b'c', // 9x
b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', // 10x
b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', // 11x
b'x', b'y', b'z', b'\0', b'|', b'\0', b'~', b'\0', b'\0', b'\0', // 12x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 13x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 14x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 15x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 16x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 17x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 18x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 19x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 20x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 21x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 22x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 23x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 24x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0' // 25x
];
// write_checked ensures (among other things) that the first src.len() bytes
// of dst are valid UTF-8
fn write_checked(src: &[u8], dst: &mut [u8]) -> Result<(), InvalidMethod> {
for (i, &b) in src.iter().enumerate() {
let b = METHOD_CHARS[b as usize];
if b == 0 {
return Err(InvalidMethod::new());
}
dst[i] = b;
}
Ok(())
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_method_eq() {
assert_eq!(Method::GET, Method::GET);
assert_eq!(Method::GET, "GET");
assert_eq!(&Method::GET, "GET");
assert_eq!("GET", Method::GET);
assert_eq!("GET", &Method::GET);
assert_eq!(&Method::GET, Method::GET);
assert_eq!(Method::GET, &Method::GET);
}
#[test]
fn test_invalid_method() {
assert!(Method::from_str("").is_err());
assert!(Method::from_bytes(b"").is_err());
assert!(Method::from_bytes(&[0xC0]).is_err()); // invalid utf-8
assert!(Method::from_bytes(&[0x10]).is_err()); // invalid method characters
}
#[test]
fn test_is_idempotent() {
assert!(Method::OPTIONS.is_idempotent());
assert!(Method::GET.is_idempotent());
assert!(Method::PUT.is_idempotent());
assert!(Method::DELETE.is_idempotent());
assert!(Method::HEAD.is_idempotent());
assert!(Method::TRACE.is_idempotent());
assert!(!Method::POST.is_idempotent());
assert!(!Method::CONNECT.is_idempotent());
assert!(!Method::PATCH.is_idempotent());
}
#[test]
fn test_extention_method() {
assert_eq!(Method::from_str("WOW").unwrap(), "WOW");
assert_eq!(Method::from_str("wOw!!").unwrap(), "wOw!!");
let long_method = "This_is_a_very_long_method.It_is_valid_but_unlikely.";
assert_eq!(Method::from_str(&long_method).unwrap(), long_method);
}
}

1096
zeroidc/vendor/http/src/request.rs vendored Normal file

File diff suppressed because it is too large Load Diff

799
zeroidc/vendor/http/src/response.rs vendored Normal file
View File

@@ -0,0 +1,799 @@
//! HTTP response types.
//!
//! This module contains structs related to HTTP responses, notably the
//! `Response` type itself as well as a builder to create responses. Typically
//! you'll import the `http::Response` type rather than reaching into this
//! module itself.
//!
//! # Examples
//!
//! Creating a `Response` to return
//!
//! ```
//! use http::{Request, Response, StatusCode};
//!
//! fn respond_to(req: Request<()>) -> http::Result<Response<()>> {
//! let mut builder = Response::builder()
//! .header("Foo", "Bar")
//! .status(StatusCode::OK);
//!
//! if req.headers().contains_key("Another-Header") {
//! builder = builder.header("Another-Header", "Ack");
//! }
//!
//! builder.body(())
//! }
//! ```
//!
//! A simple 404 handler
//!
//! ```
//! use http::{Request, Response, StatusCode};
//!
//! fn not_found(_req: Request<()>) -> http::Result<Response<()>> {
//! Response::builder()
//! .status(StatusCode::NOT_FOUND)
//! .body(())
//! }
//! ```
//!
//! Or otherwise inspecting the result of a request:
//!
//! ```no_run
//! use http::{Request, Response};
//!
//! fn get(url: &str) -> http::Result<Response<()>> {
//! // ...
//! # panic!()
//! }
//!
//! let response = get("https://www.rust-lang.org/").unwrap();
//!
//! if !response.status().is_success() {
//! panic!("failed to get a successful response status!");
//! }
//!
//! if let Some(date) = response.headers().get("Date") {
//! // we've got a `Date` header!
//! }
//!
//! let body = response.body();
//! // ...
//! ```
use std::any::Any;
use std::convert::TryFrom;
use std::fmt;
use crate::header::{HeaderMap, HeaderName, HeaderValue};
use crate::status::StatusCode;
use crate::version::Version;
use crate::{Extensions, Result};
/// Represents an HTTP response
///
/// An HTTP response consists of a head and a potentially optional body. The body
/// component is generic, enabling arbitrary types to represent the HTTP body.
/// For example, the body could be `Vec<u8>`, a `Stream` of byte chunks, or a
/// value that has been deserialized.
///
/// Typically you'll work with responses on the client side as the result of
/// sending a `Request` and on the server you'll be generating a `Response` to
/// send back to the client.
///
/// # Examples
///
/// Creating a `Response` to return
///
/// ```
/// use http::{Request, Response, StatusCode};
///
/// fn respond_to(req: Request<()>) -> http::Result<Response<()>> {
/// let mut builder = Response::builder()
/// .header("Foo", "Bar")
/// .status(StatusCode::OK);
///
/// if req.headers().contains_key("Another-Header") {
/// builder = builder.header("Another-Header", "Ack");
/// }
///
/// builder.body(())
/// }
/// ```
///
/// A simple 404 handler
///
/// ```
/// use http::{Request, Response, StatusCode};
///
/// fn not_found(_req: Request<()>) -> http::Result<Response<()>> {
/// Response::builder()
/// .status(StatusCode::NOT_FOUND)
/// .body(())
/// }
/// ```
///
/// Or otherwise inspecting the result of a request:
///
/// ```no_run
/// use http::{Request, Response};
///
/// fn get(url: &str) -> http::Result<Response<()>> {
/// // ...
/// # panic!()
/// }
///
/// let response = get("https://www.rust-lang.org/").unwrap();
///
/// if !response.status().is_success() {
/// panic!("failed to get a successful response status!");
/// }
///
/// if let Some(date) = response.headers().get("Date") {
/// // we've got a `Date` header!
/// }
///
/// let body = response.body();
/// // ...
/// ```
///
/// Deserialize a response of bytes via json:
///
/// ```
/// # extern crate serde;
/// # extern crate serde_json;
/// # extern crate http;
/// use http::Response;
/// use serde::de;
///
/// fn deserialize<T>(res: Response<Vec<u8>>) -> serde_json::Result<Response<T>>
/// where for<'de> T: de::Deserialize<'de>,
/// {
/// let (parts, body) = res.into_parts();
/// let body = serde_json::from_slice(&body)?;
/// Ok(Response::from_parts(parts, body))
/// }
/// #
/// # fn main() {}
/// ```
///
/// Or alternatively, serialize the body of a response to json
///
/// ```
/// # extern crate serde;
/// # extern crate serde_json;
/// # extern crate http;
/// use http::Response;
/// use serde::ser;
///
/// fn serialize<T>(res: Response<T>) -> serde_json::Result<Response<Vec<u8>>>
/// where T: ser::Serialize,
/// {
/// let (parts, body) = res.into_parts();
/// let body = serde_json::to_vec(&body)?;
/// Ok(Response::from_parts(parts, body))
/// }
/// #
/// # fn main() {}
/// ```
pub struct Response<T> {
head: Parts,
body: T,
}
/// Component parts of an HTTP `Response`
///
/// The HTTP response head consists of a status, version, and a set of
/// header fields.
pub struct Parts {
/// The response's status
pub status: StatusCode,
/// The response's version
pub version: Version,
/// The response's headers
pub headers: HeaderMap<HeaderValue>,
/// The response's extensions
pub extensions: Extensions,
_priv: (),
}
/// An HTTP response builder
///
/// This type can be used to construct an instance of `Response` through a
/// builder-like pattern.
#[derive(Debug)]
pub struct Builder {
inner: Result<Parts>,
}
impl Response<()> {
/// Creates a new builder-style object to manufacture a `Response`
///
/// This method returns an instance of `Builder` which can be used to
/// create a `Response`.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response = Response::builder()
/// .status(200)
/// .header("X-Custom-Foo", "Bar")
/// .body(())
/// .unwrap();
/// ```
#[inline]
pub fn builder() -> Builder {
Builder::new()
}
}
impl<T> Response<T> {
/// Creates a new blank `Response` with the body
///
/// The component ports of this response will be set to their default, e.g.
/// the ok status, no headers, etc.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response = Response::new("hello world");
///
/// assert_eq!(response.status(), StatusCode::OK);
/// assert_eq!(*response.body(), "hello world");
/// ```
#[inline]
pub fn new(body: T) -> Response<T> {
Response {
head: Parts::new(),
body: body,
}
}
/// Creates a new `Response` with the given head and body
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response = Response::new("hello world");
/// let (mut parts, body) = response.into_parts();
///
/// parts.status = StatusCode::BAD_REQUEST;
/// let response = Response::from_parts(parts, body);
///
/// assert_eq!(response.status(), StatusCode::BAD_REQUEST);
/// assert_eq!(*response.body(), "hello world");
/// ```
#[inline]
pub fn from_parts(parts: Parts, body: T) -> Response<T> {
Response {
head: parts,
body: body,
}
}
/// Returns the `StatusCode`.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response: Response<()> = Response::default();
/// assert_eq!(response.status(), StatusCode::OK);
/// ```
#[inline]
pub fn status(&self) -> StatusCode {
self.head.status
}
/// Returns a mutable reference to the associated `StatusCode`.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let mut response: Response<()> = Response::default();
/// *response.status_mut() = StatusCode::CREATED;
/// assert_eq!(response.status(), StatusCode::CREATED);
/// ```
#[inline]
pub fn status_mut(&mut self) -> &mut StatusCode {
&mut self.head.status
}
/// Returns a reference to the associated version.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response: Response<()> = Response::default();
/// assert_eq!(response.version(), Version::HTTP_11);
/// ```
#[inline]
pub fn version(&self) -> Version {
self.head.version
}
/// Returns a mutable reference to the associated version.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let mut response: Response<()> = Response::default();
/// *response.version_mut() = Version::HTTP_2;
/// assert_eq!(response.version(), Version::HTTP_2);
/// ```
#[inline]
pub fn version_mut(&mut self) -> &mut Version {
&mut self.head.version
}
/// Returns a reference to the associated header field map.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response: Response<()> = Response::default();
/// assert!(response.headers().is_empty());
/// ```
#[inline]
pub fn headers(&self) -> &HeaderMap<HeaderValue> {
&self.head.headers
}
/// Returns a mutable reference to the associated header field map.
///
/// # Examples
///
/// ```
/// # use http::*;
/// # use http::header::*;
/// let mut response: Response<()> = Response::default();
/// response.headers_mut().insert(HOST, HeaderValue::from_static("world"));
/// assert!(!response.headers().is_empty());
/// ```
#[inline]
pub fn headers_mut(&mut self) -> &mut HeaderMap<HeaderValue> {
&mut self.head.headers
}
/// Returns a reference to the associated extensions.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response: Response<()> = Response::default();
/// assert!(response.extensions().get::<i32>().is_none());
/// ```
#[inline]
pub fn extensions(&self) -> &Extensions {
&self.head.extensions
}
/// Returns a mutable reference to the associated extensions.
///
/// # Examples
///
/// ```
/// # use http::*;
/// # use http::header::*;
/// let mut response: Response<()> = Response::default();
/// response.extensions_mut().insert("hello");
/// assert_eq!(response.extensions().get(), Some(&"hello"));
/// ```
#[inline]
pub fn extensions_mut(&mut self) -> &mut Extensions {
&mut self.head.extensions
}
/// Returns a reference to the associated HTTP body.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response: Response<String> = Response::default();
/// assert!(response.body().is_empty());
/// ```
#[inline]
pub fn body(&self) -> &T {
&self.body
}
/// Returns a mutable reference to the associated HTTP body.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let mut response: Response<String> = Response::default();
/// response.body_mut().push_str("hello world");
/// assert!(!response.body().is_empty());
/// ```
#[inline]
pub fn body_mut(&mut self) -> &mut T {
&mut self.body
}
/// Consumes the response, returning just the body.
///
/// # Examples
///
/// ```
/// # use http::Response;
/// let response = Response::new(10);
/// let body = response.into_body();
/// assert_eq!(body, 10);
/// ```
#[inline]
pub fn into_body(self) -> T {
self.body
}
/// Consumes the response returning the head and body parts.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response: Response<()> = Response::default();
/// let (parts, body) = response.into_parts();
/// assert_eq!(parts.status, StatusCode::OK);
/// ```
#[inline]
pub fn into_parts(self) -> (Parts, T) {
(self.head, self.body)
}
/// Consumes the response returning a new response with body mapped to the
/// return type of the passed in function.
///
/// # Examples
///
/// ```
/// # use http::*;
/// let response = Response::builder().body("some string").unwrap();
/// let mapped_response: Response<&[u8]> = response.map(|b| {
/// assert_eq!(b, "some string");
/// b.as_bytes()
/// });
/// assert_eq!(mapped_response.body(), &"some string".as_bytes());
/// ```
#[inline]
pub fn map<F, U>(self, f: F) -> Response<U>
where
F: FnOnce(T) -> U,
{
Response {
body: f(self.body),
head: self.head,
}
}
}
impl<T: Default> Default for Response<T> {
#[inline]
fn default() -> Response<T> {
Response::new(T::default())
}
}
impl<T: fmt::Debug> fmt::Debug for Response<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Response")
.field("status", &self.status())
.field("version", &self.version())
.field("headers", self.headers())
// omits Extensions because not useful
.field("body", self.body())
.finish()
}
}
impl Parts {
/// Creates a new default instance of `Parts`
fn new() -> Parts {
Parts {
status: StatusCode::default(),
version: Version::default(),
headers: HeaderMap::default(),
extensions: Extensions::default(),
_priv: (),
}
}
}
impl fmt::Debug for Parts {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Parts")
.field("status", &self.status)
.field("version", &self.version)
.field("headers", &self.headers)
// omits Extensions because not useful
// omits _priv because not useful
.finish()
}
}
impl Builder {
/// Creates a new default instance of `Builder` to construct either a
/// `Head` or a `Response`.
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let response = response::Builder::new()
/// .status(200)
/// .body(())
/// .unwrap();
/// ```
#[inline]
pub fn new() -> Builder {
Builder::default()
}
/// Set the HTTP status for this response.
///
/// This function will configure the HTTP status code of the `Response` that
/// will be returned from `Builder::build`.
///
/// By default this is `200`.
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let response = Response::builder()
/// .status(200)
/// .body(())
/// .unwrap();
/// ```
pub fn status<T>(self, status: T) -> Builder
where
StatusCode: TryFrom<T>,
<StatusCode as TryFrom<T>>::Error: Into<crate::Error>,
{
self.and_then(move |mut head| {
head.status = TryFrom::try_from(status).map_err(Into::into)?;
Ok(head)
})
}
/// Set the HTTP version for this response.
///
/// This function will configure the HTTP version of the `Response` that
/// will be returned from `Builder::build`.
///
/// By default this is HTTP/1.1
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let response = Response::builder()
/// .version(Version::HTTP_2)
/// .body(())
/// .unwrap();
/// ```
pub fn version(self, version: Version) -> Builder {
self.and_then(move |mut head| {
head.version = version;
Ok(head)
})
}
/// Appends a header to this response builder.
///
/// This function will append the provided key/value as a header to the
/// internal `HeaderMap` being constructed. Essentially this is equivalent
/// to calling `HeaderMap::append`.
///
/// # Examples
///
/// ```
/// # use http::*;
/// # use http::header::HeaderValue;
///
/// let response = Response::builder()
/// .header("Content-Type", "text/html")
/// .header("X-Custom-Foo", "bar")
/// .header("content-length", 0)
/// .body(())
/// .unwrap();
/// ```
pub fn header<K, V>(self, key: K, value: V) -> Builder
where
HeaderName: TryFrom<K>,
<HeaderName as TryFrom<K>>::Error: Into<crate::Error>,
HeaderValue: TryFrom<V>,
<HeaderValue as TryFrom<V>>::Error: Into<crate::Error>,
{
self.and_then(move |mut head| {
let name = <HeaderName as TryFrom<K>>::try_from(key).map_err(Into::into)?;
let value = <HeaderValue as TryFrom<V>>::try_from(value).map_err(Into::into)?;
head.headers.append(name, value);
Ok(head)
})
}
/// Get header on this response builder.
///
/// When builder has error returns None.
///
/// # Example
///
/// ```
/// # use http::Response;
/// # use http::header::HeaderValue;
/// let res = Response::builder()
/// .header("Accept", "text/html")
/// .header("X-Custom-Foo", "bar");
/// let headers = res.headers_ref().unwrap();
/// assert_eq!( headers["Accept"], "text/html" );
/// assert_eq!( headers["X-Custom-Foo"], "bar" );
/// ```
pub fn headers_ref(&self) -> Option<&HeaderMap<HeaderValue>> {
self.inner.as_ref().ok().map(|h| &h.headers)
}
/// Get header on this response builder.
/// when builder has error returns None
///
/// # Example
///
/// ```
/// # use http::*;
/// # use http::header::HeaderValue;
/// # use http::response::Builder;
/// let mut res = Response::builder();
/// {
/// let headers = res.headers_mut().unwrap();
/// headers.insert("Accept", HeaderValue::from_static("text/html"));
/// headers.insert("X-Custom-Foo", HeaderValue::from_static("bar"));
/// }
/// let headers = res.headers_ref().unwrap();
/// assert_eq!( headers["Accept"], "text/html" );
/// assert_eq!( headers["X-Custom-Foo"], "bar" );
/// ```
pub fn headers_mut(&mut self) -> Option<&mut HeaderMap<HeaderValue>> {
self.inner.as_mut().ok().map(|h| &mut h.headers)
}
/// Adds an extension to this builder
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let response = Response::builder()
/// .extension("My Extension")
/// .body(())
/// .unwrap();
///
/// assert_eq!(response.extensions().get::<&'static str>(),
/// Some(&"My Extension"));
/// ```
pub fn extension<T>(self, extension: T) -> Builder
where
T: Any + Send + Sync + 'static,
{
self.and_then(move |mut head| {
head.extensions.insert(extension);
Ok(head)
})
}
/// Get a reference to the extensions for this response builder.
///
/// If the builder has an error, this returns `None`.
///
/// # Example
///
/// ```
/// # use http::Response;
/// let res = Response::builder().extension("My Extension").extension(5u32);
/// let extensions = res.extensions_ref().unwrap();
/// assert_eq!(extensions.get::<&'static str>(), Some(&"My Extension"));
/// assert_eq!(extensions.get::<u32>(), Some(&5u32));
/// ```
pub fn extensions_ref(&self) -> Option<&Extensions> {
self.inner.as_ref().ok().map(|h| &h.extensions)
}
/// Get a mutable reference to the extensions for this response builder.
///
/// If the builder has an error, this returns `None`.
///
/// # Example
///
/// ```
/// # use http::Response;
/// let mut res = Response::builder().extension("My Extension");
/// let mut extensions = res.extensions_mut().unwrap();
/// assert_eq!(extensions.get::<&'static str>(), Some(&"My Extension"));
/// extensions.insert(5u32);
/// assert_eq!(extensions.get::<u32>(), Some(&5u32));
/// ```
pub fn extensions_mut(&mut self) -> Option<&mut Extensions> {
self.inner.as_mut().ok().map(|h| &mut h.extensions)
}
/// "Consumes" this builder, using the provided `body` to return a
/// constructed `Response`.
///
/// # Errors
///
/// This function may return an error if any previously configured argument
/// failed to parse or get converted to the internal representation. For
/// example if an invalid `head` was specified via `header("Foo",
/// "Bar\r\n")` the error will be returned when this function is called
/// rather than when `header` was called.
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let response = Response::builder()
/// .body(())
/// .unwrap();
/// ```
pub fn body<T>(self, body: T) -> Result<Response<T>> {
self.inner.map(move |head| {
Response {
head,
body,
}
})
}
// private
fn and_then<F>(self, func: F) -> Self
where
F: FnOnce(Parts) -> Result<Parts>
{
Builder {
inner: self.inner.and_then(func),
}
}
}
impl Default for Builder {
#[inline]
fn default() -> Builder {
Builder {
inner: Ok(Parts::new()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_can_map_a_body_from_one_type_to_another() {
let response = Response::builder().body("some string").unwrap();
let mapped_response = response.map(|s| {
assert_eq!(s, "some string");
123u32
});
assert_eq!(mapped_response.body(), &123u32);
}
}

588
zeroidc/vendor/http/src/status.rs vendored Normal file
View File

@@ -0,0 +1,588 @@
//! HTTP status codes
//!
//! This module contains HTTP-status code related structs an errors. The main
//! type in this module is `StatusCode` which is not intended to be used through
//! this module but rather the `http::StatusCode` type.
//!
//! # Examples
//!
//! ```
//! use http::StatusCode;
//!
//! assert_eq!(StatusCode::from_u16(200).unwrap(), StatusCode::OK);
//! assert_eq!(StatusCode::NOT_FOUND, 404);
//! assert!(StatusCode::OK.is_success());
//! ```
use std::convert::TryFrom;
use std::num::NonZeroU16;
use std::error::Error;
use std::fmt;
use std::str::FromStr;
/// An HTTP status code (`status-code` in RFC 7230 et al.).
///
/// Constants are provided for known status codes, including those in the IANA
/// [HTTP Status Code Registry](
/// https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml).
///
/// Status code values in the range 100-999 (inclusive) are supported by this
/// type. Values in the range 100-599 are semantically classified by the most
/// significant digit. See [`StatusCode::is_success`], etc. Values above 599
/// are unclassified but allowed for legacy compatibility, though their use is
/// discouraged. Applications may interpret such values as protocol errors.
///
/// # Examples
///
/// ```
/// use http::StatusCode;
///
/// assert_eq!(StatusCode::from_u16(200).unwrap(), StatusCode::OK);
/// assert_eq!(StatusCode::NOT_FOUND.as_u16(), 404);
/// assert!(StatusCode::OK.is_success());
/// ```
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StatusCode(NonZeroU16);
/// A possible error value when converting a `StatusCode` from a `u16` or `&str`
///
/// This error indicates that the supplied input was not a valid number, was less
/// than 100, or was greater than 999.
pub struct InvalidStatusCode {
_priv: (),
}
impl StatusCode {
/// Converts a u16 to a status code.
///
/// The function validates the correctness of the supplied u16. It must be
/// greater or equal to 100 and less than 1000.
///
/// # Example
///
/// ```
/// use http::StatusCode;
///
/// let ok = StatusCode::from_u16(200).unwrap();
/// assert_eq!(ok, StatusCode::OK);
///
/// let err = StatusCode::from_u16(99);
/// assert!(err.is_err());
/// ```
#[inline]
pub fn from_u16(src: u16) -> Result<StatusCode, InvalidStatusCode> {
if src < 100 || src >= 1000 {
return Err(InvalidStatusCode::new());
}
NonZeroU16::new(src)
.map(StatusCode)
.ok_or_else(InvalidStatusCode::new)
}
/// Converts a &[u8] to a status code
pub fn from_bytes(src: &[u8]) -> Result<StatusCode, InvalidStatusCode> {
if src.len() != 3 {
return Err(InvalidStatusCode::new());
}
let a = src[0].wrapping_sub(b'0') as u16;
let b = src[1].wrapping_sub(b'0') as u16;
let c = src[2].wrapping_sub(b'0') as u16;
if a == 0 || a > 9 || b > 9 || c > 9 {
return Err(InvalidStatusCode::new());
}
let status = (a * 100) + (b * 10) + c;
NonZeroU16::new(status)
.map(StatusCode)
.ok_or_else(InvalidStatusCode::new)
}
/// Returns the `u16` corresponding to this `StatusCode`.
///
/// # Note
///
/// This is the same as the `From<StatusCode>` implementation, but
/// included as an inherent method because that implementation doesn't
/// appear in rustdocs, as well as a way to force the type instead of
/// relying on inference.
///
/// # Example
///
/// ```
/// let status = http::StatusCode::OK;
/// assert_eq!(status.as_u16(), 200);
/// ```
#[inline]
pub fn as_u16(&self) -> u16 {
(*self).into()
}
/// Returns a &str representation of the `StatusCode`
///
/// The return value only includes a numerical representation of the
/// status code. The canonical reason is not included.
///
/// # Example
///
/// ```
/// let status = http::StatusCode::OK;
/// assert_eq!(status.as_str(), "200");
/// ```
#[inline]
pub fn as_str(&self) -> &str {
let offset = (self.0.get() - 100) as usize;
let offset = offset * 3;
// Invariant: self has checked range [100, 999] and CODE_DIGITS is
// ASCII-only, of length 900 * 3 = 2700 bytes
#[cfg(debug_assertions)]
{ &CODE_DIGITS[offset..offset+3] }
#[cfg(not(debug_assertions))]
unsafe { CODE_DIGITS.get_unchecked(offset..offset+3) }
}
/// Get the standardised `reason-phrase` for this status code.
///
/// This is mostly here for servers writing responses, but could potentially have application
/// at other times.
///
/// The reason phrase is defined as being exclusively for human readers. You should avoid
/// deriving any meaning from it at all costs.
///
/// Bear in mind also that in HTTP/2.0 and HTTP/3.0 the reason phrase is abolished from
/// transmission, and so this canonical reason phrase really is the only reason phrase youll
/// find.
///
/// # Example
///
/// ```
/// let status = http::StatusCode::OK;
/// assert_eq!(status.canonical_reason(), Some("OK"));
/// ```
pub fn canonical_reason(&self) -> Option<&'static str> {
canonical_reason(self.0.get())
}
/// Check if status is within 100-199.
#[inline]
pub fn is_informational(&self) -> bool {
200 > self.0.get() && self.0.get() >= 100
}
/// Check if status is within 200-299.
#[inline]
pub fn is_success(&self) -> bool {
300 > self.0.get() && self.0.get() >= 200
}
/// Check if status is within 300-399.
#[inline]
pub fn is_redirection(&self) -> bool {
400 > self.0.get() && self.0.get() >= 300
}
/// Check if status is within 400-499.
#[inline]
pub fn is_client_error(&self) -> bool {
500 > self.0.get() && self.0.get() >= 400
}
/// Check if status is within 500-599.
#[inline]
pub fn is_server_error(&self) -> bool {
600 > self.0.get() && self.0.get() >= 500
}
}
impl fmt::Debug for StatusCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
/// Formats the status code, *including* the canonical reason.
///
/// # Example
///
/// ```
/// # use http::StatusCode;
/// assert_eq!(format!("{}", StatusCode::OK), "200 OK");
/// ```
impl fmt::Display for StatusCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} {}",
u16::from(*self),
self.canonical_reason().unwrap_or("<unknown status code>")
)
}
}
impl Default for StatusCode {
#[inline]
fn default() -> StatusCode {
StatusCode::OK
}
}
impl PartialEq<u16> for StatusCode {
#[inline]
fn eq(&self, other: &u16) -> bool {
self.as_u16() == *other
}
}
impl PartialEq<StatusCode> for u16 {
#[inline]
fn eq(&self, other: &StatusCode) -> bool {
*self == other.as_u16()
}
}
impl From<StatusCode> for u16 {
#[inline]
fn from(status: StatusCode) -> u16 {
status.0.get()
}
}
impl FromStr for StatusCode {
type Err = InvalidStatusCode;
fn from_str(s: &str) -> Result<StatusCode, InvalidStatusCode> {
StatusCode::from_bytes(s.as_ref())
}
}
impl<'a> From<&'a StatusCode> for StatusCode {
#[inline]
fn from(t: &'a StatusCode) -> Self {
t.clone()
}
}
impl<'a> TryFrom<&'a [u8]> for StatusCode {
type Error = InvalidStatusCode;
#[inline]
fn try_from(t: &'a [u8]) -> Result<Self, Self::Error> {
StatusCode::from_bytes(t)
}
}
impl<'a> TryFrom<&'a str> for StatusCode {
type Error = InvalidStatusCode;
#[inline]
fn try_from(t: &'a str) -> Result<Self, Self::Error> {
t.parse()
}
}
impl TryFrom<u16> for StatusCode {
type Error = InvalidStatusCode;
#[inline]
fn try_from(t: u16) -> Result<Self, Self::Error> {
StatusCode::from_u16(t)
}
}
macro_rules! status_codes {
(
$(
$(#[$docs:meta])*
($num:expr, $konst:ident, $phrase:expr);
)+
) => {
impl StatusCode {
$(
$(#[$docs])*
pub const $konst: StatusCode = StatusCode(unsafe { NonZeroU16::new_unchecked($num) });
)+
}
fn canonical_reason(num: u16) -> Option<&'static str> {
match num {
$(
$num => Some($phrase),
)+
_ => None
}
}
}
}
status_codes! {
/// 100 Continue
/// [[RFC7231, Section 6.2.1](https://tools.ietf.org/html/rfc7231#section-6.2.1)]
(100, CONTINUE, "Continue");
/// 101 Switching Protocols
/// [[RFC7231, Section 6.2.2](https://tools.ietf.org/html/rfc7231#section-6.2.2)]
(101, SWITCHING_PROTOCOLS, "Switching Protocols");
/// 102 Processing
/// [[RFC2518](https://tools.ietf.org/html/rfc2518)]
(102, PROCESSING, "Processing");
/// 200 OK
/// [[RFC7231, Section 6.3.1](https://tools.ietf.org/html/rfc7231#section-6.3.1)]
(200, OK, "OK");
/// 201 Created
/// [[RFC7231, Section 6.3.2](https://tools.ietf.org/html/rfc7231#section-6.3.2)]
(201, CREATED, "Created");
/// 202 Accepted
/// [[RFC7231, Section 6.3.3](https://tools.ietf.org/html/rfc7231#section-6.3.3)]
(202, ACCEPTED, "Accepted");
/// 203 Non-Authoritative Information
/// [[RFC7231, Section 6.3.4](https://tools.ietf.org/html/rfc7231#section-6.3.4)]
(203, NON_AUTHORITATIVE_INFORMATION, "Non Authoritative Information");
/// 204 No Content
/// [[RFC7231, Section 6.3.5](https://tools.ietf.org/html/rfc7231#section-6.3.5)]
(204, NO_CONTENT, "No Content");
/// 205 Reset Content
/// [[RFC7231, Section 6.3.6](https://tools.ietf.org/html/rfc7231#section-6.3.6)]
(205, RESET_CONTENT, "Reset Content");
/// 206 Partial Content
/// [[RFC7233, Section 4.1](https://tools.ietf.org/html/rfc7233#section-4.1)]
(206, PARTIAL_CONTENT, "Partial Content");
/// 207 Multi-Status
/// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
(207, MULTI_STATUS, "Multi-Status");
/// 208 Already Reported
/// [[RFC5842](https://tools.ietf.org/html/rfc5842)]
(208, ALREADY_REPORTED, "Already Reported");
/// 226 IM Used
/// [[RFC3229](https://tools.ietf.org/html/rfc3229)]
(226, IM_USED, "IM Used");
/// 300 Multiple Choices
/// [[RFC7231, Section 6.4.1](https://tools.ietf.org/html/rfc7231#section-6.4.1)]
(300, MULTIPLE_CHOICES, "Multiple Choices");
/// 301 Moved Permanently
/// [[RFC7231, Section 6.4.2](https://tools.ietf.org/html/rfc7231#section-6.4.2)]
(301, MOVED_PERMANENTLY, "Moved Permanently");
/// 302 Found
/// [[RFC7231, Section 6.4.3](https://tools.ietf.org/html/rfc7231#section-6.4.3)]
(302, FOUND, "Found");
/// 303 See Other
/// [[RFC7231, Section 6.4.4](https://tools.ietf.org/html/rfc7231#section-6.4.4)]
(303, SEE_OTHER, "See Other");
/// 304 Not Modified
/// [[RFC7232, Section 4.1](https://tools.ietf.org/html/rfc7232#section-4.1)]
(304, NOT_MODIFIED, "Not Modified");
/// 305 Use Proxy
/// [[RFC7231, Section 6.4.5](https://tools.ietf.org/html/rfc7231#section-6.4.5)]
(305, USE_PROXY, "Use Proxy");
/// 307 Temporary Redirect
/// [[RFC7231, Section 6.4.7](https://tools.ietf.org/html/rfc7231#section-6.4.7)]
(307, TEMPORARY_REDIRECT, "Temporary Redirect");
/// 308 Permanent Redirect
/// [[RFC7238](https://tools.ietf.org/html/rfc7238)]
(308, PERMANENT_REDIRECT, "Permanent Redirect");
/// 400 Bad Request
/// [[RFC7231, Section 6.5.1](https://tools.ietf.org/html/rfc7231#section-6.5.1)]
(400, BAD_REQUEST, "Bad Request");
/// 401 Unauthorized
/// [[RFC7235, Section 3.1](https://tools.ietf.org/html/rfc7235#section-3.1)]
(401, UNAUTHORIZED, "Unauthorized");
/// 402 Payment Required
/// [[RFC7231, Section 6.5.2](https://tools.ietf.org/html/rfc7231#section-6.5.2)]
(402, PAYMENT_REQUIRED, "Payment Required");
/// 403 Forbidden
/// [[RFC7231, Section 6.5.3](https://tools.ietf.org/html/rfc7231#section-6.5.3)]
(403, FORBIDDEN, "Forbidden");
/// 404 Not Found
/// [[RFC7231, Section 6.5.4](https://tools.ietf.org/html/rfc7231#section-6.5.4)]
(404, NOT_FOUND, "Not Found");
/// 405 Method Not Allowed
/// [[RFC7231, Section 6.5.5](https://tools.ietf.org/html/rfc7231#section-6.5.5)]
(405, METHOD_NOT_ALLOWED, "Method Not Allowed");
/// 406 Not Acceptable
/// [[RFC7231, Section 6.5.6](https://tools.ietf.org/html/rfc7231#section-6.5.6)]
(406, NOT_ACCEPTABLE, "Not Acceptable");
/// 407 Proxy Authentication Required
/// [[RFC7235, Section 3.2](https://tools.ietf.org/html/rfc7235#section-3.2)]
(407, PROXY_AUTHENTICATION_REQUIRED, "Proxy Authentication Required");
/// 408 Request Timeout
/// [[RFC7231, Section 6.5.7](https://tools.ietf.org/html/rfc7231#section-6.5.7)]
(408, REQUEST_TIMEOUT, "Request Timeout");
/// 409 Conflict
/// [[RFC7231, Section 6.5.8](https://tools.ietf.org/html/rfc7231#section-6.5.8)]
(409, CONFLICT, "Conflict");
/// 410 Gone
/// [[RFC7231, Section 6.5.9](https://tools.ietf.org/html/rfc7231#section-6.5.9)]
(410, GONE, "Gone");
/// 411 Length Required
/// [[RFC7231, Section 6.5.10](https://tools.ietf.org/html/rfc7231#section-6.5.10)]
(411, LENGTH_REQUIRED, "Length Required");
/// 412 Precondition Failed
/// [[RFC7232, Section 4.2](https://tools.ietf.org/html/rfc7232#section-4.2)]
(412, PRECONDITION_FAILED, "Precondition Failed");
/// 413 Payload Too Large
/// [[RFC7231, Section 6.5.11](https://tools.ietf.org/html/rfc7231#section-6.5.11)]
(413, PAYLOAD_TOO_LARGE, "Payload Too Large");
/// 414 URI Too Long
/// [[RFC7231, Section 6.5.12](https://tools.ietf.org/html/rfc7231#section-6.5.12)]
(414, URI_TOO_LONG, "URI Too Long");
/// 415 Unsupported Media Type
/// [[RFC7231, Section 6.5.13](https://tools.ietf.org/html/rfc7231#section-6.5.13)]
(415, UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type");
/// 416 Range Not Satisfiable
/// [[RFC7233, Section 4.4](https://tools.ietf.org/html/rfc7233#section-4.4)]
(416, RANGE_NOT_SATISFIABLE, "Range Not Satisfiable");
/// 417 Expectation Failed
/// [[RFC7231, Section 6.5.14](https://tools.ietf.org/html/rfc7231#section-6.5.14)]
(417, EXPECTATION_FAILED, "Expectation Failed");
/// 418 I'm a teapot
/// [curiously not registered by IANA but [RFC2324](https://tools.ietf.org/html/rfc2324)]
(418, IM_A_TEAPOT, "I'm a teapot");
/// 421 Misdirected Request
/// [RFC7540, Section 9.1.2](http://tools.ietf.org/html/rfc7540#section-9.1.2)
(421, MISDIRECTED_REQUEST, "Misdirected Request");
/// 422 Unprocessable Entity
/// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
(422, UNPROCESSABLE_ENTITY, "Unprocessable Entity");
/// 423 Locked
/// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
(423, LOCKED, "Locked");
/// 424 Failed Dependency
/// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
(424, FAILED_DEPENDENCY, "Failed Dependency");
/// 426 Upgrade Required
/// [[RFC7231, Section 6.5.15](https://tools.ietf.org/html/rfc7231#section-6.5.15)]
(426, UPGRADE_REQUIRED, "Upgrade Required");
/// 428 Precondition Required
/// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
(428, PRECONDITION_REQUIRED, "Precondition Required");
/// 429 Too Many Requests
/// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
(429, TOO_MANY_REQUESTS, "Too Many Requests");
/// 431 Request Header Fields Too Large
/// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
(431, REQUEST_HEADER_FIELDS_TOO_LARGE, "Request Header Fields Too Large");
/// 451 Unavailable For Legal Reasons
/// [[RFC7725](http://tools.ietf.org/html/rfc7725)]
(451, UNAVAILABLE_FOR_LEGAL_REASONS, "Unavailable For Legal Reasons");
/// 500 Internal Server Error
/// [[RFC7231, Section 6.6.1](https://tools.ietf.org/html/rfc7231#section-6.6.1)]
(500, INTERNAL_SERVER_ERROR, "Internal Server Error");
/// 501 Not Implemented
/// [[RFC7231, Section 6.6.2](https://tools.ietf.org/html/rfc7231#section-6.6.2)]
(501, NOT_IMPLEMENTED, "Not Implemented");
/// 502 Bad Gateway
/// [[RFC7231, Section 6.6.3](https://tools.ietf.org/html/rfc7231#section-6.6.3)]
(502, BAD_GATEWAY, "Bad Gateway");
/// 503 Service Unavailable
/// [[RFC7231, Section 6.6.4](https://tools.ietf.org/html/rfc7231#section-6.6.4)]
(503, SERVICE_UNAVAILABLE, "Service Unavailable");
/// 504 Gateway Timeout
/// [[RFC7231, Section 6.6.5](https://tools.ietf.org/html/rfc7231#section-6.6.5)]
(504, GATEWAY_TIMEOUT, "Gateway Timeout");
/// 505 HTTP Version Not Supported
/// [[RFC7231, Section 6.6.6](https://tools.ietf.org/html/rfc7231#section-6.6.6)]
(505, HTTP_VERSION_NOT_SUPPORTED, "HTTP Version Not Supported");
/// 506 Variant Also Negotiates
/// [[RFC2295](https://tools.ietf.org/html/rfc2295)]
(506, VARIANT_ALSO_NEGOTIATES, "Variant Also Negotiates");
/// 507 Insufficient Storage
/// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
(507, INSUFFICIENT_STORAGE, "Insufficient Storage");
/// 508 Loop Detected
/// [[RFC5842](https://tools.ietf.org/html/rfc5842)]
(508, LOOP_DETECTED, "Loop Detected");
/// 510 Not Extended
/// [[RFC2774](https://tools.ietf.org/html/rfc2774)]
(510, NOT_EXTENDED, "Not Extended");
/// 511 Network Authentication Required
/// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
(511, NETWORK_AUTHENTICATION_REQUIRED, "Network Authentication Required");
}
impl InvalidStatusCode {
fn new() -> InvalidStatusCode {
InvalidStatusCode {
_priv: (),
}
}
}
impl fmt::Debug for InvalidStatusCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("InvalidStatusCode")
// skip _priv noise
.finish()
}
}
impl fmt::Display for InvalidStatusCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("invalid status code")
}
}
impl Error for InvalidStatusCode {}
// A string of packed 3-ASCII-digit status code values for the supported range
// of [100, 999] (900 codes, 2700 bytes).
const CODE_DIGITS: &'static str = "\
100101102103104105106107108109110111112113114115116117118119\
120121122123124125126127128129130131132133134135136137138139\
140141142143144145146147148149150151152153154155156157158159\
160161162163164165166167168169170171172173174175176177178179\
180181182183184185186187188189190191192193194195196197198199\
200201202203204205206207208209210211212213214215216217218219\
220221222223224225226227228229230231232233234235236237238239\
240241242243244245246247248249250251252253254255256257258259\
260261262263264265266267268269270271272273274275276277278279\
280281282283284285286287288289290291292293294295296297298299\
300301302303304305306307308309310311312313314315316317318319\
320321322323324325326327328329330331332333334335336337338339\
340341342343344345346347348349350351352353354355356357358359\
360361362363364365366367368369370371372373374375376377378379\
380381382383384385386387388389390391392393394395396397398399\
400401402403404405406407408409410411412413414415416417418419\
420421422423424425426427428429430431432433434435436437438439\
440441442443444445446447448449450451452453454455456457458459\
460461462463464465466467468469470471472473474475476477478479\
480481482483484485486487488489490491492493494495496497498499\
500501502503504505506507508509510511512513514515516517518519\
520521522523524525526527528529530531532533534535536537538539\
540541542543544545546547548549550551552553554555556557558559\
560561562563564565566567568569570571572573574575576577578579\
580581582583584585586587588589590591592593594595596597598599\
600601602603604605606607608609610611612613614615616617618619\
620621622623624625626627628629630631632633634635636637638639\
640641642643644645646647648649650651652653654655656657658659\
660661662663664665666667668669670671672673674675676677678679\
680681682683684685686687688689690691692693694695696697698699\
700701702703704705706707708709710711712713714715716717718719\
720721722723724725726727728729730731732733734735736737738739\
740741742743744745746747748749750751752753754755756757758759\
760761762763764765766767768769770771772773774775776777778779\
780781782783784785786787788789790791792793794795796797798799\
800801802803804805806807808809810811812813814815816817818819\
820821822823824825826827828829830831832833834835836837838839\
840841842843844845846847848849850851852853854855856857858859\
860861862863864865866867868869870871872873874875876877878879\
880881882883884885886887888889890891892893894895896897898899\
900901902903904905906907908909910911912913914915916917918919\
920921922923924925926927928929930931932933934935936937938939\
940941942943944945946947948949950951952953954955956957958959\
960961962963964965966967968969970971972973974975976977978979\
980981982983984985986987988989990991992993994995996997998999";

671
zeroidc/vendor/http/src/uri/authority.rs vendored Normal file
View File

@@ -0,0 +1,671 @@
use std::convert::TryFrom;
use std::hash::{Hash, Hasher};
use std::str::FromStr;
use std::{cmp, fmt, str};
use bytes::Bytes;
use super::{ErrorKind, InvalidUri, Port, URI_CHARS};
use crate::byte_str::ByteStr;
/// Represents the authority component of a URI.
#[derive(Clone)]
pub struct Authority {
pub(super) data: ByteStr,
}
impl Authority {
pub(super) fn empty() -> Self {
Authority {
data: ByteStr::new(),
}
}
// Not public while `bytes` is unstable.
pub(super) fn from_shared(s: Bytes) -> Result<Self, InvalidUri> {
// Precondition on create_authority: trivially satisfied by the
// identity clousre
create_authority(s, |s| s)
}
/// Attempt to convert an `Authority` from a static string.
///
/// This function will not perform any copying, and the string will be
/// checked if it is empty or contains an invalid character.
///
/// # Panics
///
/// This function panics if the argument contains invalid characters or
/// is empty.
///
/// # Examples
///
/// ```
/// # use http::uri::Authority;
/// let authority = Authority::from_static("example.com");
/// assert_eq!(authority.host(), "example.com");
/// ```
pub fn from_static(src: &'static str) -> Self {
Authority::from_shared(Bytes::from_static(src.as_bytes()))
.expect("static str is not valid authority")
}
/// Attempt to convert a `Bytes` buffer to a `Authority`.
///
/// 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<Self, InvalidUri>
where
T: AsRef<[u8]> + 'static,
{
if_downcast_into!(T, Bytes, src, {
return Authority::from_shared(src);
});
Authority::try_from(src.as_ref())
}
// Note: this may return an *empty* Authority. You might want `parse_non_empty`.
// Postcondition: for all Ok() returns, s[..ret.unwrap()] is valid UTF-8 where
// ret is the return value.
pub(super) fn parse(s: &[u8]) -> Result<usize, InvalidUri> {
let mut colon_cnt = 0;
let mut start_bracket = false;
let mut end_bracket = false;
let mut has_percent = false;
let mut end = s.len();
let mut at_sign_pos = None;
// Among other things, this loop checks that every byte in s up to the
// first '/', '?', or '#' is a valid URI character (or in some contexts,
// a '%'). This means that each such byte is a valid single-byte UTF-8
// code point.
for (i, &b) in s.iter().enumerate() {
match URI_CHARS[b as usize] {
b'/' | b'?' | b'#' => {
end = i;
break;
}
b':' => {
colon_cnt += 1;
}
b'[' => {
if has_percent || start_bracket {
// Something other than the userinfo has a `%`, so reject it.
return Err(ErrorKind::InvalidAuthority.into());
}
start_bracket = true;
}
b']' => {
if end_bracket {
return Err(ErrorKind::InvalidAuthority.into());
}
end_bracket = true;
// Those were part of an IPv6 hostname, so forget them...
colon_cnt = 0;
has_percent = false;
}
b'@' => {
at_sign_pos = Some(i);
// Those weren't a port colon, but part of the
// userinfo, so it needs to be forgotten.
colon_cnt = 0;
has_percent = false;
}
0 if b == b'%' => {
// Per https://tools.ietf.org/html/rfc3986#section-3.2.1 and
// https://url.spec.whatwg.org/#authority-state
// the userinfo can have a percent-encoded username and password,
// so record that a `%` was found. If this turns out to be
// part of the userinfo, this flag will be cleared.
// Also per https://tools.ietf.org/html/rfc6874, percent-encoding can
// be used to indicate a zone identifier.
// If the flag hasn't been cleared at the end, that means this
// was part of the hostname (and not part of an IPv6 address), and
// will fail with an error.
has_percent = true;
}
0 => {
return Err(ErrorKind::InvalidUriChar.into());
}
_ => {}
}
}
if start_bracket ^ end_bracket {
return Err(ErrorKind::InvalidAuthority.into());
}
if colon_cnt > 1 {
// Things like 'localhost:8080:3030' are rejected.
return Err(ErrorKind::InvalidAuthority.into());
}
if end > 0 && at_sign_pos == Some(end - 1) {
// If there's nothing after an `@`, this is bonkers.
return Err(ErrorKind::InvalidAuthority.into());
}
if has_percent {
// Something after the userinfo has a `%`, so reject it.
return Err(ErrorKind::InvalidAuthority.into());
}
Ok(end)
}
// Parse bytes as an Authority, not allowing an empty string.
//
// This should be used by functions that allow a user to parse
// an `Authority` by itself.
//
// Postcondition: for all Ok() returns, s[..ret.unwrap()] is valid UTF-8 where
// ret is the return value.
fn parse_non_empty(s: &[u8]) -> Result<usize, InvalidUri> {
if s.is_empty() {
return Err(ErrorKind::Empty.into());
}
Authority::parse(s)
}
/// Get the host of this `Authority`.
///
/// The host subcomponent of authority is identified by an IP literal
/// encapsulated within square brackets, an IPv4 address in dotted- decimal
/// form, or a registered name. The host subcomponent is **case-insensitive**.
///
/// ```notrust
/// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
/// |---------|
/// |
/// host
/// ```
///
/// # Examples
///
/// ```
/// # use http::uri::*;
/// let authority: Authority = "example.org:80".parse().unwrap();
///
/// assert_eq!(authority.host(), "example.org");
/// ```
#[inline]
pub fn host(&self) -> &str {
host(self.as_str())
}
/// Get the port part of this `Authority`.
///
/// The port subcomponent of authority is designated by an optional port
/// number following the host and delimited from it by a single colon (":")
/// character. It can be turned into a decimal port number with the `as_u16`
/// method or as a `str` with the `as_str` method.
///
/// ```notrust
/// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
/// |-|
/// |
/// port
/// ```
///
/// # Examples
///
/// Authority with port
///
/// ```
/// # use http::uri::Authority;
/// let authority: Authority = "example.org:80".parse().unwrap();
///
/// let port = authority.port().unwrap();
/// assert_eq!(port.as_u16(), 80);
/// assert_eq!(port.as_str(), "80");
/// ```
///
/// Authority without port
///
/// ```
/// # use http::uri::Authority;
/// let authority: Authority = "example.org".parse().unwrap();
///
/// assert!(authority.port().is_none());
/// ```
pub fn port(&self) -> Option<Port<&str>> {
let bytes = self.as_str();
bytes
.rfind(":")
.and_then(|i| Port::from_str(&bytes[i + 1..]).ok())
}
/// Get the port of this `Authority` as a `u16`.
///
/// # Example
///
/// ```
/// # use http::uri::Authority;
/// let authority: Authority = "example.org:80".parse().unwrap();
///
/// assert_eq!(authority.port_u16(), Some(80));
/// ```
pub fn port_u16(&self) -> Option<u16> {
self.port().and_then(|p| Some(p.as_u16()))
}
/// Return a str representation of the authority
#[inline]
pub fn as_str(&self) -> &str {
&self.data[..]
}
}
// Purposefully not public while `bytes` is unstable.
// impl TryFrom<Bytes> for Authority
impl AsRef<str> for Authority {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl PartialEq for Authority {
fn eq(&self, other: &Authority) -> bool {
self.data.eq_ignore_ascii_case(&other.data)
}
}
impl Eq for Authority {}
/// Case-insensitive equality
///
/// # Examples
///
/// ```
/// # use http::uri::Authority;
/// let authority: Authority = "HELLO.com".parse().unwrap();
/// assert_eq!(authority, "hello.coM");
/// assert_eq!("hello.com", authority);
/// ```
impl PartialEq<str> for Authority {
fn eq(&self, other: &str) -> bool {
self.data.eq_ignore_ascii_case(other)
}
}
impl PartialEq<Authority> for str {
fn eq(&self, other: &Authority) -> bool {
self.eq_ignore_ascii_case(other.as_str())
}
}
impl<'a> PartialEq<Authority> for &'a str {
fn eq(&self, other: &Authority) -> bool {
self.eq_ignore_ascii_case(other.as_str())
}
}
impl<'a> PartialEq<&'a str> for Authority {
fn eq(&self, other: &&'a str) -> bool {
self.data.eq_ignore_ascii_case(other)
}
}
impl PartialEq<String> for Authority {
fn eq(&self, other: &String) -> bool {
self.data.eq_ignore_ascii_case(other.as_str())
}
}
impl PartialEq<Authority> for String {
fn eq(&self, other: &Authority) -> bool {
self.as_str().eq_ignore_ascii_case(other.as_str())
}
}
/// Case-insensitive ordering
///
/// # Examples
///
/// ```
/// # use http::uri::Authority;
/// let authority: Authority = "DEF.com".parse().unwrap();
/// assert!(authority < "ghi.com");
/// assert!(authority > "abc.com");
/// ```
impl PartialOrd for Authority {
fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
left.partial_cmp(right)
}
}
impl PartialOrd<str> for Authority {
fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
let right = other.as_bytes().iter().map(|b| b.to_ascii_lowercase());
left.partial_cmp(right)
}
}
impl PartialOrd<Authority> for str {
fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
let left = self.as_bytes().iter().map(|b| b.to_ascii_lowercase());
let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
left.partial_cmp(right)
}
}
impl<'a> PartialOrd<Authority> for &'a str {
fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
let left = self.as_bytes().iter().map(|b| b.to_ascii_lowercase());
let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
left.partial_cmp(right)
}
}
impl<'a> PartialOrd<&'a str> for Authority {
fn partial_cmp(&self, other: &&'a str) -> Option<cmp::Ordering> {
let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
let right = other.as_bytes().iter().map(|b| b.to_ascii_lowercase());
left.partial_cmp(right)
}
}
impl PartialOrd<String> for Authority {
fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
let left = self.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
let right = other.as_bytes().iter().map(|b| b.to_ascii_lowercase());
left.partial_cmp(right)
}
}
impl PartialOrd<Authority> for String {
fn partial_cmp(&self, other: &Authority) -> Option<cmp::Ordering> {
let left = self.as_bytes().iter().map(|b| b.to_ascii_lowercase());
let right = other.data.as_bytes().iter().map(|b| b.to_ascii_lowercase());
left.partial_cmp(right)
}
}
/// Case-insensitive hashing
///
/// # Examples
///
/// ```
/// # use http::uri::Authority;
/// # use std::hash::{Hash, Hasher};
/// # use std::collections::hash_map::DefaultHasher;
///
/// let a: Authority = "HELLO.com".parse().unwrap();
/// let b: Authority = "hello.coM".parse().unwrap();
///
/// let mut s = DefaultHasher::new();
/// a.hash(&mut s);
/// let a = s.finish();
///
/// let mut s = DefaultHasher::new();
/// b.hash(&mut s);
/// let b = s.finish();
///
/// assert_eq!(a, b);
/// ```
impl Hash for Authority {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.data.len().hash(state);
for &b in self.data.as_bytes() {
state.write_u8(b.to_ascii_lowercase());
}
}
}
impl<'a> TryFrom<&'a [u8]> for Authority {
type Error = InvalidUri;
#[inline]
fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
// parse first, and only turn into Bytes if valid
// Preconditon on create_authority: copy_from_slice() copies all of
// bytes from the [u8] parameter into a new Bytes
create_authority(s, |s| Bytes::copy_from_slice(s))
}
}
impl<'a> TryFrom<&'a str> for Authority {
type Error = InvalidUri;
#[inline]
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
TryFrom::try_from(s.as_bytes())
}
}
impl TryFrom<Vec<u8>> for Authority {
type Error = InvalidUri;
#[inline]
fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
Authority::from_shared(vec.into())
}
}
impl TryFrom<String> for Authority {
type Error = InvalidUri;
#[inline]
fn try_from(t: String) -> Result<Self, Self::Error> {
Authority::from_shared(t.into())
}
}
impl FromStr for Authority {
type Err = InvalidUri;
fn from_str(s: &str) -> Result<Self, InvalidUri> {
TryFrom::try_from(s)
}
}
impl fmt::Debug for Authority {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl fmt::Display for Authority {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
fn host(auth: &str) -> &str {
let host_port = auth
.rsplitn(2, '@')
.next()
.expect("split always has at least 1 item");
if host_port.as_bytes()[0] == b'[' {
let i = host_port
.find(']')
.expect("parsing should validate brackets");
// ..= ranges aren't available in 1.20, our minimum Rust version...
&host_port[0..i + 1]
} else {
host_port
.split(':')
.next()
.expect("split always has at least 1 item")
}
}
// Precondition: f converts all of the bytes in the passed in B into the
// returned Bytes.
fn create_authority<B, F>(b: B, f: F) -> Result<Authority, InvalidUri>
where
B: AsRef<[u8]>,
F: FnOnce(B) -> Bytes,
{
let s = b.as_ref();
let authority_end = Authority::parse_non_empty(s)?;
if authority_end != s.len() {
return Err(ErrorKind::InvalidUriChar.into());
}
let bytes = f(b);
Ok(Authority {
// Safety: the postcondition on parse_non_empty() and the check against
// s.len() ensure that b is valid UTF-8. The precondition on f ensures
// that this is carried through to bytes.
data: unsafe { ByteStr::from_utf8_unchecked(bytes) },
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_empty_string_is_error() {
let err = Authority::parse_non_empty(b"").unwrap_err();
assert_eq!(err.0, ErrorKind::Empty);
}
#[test]
fn equal_to_self_of_same_authority() {
let authority1: Authority = "example.com".parse().unwrap();
let authority2: Authority = "EXAMPLE.COM".parse().unwrap();
assert_eq!(authority1, authority2);
assert_eq!(authority2, authority1);
}
#[test]
fn not_equal_to_self_of_different_authority() {
let authority1: Authority = "example.com".parse().unwrap();
let authority2: Authority = "test.com".parse().unwrap();
assert_ne!(authority1, authority2);
assert_ne!(authority2, authority1);
}
#[test]
fn equates_with_a_str() {
let authority: Authority = "example.com".parse().unwrap();
assert_eq!(&authority, "EXAMPLE.com");
assert_eq!("EXAMPLE.com", &authority);
assert_eq!(authority, "EXAMPLE.com");
assert_eq!("EXAMPLE.com", authority);
}
#[test]
fn from_static_equates_with_a_str() {
let authority = Authority::from_static("example.com");
assert_eq!(authority, "example.com");
}
#[test]
fn not_equal_with_a_str_of_a_different_authority() {
let authority: Authority = "example.com".parse().unwrap();
assert_ne!(&authority, "test.com");
assert_ne!("test.com", &authority);
assert_ne!(authority, "test.com");
assert_ne!("test.com", authority);
}
#[test]
fn equates_with_a_string() {
let authority: Authority = "example.com".parse().unwrap();
assert_eq!(authority, "EXAMPLE.com".to_string());
assert_eq!("EXAMPLE.com".to_string(), authority);
}
#[test]
fn equates_with_a_string_of_a_different_authority() {
let authority: Authority = "example.com".parse().unwrap();
assert_ne!(authority, "test.com".to_string());
assert_ne!("test.com".to_string(), authority);
}
#[test]
fn compares_to_self() {
let authority1: Authority = "abc.com".parse().unwrap();
let authority2: Authority = "def.com".parse().unwrap();
assert!(authority1 < authority2);
assert!(authority2 > authority1);
}
#[test]
fn compares_with_a_str() {
let authority: Authority = "def.com".parse().unwrap();
// with ref
assert!(&authority < "ghi.com");
assert!("ghi.com" > &authority);
assert!(&authority > "abc.com");
assert!("abc.com" < &authority);
// no ref
assert!(authority < "ghi.com");
assert!("ghi.com" > authority);
assert!(authority > "abc.com");
assert!("abc.com" < authority);
}
#[test]
fn compares_with_a_string() {
let authority: Authority = "def.com".parse().unwrap();
assert!(authority < "ghi.com".to_string());
assert!("ghi.com".to_string() > authority);
assert!(authority > "abc.com".to_string());
assert!("abc.com".to_string() < authority);
}
#[test]
fn allows_percent_in_userinfo() {
let authority_str = "a%2f:b%2f@example.com";
let authority: Authority = authority_str.parse().unwrap();
assert_eq!(authority, authority_str);
}
#[test]
fn rejects_percent_in_hostname() {
let err = Authority::parse_non_empty(b"example%2f.com").unwrap_err();
assert_eq!(err.0, ErrorKind::InvalidAuthority);
let err = Authority::parse_non_empty(b"a%2f:b%2f@example%2f.com").unwrap_err();
assert_eq!(err.0, ErrorKind::InvalidAuthority);
}
#[test]
fn allows_percent_in_ipv6_address() {
let authority_str = "[fe80::1:2:3:4%25eth0]";
let result: Authority = authority_str.parse().unwrap();
assert_eq!(result, authority_str);
}
#[test]
fn rejects_percent_outside_ipv6_address() {
let err = Authority::parse_non_empty(b"1234%20[fe80::1:2:3:4]").unwrap_err();
assert_eq!(err.0, ErrorKind::InvalidAuthority);
let err = Authority::parse_non_empty(b"[fe80::1:2:3:4]%20").unwrap_err();
assert_eq!(err.0, ErrorKind::InvalidAuthority);
}
#[test]
fn rejects_invalid_utf8() {
let err = Authority::try_from([0xc0u8].as_ref()).unwrap_err();
assert_eq!(err.0, ErrorKind::InvalidUriChar);
let err = Authority::from_shared(Bytes::from_static([0xc0u8].as_ref()))
.unwrap_err();
assert_eq!(err.0, ErrorKind::InvalidUriChar);
}
#[test]
fn rejects_invalid_use_of_brackets() {
let err = Authority::parse_non_empty(b"[]@[").unwrap_err();
assert_eq!(err.0, ErrorKind::InvalidAuthority);
}
}

197
zeroidc/vendor/http/src/uri/builder.rs vendored Normal file
View File

@@ -0,0 +1,197 @@
use std::convert::{TryFrom, TryInto};
use super::{Authority, Parts, PathAndQuery, Scheme};
use crate::Uri;
/// A builder for `Uri`s.
///
/// This type can be used to construct an instance of `Uri`
/// through a builder pattern.
#[derive(Debug)]
pub struct Builder {
parts: Result<Parts, crate::Error>,
}
impl Builder {
/// Creates a new default instance of `Builder` to construct a `Uri`.
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let uri = uri::Builder::new()
/// .scheme("https")
/// .authority("hyper.rs")
/// .path_and_query("/")
/// .build()
/// .unwrap();
/// ```
#[inline]
pub fn new() -> Builder {
Builder::default()
}
/// Set the `Scheme` for this URI.
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let mut builder = uri::Builder::new();
/// builder.scheme("https");
/// ```
pub fn scheme<T>(self, scheme: T) -> Self
where
Scheme: TryFrom<T>,
<Scheme as TryFrom<T>>::Error: Into<crate::Error>,
{
self.map(move |mut parts| {
let scheme = scheme.try_into().map_err(Into::into)?;
parts.scheme = Some(scheme);
Ok(parts)
})
}
/// Set the `Authority` for this URI.
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let uri = uri::Builder::new()
/// .authority("tokio.rs")
/// .build()
/// .unwrap();
/// ```
pub fn authority<T>(self, auth: T) -> Self
where
Authority: TryFrom<T>,
<Authority as TryFrom<T>>::Error: Into<crate::Error>,
{
self.map(move |mut parts| {
let auth = auth.try_into().map_err(Into::into)?;
parts.authority = Some(auth);
Ok(parts)
})
}
/// Set the `PathAndQuery` for this URI.
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let uri = uri::Builder::new()
/// .path_and_query("/hello?foo=bar")
/// .build()
/// .unwrap();
/// ```
pub fn path_and_query<T>(self, p_and_q: T) -> Self
where
PathAndQuery: TryFrom<T>,
<PathAndQuery as TryFrom<T>>::Error: Into<crate::Error>,
{
self.map(move |mut parts| {
let p_and_q = p_and_q.try_into().map_err(Into::into)?;
parts.path_and_query = Some(p_and_q);
Ok(parts)
})
}
/// Consumes this builder, and tries to construct a valid `Uri` from
/// the configured pieces.
///
/// # Errors
///
/// This function may return an error if any previously configured argument
/// failed to parse or get converted to the internal representation. For
/// example if an invalid `scheme` was specified via `scheme("!@#%/^")`
/// the error will be returned when this function is called rather than
/// when `scheme` was called.
///
/// Additionally, the various forms of URI require certain combinations of
/// parts to be set to be valid. If the parts don't fit into any of the
/// valid forms of URI, a new error is returned.
///
/// # Examples
///
/// ```
/// # use http::*;
///
/// let uri = Uri::builder()
/// .build()
/// .unwrap();
/// ```
pub fn build(self) -> Result<Uri, crate::Error> {
let parts = self.parts?;
Uri::from_parts(parts).map_err(Into::into)
}
// private
fn map<F>(self, func: F) -> Self
where
F: FnOnce(Parts) -> Result<Parts, crate::Error>,
{
Builder {
parts: self.parts.and_then(func),
}
}
}
impl Default for Builder {
#[inline]
fn default() -> Builder {
Builder {
parts: Ok(Parts::default()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn build_from_str() {
let uri = Builder::new()
.scheme(Scheme::HTTP)
.authority("hyper.rs")
.path_and_query("/foo?a=1")
.build()
.unwrap();
assert_eq!(uri.scheme_str(), Some("http"));
assert_eq!(uri.authority().unwrap().host(), "hyper.rs");
assert_eq!(uri.path(), "/foo");
assert_eq!(uri.query(), Some("a=1"));
}
#[test]
fn build_from_string() {
for i in 1..10 {
let uri = Builder::new()
.path_and_query(format!("/foo?a={}", i))
.build()
.unwrap();
let expected_query = format!("a={}", i);
assert_eq!(uri.path(), "/foo");
assert_eq!(uri.query(), Some(expected_query.as_str()));
}
}
#[test]
fn build_from_string_ref() {
for i in 1..10 {
let p_a_q = format!("/foo?a={}", i);
let uri = Builder::new().path_and_query(&p_a_q).build().unwrap();
let expected_query = format!("a={}", i);
assert_eq!(uri.path(), "/foo");
assert_eq!(uri.query(), Some(expected_query.as_str()));
}
}
}

1118
zeroidc/vendor/http/src/uri/mod.rs vendored Normal file

File diff suppressed because it is too large Load Diff

558
zeroidc/vendor/http/src/uri/path.rs vendored Normal file
View File

@@ -0,0 +1,558 @@
use std::convert::TryFrom;
use std::str::FromStr;
use std::{cmp, fmt, str};
use bytes::Bytes;
use super::{ErrorKind, InvalidUri};
use crate::byte_str::ByteStr;
/// Represents the path component of a URI
#[derive(Clone)]
pub struct PathAndQuery {
pub(super) data: ByteStr,
pub(super) query: u16,
}
const NONE: u16 = ::std::u16::MAX;
impl PathAndQuery {
// Not public while `bytes` is unstable.
pub(super) fn from_shared(mut src: Bytes) -> Result<Self, InvalidUri> {
let mut query = NONE;
let mut fragment = None;
// block for iterator borrow
{
let mut iter = src.as_ref().iter().enumerate();
// path ...
for (i, &b) in &mut iter {
// See https://url.spec.whatwg.org/#path-state
match b {
b'?' => {
debug_assert_eq!(query, NONE);
query = i as u16;
break;
}
b'#' => {
fragment = Some(i);
break;
}
// This is the range of bytes that don't need to be
// percent-encoded in the path. If it should have been
// percent-encoded, then error.
0x21 |
0x24..=0x3B |
0x3D |
0x40..=0x5F |
0x61..=0x7A |
0x7C |
0x7E => {},
// These are code points that are supposed to be
// percent-encoded in the path but there are clients
// out there sending them as is and httparse accepts
// to parse those requests, so they are allowed here
// for parity.
//
// For reference, those are code points that are used
// to send requests with JSON directly embedded in
// the URI path. Yes, those things happen for real.
b'"' |
b'{' | b'}' => {},
_ => return Err(ErrorKind::InvalidUriChar.into()),
}
}
// query ...
if query != NONE {
for (i, &b) in iter {
match b {
// While queries *should* be percent-encoded, most
// bytes are actually allowed...
// See https://url.spec.whatwg.org/#query-state
//
// Allowed: 0x21 / 0x24 - 0x3B / 0x3D / 0x3F - 0x7E
0x21 |
0x24..=0x3B |
0x3D |
0x3F..=0x7E => {},
b'#' => {
fragment = Some(i);
break;
}
_ => return Err(ErrorKind::InvalidUriChar.into()),
}
}
}
}
if let Some(i) = fragment {
src.truncate(i);
}
Ok(PathAndQuery {
data: unsafe { ByteStr::from_utf8_unchecked(src) },
query: query,
})
}
/// Convert a `PathAndQuery` from a static string.
///
/// This function will not perform any copying, however the string is
/// checked to ensure that it is valid.
///
/// # Panics
///
/// This function panics if the argument is an invalid path and query.
///
/// # Examples
///
/// ```
/// # use http::uri::*;
/// let v = PathAndQuery::from_static("/hello?world");
///
/// assert_eq!(v.path(), "/hello");
/// assert_eq!(v.query(), Some("world"));
/// ```
#[inline]
pub fn from_static(src: &'static str) -> Self {
let src = Bytes::from_static(src.as_bytes());
PathAndQuery::from_shared(src).unwrap()
}
/// Attempt to convert a `Bytes` buffer to a `PathAndQuery`.
///
/// 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<Self, InvalidUri>
where
T: AsRef<[u8]> + 'static,
{
if_downcast_into!(T, Bytes, src, {
return PathAndQuery::from_shared(src);
});
PathAndQuery::try_from(src.as_ref())
}
pub(super) fn empty() -> Self {
PathAndQuery {
data: ByteStr::new(),
query: NONE,
}
}
pub(super) fn slash() -> Self {
PathAndQuery {
data: ByteStr::from_static("/"),
query: NONE,
}
}
pub(super) fn star() -> Self {
PathAndQuery {
data: ByteStr::from_static("*"),
query: NONE,
}
}
/// Returns the path component
///
/// The path component is **case sensitive**.
///
/// ```notrust
/// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
/// |--------|
/// |
/// path
/// ```
///
/// If the URI is `*` then the path component is equal to `*`.
///
/// # Examples
///
/// ```
/// # use http::uri::*;
///
/// let path_and_query: PathAndQuery = "/hello/world".parse().unwrap();
///
/// assert_eq!(path_and_query.path(), "/hello/world");
/// ```
#[inline]
pub fn path(&self) -> &str {
let ret = if self.query == NONE {
&self.data[..]
} else {
&self.data[..self.query as usize]
};
if ret.is_empty() {
return "/";
}
ret
}
/// Returns the query string component
///
/// The query component contains non-hierarchical data that, along with data
/// in the path component, serves to identify a resource within the scope of
/// the URI's scheme and naming authority (if any). The query component is
/// indicated by the first question mark ("?") character and terminated by a
/// number sign ("#") character or by the end of the URI.
///
/// ```notrust
/// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
/// |-------------------|
/// |
/// query
/// ```
///
/// # Examples
///
/// With a query string component
///
/// ```
/// # use http::uri::*;
/// let path_and_query: PathAndQuery = "/hello/world?key=value&foo=bar".parse().unwrap();
///
/// assert_eq!(path_and_query.query(), Some("key=value&foo=bar"));
/// ```
///
/// Without a query string component
///
/// ```
/// # use http::uri::*;
/// let path_and_query: PathAndQuery = "/hello/world".parse().unwrap();
///
/// assert!(path_and_query.query().is_none());
/// ```
#[inline]
pub fn query(&self) -> Option<&str> {
if self.query == NONE {
None
} else {
let i = self.query + 1;
Some(&self.data[i as usize..])
}
}
/// Returns the path and query as a string component.
///
/// # Examples
///
/// With a query string component
///
/// ```
/// # use http::uri::*;
/// let path_and_query: PathAndQuery = "/hello/world?key=value&foo=bar".parse().unwrap();
///
/// assert_eq!(path_and_query.as_str(), "/hello/world?key=value&foo=bar");
/// ```
///
/// Without a query string component
///
/// ```
/// # use http::uri::*;
/// let path_and_query: PathAndQuery = "/hello/world".parse().unwrap();
///
/// assert_eq!(path_and_query.as_str(), "/hello/world");
/// ```
#[inline]
pub fn as_str(&self) -> &str {
let ret = &self.data[..];
if ret.is_empty() {
return "/";
}
ret
}
}
impl<'a> TryFrom<&'a [u8]> for PathAndQuery {
type Error = InvalidUri;
#[inline]
fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
PathAndQuery::from_shared(Bytes::copy_from_slice(s))
}
}
impl<'a> TryFrom<&'a str> for PathAndQuery {
type Error = InvalidUri;
#[inline]
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
TryFrom::try_from(s.as_bytes())
}
}
impl<'a> TryFrom<Vec<u8>> for PathAndQuery {
type Error = InvalidUri;
#[inline]
fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
PathAndQuery::from_shared(vec.into())
}
}
impl TryFrom<String> for PathAndQuery {
type Error = InvalidUri;
#[inline]
fn try_from(s: String) -> Result<Self, Self::Error> {
PathAndQuery::from_shared(s.into())
}
}
impl TryFrom<&String> for PathAndQuery {
type Error = InvalidUri;
#[inline]
fn try_from(s: &String) -> Result<Self, Self::Error> {
TryFrom::try_from(s.as_bytes())
}
}
impl FromStr for PathAndQuery {
type Err = InvalidUri;
#[inline]
fn from_str(s: &str) -> Result<Self, InvalidUri> {
TryFrom::try_from(s)
}
}
impl fmt::Debug for PathAndQuery {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl fmt::Display for PathAndQuery {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
if !self.data.is_empty() {
match self.data.as_bytes()[0] {
b'/' | b'*' => write!(fmt, "{}", &self.data[..]),
_ => write!(fmt, "/{}", &self.data[..]),
}
} else {
write!(fmt, "/")
}
}
}
// ===== PartialEq / PartialOrd =====
impl PartialEq for PathAndQuery {
#[inline]
fn eq(&self, other: &PathAndQuery) -> bool {
self.data == other.data
}
}
impl Eq for PathAndQuery {}
impl PartialEq<str> for PathAndQuery {
#[inline]
fn eq(&self, other: &str) -> bool {
self.as_str() == other
}
}
impl<'a> PartialEq<PathAndQuery> for &'a str {
#[inline]
fn eq(&self, other: &PathAndQuery) -> bool {
self == &other.as_str()
}
}
impl<'a> PartialEq<&'a str> for PathAndQuery {
#[inline]
fn eq(&self, other: &&'a str) -> bool {
self.as_str() == *other
}
}
impl PartialEq<PathAndQuery> for str {
#[inline]
fn eq(&self, other: &PathAndQuery) -> bool {
self == other.as_str()
}
}
impl PartialEq<String> for PathAndQuery {
#[inline]
fn eq(&self, other: &String) -> bool {
self.as_str() == other.as_str()
}
}
impl PartialEq<PathAndQuery> for String {
#[inline]
fn eq(&self, other: &PathAndQuery) -> bool {
self.as_str() == other.as_str()
}
}
impl PartialOrd for PathAndQuery {
#[inline]
fn partial_cmp(&self, other: &PathAndQuery) -> Option<cmp::Ordering> {
self.as_str().partial_cmp(other.as_str())
}
}
impl PartialOrd<str> for PathAndQuery {
#[inline]
fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
self.as_str().partial_cmp(other)
}
}
impl PartialOrd<PathAndQuery> for str {
#[inline]
fn partial_cmp(&self, other: &PathAndQuery) -> Option<cmp::Ordering> {
self.partial_cmp(other.as_str())
}
}
impl<'a> PartialOrd<&'a str> for PathAndQuery {
#[inline]
fn partial_cmp(&self, other: &&'a str) -> Option<cmp::Ordering> {
self.as_str().partial_cmp(*other)
}
}
impl<'a> PartialOrd<PathAndQuery> for &'a str {
#[inline]
fn partial_cmp(&self, other: &PathAndQuery) -> Option<cmp::Ordering> {
self.partial_cmp(&other.as_str())
}
}
impl PartialOrd<String> for PathAndQuery {
#[inline]
fn partial_cmp(&self, other: &String) -> Option<cmp::Ordering> {
self.as_str().partial_cmp(other.as_str())
}
}
impl PartialOrd<PathAndQuery> for String {
#[inline]
fn partial_cmp(&self, other: &PathAndQuery) -> Option<cmp::Ordering> {
self.as_str().partial_cmp(other.as_str())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn equal_to_self_of_same_path() {
let p1: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
let p2: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
assert_eq!(p1, p2);
assert_eq!(p2, p1);
}
#[test]
fn not_equal_to_self_of_different_path() {
let p1: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
let p2: PathAndQuery = "/world&foo=bar".parse().unwrap();
assert_ne!(p1, p2);
assert_ne!(p2, p1);
}
#[test]
fn equates_with_a_str() {
let path_and_query: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
assert_eq!(&path_and_query, "/hello/world&foo=bar");
assert_eq!("/hello/world&foo=bar", &path_and_query);
assert_eq!(path_and_query, "/hello/world&foo=bar");
assert_eq!("/hello/world&foo=bar", path_and_query);
}
#[test]
fn not_equal_with_a_str_of_a_different_path() {
let path_and_query: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
// as a reference
assert_ne!(&path_and_query, "/hello&foo=bar");
assert_ne!("/hello&foo=bar", &path_and_query);
// without reference
assert_ne!(path_and_query, "/hello&foo=bar");
assert_ne!("/hello&foo=bar", path_and_query);
}
#[test]
fn equates_with_a_string() {
let path_and_query: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
assert_eq!(path_and_query, "/hello/world&foo=bar".to_string());
assert_eq!("/hello/world&foo=bar".to_string(), path_and_query);
}
#[test]
fn not_equal_with_a_string_of_a_different_path() {
let path_and_query: PathAndQuery = "/hello/world&foo=bar".parse().unwrap();
assert_ne!(path_and_query, "/hello&foo=bar".to_string());
assert_ne!("/hello&foo=bar".to_string(), path_and_query);
}
#[test]
fn compares_to_self() {
let p1: PathAndQuery = "/a/world&foo=bar".parse().unwrap();
let p2: PathAndQuery = "/b/world&foo=bar".parse().unwrap();
assert!(p1 < p2);
assert!(p2 > p1);
}
#[test]
fn compares_with_a_str() {
let path_and_query: PathAndQuery = "/b/world&foo=bar".parse().unwrap();
// by ref
assert!(&path_and_query < "/c/world&foo=bar");
assert!("/c/world&foo=bar" > &path_and_query);
assert!(&path_and_query > "/a/world&foo=bar");
assert!("/a/world&foo=bar" < &path_and_query);
// by val
assert!(path_and_query < "/c/world&foo=bar");
assert!("/c/world&foo=bar" > path_and_query);
assert!(path_and_query > "/a/world&foo=bar");
assert!("/a/world&foo=bar" < path_and_query);
}
#[test]
fn compares_with_a_string() {
let path_and_query: PathAndQuery = "/b/world&foo=bar".parse().unwrap();
assert!(path_and_query < "/c/world&foo=bar".to_string());
assert!("/c/world&foo=bar".to_string() > path_and_query);
assert!(path_and_query > "/a/world&foo=bar".to_string());
assert!("/a/world&foo=bar".to_string() < path_and_query);
}
#[test]
fn ignores_valid_percent_encodings() {
assert_eq!("/a%20b", pq("/a%20b?r=1").path());
assert_eq!("qr=%31", pq("/a/b?qr=%31").query().unwrap());
}
#[test]
fn ignores_invalid_percent_encodings() {
assert_eq!("/a%%b", pq("/a%%b?r=1").path());
assert_eq!("/aaa%", pq("/aaa%").path());
assert_eq!("/aaa%", pq("/aaa%?r=1").path());
assert_eq!("/aa%2", pq("/aa%2").path());
assert_eq!("/aa%2", pq("/aa%2?r=1").path());
assert_eq!("qr=%3", pq("/a/b?qr=%3").query().unwrap());
}
#[test]
fn json_is_fine() {
assert_eq!(r#"/{"bread":"baguette"}"#, pq(r#"/{"bread":"baguette"}"#).path());
}
fn pq(s: &str) -> PathAndQuery {
s.parse().expect(&format!("parsing {}", s))
}
}

151
zeroidc/vendor/http/src/uri/port.rs vendored Normal file
View File

@@ -0,0 +1,151 @@
use std::fmt;
use super::{ErrorKind, InvalidUri};
/// The port component of a URI.
pub struct Port<T> {
port: u16,
repr: T,
}
impl<T> Port<T> {
/// Returns the port number as a `u16`.
///
/// # Examples
///
/// Port as `u16`.
///
/// ```
/// # use http::uri::Authority;
/// let authority: Authority = "example.org:80".parse().unwrap();
///
/// let port = authority.port().unwrap();
/// assert_eq!(port.as_u16(), 80);
/// ```
pub fn as_u16(&self) -> u16 {
self.port
}
}
impl<T> Port<T>
where
T: AsRef<str>,
{
/// Converts a `str` to a port number.
///
/// The supplied `str` must be a valid u16.
pub(crate) fn from_str(bytes: T) -> Result<Self, InvalidUri> {
bytes
.as_ref()
.parse::<u16>()
.map(|port| Port { port, repr: bytes })
.map_err(|_| ErrorKind::InvalidPort.into())
}
/// Returns the port number as a `str`.
///
/// # Examples
///
/// Port as `str`.
///
/// ```
/// # use http::uri::Authority;
/// let authority: Authority = "example.org:80".parse().unwrap();
///
/// let port = authority.port().unwrap();
/// assert_eq!(port.as_str(), "80");
/// ```
pub fn as_str(&self) -> &str {
self.repr.as_ref()
}
}
impl<T> fmt::Debug for Port<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Port").field(&self.port).finish()
}
}
impl<T> fmt::Display for Port<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Use `u16::fmt` so that it respects any formatting flags that
// may have been set (like padding, align, etc).
fmt::Display::fmt(&self.port, f)
}
}
impl<T> From<Port<T>> for u16 {
fn from(port: Port<T>) -> Self {
port.as_u16()
}
}
impl<T> AsRef<str> for Port<T>
where
T: AsRef<str>,
{
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl<T, U> PartialEq<Port<U>> for Port<T> {
fn eq(&self, other: &Port<U>) -> bool {
self.port == other.port
}
}
impl<T> PartialEq<u16> for Port<T> {
fn eq(&self, other: &u16) -> bool {
self.port == *other
}
}
impl<T> PartialEq<Port<T>> for u16 {
fn eq(&self, other: &Port<T>) -> bool {
other.port == *self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn partialeq_port() {
let port_a = Port::from_str("8080").unwrap();
let port_b = Port::from_str("8080").unwrap();
assert_eq!(port_a, port_b);
}
#[test]
fn partialeq_port_different_reprs() {
let port_a = Port {
repr: "8081",
port: 8081,
};
let port_b = Port {
repr: String::from("8081"),
port: 8081,
};
assert_eq!(port_a, port_b);
assert_eq!(port_b, port_a);
}
#[test]
fn partialeq_u16() {
let port = Port::from_str("8080").unwrap();
// test equals in both directions
assert_eq!(port, 8080);
assert_eq!(8080, port);
}
#[test]
fn u16_from_port() {
let port = Port::from_str("8080").unwrap();
assert_eq!(8080, u16::from(port));
}
}

363
zeroidc/vendor/http/src/uri/scheme.rs vendored Normal file
View File

@@ -0,0 +1,363 @@
use std::convert::TryFrom;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::str::FromStr;
use bytes::Bytes;
use super::{ErrorKind, InvalidUri};
use crate::byte_str::ByteStr;
/// Represents the scheme component of a URI
#[derive(Clone)]
pub struct Scheme {
pub(super) inner: Scheme2,
}
#[derive(Clone, Debug)]
pub(super) enum Scheme2<T = Box<ByteStr>> {
None,
Standard(Protocol),
Other(T),
}
#[derive(Copy, Clone, Debug)]
pub(super) enum Protocol {
Http,
Https,
}
impl Scheme {
/// HTTP protocol scheme
pub const HTTP: Scheme = Scheme {
inner: Scheme2::Standard(Protocol::Http),
};
/// HTTP protocol over TLS.
pub const HTTPS: Scheme = Scheme {
inner: Scheme2::Standard(Protocol::Https),
};
pub(super) fn empty() -> Self {
Scheme {
inner: Scheme2::None,
}
}
/// Return a str representation of the scheme
///
/// # Examples
///
/// ```
/// # use http::uri::*;
/// let scheme: Scheme = "http".parse().unwrap();
/// assert_eq!(scheme.as_str(), "http");
/// ```
#[inline]
pub fn as_str(&self) -> &str {
use self::Protocol::*;
use self::Scheme2::*;
match self.inner {
Standard(Http) => "http",
Standard(Https) => "https",
Other(ref v) => &v[..],
None => unreachable!(),
}
}
}
impl<'a> TryFrom<&'a [u8]> for Scheme {
type Error = InvalidUri;
#[inline]
fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
use self::Scheme2::*;
match Scheme2::parse_exact(s)? {
None => Err(ErrorKind::InvalidScheme.into()),
Standard(p) => Ok(Standard(p).into()),
Other(_) => {
let bytes = Bytes::copy_from_slice(s);
// Safety: postcondition on parse_exact() means that s and
// hence bytes are valid UTF-8.
let string = unsafe { ByteStr::from_utf8_unchecked(bytes) };
Ok(Other(Box::new(string)).into())
}
}
}
}
impl<'a> TryFrom<&'a str> for Scheme {
type Error = InvalidUri;
#[inline]
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
TryFrom::try_from(s.as_bytes())
}
}
impl FromStr for Scheme {
type Err = InvalidUri;
fn from_str(s: &str) -> Result<Self, Self::Err> {
TryFrom::try_from(s)
}
}
impl fmt::Debug for Scheme {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.as_str(), f)
}
}
impl fmt::Display for Scheme {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl AsRef<str> for Scheme {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl PartialEq for Scheme {
fn eq(&self, other: &Scheme) -> bool {
use self::Protocol::*;
use self::Scheme2::*;
match (&self.inner, &other.inner) {
(&Standard(Http), &Standard(Http)) => true,
(&Standard(Https), &Standard(Https)) => true,
(&Other(ref a), &Other(ref b)) => a.eq_ignore_ascii_case(b),
(&None, _) | (_, &None) => unreachable!(),
_ => false,
}
}
}
impl Eq for Scheme {}
/// Case-insensitive equality
///
/// # Examples
///
/// ```
/// # use http::uri::Scheme;
/// let scheme: Scheme = "HTTP".parse().unwrap();
/// assert_eq!(scheme, *"http");
/// ```
impl PartialEq<str> for Scheme {
fn eq(&self, other: &str) -> bool {
self.as_str().eq_ignore_ascii_case(other)
}
}
/// Case-insensitive equality
impl PartialEq<Scheme> for str {
fn eq(&self, other: &Scheme) -> bool {
other == self
}
}
/// Case-insensitive hashing
impl Hash for Scheme {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
match self.inner {
Scheme2::None => (),
Scheme2::Standard(Protocol::Http) => state.write_u8(1),
Scheme2::Standard(Protocol::Https) => state.write_u8(2),
Scheme2::Other(ref other) => {
other.len().hash(state);
for &b in other.as_bytes() {
state.write_u8(b.to_ascii_lowercase());
}
}
}
}
}
impl<T> Scheme2<T> {
pub(super) fn is_none(&self) -> bool {
match *self {
Scheme2::None => true,
_ => false,
}
}
}
// Require the scheme to not be too long in order to enable further
// optimizations later.
const MAX_SCHEME_LEN: usize = 64;
// scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
//
// SCHEME_CHARS is a table of valid characters in the scheme part of a URI. An
// entry in the table is 0 for invalid characters. For valid characters the
// entry is itself (i.e. the entry for 43 is b'+' because b'+' == 43u8). An
// important characteristic of this table is that all entries above 127 are
// invalid. This makes all of the valid entries a valid single-byte UTF-8 code
// point. This means that a slice of such valid entries is valid UTF-8.
const SCHEME_CHARS: [u8; 256] = [
// 0 1 2 3 4 5 6 7 8 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3x
0, 0, 0, b'+', 0, b'-', b'.', 0, b'0', b'1', // 4x
b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b':', 0, // 5x
0, 0, 0, 0, 0, b'A', b'B', b'C', b'D', b'E', // 6x
b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', // 7x
b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', // 8x
b'Z', 0, 0, 0, 0, 0, 0, b'a', b'b', b'c', // 9x
b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', // 10x
b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', // 11x
b'x', b'y', b'z', 0, 0, 0, b'~', 0, 0, 0, // 12x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 13x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 14x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 15x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 17x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 18x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 19x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 21x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 22x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 23x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 24x
0, 0, 0, 0, 0, 0 // 25x
];
impl Scheme2<usize> {
// Postcondition: On all Ok() returns, s is valid UTF-8
fn parse_exact(s: &[u8]) -> Result<Scheme2<()>, InvalidUri> {
match s {
b"http" => Ok(Protocol::Http.into()),
b"https" => Ok(Protocol::Https.into()),
_ => {
if s.len() > MAX_SCHEME_LEN {
return Err(ErrorKind::SchemeTooLong.into());
}
// check that each byte in s is a SCHEME_CHARS which implies
// that it is a valid single byte UTF-8 code point.
for &b in s {
match SCHEME_CHARS[b as usize] {
b':' => {
// Don't want :// here
return Err(ErrorKind::InvalidScheme.into());
}
0 => {
return Err(ErrorKind::InvalidScheme.into());
}
_ => {}
}
}
Ok(Scheme2::Other(()))
}
}
}
pub(super) fn parse(s: &[u8]) -> Result<Scheme2<usize>, InvalidUri> {
if s.len() >= 7 {
// Check for HTTP
if s[..7].eq_ignore_ascii_case(b"http://") {
// Prefix will be striped
return Ok(Protocol::Http.into());
}
}
if s.len() >= 8 {
// Check for HTTPs
if s[..8].eq_ignore_ascii_case(b"https://") {
return Ok(Protocol::Https.into());
}
}
if s.len() > 3 {
for i in 0..s.len() {
let b = s[i];
match SCHEME_CHARS[b as usize] {
b':' => {
// Not enough data remaining
if s.len() < i + 3 {
break;
}
// Not a scheme
if &s[i + 1..i + 3] != b"//" {
break;
}
if i > MAX_SCHEME_LEN {
return Err(ErrorKind::SchemeTooLong.into());
}
// Return scheme
return Ok(Scheme2::Other(i));
}
// Invald scheme character, abort
0 => break,
_ => {}
}
}
}
Ok(Scheme2::None)
}
}
impl Protocol {
pub(super) fn len(&self) -> usize {
match *self {
Protocol::Http => 4,
Protocol::Https => 5,
}
}
}
impl<T> From<Protocol> for Scheme2<T> {
fn from(src: Protocol) -> Self {
Scheme2::Standard(src)
}
}
#[doc(hidden)]
impl From<Scheme2> for Scheme {
fn from(src: Scheme2) -> Self {
Scheme { inner: src }
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn scheme_eq_to_str() {
assert_eq!(&scheme("http"), "http");
assert_eq!(&scheme("https"), "https");
assert_eq!(&scheme("ftp"), "ftp");
assert_eq!(&scheme("my+funky+scheme"), "my+funky+scheme");
}
#[test]
fn invalid_scheme_is_error() {
Scheme::try_from("my_funky_scheme").expect_err("Unexpectly valid Scheme");
// Invalid UTF-8
Scheme::try_from([0xC0].as_ref()).expect_err("Unexpectly valid Scheme");
}
fn scheme(s: &str) -> Scheme {
s.parse().expect(&format!("Invalid scheme: {}", s))
}
}

519
zeroidc/vendor/http/src/uri/tests.rs vendored Normal file
View File

@@ -0,0 +1,519 @@
use std::str::FromStr;
use super::{ErrorKind, InvalidUri, Port, Uri, URI_CHARS};
#[test]
fn test_char_table() {
for (i, &v) in URI_CHARS.iter().enumerate() {
if v != 0 {
assert_eq!(i, v as usize);
}
}
}
macro_rules! part {
($s:expr) => {
Some(&$s.parse().unwrap())
};
}
macro_rules! test_parse {
(
$test_name:ident,
$str:expr,
$alt:expr,
$($method:ident = $value:expr,)*
) => (
#[test]
fn $test_name() {
let orig_str = $str;
let uri = match Uri::from_str(orig_str) {
Ok(uri) => uri,
Err(err) => {
panic!("parse error {:?} from {:?}", err, orig_str);
},
};
$(
assert_eq!(uri.$method(), $value, "{}: uri = {:?}", stringify!($method), uri);
)+
assert_eq!(uri, orig_str, "partial eq to original str");
assert_eq!(uri, uri.clone(), "clones are equal");
let new_str = uri.to_string();
let new_uri = Uri::from_str(&new_str).expect("to_string output parses again as a Uri");
assert_eq!(new_uri, orig_str, "round trip still equals original str");
const ALT: &'static [&'static str] = &$alt;
for &alt in ALT.iter() {
let other: Uri = alt.parse().unwrap();
assert_eq!(uri, *alt);
assert_eq!(uri, other);
}
}
);
}
test_parse! {
test_uri_parse_path_and_query,
"/some/path/here?and=then&hello#and-bye",
[],
scheme = None,
authority = None,
path = "/some/path/here",
query = Some("and=then&hello"),
host = None,
}
test_parse! {
test_uri_parse_absolute_form,
"http://127.0.0.1:61761/chunks",
[],
scheme = part!("http"),
authority = part!("127.0.0.1:61761"),
path = "/chunks",
query = None,
host = Some("127.0.0.1"),
port = Port::from_str("61761").ok(),
}
test_parse! {
test_uri_parse_absolute_form_without_path,
"https://127.0.0.1:61761",
["https://127.0.0.1:61761/"],
scheme = part!("https"),
authority = part!("127.0.0.1:61761"),
path = "/",
query = None,
host = Some("127.0.0.1"),
port = Port::from_str("61761").ok(),
}
test_parse! {
test_uri_parse_asterisk_form,
"*",
[],
scheme = None,
authority = None,
path = "*",
query = None,
host = None,
}
test_parse! {
test_uri_parse_authority_no_port,
"localhost",
["LOCALHOST", "LocaLHOSt"],
scheme = None,
authority = part!("localhost"),
path = "",
query = None,
port = None,
host = Some("localhost"),
}
test_parse! {
test_uri_authority_only_one_character_issue_197,
"S",
[],
scheme = None,
authority = part!("S"),
path = "",
query = None,
port = None,
host = Some("S"),
}
test_parse! {
test_uri_parse_authority_form,
"localhost:3000",
["localhosT:3000"],
scheme = None,
authority = part!("localhost:3000"),
path = "",
query = None,
host = Some("localhost"),
port = Port::from_str("3000").ok(),
}
test_parse! {
test_uri_parse_absolute_with_default_port_http,
"http://127.0.0.1:80",
["http://127.0.0.1:80/"],
scheme = part!("http"),
authority = part!("127.0.0.1:80"),
host = Some("127.0.0.1"),
path = "/",
query = None,
port = Port::from_str("80").ok(),
}
test_parse! {
test_uri_parse_absolute_with_default_port_https,
"https://127.0.0.1:443",
["https://127.0.0.1:443/"],
scheme = part!("https"),
authority = part!("127.0.0.1:443"),
host = Some("127.0.0.1"),
path = "/",
query = None,
port = Port::from_str("443").ok(),
}
test_parse! {
test_uri_parse_fragment_questionmark,
"http://127.0.0.1/#?",
[],
scheme = part!("http"),
authority = part!("127.0.0.1"),
host = Some("127.0.0.1"),
path = "/",
query = None,
port = None,
}
test_parse! {
test_uri_parse_path_with_terminating_questionmark,
"http://127.0.0.1/path?",
[],
scheme = part!("http"),
authority = part!("127.0.0.1"),
path = "/path",
query = Some(""),
port = None,
}
test_parse! {
test_uri_parse_absolute_form_with_empty_path_and_nonempty_query,
"http://127.0.0.1?foo=bar",
[],
scheme = part!("http"),
authority = part!("127.0.0.1"),
path = "/",
query = Some("foo=bar"),
port = None,
}
test_parse! {
test_uri_parse_absolute_form_with_empty_path_and_fragment_with_slash,
"http://127.0.0.1#foo/bar",
[],
scheme = part!("http"),
authority = part!("127.0.0.1"),
path = "/",
query = None,
port = None,
}
test_parse! {
test_uri_parse_absolute_form_with_empty_path_and_fragment_with_questionmark,
"http://127.0.0.1#foo?bar",
[],
scheme = part!("http"),
authority = part!("127.0.0.1"),
path = "/",
query = None,
port = None,
}
test_parse! {
test_uri_parse_long_host_with_no_scheme,
"thequickbrownfoxjumpedoverthelazydogtofindthelargedangerousdragon.localhost",
[],
scheme = None,
authority = part!("thequickbrownfoxjumpedoverthelazydogtofindthelargedangerousdragon.localhost"),
path = "",
query = None,
port = None,
}
test_parse! {
test_uri_parse_long_host_with_port_and_no_scheme,
"thequickbrownfoxjumpedoverthelazydogtofindthelargedangerousdragon.localhost:1234",
[],
scheme = None,
authority = part!("thequickbrownfoxjumpedoverthelazydogtofindthelargedangerousdragon.localhost:1234"),
path = "",
query = None,
port = Port::from_str("1234").ok(),
}
test_parse! {
test_userinfo1,
"http://a:b@127.0.0.1:1234/",
[],
scheme = part!("http"),
authority = part!("a:b@127.0.0.1:1234"),
host = Some("127.0.0.1"),
path = "/",
query = None,
port = Port::from_str("1234").ok(),
}
test_parse! {
test_userinfo2,
"http://a:b@127.0.0.1/",
[],
scheme = part!("http"),
authority = part!("a:b@127.0.0.1"),
host = Some("127.0.0.1"),
path = "/",
query = None,
port = None,
}
test_parse! {
test_userinfo3,
"http://a@127.0.0.1/",
[],
scheme = part!("http"),
authority = part!("a@127.0.0.1"),
host = Some("127.0.0.1"),
path = "/",
query = None,
port = None,
}
test_parse! {
test_userinfo_with_port,
"user@localhost:3000",
[],
scheme = None,
authority = part!("user@localhost:3000"),
path = "",
query = None,
host = Some("localhost"),
port = Port::from_str("3000").ok(),
}
test_parse! {
test_userinfo_pass_with_port,
"user:pass@localhost:3000",
[],
scheme = None,
authority = part!("user:pass@localhost:3000"),
path = "",
query = None,
host = Some("localhost"),
port = Port::from_str("3000").ok(),
}
test_parse! {
test_ipv6,
"http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]/",
[],
scheme = part!("http"),
authority = part!("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"),
host = Some("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"),
path = "/",
query = None,
port = None,
}
test_parse! {
test_ipv6_shorthand,
"http://[::1]/",
[],
scheme = part!("http"),
authority = part!("[::1]"),
host = Some("[::1]"),
path = "/",
query = None,
port = None,
}
test_parse! {
test_ipv6_shorthand2,
"http://[::]/",
[],
scheme = part!("http"),
authority = part!("[::]"),
host = Some("[::]"),
path = "/",
query = None,
port = None,
}
test_parse! {
test_ipv6_shorthand3,
"http://[2001:db8::2:1]/",
[],
scheme = part!("http"),
authority = part!("[2001:db8::2:1]"),
host = Some("[2001:db8::2:1]"),
path = "/",
query = None,
port = None,
}
test_parse! {
test_ipv6_with_port,
"http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8008/",
[],
scheme = part!("http"),
authority = part!("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8008"),
host = Some("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"),
path = "/",
query = None,
port = Port::from_str("8008").ok(),
}
test_parse! {
test_percentage_encoded_path,
"/echo/abcdefgh_i-j%20/abcdefg_i-j%20478",
[],
scheme = None,
authority = None,
host = None,
path = "/echo/abcdefgh_i-j%20/abcdefg_i-j%20478",
query = None,
port = None,
}
test_parse! {
test_path_permissive,
"/foo=bar|baz\\^~%",
[],
path = "/foo=bar|baz\\^~%",
}
test_parse! {
test_query_permissive,
"/?foo={bar|baz}\\^`",
[],
query = Some("foo={bar|baz}\\^`"),
}
#[test]
fn test_uri_parse_error() {
fn err(s: &str) {
Uri::from_str(s).unwrap_err();
}
err("http://");
err("htt:p//host");
err("hyper.rs/");
err("hyper.rs?key=val");
err("?key=val");
err("localhost/");
err("localhost?key=val");
err("\0");
err("http://[::1");
err("http://::1]");
err("localhost:8080:3030");
err("@");
err("http://username:password@/wut");
// illegal queries
err("/?foo\rbar");
err("/?foo\nbar");
err("/?<");
err("/?>");
}
#[test]
fn test_max_uri_len() {
let mut uri = vec![];
uri.extend(b"http://localhost/");
uri.extend(vec![b'a'; 70 * 1024]);
let uri = String::from_utf8(uri).unwrap();
let res: Result<Uri, InvalidUri> = uri.parse();
assert_eq!(res.unwrap_err().0, ErrorKind::TooLong);
}
#[test]
fn test_overflowing_scheme() {
let mut uri = vec![];
uri.extend(vec![b'a'; 256]);
uri.extend(b"://localhost/");
let uri = String::from_utf8(uri).unwrap();
let res: Result<Uri, InvalidUri> = uri.parse();
assert_eq!(res.unwrap_err().0, ErrorKind::SchemeTooLong);
}
#[test]
fn test_max_length_scheme() {
let mut uri = vec![];
uri.extend(vec![b'a'; 64]);
uri.extend(b"://localhost/");
let uri = String::from_utf8(uri).unwrap();
let uri: Uri = uri.parse().unwrap();
assert_eq!(uri.scheme_str().unwrap().len(), 64);
}
#[test]
fn test_uri_to_path_and_query() {
let cases = vec![
("/", "/"),
("/foo?bar", "/foo?bar"),
("/foo?bar#nope", "/foo?bar"),
("http://hyper.rs", "/"),
("http://hyper.rs/", "/"),
("http://hyper.rs/path", "/path"),
("http://hyper.rs?query", "/?query"),
("*", "*"),
];
for case in cases {
let uri = Uri::from_str(case.0).unwrap();
let s = uri.path_and_query().unwrap().to_string();
assert_eq!(s, case.1);
}
}
#[test]
fn test_authority_uri_parts_round_trip() {
let s = "hyper.rs";
let uri = Uri::from_str(s).expect("first parse");
assert_eq!(uri, s);
assert_eq!(uri.to_string(), s);
let parts = uri.into_parts();
let uri2 = Uri::from_parts(parts).expect("from_parts");
assert_eq!(uri2, s);
assert_eq!(uri2.to_string(), s);
}
#[test]
fn test_partial_eq_path_with_terminating_questionmark() {
let a = "/path";
let uri = Uri::from_str("/path?").expect("first parse");
assert_eq!(uri, a);
}

75
zeroidc/vendor/http/src/version.rs vendored Normal file
View File

@@ -0,0 +1,75 @@
//! HTTP version
//!
//! This module contains a definition of the `Version` type. The `Version`
//! type is intended to be accessed through the root of the crate
//! (`http::Version`) rather than this module.
//!
//! The `Version` type contains constants that represent the various versions
//! of the HTTP protocol.
//!
//! # Examples
//!
//! ```
//! use http::Version;
//!
//! let http11 = Version::HTTP_11;
//! let http2 = Version::HTTP_2;
//! assert!(http11 != http2);
//!
//! println!("{:?}", http2);
//! ```
use std::fmt;
/// Represents a version of the HTTP spec.
#[derive(PartialEq, PartialOrd, Copy, Clone, Eq, Ord, Hash)]
pub struct Version(Http);
impl Version {
/// `HTTP/0.9`
pub const HTTP_09: Version = Version(Http::Http09);
/// `HTTP/1.0`
pub const HTTP_10: Version = Version(Http::Http10);
/// `HTTP/1.1`
pub const HTTP_11: Version = Version(Http::Http11);
/// `HTTP/2.0`
pub const HTTP_2: Version = Version(Http::H2);
/// `HTTP/3.0`
pub const HTTP_3: Version = Version(Http::H3);
}
#[derive(PartialEq, PartialOrd, Copy, Clone, Eq, Ord, Hash)]
enum Http {
Http09,
Http10,
Http11,
H2,
H3,
__NonExhaustive,
}
impl Default for Version {
#[inline]
fn default() -> Version {
Version::HTTP_11
}
}
impl fmt::Debug for Version {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use self::Http::*;
f.write_str(match self.0 {
Http09 => "HTTP/0.9",
Http10 => "HTTP/1.0",
Http11 => "HTTP/1.1",
H2 => "HTTP/2.0",
H3 => "HTTP/3.0",
__NonExhaustive => unreachable!(),
})
}
}