aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs268
1 files changed, 176 insertions, 92 deletions
diff --git a/src/main.rs b/src/main.rs
index 1ad6f26..ccdaa37 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,15 +1,128 @@
#![allow(unused)]
+use http_server_starter_rust::router::Router;
use itertools::Itertools;
use std::collections::HashMap;
+use std::fs::File;
use std::io::{self, Read, Write};
use std::net::{TcpListener, TcpStream};
-use std::{str, thread};
+use std::str::Utf8Error;
+use std::sync::{Arc, Mutex};
+use std::{str, thread, usize};
-use http_server_starter_rust::http_types::*;
use http_server_starter_rust::request::*;
use http_server_starter_rust::response::*;
+use http_server_starter_rust::{extractor, http_types::*};
-fn handle_client(mut stream: TcpStream) {
+fn read_file_as_bytes(path: &str) -> io::Result<Vec<u8>> {
+ // Open the file in read-only mode
+ let mut file = File::open(path)?;
+
+ // Create a buffer to hold the file contents
+ let mut buffer = Vec::new();
+
+ // Read the file contents into the buffer
+ file.read_to_end(&mut buffer)?;
+
+ // Return the buffer
+ Ok(buffer)
+}
+
+fn handle_echo(request: &Request, ctx: Option<&HashMap<String, String>>) -> Response {
+ let mut headers = HashMap::new();
+ // Extract the route regardless of the variant
+ let mut echo_string = "".to_string();
+ let route = match request.method() {
+ Method::Get(route) | Method::Post(route) | Method::Put(route) => route,
+ };
+
+ for ch in route.chars().skip(1).skip_while(|&ch| ch != '/').skip(1) {
+ echo_string.push(ch);
+ }
+ if echo_string.chars().last().unwrap() == '/' {
+ echo_string.pop();
+ }
+ let len = echo_string.len().to_string();
+ headers.insert("Content-Type".to_string(), "text/plain".to_string());
+ headers.insert("Content-Length".to_string(), len);
+ let body = echo_string;
+ Response::new(
+ "1.1".to_string(),
+ StatusCode::Ok,
+ Some(Headers(headers)),
+ Some(body),
+ )
+}
+
+fn handle_files(request: &Request, ctx: Option<&HashMap<String, String>>) -> Response {
+ // Extract the route regardless of the variant
+ let mut file = "".to_string();
+ let route = match request.method() {
+ Method::Get(route) | Method::Post(route) | Method::Put(route) => route,
+ };
+
+ let mut directory = ctx.unwrap().get(&"dir".to_string()).unwrap().clone();
+ directory.pop(); // remove last slash
+
+ for ch in route.chars().skip(1).skip_while(|&ch| ch != '/') {
+ file.push(ch);
+ }
+ if file.chars().last().unwrap() == '/' {
+ file.pop();
+ }
+ let len = file.len().to_string();
+
+ let full_path = &(directory + &file);
+ dbg!(full_path);
+
+ match read_file_as_bytes(full_path) {
+ Ok(bytes) => {
+ let mut headers = HashMap::new();
+ headers.insert(
+ "Content-Type".to_string(),
+ "application/octet-stream".to_string(),
+ );
+ headers.insert("Content-Length".to_string(), bytes.len().to_string());
+ let body = String::from_utf8(bytes).unwrap();
+ Response::new(
+ "1.1".to_string(),
+ StatusCode::Ok,
+ Some(Headers(headers)),
+ Some(body),
+ )
+ }
+ Err(_) => Response::new("1.1".to_string(), StatusCode::NotFound, None, None),
+ }
+}
+
+fn handle_user_agent(request: &Request, ctx: Option<&HashMap<String, String>>) -> Response {
+ let mut headers = HashMap::new();
+ let user_agent = request.get_tag("User-Agent".to_string());
+ let len = user_agent.len().to_string();
+ headers.insert("Content-Type".to_string(), "text/plain".to_string());
+ headers.insert("Content-Length".to_string(), len);
+ let body = user_agent.to_string();
+ Response::new(
+ "1.1".to_string(),
+ StatusCode::Ok,
+ Some(Headers(headers)),
+ Some(body),
+ )
+ .into()
+}
+
+fn handle_success(request: &Request, ctx: Option<&HashMap<String, String>>) -> Response {
+ Response::new("1.1".to_string(), StatusCode::Ok, None, None).into()
+}
+
+fn handle_not_found(request: Request, ctx: Option<&HashMap<String, String>>) -> Response {
+ Response::new("1.1".to_string(), StatusCode::NotFound, None, None).into()
+}
+
+fn serve(
+ mut stream: TcpStream,
+ router: Arc<Mutex<Router>>,
+ ctx: Arc<Mutex<HashMap<String, String>>>,
+) -> io::Result<usize> {
// Buffer to store the data received from the client
let mut buffer = [0; 512];
@@ -17,107 +130,78 @@ fn handle_client(mut stream: TcpStream) {
match stream.read(&mut buffer) {
Ok(_) => {
// Convert buffer to a string and print the received data
- if let Ok(request) = str::from_utf8(&buffer) {
- println!("Received request: {}", request);
- let request = Request::from(request);
- println!("Request after parsing: {:?}", request);
- let succses: String =
- Response::new("1.1".to_string(), StatusCode::Ok, None, None).into();
- let succses = succses.as_bytes();
-
- let not_found: String =
- Response::new("1.1".to_string(), StatusCode::NotFound, None, None).into();
- let not_found = not_found.as_bytes();
-
- match request.method {
- HTTPMethod::Get((endpoint, target)) => {
- match (endpoint.as_str(), target.as_str()) {
- ("", "") => match stream.write(succses) {
- Ok(_) => {
- println!("Response sent successfully");
- }
- Err(e) => eprintln!("Failed to send response: {}", e),
- },
- ("echo", target) => {
- let mut headers = HashMap::new();
- headers
- .insert("Content-Type".to_string(), "text/plain".to_string());
- headers.insert(
- "Content-Length".to_string(),
- (target.len() - 1).to_string(),
- );
- let body = target[0..target.len() - 1].to_string();
- let response: String = Response::new(
- "1.1".to_string(),
- StatusCode::Ok,
- Some(Headers(headers)),
- Some(body),
- )
- .into();
- dbg!(&response);
- let response = response.as_bytes();
-
- match stream.write(response) {
- Ok(_) => {
- println!("Response sent successfully");
- println!("Hello echo");
- }
- Err(e) => eprintln!("Failed to send response: {}", e),
- }
- }
- ("user-agent", _) => {
- let mut headers = HashMap::new();
- let user_agent: String =
- request.headers.unwrap().0.get("User-Agent").unwrap().into();
- headers
- .insert("Content-Type".to_string(), "text/plain".to_string());
- headers.insert(
- "Content-Length".to_string(),
- user_agent.len().to_string(),
- );
- let body = user_agent;
- let response: String = Response::new(
- "1.1".to_string(),
- StatusCode::Ok,
- Some(Headers(headers)),
- Some(body),
- )
- .into();
- dbg!(&response);
- let response = response.as_bytes();
-
- match stream.write(response) {
- Ok(_) => {
- println!("Response sent successfully");
- println!("Hello user-agent");
- }
- Err(e) => eprintln!("Failed to send response: {}", e),
- }
- }
- _ => match stream.write(not_found) {
- Ok(_) => println!("Response sent successfully"),
- Err(e) => eprintln!("Failed to send response: {}", e),
- },
- }
- }
- HTTPMethod::Post(_target) => todo!(),
- HTTPMethod::Put(_target) => todo!(),
+ match str::from_utf8(&buffer) {
+ Ok(request) => {
+ use Method::*;
+ println!("Received request:\n{}", request);
+ let request_lines: Vec<&str> = request.split("\r\n").collect();
+ let request = Request::from(request_lines);
+ let request_string: String = (&request).into();
+
+ println!("Request after parsing:\n{}", request_string);
+ dbg!(&request.method);
+
+ let response: String = {
+ let router = router.lock().unwrap();
+ let ctx = ctx.lock().unwrap();
+ router.handle(&request, Some(&ctx)).into()
+ };
+ stream.write(response.as_bytes())
}
+ Err(_) => todo!(),
}
}
- Err(e) => {
- eprintln!("Failed to read from stream: {}", e);
- }
+ Err(_) => todo!(),
}
}
fn main() -> io::Result<()> {
+ // Collect the command-line arguments
+ let args: Vec<String> = std::env::args().collect();
+
+ let mut dir = "".to_string();
+
+ let ctx = Arc::new(Mutex::new(HashMap::new()));
+
+ // Check if the correct number of arguments are provided
+ if args.len() == 3 {
+ // Parse the arguments
+ if args[1] == "--directory" {
+ dir += &args[2];
+ println!("Directory: {}", dir);
+ } else {
+ eprintln!("Unknown argument: {}", args[1]);
+ eprintln!("Usage: {} --directory <path>", args[0]);
+ return Ok(());
+ }
+ } else {
+ eprintln!("Usage: {} --directory <path>", args[0]);
+ }
+
let listener = TcpListener::bind("127.0.0.1:4221").unwrap();
+ let router = Arc::new(Mutex::new(Router::new()));
+ ctx.lock().unwrap().insert("dir".to_string(), dir);
+
+ {
+ let mut router = router.lock().unwrap();
+ router
+ .route(get("/"), handle_success)
+ .route(get("/echo/:var/"), handle_echo)
+ .route(get("/user-agent/"), handle_user_agent)
+ .route(get("/files/:file/"), handle_files);
+ }
+
for stream in listener.incoming() {
match stream {
Ok(stream) => {
- thread::spawn(move || handle_client(stream));
+ let router = Arc::clone(&router);
+ let ctx = Arc::clone(&ctx);
+ thread::spawn(move || {
+ if let Err(e) = serve(stream, router, ctx) {
+ eprintln!("Failed to serve connection: {}", e);
+ }
+ });
}
Err(e) => {
eprintln!("error: {}", e);