diff --git a/.gitignore b/.gitignore index d01bd1a..efe3eb1 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,8 @@ Cargo.lock # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ \ No newline at end of file +#.idea/ + +# Added by cargo + +/target diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..c949f62 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "hermes" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/public/200.json b/public/200.json new file mode 100644 index 0000000..dd2e842 --- /dev/null +++ b/public/200.json @@ -0,0 +1,5 @@ +{ + "SomeKey": "Some Value goes here", + "SomeOther": "thisisAOnthervalue", + "Integer": 123 +} diff --git a/public/404.html b/public/404.html new file mode 100644 index 0000000..22dfb0b --- /dev/null +++ b/public/404.html @@ -0,0 +1,9 @@ + + + + Page Not Found | Hermes + + +

The requested page could not be found.

+ + diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..b8b1728 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,92 @@ +use std::{ + fs, + io::{prelude::*, BufReader}, + net::{TcpListener, TcpStream}, +}; + +#[allow(dead_code)] +struct IncomingRequest { + req_type: String, + path: String +} + +// Listen on port and return response. +fn main() { + let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); + + for stream in listener.incoming() { + let stream = stream.unwrap(); + handle_connection(stream); + } +} + +#[allow(unused_assignments)] +fn handle_connection(mut stream: TcpStream) { + let buf_reader = BufReader::new(&stream); + let http_request: Vec<_> = buf_reader + .lines() + .map(|result| result.unwrap()) + .take_while(|line| !line.is_empty()) + .collect(); + + let request_line: String = http_request.first().expect("Not a string").to_string(); + let req_vec: Vec<&str> = request_line.split(" ").collect(); + let inc_request = IncomingRequest { + req_type: req_vec[0].to_string(), + path: req_vec[1].to_string(), + }; + let api_key: String = get_api_key(http_request); + let mut response = String::new(); + // If not a GET request, or missing API key, throw 404. + if inc_request.req_type != "GET" || api_key.is_empty() { + response = return_404(); + } + else { + // Check that the API key is in fact fact valuid. + // Not really checking right now. + response = return_200(); + } + // If not present, return 404. + // Perhaps move both of those conditions to a new function. + stream.write_all(response.as_bytes()).unwrap(); +} + +// get the apy key from the headers. +fn get_api_key(headers: Vec) -> String { + let mut api_key = String::new(); + + for header in headers { + // split header, strip whitespace, check if exists. + let split_header: Vec<&str> = header.split(":").collect(); + let header_key: String = split_header.first().expect("Nothing here").to_string(); + if header_key == "x-api-key" { + api_key = split_header[1].to_string(); + } + } + + api_key +} + +// Return a 404. +fn return_404() -> String { + let status_line = "HTTP/1.1 404 Not Found"; + let contents = fs::read_to_string("./public/404.html").unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + response +} + +// Return a 200 with the json. +fn return_200() -> String { + let status_line = "HTTP/1.1 200 OK"; + let contents = fs::read_to_string("./public/200.json").unwrap(); + let length = contents.len(); + + let response = + format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); + + response +}