use std::collections::HashMap;
use std::path;
use actix_web::http::header::ContentType;
use actix_web::web::Payload;
use actix_web::{http::StatusCode, HttpRequest, HttpResponse};
use serde_json::Value;
use crate::models::app::ResponseTemplate;
use crate::util::req::extract_port;
use crate::{models::app::App, util::req::extract_host};
use crate::models::request::Request;
use crate::models::response::Response;
use crate::models::route::Route;
use crate::types::method::Method;
use crate::util::qs::parse_query;
use crate::util::ua::parse_user_agent;
use crate::models::guard::Guard::{Host, Port};
use libcoerced::{generic::text_verify, json::json_verify};
use super::pathfinder::process_path;
fn root_parse_headers(req: &HttpRequest) -> Vec<(String, String)> {
req.headers().iter().map(|(key, value)| {
(key.to_string(), value.to_str().unwrap().to_string())
}).collect()
}
fn root_create_request(req: HttpRequest, stream: Payload, method: Method, root_url: &str) -> Result<Request, String> {
let user_agent = parse_user_agent(req.headers().get("User-Agent").unwrap().to_str().unwrap().to_string());
let headers = root_parse_headers(&req);
let body = String::new();
let path = req.uri().path().to_string();
let (valid, params) = process_path(root_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 root_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 root_verify_response(data: &Response, route: &Route) -> bool {
for (status, verify) in route.response_verify.iter() {
let response_fn = verify.as_ref();
if status.into_u16() == data.status {
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
}
fn root_build_response(response: Response) -> actix_web::HttpResponse {
let mut builder = actix_web::HttpResponse::build(StatusCode::from_u16(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()))
}
pub async fn root_handle_request(req: HttpRequest, stream: Payload, method: Method, obj: &App<'_>, response_templates: &Vec<ResponseTemplate>) -> HttpResponse {
let root = obj.root.1.as_ref().unwrap();
if root.method != method {
return actix_web::HttpResponse::MethodNotAllowed().body("Method not allowed.");
}
let request = root_create_request(req, stream, method, obj.root.0.as_str());
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 = root_verify_request(&request, root);
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 = (root.function)(request).await;
if response.is_err() {
return actix_web::HttpResponse::InternalServerError().body(response.unwrap_err().to_string());
}
let response = response.unwrap();
if !root_verify_response(&response, root) {
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.");
}
root_build_response(response)
}