use std::io::Write;
use eyre::Context;
use http::{StatusCode, Version};
use crate::{
types::{Headers, Request, Response},
Encoder,
};
use fluke_buffet::{PieceCore, PieceList, RollMut, WriteOwned};
use super::body::{write_h1_body_chunk, write_h1_body_end, BodyWriteMode};
pub(crate) fn encode_request(
req: Request,
list: &mut PieceList,
out_scratch: &mut RollMut,
) -> eyre::Result<()> {
list.push_back(req.method.into_chunk());
list.push_back(" ");
assert_eq!(out_scratch.len(), 0);
out_scratch.write_all(req.uri.path().as_bytes())?;
list.push_back(out_scratch.take_all());
match req.version {
Version::HTTP_10 => list.push_back(" HTTP/1.0\r\n"),
Version::HTTP_11 => list.push_back(" HTTP/1.1\r\n"),
_ => return Err(eyre::eyre!("unsupported HTTP version {:?}", req.version)),
}
encode_headers(req.headers, list)?;
list.push_back("\r\n");
Ok(())
}
fn encode_response(res: Response, list: &mut PieceList) -> eyre::Result<()> {
match res.version {
Version::HTTP_10 => list.push_back(&b"HTTP/1.0 "[..]),
Version::HTTP_11 => list.push_back(&b"HTTP/1.1 "[..]),
_ => return Err(eyre::eyre!("unsupported HTTP version {:?}", res.version)),
}
list.push_back(encode_status_code(res.status));
list.push_back(" ");
list.push_back(res.status.canonical_reason().unwrap_or("Unknown"));
list.push_back("\r\n");
encode_headers(res.headers, list)?;
list.push_back("\r\n");
Ok(())
}
pub(crate) fn encode_headers(headers: Headers, list: &mut PieceList) -> eyre::Result<()> {
let mut last_header_name = None;
for (name, value) in headers {
match name {
Some(name) => {
last_header_name = Some(name.clone());
list.push_back(name);
}
None => {
let name = match last_header_name {
Some(ref name) => name.clone(),
None => unreachable!("HeaderMap's IntoIter violated its contract"),
};
list.push_back(name);
}
}
list.push_back(": ");
list.push_back(value);
list.push_back("\r\n");
}
Ok(())
}
fn encode_status_code(code: StatusCode) -> &'static str {
let offset = (code.as_u16() - 100) as usize;
let offset = offset * 3;
#[cfg(debug_assertions)]
{
&CODE_DIGITS[offset..offset + 3]
}
#[cfg(not(debug_assertions))]
unsafe {
CODE_DIGITS.get_unchecked(offset..offset + 3)
}
}
const CODE_DIGITS: &str = "\
100101102103104105106107108109110111112113114115116117118119\
120121122123124125126127128129130131132133134135136137138139\
140141142143144145146147148149150151152153154155156157158159\
160161162163164165166167168169170171172173174175176177178179\
180181182183184185186187188189190191192193194195196197198199\
200201202203204205206207208209210211212213214215216217218219\
220221222223224225226227228229230231232233234235236237238239\
240241242243244245246247248249250251252253254255256257258259\
260261262263264265266267268269270271272273274275276277278279\
280281282283284285286287288289290291292293294295296297298299\
300301302303304305306307308309310311312313314315316317318319\
320321322323324325326327328329330331332333334335336337338339\
340341342343344345346347348349350351352353354355356357358359\
360361362363364365366367368369370371372373374375376377378379\
380381382383384385386387388389390391392393394395396397398399\
400401402403404405406407408409410411412413414415416417418419\
420421422423424425426427428429430431432433434435436437438439\
440441442443444445446447448449450451452453454455456457458459\
460461462463464465466467468469470471472473474475476477478479\
480481482483484485486487488489490491492493494495496497498499\
500501502503504505506507508509510511512513514515516517518519\
520521522523524525526527528529530531532533534535536537538539\
540541542543544545546547548549550551552553554555556557558559\
560561562563564565566567568569570571572573574575576577578579\
580581582583584585586587588589590591592593594595596597598599\
600601602603604605606607608609610611612613614615616617618619\
620621622623624625626627628629630631632633634635636637638639\
640641642643644645646647648649650651652653654655656657658659\
660661662663664665666667668669670671672673674675676677678679\
680681682683684685686687688689690691692693694695696697698699\
700701702703704705706707708709710711712713714715716717718719\
720721722723724725726727728729730731732733734735736737738739\
740741742743744745746747748749750751752753754755756757758759\
760761762763764765766767768769770771772773774775776777778779\
780781782783784785786787788789790791792793794795796797798799\
800801802803804805806807808809810811812813814815816817818819\
820821822823824825826827828829830831832833834835836837838839\
840841842843844845846847848849850851852853854855856857858859\
860861862863864865866867868869870871872873874875876877878879\
880881882883884885886887888889890891892893894895896897898899\
900901902903904905906907908909910911912913914915916917918919\
920921922923924925926927928929930931932933934935936937938939\
940941942943944945946947948949950951952953954955956957958959\
960961962963964965966967968969970971972973974975976977978979\
980981982983984985986987988989990991992993994995996997998999";
pub struct H1Encoder<T>
where
T: WriteOwned,
{
pub(crate) transport_w: T,
}
impl<T> Encoder for H1Encoder<T>
where
T: WriteOwned,
{
async fn write_response(&mut self, res: Response) -> eyre::Result<()> {
let mut list = PieceList::default();
encode_response(res, &mut list)?;
self.transport_w
.writev_all_owned(list)
.await
.wrap_err("writing response headers upstream")?;
Ok(())
}
async fn write_body_chunk(
&mut self,
chunk: PieceCore,
mode: BodyWriteMode,
) -> eyre::Result<()> {
write_h1_body_chunk(&mut self.transport_w, chunk, mode).await
}
async fn write_body_end(&mut self, mode: BodyWriteMode) -> eyre::Result<()> {
write_h1_body_end(&mut self.transport_w, mode).await
}
async fn write_trailers(&mut self, trailers: Box<Headers>) -> eyre::Result<()> {
let mut list = PieceList::default();
encode_headers(*trailers, &mut list)?;
self.transport_w
.writev_all_owned(list)
.await
.wrap_err("writing response headers upstream")?;
Ok(())
}
}