use crate::{
Conn, Headers, HttpConfig, HttpContext, KnownHeaderName, Method, ProtocolSession, TypeSet,
Version, after_send::AfterSend, received_body::ReceivedBodyState,
};
use futures_lite::io::{AsyncRead, AsyncWrite, Cursor, Result};
use std::{
borrow::Cow,
pin::Pin,
sync::Arc,
task::{Context, Poll},
time::Instant,
};
#[doc(hidden)]
#[derive(Debug)]
pub struct Synthetic {
data: Cursor<Vec<u8>>,
closed: bool,
}
impl AsyncRead for Synthetic {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<Result<usize>> {
let Synthetic { data, closed } = &mut *self;
if *closed {
Poll::Ready(Ok(0))
} else {
match Pin::new(data).poll_read(cx, buf) {
Poll::Ready(Ok(0)) => Poll::Pending,
other => other,
}
}
}
}
impl Synthetic {
#[doc(hidden)]
pub fn len(&self) -> usize {
self.data.get_ref().len()
}
#[doc(hidden)]
pub fn is_empty(&self) -> bool {
self.data.get_ref().is_empty()
}
#[doc(hidden)]
pub fn close(&mut self) {
self.closed = true;
}
}
impl AsyncWrite for Synthetic {
fn poll_write(self: Pin<&mut Self>, _cx: &mut Context<'_>, _buf: &[u8]) -> Poll<Result<usize>> {
Poll::Ready(Ok(0))
}
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<()>> {
Poll::Ready(Ok(()))
}
fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<()>> {
Poll::Ready(Ok(()))
}
}
impl From<Cursor<Vec<u8>>> for Synthetic {
fn from(data: Cursor<Vec<u8>>) -> Self {
Self {
data,
closed: false,
}
}
}
impl From<Vec<u8>> for Synthetic {
fn from(v: Vec<u8>) -> Self {
Cursor::new(v).into()
}
}
impl From<&[u8]> for Synthetic {
fn from(v: &[u8]) -> Self {
v.to_owned().into()
}
}
impl From<String> for Synthetic {
fn from(v: String) -> Self {
v.into_bytes().into()
}
}
impl From<&str> for Synthetic {
fn from(v: &str) -> Self {
v.as_bytes().into()
}
}
impl From<()> for Synthetic {
fn from((): ()) -> Self {
Vec::new().into()
}
}
impl From<Option<Vec<u8>>> for Synthetic {
fn from(v: Option<Vec<u8>>) -> Self {
v.unwrap_or_default().into()
}
}
impl Conn<Synthetic> {
#[doc(hidden)]
pub fn new_synthetic(
method: Method,
path: impl Into<String>,
body: impl Into<Synthetic>,
) -> Self {
let transport = body.into();
let mut request_headers = Headers::new();
request_headers.insert(KnownHeaderName::ContentLength, transport.len().to_string());
Self {
context: Arc::default(),
transport,
request_headers,
response_headers: Headers::new(),
path: Cow::Owned(path.into()),
method,
status: None,
version: Version::Http1_1,
state: TypeSet::new(),
response_body: None,
buffer: Vec::with_capacity(HttpConfig::DEFAULT.request_buffer_initial_len).into(),
request_body_state: ReceivedBodyState::Start,
secure: false,
after_send: AfterSend::default(),
start_time: Instant::now(),
peer_ip: None,
authority: None,
scheme: None,
protocol: None,
protocol_session: ProtocolSession::Http1,
request_trailers: None,
}
}
#[doc(hidden)]
pub fn set_context(&mut self, context: Arc<HttpContext>) {
self.context = context;
}
#[doc(hidden)]
#[must_use]
pub fn with_context(mut self, context: Arc<HttpContext>) -> Self {
self.set_context(context);
self
}
#[doc(hidden)]
pub fn close(&mut self) {
self.transport.close();
}
#[doc(hidden)]
pub fn replace_body(&mut self, body: impl Into<Synthetic>) {
let transport = body.into();
self.request_headers_mut()
.insert(KnownHeaderName::ContentLength, transport.len().to_string());
self.transport = transport;
self.request_body_state = ReceivedBodyState::default();
}
}