httpio 0.2.4

A transport-agnostic, async HTTP/1.1 client library for any runtime.
Documentation
use crate::enums::http_error::HttpError;
use crate::structures::http_request::HttpRequest;
use crate::structures::http_response::HttpResponse;
use crate::structures::http_stream::HttpStream;
use crate::structures::http_message::HttpMessage;
use futures::{AsyncBufRead, AsyncWrite, AsyncWriteExt};

pub struct HttpServerConnection<R: AsyncBufRead + Unpin, W: AsyncWrite + Unpin> {
    pub stream: HttpStream<R, W>,
}

impl<R: AsyncBufRead + Unpin, W: AsyncWrite + Unpin> HttpServerConnection<R, W> {
    pub fn new(stream_reader: R, stream_writer: W) -> Self {
        let stream = HttpStream::new(stream_reader, stream_writer);
        HttpServerConnection { stream }
    }

    pub async fn read_request(&mut self) -> Result<HttpRequest, HttpError> {
        let message = HttpMessage::read(&mut self.stream.reader).await?;
        HttpRequest::new(message)
    }

    pub async fn send_response(&mut self, response: HttpResponse) -> Result<usize, HttpError> {
        let bytes = response.as_bytes();
        let size = self.stream.writer.write(&bytes).await?;
        self.stream.writer.flush().await?;
        Ok(size)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::enums::http_body::HttpBody;
    use crate::enums::http_request_method::HttpRequestMethod;
    use crate::enums::http_status_code::HttpStatusCode;
    use futures::executor::block_on;
    use futures::io::Cursor;

    #[test]
    fn test_read_request() {
        let input = b"POST /submit HTTP/1.1\r\nContent-Length: 5\r\n\r\nHello";
        let reader = Cursor::new(input);
        let writer = Cursor::new(Vec::new());
        let mut connection = HttpServerConnection::new(reader, writer);

        let request = block_on(connection.read_request()).unwrap();

        assert!(matches!(request.method, HttpRequestMethod::Post));
        assert_eq!(request.path, "/submit");
        assert_eq!(request.body.get_content(), b"Hello");
    }

    #[test]
    fn test_send_response() {
        let reader = Cursor::new(Vec::new());
        let writer = Cursor::new(Vec::new());
        let mut connection = HttpServerConnection::new(reader, writer);

        let body = HttpBody::Content("Response".into());
        let response = HttpResponse::new(HttpStatusCode::Ok, body);

        block_on(connection.send_response(response)).unwrap();

        let output = connection.stream.writer.into_inner();
        let output_str = std::str::from_utf8(&output).unwrap();

        assert!(output_str.starts_with("HTTP/1.1 200 OK"));
        assert!(output_str.contains("Content-Length:8"));
        assert!(output_str.ends_with("Response"));
    }
}