diff --git a/hteapot.toml b/hteapot.toml index 73549a3..2da0d86 100644 --- a/hteapot.toml +++ b/hteapot.toml @@ -1,10 +1,11 @@ [HTEAPOT] port = 8081 -host = "0.0.0.0" #test de comentario +host = "0.0.0.0" root = "public" threads = 5 cache = true cache_ttl = 3600 [proxy] -"/test" = "https://example.com" -"/google" = "http://google.com" \ No newline at end of file +"/test" = "http://example.com" +"/google" = "http://google.com" +# "/" = "http://ifconfig.co" # this will override all the proxys and local request \ No newline at end of file diff --git a/src/brew.rs b/src/brew.rs index 486bfb7..f5f7e0f 100644 --- a/src/brew.rs +++ b/src/brew.rs @@ -1,12 +1,13 @@ // Written by Alberto Ruiz 2024-04-08 // This is the HTTP client module, it will handle the requests and responses -use std::{io::{Read, Write}, net::TcpStream}; +use std::{io::{Read, Write}, net::TcpStream, vec}; struct Url { scheme: String, domain: String, + path: String, port: String } @@ -14,7 +15,7 @@ struct Url { fn parse_url(url: &str) -> Result { let url_parts = url.split(":").collect::>(); let prefix = url_parts[0]; - let domain = url_parts[1].trim_start_matches("//"); + let domain_path = url_parts[1].trim_start_matches("//"); let port = if url_parts.len() == 3 { url_parts[2] } else { @@ -24,41 +25,45 @@ fn parse_url(url: &str) -> Result { _ => "80" } }; + let (domain,path) = domain_path.split_once('/').unwrap(); Ok(Url { scheme: prefix.to_string(), domain: domain.to_string(), + path: path.to_string(), port: port.to_string() }) } -pub fn fetch(url: &str) -> Result { +pub fn fetch(url: &str) -> Result,&str> { let url = parse_url(url); if url.is_err() { return Err("Error parsing url")} let url = url.unwrap(); if url.scheme == "https" { return Err("not supported yet"); } + let client = TcpStream::connect(format!("{}:{}",url.domain,url.port)); if client.is_err() { return Err("Error fetching"); } let mut client = client.unwrap(); - let http_request = format!("GET / HTTP/1.1\r\nHost: {}\r\n\r\n", url.domain); + let http_request = format!("GET /{} HTTP/1.1\r\nHost: {}\r\n\r\n",url.path, url.domain); client.write(http_request.as_bytes()).unwrap(); let mut response = String::new(); + let mut full_buffer: Vec = Vec::new(); let mut buffer = [0; 1024]; loop { match client.read(&mut buffer) { Ok(0) => break, Ok(n) => { - response.push_str(std::str::from_utf8(&buffer[..n]).unwrap()); - if response.ends_with("\n") {break} //TODO: break when size == header - + if n == 0 {break;} + full_buffer.extend(buffer.iter().cloned()); + if buffer.last().unwrap() == &0 {break;} }, Err(_) => break } } - Ok(response) + Ok(full_buffer) } diff --git a/src/main.rs b/src/main.rs index d2775f6..98cf005 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,6 +24,7 @@ fn main() { } else { config::Config::new_default() }; + let proxy_only = config.proxy_rules.get("/").is_some(); let logger = Mutex::new(Logger::new(io::stdout())); let cache: Mutex, u64)>> = Mutex::new(HashMap::new()); let server = Hteapot::new_threaded(config.host.as_str(), config.port,config.threads); @@ -31,6 +32,10 @@ fn main() { if config.cache { logger.lock().expect("this doesnt work :C").msg("Cache Enabled".to_string()); } + if proxy_only { + logger.lock().expect("this doesnt work :C").msg("WARNING: All requests are proxied to /. Local paths won’t be used.".to_string()); + } + server.listen( move |req| { //let mut logger = Logger::new(io::stdout()); @@ -42,12 +47,32 @@ fn main() { } else { req.path.clone() }; - if config.proxy_rules.contains_key(&req.path) { - logger.lock().expect("this doesnt work :C").msg(format!("Proxying to: {}", config.proxy_rules.get(&req.path).unwrap())); - let url = config.proxy_rules.get(&req.path).unwrap(); - return match fetch(url) { + let path_clone = req.path.clone(); + let divided_path: Vec<&str> = path_clone.split('/').skip(1).collect(); + if divided_path.is_empty() { + return Hteapot::response_maker(HttpStatus::BadRequest, b"Invalid path", None); + } + + let first_one = format!("/{}",divided_path[0]); + let rest_path = divided_path[1..].join("/"); + + if proxy_only || config.proxy_rules.contains_key(&first_one) { + let url = if proxy_only { + let url = config.proxy_rules.get("/").unwrap(); + if rest_path.len() != 0 { + format!("{}{}/{}",url,first_one,rest_path) + + } else { + format!("{}{}",url,first_one) + } + } else { + let url = config.proxy_rules.get(&first_one).unwrap(); + format!("{}/{}",url,rest_path) + }; + logger.lock().expect("this doesnt work :C").msg(format!("Proxying to: {}", url)); + return match fetch(&url) { Ok(response) => { - response.into() + response }, Err(err) => { Hteapot::response_maker(HttpStatus::InternalServerError, err.as_bytes(), None)