use {
crate::{
addr::Address,
body::{Boxed, IntoRequestBody, prelude::*},
client::Client,
},
futures_lite::prelude::*,
http::{HeaderMap, Method, StatusCode, Uri, Version, request, response},
std::{convert::Infallible, error, fmt, io},
};
#[cfg(feature = "rtn")]
pub use crate::proto_rtn::HandshakeWith;
#[derive(Clone, Debug)]
pub struct Session<I> {
pub addr: Address,
pub io: I,
}
pub trait Handshake<I, B> {
type Client: Client<B>;
async fn handshake(
self,
se: Session<I>,
) -> Result<(Self::Client, impl Future<Output = ()>), Error>;
}
#[derive(Debug)]
pub enum Error {
Io(io::Error),
InvalidHost,
UnsupportedProtocol(Box<[u8]>),
}
impl Error {
pub fn try_into_io(self) -> Result<io::Error, Self> {
match self {
Self::Io(e) => Ok(e),
e => Err(e),
}
}
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
Self::Io(e)
}
}
impl From<Error> for io::Error {
fn from(e: Error) -> Self {
e.try_into_io().unwrap_or_else(Self::other)
}
}
impl From<Infallible> for Error {
fn from(e: Infallible) -> Self {
match e {}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(e) => write!(f, "io error: {e}"),
Self::InvalidHost => write!(f, "invalid host"),
Self::UnsupportedProtocol(proto) => {
write!(f, "unsupported protocol: ")?;
for chunk in proto.utf8_chunks() {
write!(f, "{}", chunk.valid())?;
if !chunk.invalid().is_empty() {
write!(f, "{}", char::REPLACEMENT_CHARACTER)?;
}
}
Ok(())
}
}
}
}
impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
Self::Io(e) => Some(e),
Self::InvalidHost => None,
Self::UnsupportedProtocol(_) => None,
}
}
}
#[derive(Debug)]
pub struct Request<B = Boxed<'static>> {
head: request::Parts,
body: B,
}
impl<B> Request<B> {
pub fn new(method: Method, uri: Uri, body: B) -> Self {
let (mut head, body) = http::Request::new(body).into_parts();
head.method = method;
head.uri = uri;
Self { head, body }
}
pub fn get<I>(uri: Uri, body: I) -> Self
where
I: IntoRequestBody<Body = B>,
{
let mut req = Self::new(Method::GET, uri, body.into_req_body());
I::upd_req(&mut req);
req
}
pub fn head<I>(uri: Uri, body: I) -> Self
where
I: IntoRequestBody<Body = B>,
{
let mut req = Self::new(Method::HEAD, uri, body.into_req_body());
I::upd_req(&mut req);
req
}
pub fn post<I>(uri: Uri, body: I) -> Self
where
I: IntoRequestBody<Body = B>,
{
let mut req = Self::new(Method::POST, uri, body.into_req_body());
I::upd_req(&mut req);
req
}
pub fn put<I>(uri: Uri, body: I) -> Self
where
I: IntoRequestBody<Body = B>,
{
let mut req = Self::new(Method::PUT, uri, body.into_req_body());
I::upd_req(&mut req);
req
}
pub fn delete<I>(uri: Uri, body: I) -> Self
where
I: IntoRequestBody<Body = B>,
{
let mut req = Self::new(Method::DELETE, uri, body.into_req_body());
I::upd_req(&mut req);
req
}
pub fn options<I>(uri: Uri, body: I) -> Self
where
I: IntoRequestBody<Body = B>,
{
let mut req = Self::new(Method::OPTIONS, uri, body.into_req_body());
I::upd_req(&mut req);
req
}
pub fn patch<I>(uri: Uri, body: I) -> Self
where
I: IntoRequestBody<Body = B>,
{
let mut req = Self::new(Method::PATCH, uri, body.into_req_body());
I::upd_req(&mut req);
req
}
#[cfg(any(feature = "http1", feature = "http2"))]
pub(crate) fn version_mut(&mut self) -> &mut Version {
&mut self.head.version
}
pub fn method(&self) -> &Method {
&self.head.method
}
pub fn method_mut(&mut self) -> &mut Method {
&mut self.head.method
}
pub fn uri(&self) -> &Uri {
&self.head.uri
}
pub fn headers(&self) -> &HeaderMap {
&self.head.headers
}
pub fn headers_mut(&mut self) -> &mut HeaderMap {
&mut self.head.headers
}
pub fn map_body<F, C>(self, f: F) -> Request<C>
where
F: FnOnce(B) -> C,
{
Request {
head: self.head,
body: f(self.body),
}
}
}
impl<B> From<Request<B>> for http::Request<B> {
fn from(Request { head, body }: Request<B>) -> Self {
Self::from_parts(head, body)
}
}
impl<B> From<http::Request<B>> for Request<B> {
fn from(req: http::Request<B>) -> Self {
let (head, body) = req.into_parts();
Self { head, body }
}
}
impl<B> IntoBody for Request<B>
where
B: IntoBody,
{
type Chunk = B::Chunk;
type Body = B::Body;
fn into_body(self) -> Self::Body {
self.body.into_body()
}
}
#[derive(Debug)]
pub struct Response<B = Boxed<'static>> {
head: response::Parts,
body: B,
}
impl<B> Response<B> {
pub fn new(res: http::Response<B>) -> Self {
let (head, body) = res.into_parts();
Self { head, body }
}
pub fn status(&self) -> StatusCode {
self.head.status
}
pub fn version(&self) -> Version {
self.head.version
}
pub fn headers(&self) -> &HeaderMap {
&self.head.headers
}
pub fn headers_mut(&mut self) -> &mut HeaderMap {
&mut self.head.headers
}
pub fn map<F, C>(self, f: F) -> Response<C>
where
F: FnOnce(B) -> C,
{
Response {
head: self.head,
body: f(self.body),
}
}
}
impl<B> From<Response<B>> for http::Response<B> {
fn from(Response { head, body }: Response<B>) -> Self {
Self::from_parts(head, body)
}
}
impl<B> From<http::Response<B>> for Response<B> {
fn from(res: http::Response<B>) -> Self {
let (head, body) = res.into_parts();
Self { head, body }
}
}
impl<B> IntoBody for Response<B>
where
B: IntoBody,
{
type Chunk = B::Chunk;
type Body = B::Body;
fn into_body(self) -> Self::Body {
self.body.into_body()
}
}