use std::io; use tokio::net::*; type Error = io::Error; type Fd = TcpStream; static BODY: [u8; 4 << 20] = [0; 4 << 20]; pub struct HttpReq { status: u32, } impl HttpReq { pub const fn new() -> HttpReq { HttpReq { status: 0 } } fn parse(&mut self, data: &[u8]) { for c in data { match c { b'\r' => { if (self.status & 0x01) == 0 { self.status += 1; } else { self.status = 1; } } b'\n' => { if (self.status & 0x01) == 1 { self.status += 1; } else { self.status = 0; } } _ => self.status = 0, } if self.status == 4 { break; } } } fn is_ok(&self) -> bool { self.status == 4 } fn try_read(&mut self, conn: &Fd) -> Result<(), Error> { let mut buf = [0_u8; 2048]; match conn.try_read(&mut buf) { Ok(0) => Err(Error::new(io::ErrorKind::InvalidInput, "")), Ok(n) => { self.parse(&buf[..n]); Ok(()) } Err(e) => Err(e), } } pub async fn read(&mut self, conn: &Fd) -> Result<(), Error> { while !self.is_ok() { match self.try_read(conn) { Ok(_) => {}, Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { conn.readable().await?; continue; } Err(e) => return Err(e), } } Ok(()) } } pub struct HttpRsp { body_size: usize, } impl HttpRsp { pub const fn new(body_size: usize) -> Self { Self { body_size } } async fn write_head(&self, conn: &Fd) -> Result<(), Error> { let hdr = format!( "HTTP/1.1 200 Ok\r\nContent-Length: {}\r\n\r\n", self.body_size ); let _ = write_all(conn, hdr.as_bytes()).await?; Ok(()) } pub async fn write(&self, conn: &Fd) -> Result<(), Error> { self.write_head(conn).await?; let mut size = self.body_size; while size > 0 { let len = core::cmp::min(size, BODY.len()); let _ = write_all(conn, &BODY[..len]).await?; size -= len; } Ok(()) } } async fn write_all(conn: &Fd, mut data: &[u8]) -> Result<(), Error> { let mut len = data.len(); while len > 0 { match conn.try_write(data) { Ok(n) => { data = &data[n..]; len -= n; } Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { conn.writable().await?; continue; } Err(e) => return Err(e), } } Ok(()) }