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