httpio 0.2.4

A transport-agnostic, async HTTP/1.1 client library for any runtime.
Documentation
use crate::enums::http_error::{HttpError, HttpErrorKind};
use crate::enums::http_request_method::HttpRequestMethod;
use crate::enums::http_version::HttpVersion;
use crate::structures::http_message::HttpMessage;
use std::str::FromStr;

pub struct HttpRequest {
    pub message: HttpMessage,
    pub method: HttpRequestMethod,
    pub path: String,
    pub version: HttpVersion,
}

impl HttpRequest {
    pub fn new(message: HttpMessage) -> Result<Self, HttpError> {
        let (method, path, version) = {
            let start_line = &message.start_line;
            let mut parts = start_line.split_whitespace();

            let method_str = parts.next().ok_or(HttpErrorKind::Parse)?;
            let path = parts.next().ok_or(HttpErrorKind::Parse)?;
            let version_str = parts.next().ok_or(HttpErrorKind::Parse)?;

            let method = HttpRequestMethod::from_str(method_str)?;
            let version = HttpVersion::from_str(version_str)?;
            
            (method, path.to_string(), version)
        };

        Ok(HttpRequest {
            message,
            method,
            path,
            version,
        })
    }
}

impl std::ops::Deref for HttpRequest {
    type Target = HttpMessage;

    fn deref(&self) -> &Self::Target {
        &self.message
    }
}

impl std::ops::DerefMut for HttpRequest {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.message
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::enums::http_body::HttpBody;
    use crate::structures::header::header_list::HttpHeaderList;

    #[test]
    fn test_valid_request_parsing() {
        let start_line = "GET /index.html HTTP/1.1";
        let message = HttpMessage::new(start_line, HttpHeaderList::default(), HttpBody::None);
        let request = HttpRequest::new(message).unwrap();

        assert!(matches!(request.method, HttpRequestMethod::Get));
        assert_eq!(request.path, "/index.html");
        assert!(matches!(request.version, HttpVersion::Http11));
    }

    #[test]
    fn test_invalid_request_line() {
        let start_line = "INVALID";
        let message = HttpMessage::new(start_line, HttpHeaderList::default(), HttpBody::None);
        let result = HttpRequest::new(message);

        assert!(result.is_err());
    }

    #[test]
    fn test_deref() {
        let start_line = "GET / HTTP/1.1";
        let message = HttpMessage::new(start_line, HttpHeaderList::default(), HttpBody::None);
        let request = HttpRequest::new(message).unwrap();

        // Access HttpMessage field via deref
        assert_eq!(request.start_line, "GET / HTTP/1.1");
    }
}