use crate::config::global_config;
use crate::request::{CreatingRequestErrors, HttpPath};
#[derive(Debug)]
pub struct HttpFirstLine<'buf>{
pub(crate) version:&'buf str,
pub(crate) path:HttpPath<'buf>,
#[cfg(feature = "server")]
pub (crate) method:&'buf str,
pub first_line_length:usize,
}
impl <'buf> HttpFirstLine<'buf> {
#[cfg(feature = "server")]
#[inline(always)]
pub (crate) fn from_server(bytes: &'buf [u8]) -> Result<HttpFirstLine<'buf>, CreatingRequestErrors> {
let len = bytes.len();
let base_ptr = bytes.as_ptr();
let global_conf = global_config();
if len < 12 { return Err(CreatingRequestErrors::InsufficientDataSoReadMore); }
let (method_len, method_end_ptr) = unsafe {
let first_8 =(base_ptr as *const u64).read_unaligned() ;
if (first_8 & 0xFFFFFF) == 0x20544547 { (3, base_ptr.add(3))
} else if (first_8 & 0xFFFFFFFFFF) == 0x2054534f50 { (4, base_ptr.add(4))
} else if (first_8 & 0xFFFFFFFFFF) == 0x20545550 { (3, base_ptr.add(3))
} else {
let m_end = memchr::memchr(b' ', bytes)
.ok_or(CreatingRequestErrors::InsufficientDataSoReadMore)?;
if m_end >= global_conf.max_method_size { return Err(CreatingRequestErrors::InvalidHttpFormat); }
(m_end, base_ptr.add(m_end))
}
};
let method_slice = unsafe { std::slice::from_raw_parts(base_ptr, method_len) };
let path_start_ptr = unsafe { method_end_ptr.add(1) };
let path_max_search = len - (path_start_ptr as usize - base_ptr as usize);
let path_len = unsafe {
let search_slice = std::slice::from_raw_parts(path_start_ptr, path_max_search);
memchr::memchr(b' ', search_slice)
.ok_or(CreatingRequestErrors::InsufficientDataSoReadMore)?
};
if path_len >= global_conf.max_path_size {
return Err(CreatingRequestErrors::DangerousInvalidHttpFormat);
}
let path_slice = unsafe { std::slice::from_raw_parts(path_start_ptr, path_len) };
let version_start_ptr = unsafe { path_start_ptr.add(path_len + 1) };
let ver_max_search = len - (version_start_ptr as usize - base_ptr as usize);
let cr_pos = unsafe {
let search_slice = std::slice::from_raw_parts(version_start_ptr, ver_max_search);
memchr::memchr(b'\r', search_slice)
.ok_or(CreatingRequestErrors::InsufficientDataSoReadMore)?
};
if cr_pos >= global_conf.max_version_size {
return Err(CreatingRequestErrors::DangerousInvalidHttpFormat);
}
unsafe {
let lf_ptr = version_start_ptr.add(cr_pos + 1);
let end_ptr = base_ptr.add(len);
if lf_ptr >= end_ptr || *lf_ptr != b'\n' {
return Err(CreatingRequestErrors::InvalidHttpFormat);
}
let version_slice = std::slice::from_raw_parts(version_start_ptr, cr_pos);
Ok(HttpFirstLine {
method: std::str::from_utf8_unchecked(method_slice),
version: std::str::from_utf8_unchecked(version_slice),
path: HttpPath::new(path_slice),
first_line_length: (lf_ptr as usize - base_ptr as usize) + 1,
})
}
}
}