server/
request.rs

1//! # use server::request::{ [RequestObject], [handle_connection] }
2//! 
3//! A library that hanldes requests made to the web-server.
4
5use std::{fs, net::TcpStream};
6use std::io::prelude::*;
7use super::process::CliArgs;
8
9#[derive(Debug)]
10/// The requests made to the web-server are represented in the data structure `RequestObject`
11/// The only supported request method on the server is `GET`
12pub struct RequestObject {
13    /// This represents the request method of the request received by the server
14    pub method: String,
15
16    /// This represents the route of the asset/file requested by the client side.
17    pub route: String,
18}
19
20impl RequestObject {
21    /// Returns a struct with a request method and request route.
22    /// 
23    /// # Args
24    /// 
25    /// * `request` - This is the request in a string format containing necessary request information.
26    /// 
27    /// # Example
28    /// 
29    /// ```
30    /// use server::request::RequestObject;
31    /// let req_obj: Option<RequestObject> = RequestObject::new(&String::from("GET / Content-Length: 0\r\n\r\n"));
32    /// 
33    /// match req_obj {
34    ///     Some(obj) => {
35    ///         assert!(obj.method == "GET");
36    ///         assert!(obj.route == "/");
37    ///     }
38    ///     None => {}
39    /// }
40    /// 
41    /// ```
42    /// 
43    /// # Panics
44    /// 
45    /// - Panics if the request methos is not a `GET` method
46    /// - Panics if the route does not start with `/`.
47    ///  
48    pub fn new(request: &String) -> Option<RequestObject> {
49        let allowed_methods = ["GET"];
50        let req_args: Vec<&str> = request.split(" ").collect();
51        let method = req_args[0];
52        let route = req_args[1];
53
54        assert!(allowed_methods.contains(&method), "Invalid request method");
55        assert!(route.starts_with("/"), "Invalid request route");
56
57        Some(RequestObject {
58            method: String::from(method),
59            route: String::from(route)
60        })
61    }   
62}
63
64/// Function that handles a request stream.
65/// The request is processed based on the method and route.
66/// The route determines the file path for a `GET` request.
67/// 
68/// Args
69/// 
70/// * `stream` - A TcpStream type which basically is a stream of bytes that represents the client request.
71/// 
72pub fn handle_connection(mut stream: TcpStream) {
73    let mut buffer = [0; 1024];
74    stream.read(&mut buffer).unwrap();
75
76    let str_buffer = String::from_utf8(buffer.clone().to_vec()).unwrap();
77    let request_obj = RequestObject::new(&str_buffer);
78
79    match &request_obj {
80        Some(req) => {
81            if req.method == "GET" {
82                let route = req.route.as_str();
83                let content: String;
84                match route {
85                    value => {
86                        let mut file_path = value;
87                        if (!value.contains(".") && !value.contains(".html")) || value == "/index.html" {
88                            file_path = "/index.html"
89                        }
90                        let file_content = fs::read_to_string(String::from(CliArgs::get().dir_path) + file_path);
91
92                        match file_content {
93                            Ok(data) => {
94                                content = data.clone()
95                            }
96                            Err(_) => {
97                                content = fs::read_to_string("assets/404.html").unwrap();
98                            }
99                        }
100                    }
101                }
102                
103                let response = format!(
104                    "HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}",
105                    content.len(),
106                    content,
107                );
108                stream.write(response.as_bytes()).unwrap();
109                stream.flush().unwrap();
110            }
111        }
112        None => {}
113    }
114}