use std::{collections::HashMap, path};
use actix_web::{http::header::ContentType, web::Payload, HttpRequest};
use libcoerced::{generic::text_verify, json::json_verify};
use serde_json::Value;
use crate::{models::{app::{App, ResponseTemplate}, guard::Guard::{Host, Port}, request::Request, response::Response, route::Route}, types::method::Method, util::{qs::parse_query, req::{extract_host, extract_port}, ua::parse_user_agent}};
use super::pathfinder::process_path;
fn frag_normalize_path(path: &str) -> String {
let mut normalized = path.to_string();
if normalized.starts_with("/") {
normalized = normalized[1..].to_string();
}
if normalized.ends_with("/") {
normalized = normalized[..normalized.len() - 1].to_string();
}
normalized
}
fn frag_parse_headers(req: &HttpRequest) -> Vec<(String, String)> {
req.headers().iter().map(|(key, value)| {
(key.to_string(), value.to_str().unwrap().to_string())
}).collect()
}
fn frag_create_request(req: HttpRequest, stream: Payload, method: Method, match_url: &str) -> Result<Request, String> {
let user_agent = parse_user_agent(req.headers().get("User-Agent").unwrap().to_str().unwrap().to_string());
let headers = frag_parse_headers(&req);
let body = String::new();
let path = req.uri().path().to_string();
let (valid, params) = process_path(match_url, &path).unwrap_or((false, HashMap::new()));
if !valid {
return Err("Invalid path.".to_string());
}
let host = extract_host(&req);
let port = extract_port(&req);
Ok(Request {
host: host.unwrap_or("".to_string()),
port: port.unwrap_or(0),
method,
user_agent,
headers,
body,
query: parse_query(req.query_string().to_string()),
path: req.path().to_string(),
actix: req,
stream,
params,
})
}
fn frag_build_response(response: Response) -> actix_web::HttpResponse {
let mut builder = actix_web::HttpResponse::build(actix_web::http::StatusCode::from_u16(u16::from(response.status)).unwrap());
if response.redirect.is_some() {
return builder.insert_header(("Location", response.redirect.unwrap())).finish();
}
for (key, value) in response.headers {
builder.insert_header((key, value));
}
builder.insert_header(("Set-Cookie", response.cookie));
builder.content_type(response.content_type);
builder.body(response.body.unwrap_or("".to_string()))
}
fn frag_verify_request(data: &Request, route: &Route) -> (bool, String) {
match route.guard {
Host(_) => {
if data.host.is_empty() {
return (false, "Host is empty.".to_string());
}
},
Port(_) => {
if data.port == 0 {
return (false, "Port is 0 or invalid.".to_string());
}
},
_ => {}
}
let guard = (&route.guard).verify(data);
if guard.is_err() {
return (false, guard.unwrap_err().to_string());
}
if data.method != route.method {
return (false, "Method does not match.".to_string());
}
let request_verify = route.request_verify.as_ref();
if let Some(left) = request_verify.left() {
let s = text_verify(left, data.body.as_str());
if !s {
return (false, "Text verification failed.".to_string());
}
return (true, "".to_string());
}
if let Some(right) = request_verify.right() {
if let Ok(json_body) = serde_json::from_str::<Value>(&data.body) {
let s = json_verify(Box::new(right.clone()), json_body);
if !s {
return (false, "JSON verification failed.".to_string());
}
return (true, "".to_string());
}
}
(true, "".to_string())
}
fn frag_verify_response(data: &Response, route: &Route) -> bool {
for (status, verify) in route.response_verify.iter() {
if status.into_u16() == data.status {
let response_fn = verify.as_ref();
if let Some(left) = response_fn.left() {
if let Some(body) = data.body.clone() {
return text_verify(left, body.as_str());
}
}
if let Some(right) = response_fn.right() {
if let Some(body) = data.body.clone() {
if let Ok(json_body) = serde_json::from_str::<Value>(&body) {
return json_verify(Box::new(right.clone()), json_body);
}
}
}
}
}
true
}
pub async fn frag_handle_request(req: HttpRequest, stream: Payload, rewritten_path: String, method: Method, obj: &App<'_>, full_global_root: &str, response_templates: &Vec<ResponseTemplate>) -> actix_web::HttpResponse {
let mut path = rewritten_path.as_str();
for fragment in &obj.fragments {
let descriptor = fragment.describe();
let fragment_root = frag_normalize_path(&descriptor.root);
let global_root = frag_normalize_path(&(full_global_root.to_owned() + &fragment_root));
let global_root_route = global_root.clone();
if path == global_root || path == global_root + "/" {
let rfn = descriptor.root_fn.as_ref().unwrap();
let request = frag_create_request(req, stream, method, &descriptor.root);
if request.is_err() {
for template in response_templates {
match template {
ResponseTemplate::InvalidRequest(path) => {
let extension = path::Path::new(path).extension().unwrap();
let mut body = std::fs::read(path).unwrap();
if body.is_empty() {
body = b"Invalid request\n*DEVELOPER* - Your template file is empty!".to_vec();
return actix_web::HttpResponse::BadRequest().body(body);
}
if extension == "html" {
return actix_web::HttpResponse::BadRequest().content_type(ContentType::html()).body(body);
}
return actix_web::HttpResponse::BadRequest().body(body);
},
_ => {}
}
}
return actix_web::HttpResponse::BadRequest().body("Invalid request.");
}
let request = request.unwrap();
let rvf = frag_verify_request(&request, rfn);
if rvf.0 == false {
for template in response_templates {
match template {
ResponseTemplate::RequestVerificationFailed(path) => {
let extension = path::Path::new(path).extension().unwrap();
let mut body = std::fs::read(path).unwrap();
let body_str = String::from_utf8(body.clone()).unwrap();
body = if extension == "html" {
str::replace(&body_str, "{{error}}", ("<div>".to_string() + &str::replace(&rvf.1, "\n", "<br>") + "</div>").as_str()).into_bytes()
} else {
str::replace(&body_str, "{{error}}", &rvf.1).into_bytes()
};
if body.is_empty() {
body = ("Request verification failed:\n".to_string() + &rvf.1 + "\n*DEVELOPER* - Your template file is empty!").into_bytes();
return actix_web::HttpResponse::BadRequest().body(body);
}
if extension == "html" {
return actix_web::HttpResponse::BadRequest().content_type(ContentType::html()).body(body);
}
return actix_web::HttpResponse::BadRequest().body(body);
},
_ => {}
}
}
return actix_web::HttpResponse::BadRequest().body("Request verification failed:\n".to_string() + &rvf.1);
}
let response = (rfn.function)(request).await;
if response.is_err() {
return actix_web::HttpResponse::InternalServerError().body(response.unwrap_err().to_string());
}
let response = response.unwrap();
if !frag_verify_response(&response, rfn) {
for template in response_templates {
match template {
ResponseTemplate::ResponseVerificationFailed(path) => {
let extension = path::Path::new(path).extension().unwrap();
let mut body = std::fs::read(path).unwrap();
if body.is_empty() {
body = b"Response verification failed\n*DEVELOPER* - Your template file is empty!".to_vec();
return actix_web::HttpResponse::InternalServerError().body(body);
}
if extension == "html" {
return actix_web::HttpResponse::InternalServerError().content_type(ContentType::html()).body(body);
}
return actix_web::HttpResponse::InternalServerError().body(body);
},
_ => {}
}
}
return actix_web::HttpResponse::InternalServerError().body("Response verification failed.");
}
return frag_build_response(response);
}
for (route, route_box) in descriptor.routes {
let mut full_path = global_root_route.clone() + "/" + &route;
let route = route.to_string();
if &route == "/" {
full_path = global_root_route.clone();
}
if path.ends_with("/") {
path = &path[..path.len() - 1];
}
if method != route_box.method {
continue;
}
let http_parts = path.split("/").collect::<Vec<&str>>();
let route_parts = full_path.split("/").collect::<Vec<&str>>();
let mut okay = true;
for (http, route) in http_parts.iter().zip(route_parts.iter()) {
if route.starts_with(":") {
continue;
}
if route == &"*" {
continue;
}
if route == &"**" {
break;
}
if http != route {
okay = false;
break;
}
}
if !okay {
continue;
}
let request = frag_create_request(req, stream, method, &full_path);
if request.is_err() {
for template in response_templates {
match template {
ResponseTemplate::InvalidRequest(path) => {
let extension = path::Path::new(path).extension().unwrap();
let mut body = std::fs::read(path).unwrap();
if body.is_empty() {
body = b"Invalid request\n*DEVELOPER* - Your template file is empty!".to_vec();
return actix_web::HttpResponse::BadRequest().body(body);
}
if extension == "html" {
return actix_web::HttpResponse::BadRequest().content_type(ContentType::html()).body(body);
}
return actix_web::HttpResponse::BadRequest().body(body);
},
_ => {}
}
}
return actix_web::HttpResponse::BadRequest().body("Invalid request.");
}
let request = request.unwrap();
let rvf = frag_verify_request(&request, &route_box);
if rvf.0 == false {
for template in response_templates {
match template {
ResponseTemplate::RequestVerificationFailed(path) => {
let extension = path::Path::new(path).extension().unwrap();
let mut body = std::fs::read(path).unwrap();
let body_str = String::from_utf8(body.clone()).unwrap();
body = if extension == "html" {
str::replace(&body_str, "{{error}}", ("<div>".to_string() + &str::replace(&rvf.1, "\n", "<br>") + "</div>").as_str()).into_bytes()
} else {
str::replace(&body_str, "{{error}}", &rvf.1).into_bytes()
};
if body.is_empty() {
body = ("Request verification failed:\n".to_string() + &rvf.1 + "\n*DEVELOPER* - Your template file is empty!").into_bytes();
return actix_web::HttpResponse::BadRequest().body(body);
}
if extension == "html" {
return actix_web::HttpResponse::BadRequest().content_type(ContentType::html()).body(body);
}
return actix_web::HttpResponse::BadRequest().body(body);
},
_ => {}
}
}
return actix_web::HttpResponse::BadRequest().body("Request verification failed:\n".to_string() + &rvf.1);
}
let response = (route_box.function)(request).await;
if response.is_err() {
return actix_web::HttpResponse::InternalServerError().body(response.unwrap_err().to_string());
}
let response = response.unwrap();
if !frag_verify_response(&response, &route_box) {
for template in response_templates {
match template {
ResponseTemplate::ResponseVerificationFailed(path) => {
let extension = path::Path::new(path).extension().unwrap();
let mut body = std::fs::read(path).unwrap();
if body.is_empty() {
body = b"Response verification failed\n*DEVELOPER* - Your template file is empty!".to_vec();
return actix_web::HttpResponse::InternalServerError().body(body);
}
if extension == "html" {
return actix_web::HttpResponse::InternalServerError().content_type(ContentType::html()).body(body);
}
return actix_web::HttpResponse::InternalServerError().body(body);
},
_ => {}
}
}
return actix_web::HttpResponse::InternalServerError().body("Response verification failed.");
}
return frag_build_response(response);
}
}
for template in response_templates {
match template {
ResponseTemplate::NotFound(path) => {
let extension = path::Path::new(path).extension().unwrap();
let mut body = std::fs::read(path).unwrap();
if body.is_empty() {
body = b"Not found\n*DEVELOPER* - Your template file is empty!".to_vec();
return actix_web::HttpResponse::NotFound().body(body);
}
if extension == "html" {
return actix_web::HttpResponse::NotFound().content_type(ContentType::html()).body(body);
}
return actix_web::HttpResponse::NotFound().body(body);
},
_ => {}
}
}
actix_web::HttpResponse::NotFound().body("Not found.")
}