use crate::{Body, HeaderMap, StreamingBody, body::util::BodyExt};
use rama_core::bytes::Bytes;
use rama_core::error::{BoxError, ErrorContext as _};
use rama_http_types::Version;
use std::fmt::Write as _;
use tokio::io::{AsyncWrite, AsyncWriteExt};
mod request;
#[doc(inline)]
pub use request::write_http_request;
mod response;
#[doc(inline)]
pub use response::write_http_response;
pub mod upgrade;
pub(crate) async fn write_http1_header_map<W>(
w: &mut W,
headers: &mut HeaderMap,
version: Version,
) -> Result<(), BoxError>
where
W: AsyncWrite + Unpin + Send + Sync + 'static,
{
let header_map = std::mem::take(headers);
*headers = header_map.clone();
for (name, value) in header_map.into_ordered_iter() {
match version {
Version::HTTP_2 | Version::HTTP_3 => {
let mut line = String::with_capacity(name.as_str().len() + value.len() + 4);
write!(
line,
"{}: {}\r\n",
name.display_lowercase(),
value.to_str()?
)?;
w.write_all(line.as_bytes()).await?;
}
_ => {
w.write_all(format!("{}: {}\r\n", name, value.to_str()?).as_bytes())
.await?;
}
}
}
Ok(())
}
pub(crate) async fn write_http1_body<W, B>(
w: &mut W,
body: B,
write_body: bool,
) -> Result<Body, BoxError>
where
W: AsyncWrite + Unpin + Send + Sync + 'static,
B: StreamingBody<Data = Bytes, Error: Into<BoxError>> + Send + Sync + 'static,
{
Ok(if write_body {
let body = body.collect().await.into_box_error()?.to_bytes();
w.write_all(b"\r\n").await?;
if !body.is_empty() {
w.write_all(body.as_ref()).await?;
}
Body::from(body)
} else {
Body::new(body)
})
}