mod test;
use smallvec::SmallVec;
use crate::{config::PRE_ALLOCATED_RESPONSE_HEADERS, utils::buffer::Buffer};
use super::{
headers::{HeaderEntry, HttpHeader},
status::HttpStatus,
};
#[derive(Debug)]
pub struct HttpResponse {
pub version: (u8, u8),
pub status: HttpStatus,
pub headers: SmallVec<[HeaderEntry; PRE_ALLOCATED_RESPONSE_HEADERS]>,
pub body: Option<Buffer>,
pub range: Option<(u16, u16)>,
}
impl HttpResponse {
pub fn new(
version: (u8, u8),
status: HttpStatus,
headers: SmallVec<[HeaderEntry; PRE_ALLOCATED_RESPONSE_HEADERS]>,
body: Option<Buffer>,
range: Option<(u16, u16)>,
) -> Self {
Self {
version,
status,
headers,
body,
range,
}
}
pub fn find_header(&mut self, header: HttpHeader) -> Option<&mut HeaderEntry> {
self.headers.iter_mut().find(|entry| entry.name == header)
}
pub fn to_bytes(self) -> Vec<u8> {
let mut response = Vec::new();
response.extend_from_slice(
format!(
"HTTP/{}.{} {} {}\r\n",
self.version.0,
self.version.1,
self.status as u16,
self.status.to_string(),
)
.as_bytes(),
);
for header in &self.headers {
response.extend_from_slice(header.to_string().as_bytes());
response.extend_from_slice(b"\r\n");
}
response.extend_from_slice(b"\r\n");
if let Some(body) = self.body {
let vec = body.to_bytes();
if let Some((start, end)) = self.range {
response.extend_from_slice(&vec[start as usize..end as usize]);
} else {
response.extend_from_slice(&vec);
}
}
response
}
}
impl ToString for HttpResponse {
fn to_string(&self) -> String {
let headers_str = self
.headers
.iter()
.map(|header_entry| format!("{}\r\n", header_entry.to_string()))
.collect::<Vec<String>>()
.concat();
let body = match &self.body {
Some(body) => body.to_string(),
None => String::new(),
};
format!(
"HTTP/{}.{} {} {}\r\n{}\r\n{}",
self.version.0,
self.version.1,
self.status as u16,
self.status.to_string(),
headers_str,
body
)
}
}