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(())
}