mod body;
mod header;
mod getter;
pub use getter::*;
use std::fmt::{Display, Formatter};
pub use body::*;
pub use crate::http::request::header::{KeyValueList};
use water_http_utils::request::{CreatingRequestErrors, HttpRequest,headers::HttpHeaders};
pub use water_http_utils::request::HttpFirstLine;
pub struct IncomingRequest<'a,const HEADERS_COUNT:usize,const PATH_QUERY_COUNT:usize> {
http_request:HttpRequest<'a,HEADERS_COUNT>,
}
impl<'a,const HEADERS_COUNT:usize,const PATH_QUERY_COUNT:usize> Display for IncomingRequest<'a,HEADERS_COUNT,PATH_QUERY_COUNT> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut output = String::new();
for i in self.http_request.headers().lines() {
output.push_str(&format!("\r\n{}: {}",i.key,i.value.to_str()));
}
std::fmt::Display::fmt(
&format!(
"http_version : {} \r\n method {} \r\n path {} {output}"
,self.http_version(),
self.method(),
self.path()
),
f
)
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! inc_start_pointer {
($start:ident,$index:ident,$payload_length:ident) => {
$start = $index+1;
if $start >= $payload_length {
$start-=1;
}
};
}
impl <'a,const HEADERS_COUNT:usize,const PATH_QUERY_COUNT:usize>
IncomingRequest<'a, HEADERS_COUNT,PATH_QUERY_COUNT>
{
#[inline(always)]
pub fn get_total_headers_length(&self)->usize{
self.http_request.headers().headers_length
+ self.http_request.first_line().first_line_length
}
pub fn first_line(&self)->&HttpFirstLine<'a>{
self.http_request.first_line()
}
pub fn headers(&self) -> &HttpHeaders<'a,HEADERS_COUNT>{
self.http_request.headers()
}
pub fn new(payload:&'a[u8])->FormingRequestResult<'a,HEADERS_COUNT,PATH_QUERY_COUNT> {
let request = HttpRequest::<HEADERS_COUNT>::from_bytes(payload);
return match request {
Ok(request) => {
FormingRequestResult::Success(
IncomingRequest {
http_request:request,
}
)
}
Err(e) => {
return match e {
CreatingRequestErrors::InsufficientDataSoReadMore => { return FormingRequestResult::ReadMore}
_ => {
FormingRequestResult::Err(e)
}
}
}
}
}
pub fn path(&'a self)->&'a str {
self.http_request.path().to_str()
}
pub fn method(&self)->&'a str {
self.http_request.method()
}
pub fn http_version(&self)->&str {
self.http_request.version()
}
pub fn content_length(&self)->Option<&usize> {
self.http_request.headers().content_length()
}
pub fn get_from_path_query(&self,key:&str)->Option<&'a str>{
if let Some((_,q)) = self.http_request.path().to_query() {
let q = q.get(key);
if let Some(q) = q {
return Some(*q);
}
}
None
}
}
pub enum FormingRequestResult<'a,const HEADERS_COUNT:usize,const PATH_QUERY_COUNT:usize> {
Success(IncomingRequest<'a,HEADERS_COUNT,PATH_QUERY_COUNT>),
ReadMore,
Err(CreatingRequestErrors),
}
impl <'a,const HEADERS_COUNT:usize,const PATH_QUERY_COUNT:usize> FormingRequestResult<'a,HEADERS_COUNT,PATH_QUERY_COUNT> {
}
#[cfg(test)]
mod test {
use water_buffer::WaterBuffer as BM; type BytesMut = BM<u8>;
use crate::http::request::{FormingRequestResult, IncomingRequest};
#[allow(unused_variables)]
#[test]
fn test_building_requests_time(){
let request_bytes = b"Post /path?id=2 HTTP/1.1\r\n\
Connection: Keep-Alive\r\n\
Accept-Encoding: br,deflate\r\n\
Content-Type: Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW\r\n\
Content-Length: 238\r\n\
\r\n\
----WebKitFormBoundary7MA4YWxkTrZu0gW\r\n\
Content-Disposition: form-data; name=hellobeltopp\r\n\
\r\n\
yes\r\n\
----WebKitFormBoundary7MA4YWxkTrZu0gW\r\n\
Content-Disposition: form-data; name=ellon\r\n\
\r\n\
mask\r\n\
------WebKitFormBoundary7MA4YWxkTrZu0gW--
GET /test?id=1 HTTP/1.1\r\n\
Connection: Keep-Alive\r\n\
Accept-Encoding: br,deflate\r\n\
\r\n";
let inv1 = std::time::SystemTime::now();
let request = IncomingRequest::<'_,16,16>::new(request_bytes);
match request {
FormingRequestResult::Success( request ) => {
let data = &request_bytes[request.http_request.headers().headers_length+1..];
let s = request.http_request.path().to_query().unwrap();
let id = s.1.get("id").unwrap();
assert_eq!(*id,"2");
}
_ => {}
}
let inv2 = std::time::SystemTime::now();
let dif = inv2.duration_since(inv1).unwrap();
println!("done with {:?}",dif);
}
#[test]
fn test_reading_from_exact_buffer (){
let t1 = std::time::SystemTime::now();
let buf = BytesMut::with_capacity(4082);
let t2 = std::time::SystemTime::now();
let dif = t1.duration_since(t2);
println!("allocating buffer with 4082 capacity takes {:?}",dif);
let t1 = std::time::SystemTime::now();
drop(buf);
let t2 = std::time::SystemTime::now();
let dif = t1.duration_since(t2);
println!("deallocating the same buffer takes {:?}",dif);
}
}