mini_async_http 0.0.1

Tiny async http server based on mio
Documentation
use crate::http::Version;
use crate::http::{Headers, ParseError};
use crate::response::Response;
use crate::response::ResponseBuilder;

pub struct ResponseParser {}

impl ResponseParser {
    pub fn new() -> ResponseParser {
        return ResponseParser {};
    }

    pub fn parse_u8(&self, reader: &[u8]) -> Result<(Response, usize), ParseError> {
        let mut headers = [httparse::EMPTY_HEADER; 64];
        let mut resp = httparse::Response::new(&mut headers);

        let res = match resp.parse(reader) {
            Ok(httparse::Status::Partial) => return Err(ParseError::UnexpectedEnd),
            Ok(httparse::Status::Complete(n)) => n,
            Err(e) => return Err(ParseError::from(e)),
        };

        let mut builder = ResponseBuilder::new()
            .code(resp.code.unwrap().into())
            .reason(String::from(resp.reason.unwrap()))
            .version(Version::HTTP11);

        let mut headers = Headers::new();

        for header in resp.headers {
            let name = String::from(header.name);
            let val = String::from_utf8(header.value.to_vec()).unwrap();

            headers.set_header(&name, &val)
        }

        let length = match headers.get_header(&String::from("Content-length")) {
            Some(n) => n,
            None => {
                builder = builder.headers(headers);
                let request = match builder.build() {
                    Ok(req) => req,
                    Err(e) => return Err(ParseError::BuilderError(e)),
                };

                return Ok((request, res));
            }
        };

        let length = match length.parse::<usize>() {
            Ok(val) => val,
            Err(_e) => return Err(ParseError::LengthParse),
        };

        if reader.len() < res + length {
            return Err(ParseError::UnexpectedEnd);
        }

        let body = &reader[res..res + length];
        let builder = builder.body(body).headers(headers);

        let request = match builder.build() {
            Ok(req) => req,
            Err(e) => return Err(ParseError::BuilderError(e)),
        };

        return Ok((request, res + length));
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::fs;
    use std::path::PathBuf;

    fn get_resource_string(path: &str) -> String {
        let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        d.push("resources/test");
        d.push(path);

        return fs::read_to_string(d).unwrap();
    }

    #[test]
    fn parse() {
        let parser = ResponseParser::new();
        let input = get_resource_string("response.txt").as_bytes().to_vec();

        let (a, _) = parser.parse_u8(&input).unwrap();

        let reader = a.to_string().as_bytes().to_vec();

        let (b, _) = parser.parse_u8(&reader).unwrap();

        assert_eq!(a, b);
    }
}