mirror of
https://github.com/openharmony/third_party_rust_http.git
synced 2026-07-19 14:43:33 -04:00
introduce a Uri Builder (#219)
This commit is contained in:
+20
-1
@@ -3,7 +3,7 @@ use header::{HeaderName, HeaderValue};
|
||||
use method::Method;
|
||||
use sealed::Sealed;
|
||||
use status::StatusCode;
|
||||
use uri::Uri;
|
||||
use uri::{Scheme, Authority, PathAndQuery, Uri};
|
||||
|
||||
/// Private trait for the `http` crate to have generic methods with fallible
|
||||
/// conversions.
|
||||
@@ -22,6 +22,22 @@ pub trait HttpTryFrom<T>: Sized + Sealed {
|
||||
fn try_from(t: T) -> Result<Self, Self::Error>;
|
||||
}
|
||||
|
||||
pub(crate) trait HttpTryInto<T>: Sized {
|
||||
fn http_try_into(self) -> Result<T, Error>;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
impl<T, U> HttpTryInto<U> for T
|
||||
where
|
||||
U: HttpTryFrom<T>,
|
||||
T: Sized,
|
||||
{
|
||||
fn http_try_into(self) -> Result<U, Error> {
|
||||
HttpTryFrom::try_from(self)
|
||||
.map_err(|e: U::Error| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! reflexive {
|
||||
($($t:ty,)*) => ($(
|
||||
impl HttpTryFrom<$t> for $t {
|
||||
@@ -42,4 +58,7 @@ reflexive! {
|
||||
StatusCode,
|
||||
HeaderName,
|
||||
HeaderValue,
|
||||
Scheme,
|
||||
Authority,
|
||||
PathAndQuery,
|
||||
}
|
||||
|
||||
+1
-2
@@ -725,8 +725,7 @@ impl fmt::Debug for Parts {
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
/// Creates a new default instance of `Builder` to construct either a
|
||||
/// `Head` or a `Request`.
|
||||
/// Creates a new default instance of `Builder` to construct a `Request`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
||||
+33
-5
@@ -8,6 +8,7 @@ use std::str::FromStr;
|
||||
use bytes::Bytes;
|
||||
|
||||
use byte_str::ByteStr;
|
||||
use convert::HttpTryFrom;
|
||||
use super::{ErrorKind, InvalidUri, InvalidUriBytes, URI_CHARS, Port};
|
||||
|
||||
/// Represents the authority component of a URI.
|
||||
@@ -397,17 +398,44 @@ impl Hash for Authority {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Authority {
|
||||
type Err = InvalidUri;
|
||||
impl HttpTryFrom<Bytes> for Authority {
|
||||
type Error = InvalidUriBytes;
|
||||
#[inline]
|
||||
fn try_from(bytes: Bytes) -> Result<Self, Self::Error> {
|
||||
Authority::from_shared(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, InvalidUri> {
|
||||
let end = Authority::parse_non_empty(s.as_bytes())?;
|
||||
impl<'a> HttpTryFrom<&'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
|
||||
let end = Authority::parse_non_empty(s)?;
|
||||
|
||||
if end != s.len() {
|
||||
return Err(ErrorKind::InvalidAuthority.into());
|
||||
}
|
||||
|
||||
Ok(Authority { data: s.into() })
|
||||
Ok(Authority {
|
||||
data: unsafe { ByteStr::from_utf8_unchecked(s.into()) },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> HttpTryFrom<&'a str> for Authority {
|
||||
type Error = InvalidUri;
|
||||
#[inline]
|
||||
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
|
||||
HttpTryFrom::try_from(s.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Authority {
|
||||
type Err = InvalidUri;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, InvalidUri> {
|
||||
HttpTryFrom::try_from(s)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
use {Uri, Result};
|
||||
use convert::{HttpTryFrom, HttpTryInto};
|
||||
use super::{Authority, Scheme, Parts, PathAndQuery};
|
||||
|
||||
/// 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: Option<Result<Parts>>,
|
||||
}
|
||||
|
||||
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>(&mut self, scheme: T) -> &mut Self
|
||||
where
|
||||
Scheme: HttpTryFrom<T>,
|
||||
{
|
||||
self.map(|parts| {
|
||||
parts.scheme = Some(scheme.http_try_into()?);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
/// Set the `Authority` for this URI.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use http::*;
|
||||
///
|
||||
/// let uri = uri::Builder::new()
|
||||
/// .authority("tokio.rs")
|
||||
/// .build()
|
||||
/// .unwrap();
|
||||
/// ```
|
||||
pub fn authority<T>(&mut self, auth: T) -> &mut Self
|
||||
where
|
||||
Authority: HttpTryFrom<T>,
|
||||
{
|
||||
self.map(|parts| {
|
||||
parts.authority = Some(auth.http_try_into()?);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
/// 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>(&mut self, p_and_q: T) -> &mut Self
|
||||
where
|
||||
PathAndQuery: HttpTryFrom<T>,
|
||||
{
|
||||
self.map(|parts| {
|
||||
parts.path_and_query = Some(p_and_q.http_try_into()?);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
/// 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(&mut self) -> Result<Uri> {
|
||||
self
|
||||
.parts
|
||||
.take()
|
||||
.expect("cannot reuse Uri builder")
|
||||
.and_then(|parts| parts.http_try_into())
|
||||
}
|
||||
|
||||
fn map<F>(&mut self, f: F) -> &mut Self
|
||||
where
|
||||
F: FnOnce(&mut Parts) -> Result<()>,
|
||||
{
|
||||
let res = if let Some(Ok(ref mut parts)) = self.parts {
|
||||
f(parts)
|
||||
} else {
|
||||
return self;
|
||||
};
|
||||
|
||||
if let Err(err) = res {
|
||||
self.parts = Some(Err(err));
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Builder {
|
||||
#[inline]
|
||||
fn default() -> Builder {
|
||||
Builder {
|
||||
parts: Some(Ok(Parts::default())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,11 +38,13 @@ use std::error::Error;
|
||||
use self::scheme::Scheme2;
|
||||
|
||||
pub use self::authority::Authority;
|
||||
pub use self::builder::Builder;
|
||||
pub use self::path::PathAndQuery;
|
||||
pub use self::scheme::Scheme;
|
||||
pub use self::port::Port;
|
||||
|
||||
mod authority;
|
||||
mod builder;
|
||||
mod path;
|
||||
mod port;
|
||||
mod scheme;
|
||||
@@ -178,6 +180,27 @@ const URI_CHARS: [u8; 256] = [
|
||||
];
|
||||
|
||||
impl Uri {
|
||||
/// Creates a new builder-style object to manufacture a `Uri`.
|
||||
///
|
||||
/// This method returns an instance of `Builder` which can be usd to
|
||||
/// create a `Uri`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use http::Uri;
|
||||
///
|
||||
/// let uri = Uri::builder()
|
||||
/// .scheme("https")
|
||||
/// .authority("hyper.rs")
|
||||
/// .path_and_query("/")
|
||||
/// .build()
|
||||
/// .unwrap();
|
||||
/// ```
|
||||
pub fn builder() -> Builder {
|
||||
Builder::new()
|
||||
}
|
||||
|
||||
/// Attempt to convert a `Uri` from `Parts`
|
||||
pub fn from_parts(src: Parts) -> Result<Uri, InvalidUriParts> {
|
||||
if src.scheme.is_some() {
|
||||
|
||||
+27
-2
@@ -4,6 +4,7 @@ use std::str::FromStr;
|
||||
use bytes::Bytes;
|
||||
|
||||
use byte_str::ByteStr;
|
||||
use convert::HttpTryFrom;
|
||||
use super::{ErrorKind, InvalidUri, InvalidUriBytes, URI_CHARS};
|
||||
|
||||
/// Represents the path component of a URI
|
||||
@@ -250,11 +251,35 @@ impl PathAndQuery {
|
||||
}
|
||||
}
|
||||
|
||||
impl HttpTryFrom<Bytes> for PathAndQuery {
|
||||
type Error = InvalidUriBytes;
|
||||
#[inline]
|
||||
fn try_from(bytes: Bytes) -> Result<Self, Self::Error> {
|
||||
PathAndQuery::from_shared(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> HttpTryFrom<&'a [u8]> for PathAndQuery {
|
||||
type Error = InvalidUri;
|
||||
#[inline]
|
||||
fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
|
||||
PathAndQuery::from_shared(s.into()).map_err(|e| e.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> HttpTryFrom<&'a str> for PathAndQuery {
|
||||
type Error = InvalidUri;
|
||||
#[inline]
|
||||
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
|
||||
HttpTryFrom::try_from(s.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for PathAndQuery {
|
||||
type Err = InvalidUri;
|
||||
|
||||
#[inline]
|
||||
fn from_str(s: &str) -> Result<Self, InvalidUri> {
|
||||
PathAndQuery::from_shared(s.into()).map_err(|e| e.0)
|
||||
HttpTryFrom::try_from(s)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+37
-9
@@ -8,6 +8,7 @@ use std::str::FromStr;
|
||||
use bytes::Bytes;
|
||||
|
||||
use byte_str::ByteStr;
|
||||
use convert::HttpTryFrom;
|
||||
use super::{ErrorKind, InvalidUri, InvalidUriBytes};
|
||||
|
||||
/// Represents the scheme component of a URI
|
||||
@@ -109,19 +110,46 @@ impl Scheme {
|
||||
}
|
||||
}
|
||||
|
||||
impl HttpTryFrom<Bytes> for Scheme {
|
||||
type Error = InvalidUriBytes;
|
||||
#[inline]
|
||||
fn try_from(bytes: Bytes) -> Result<Self, Self::Error> {
|
||||
Scheme::from_shared(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> HttpTryFrom<&'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(_) => {
|
||||
// Unsafe: parse_exact already checks for a strict subset of UTF-8
|
||||
Ok(Other(Box::new(unsafe {
|
||||
ByteStr::from_utf8_unchecked(s.into())
|
||||
})).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> HttpTryFrom<&'a str> for Scheme {
|
||||
type Error = InvalidUri;
|
||||
#[inline]
|
||||
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
|
||||
HttpTryFrom::try_from(s.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Scheme {
|
||||
type Err = InvalidUri;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
use self::Scheme2::*;
|
||||
|
||||
match Scheme2::parse_exact(s.as_bytes())? {
|
||||
None => Err(ErrorKind::InvalidScheme.into()),
|
||||
Standard(p) => Ok(Standard(p).into()),
|
||||
Other(_) => {
|
||||
Ok(Other(Box::new(s.into())).into())
|
||||
}
|
||||
}
|
||||
HttpTryFrom::try_from(s)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user