use std::{fmt, future::Future, pin::Pin};
use bytes::Bytes;
use futures_core::Stream;
use crate::{Error, body::BodyStream};
mod hyper;
pub use self::hyper::{Hyper, HyperBody};
pub type BoxBody = Pin<Box<dyn Stream<Item = Result<Bytes, Error>> + Send + 'static>>;
pub trait Backend: Send + Sync + 'static {
type Body: Stream<Item = Result<Bytes, Error>> + Send + Unpin + 'static;
fn send(
&self,
request: HttpRequest,
) -> impl Future<Output = Result<HttpResponse<Self::Body>, Error>> + Send;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum Method {
Get,
Post,
}
#[non_exhaustive]
pub struct HttpRequest {
pub method: Method,
pub url: String,
pub headers: Vec<(String, String)>,
pub body: Option<HttpBody>,
}
#[derive(Debug)]
pub struct HttpBody {
pub length: u64,
pub stream: BodyStream,
}
impl fmt::Debug for HttpRequest {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let headers: Vec<(&str, &str)> = self
.headers
.iter()
.map(|(name, value)| {
let shown = if name == "authorization" {
"<withheld>"
} else {
value.as_str()
};
(name.as_str(), shown)
})
.collect();
f.debug_struct("HttpRequest")
.field("method", &self.method)
.field("url", &self.url)
.field("headers", &headers)
.field("body_length", &self.body.as_ref().map(|body| body.length))
.finish()
}
}
#[non_exhaustive]
pub struct HttpResponse<B> {
pub status: u16,
pub headers: Vec<(String, String)>,
pub body: B,
}
impl<B> HttpResponse<B> {
pub fn new(status: u16, headers: Vec<(String, String)>, body: B) -> Self {
Self {
status,
headers,
body,
}
}
pub fn header(&self, name: &str) -> Option<&str> {
self.headers
.iter()
.find(|(key, _)| key == name)
.map(|(_, value)| value.as_str())
}
}
impl<B> fmt::Debug for HttpResponse<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("HttpResponse")
.field("status", &self.status)
.field("headers", &self.headers)
.finish_non_exhaustive()
}
}