nomhttp 0.1.0

Parser HTTP for the rustyproxy project based on nom
Documentation
use std::str::FromStr;

use crate::http_header::HttpHeader;
use crate::http_response_status::HttpResponseStatus;
use crate::http_transfer_encoding::HttpTransferEncoding;

#[derive(Debug, Default, Clone)]
pub struct HttpResponse {
    status: HttpResponseStatus,
    headers: Vec<HttpHeader>,
    body: Vec<u8>,
    contentlength: Option<usize>,
    transferencoding: HttpTransferEncoding,
    head: Vec<u8>,
}

impl HttpResponse {
    pub fn new(
        status: HttpResponseStatus,
        headers: Vec<HttpHeader>,
        body: Vec<u8>,
        head: Vec<u8>,
    ) -> Self {
        let contentlength = headers.iter().find(|x| x.name().to_uppercase() == "CONTENT-LENGTH");

        let contentlength = match contentlength {
            Some(x) => {
                if let Ok(x) = x.value().parse::<usize>() {
                    Some(x)
                } else {
                    None
                }
            }
            None => None,
        };

        let transferencoding = headers
            .iter()
            .find(|x| x.name() == "Transfer-Encoding" || x.name() == "transfer-encoding");

        let transferencoding = match transferencoding {
            Some(x) => HttpTransferEncoding::from_str(x.value()).unwrap(),
            None => HttpTransferEncoding::NoEncoding,
        };

        HttpResponse {
            status,
            headers,
            body,
            contentlength,
            transferencoding,
            head,
        }
    }

    pub fn is_terminated(&self) -> bool {
        if let Some(size) = self.contentlength {
            size == self.body.len()
        } else {
            true
        }
    }
    
    pub fn headers(&self) -> &Vec<HttpHeader> {
        &self.headers
    }

    pub fn is_header_terminated(&self) -> bool {
        let tail: Vec<u8> = self.head.iter().rev().take(4).copied().collect();

        matches!(tail[..], [0x0a, 0x0d, 0x0a, 0x0d])
    }

    pub fn content_length(&self) -> Option<usize> {
        self.contentlength
    }

    pub fn as_bytes(&self) -> Vec<u8> {
        let mut full_content = vec![];

        for b in &self.head {
            full_content.push(*b);
        }

        for b in &self.body {
            full_content.push(*b);
        }

        full_content
    }

    pub fn transfer_encoding(&self) -> &HttpTransferEncoding {
        &self.transferencoding
    }

    pub fn body_mut(&mut self) -> &mut Vec<u8> {
        &mut self.body
    }

    pub fn is_transfer_complete(&self) -> bool {
        let tail: Vec<u8> = self.body.iter().rev().take(5).copied().collect();
        matches!(tail[..], [0x0a, 0x0d, 0x0a, 0x0d, 0x30])
    }

    pub fn status(&self) -> &HttpResponseStatus {
        &self.status
    }

    pub fn keep_alive(&self) -> bool {
        let kah = match self.headers.iter().find(|h| h.name() == "Connection") {
            Some(h) => h.value().to_owned(),
            None => "Close".to_string(),
        };

        !matches!(kah.as_ref(), "Close")
    }
}