commit
e1237dfa6f
12 changed files with 1957 additions and 0 deletions
File diff suppressed because it is too large
@ -0,0 +1,8 @@ |
|||
[package] |
|||
name = "chatty" |
|||
version = "0.1.0" |
|||
edition = "2024" |
|||
|
|||
[dependencies] |
|||
sqlx = {version = "0.8.6", features = ["postgres", "runtime-tokio"]} |
|||
tokio = {version = "1.47.1", features = ["full"]} |
|||
@ -0,0 +1,66 @@ |
|||
use std::net::{TcpListener, TcpStream}; |
|||
use std::thread; |
|||
use std::io::{BufReader, prelude::*}; |
|||
use std::boxed::Box; |
|||
use crate::routes::proxy; |
|||
use crate::models::HttpRequest::HttpRequest; |
|||
|
|||
pub fn http_server() { |
|||
let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); |
|||
println!("Listening on port 7878"); |
|||
|
|||
for stream in listener.incoming() { |
|||
match stream { |
|||
Ok(stream) => { |
|||
thread::spawn(move || { |
|||
handle_connection(stream); |
|||
}); |
|||
} |
|||
Err(e) => { |
|||
eprintln!("Error accepting connection: {}", e); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
fn handle_connection(mut stream: TcpStream) { |
|||
// Handle the connection (currently does nothing)
|
|||
let reader = BufReader::new(&mut stream); |
|||
let http_request = reader.lines().next().unwrap().unwrap(); |
|||
|
|||
let parsed_request = parse_http_request(&http_request); |
|||
match parsed_request { |
|||
Ok(request) => { |
|||
proxy::proxy(request, &stream); |
|||
} |
|||
Err(e) => { |
|||
eprintln!("Failed to parse HTTP request: {}", e); |
|||
} |
|||
} |
|||
|
|||
|
|||
} |
|||
|
|||
// FUNCTION TO PARSE HTTP REQUESTS
|
|||
fn parse_http_request(request: &str) -> Result<HttpRequest, Box<dyn std::error::Error>> { |
|||
let parts: Vec<&str> = request.split_whitespace().collect(); |
|||
|
|||
if parts[1].ends_with('/') == false && parts[1].contains('.') == false { |
|||
// ADD TRAILING / IF MISSING
|
|||
println!("Adding trailing / to path"); |
|||
let new_path = format!("{}/", parts[1]); |
|||
let new_request = format!("{} {} {}", parts[0], new_path, parts[2]); |
|||
return parse_http_request(&new_request); |
|||
} |
|||
|
|||
if parts.len() >= 3 { |
|||
let request = HttpRequest { |
|||
method: parts[0].to_string(), |
|||
path: parts[1].to_string(), |
|||
version: parts[2].to_string(), |
|||
}; |
|||
Ok(request) |
|||
} else { |
|||
Err("Invalid HTTP request".into()) |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
mod http; |
|||
mod routes; |
|||
mod models; |
|||
|
|||
#[tokio::main] |
|||
async fn main() { |
|||
println!("Starting application..."); |
|||
|
|||
http::http_server(); |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,6 @@ |
|||
#[derive(Debug, Clone,)] |
|||
pub struct HttpRequest { |
|||
pub method: String, |
|||
pub path: String, |
|||
pub version: String, |
|||
} |
|||
@ -0,0 +1 @@ |
|||
pub mod HttpRequest; |
|||
@ -0,0 +1,27 @@ |
|||
use crate::models::HttpRequest::HttpRequest; |
|||
use std::net::TcpStream; |
|||
use std::io::prelude::*; |
|||
|
|||
pub fn handle_auth_request(http_request: HttpRequest, mut stream: &TcpStream) { |
|||
|
|||
match http_request.method.as_str() { |
|||
"POST" => { |
|||
// Handle login or registration
|
|||
println!("Handling auth POST request for path: {}", http_request.path); |
|||
let response = "HTTP/1.1 200 OK\r\n\r\nAuth POST Response"; |
|||
stream.write_all(response.as_bytes()).unwrap(); |
|||
} |
|||
"GET" => { |
|||
// Handle fetching user info or logout
|
|||
println!("Handling auth GET request for path: {}", http_request.path); |
|||
let response = "HTTP/1.1 200 OK\r\n\r\nAuth GET Response"; |
|||
stream.write_all(response.as_bytes()).unwrap(); |
|||
} |
|||
_ => { |
|||
// Method not allowed
|
|||
let response = "HTTP/1.1 405 METHOD NOT ALLOWED\r\n\r\nMethod Not Allowed"; |
|||
stream.write_all(response.as_bytes()).unwrap(); |
|||
return; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
pub mod proxy; |
|||
pub mod statics; |
|||
pub mod auth; |
|||
@ -0,0 +1,37 @@ |
|||
use crate::models::HttpRequest::HttpRequest; |
|||
use crate::routes::statics; |
|||
use std::net::TcpStream; |
|||
use crate::routes::auth; |
|||
|
|||
fn is_file(file: &str) -> bool { |
|||
file.contains('.') |
|||
} |
|||
|
|||
pub fn proxy(http_request: HttpRequest, stream: &TcpStream) { |
|||
println!("Proxying request..."); |
|||
|
|||
let path = &http_request.path; |
|||
let parsed_path = path.trim_start_matches('/').split('/').collect::<Vec<&str>>(); |
|||
let target = parsed_path[parsed_path.len() -1]; |
|||
if is_file(target) { |
|||
statics::serve_static_file(http_request.clone(), stream); |
|||
} else { |
|||
handle_api_request(http_request.clone(), stream); |
|||
} |
|||
} |
|||
|
|||
pub fn handle_api_request(http_request: HttpRequest, stream: &TcpStream) { |
|||
|
|||
let parsed_path = http_request.path.trim_start_matches('/').split('/').collect::<Vec<&str>>(); |
|||
|
|||
match parsed_path[0] { |
|||
"api" => { |
|||
match parsed_path[1] { |
|||
"auth" => auth::handle_auth_request(http_request, &stream), |
|||
_ => (), |
|||
} |
|||
}, |
|||
_ => (), |
|||
}; |
|||
|
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
use std::net::TcpStream; |
|||
use std::io::prelude::*; |
|||
|
|||
use crate::models::HttpRequest::HttpRequest; |
|||
|
|||
pub fn serve_static_file(file_path: HttpRequest, mut stream: &TcpStream) { |
|||
|
|||
let file = std::fs::read_to_string(format!("./static/{}", file_path.path.trim_start_matches('/'))); |
|||
|
|||
let response = match file { |
|||
Ok(contents) => { |
|||
format!( |
|||
"HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}", |
|||
contents.len(), |
|||
contents |
|||
) |
|||
} |
|||
Err(_) => { |
|||
let status_line = "HTTP/1.1 404 NOT FOUND\r\n\r\n"; |
|||
let body = "404 Not Found"; |
|||
format!("{}{}", status_line, body) |
|||
} |
|||
}; |
|||
|
|||
stream.write_all(response.as_bytes()).unwrap(); |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>Document</title> |
|||
<link rel="stylesheet" href="/public/style.css"> |
|||
</head> |
|||
<body> |
|||
<h1>Hello, World!</h1> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,6 @@ |
|||
body { |
|||
font-family: Arial, sans-serif; |
|||
margin: 0; |
|||
padding: 0; |
|||
background-color: #FFAAAA; |
|||
} |
|||
Loading…
Reference in new issue