Add POST /files/{file_name}

Change-Id: I5a55f2ce4d78039267a642a7fbaf3c94752649fa
Reviewed-on: https://git.clicks.codes/c/Clicks/BYO/HttpServer/rust/+/267
Reviewed-by: Samuel Shuert <coded@clicks.codes>
Tested-by: Skyler Grey <minion@clicks.codes>
diff --git a/src/main.rs b/src/main.rs
index 9e7d884..df41f2d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -12,38 +12,66 @@
     String(String)
 }
 
+#[derive(PartialEq)]
+enum RequestSection {
+    RequestLine,
+    Headers,
+    Body
+}
+
 async fn process_socket(mut stream: TcpStream) -> Result<(), &'static str> {
     println!("accepted new connection");
     let mut request: HashMap<String, String> = HashMap::new();
-    let mut line_num: usize = 0;
+    let mut section: RequestSection = RequestSection::RequestLine;
     loop {
         let mut line = String::default();
 
-        loop {
-            let mut buf: [u8; 1] = [0; 1];
+        if section == RequestSection::Body {
+            let content_size: usize = request.get("Content-Length").unwrap().parse::<usize>().unwrap();
+            let mut buf: Vec<u8> = vec![0; content_size];
             stream.read_exact(&mut buf).await.unwrap();
+        } else {
+            loop {
+                let mut buf: [u8; 1] = [0; 1];
+                stream.read_exact(&mut buf).await.unwrap();
 
-            let character = buf[0].as_char();
-            if character == '\n' {
-                break
-            } else if character != '\r' {
-                line.push(character);
+                let character = buf[0].as_char();
+
+                if character == '\n' {
+                    break
+                } else if character != '\r' {
+                    line.push(character);
+                }
             }
         }
 
-        if line_num == 0 {
-            let mut splits = line.split(' ');
-            request.insert("method".to_owned(), splits.next().unwrap().to_owned());
-            request.insert("path".to_owned(), splits.next().unwrap().to_owned());
-        } else {
-            let mut splits = line.split(":");
-            let key = splits.next().unwrap();
-            let value = splits.next().unwrap_or_default().trim();
-            request.insert(key.to_owned(), value.to_owned());
+        match section {
+            RequestSection::RequestLine => {
+                let mut splits = line.split(' ');
+                request.insert("method".to_owned(), splits.next().unwrap().to_owned());
+                request.insert("path".to_owned(), splits.next().unwrap().to_owned());
+                
+                section = RequestSection::Headers;
+            }
+            RequestSection::Headers => {
+                if line == "" {
+                    section = RequestSection::Body;
+                } else {
+                    let mut splits = line.split(":");
+                    let key = splits.next().unwrap();
+                    let value = splits.next().unwrap_or_default().trim();
+                    request.insert(key.to_owned(), value.to_owned());
+                }
+            },
+            RequestSection::Body => {
+                request.insert("body".to_owned(), line);
+                break;
+            },
         }
 
-        if request.get("path").unwrap() != "/user-agent" || request.contains_key("User-Agent") { break };
-        line_num += 1;
+        if request.get("path").unwrap() == "/user-agent" && !request.contains_key("User-Agent") { continue; };
+        if request.get("path").unwrap().starts_with("/files/") && request.get("method").unwrap() == "POST" && !request.contains_key("body") { continue; };
+        break;
     }
 
     let mut path = request.get("path").unwrap().split("/");
@@ -70,26 +98,44 @@
             response_headers.push("Content-Type: text/plain".into());
         },
         "files" => {
-            let file_name = path.join("/");
             let args: Vec<String> = args().collect();
             let dir_arg = args.iter().find_position(|item| **item == "--directory");
+            let file_name = path.join("/");
             let file_path = if dir_arg.is_some() {
                 args[dir_arg.unwrap().0+1].to_owned() + "/" + file_name.as_str()
             } else {
                 return Err("No directory Given".into())
             };
-            let maybe_file = File::open(file_path).await;
-
-            match maybe_file {
-                Ok(file) => {
-                    response_status = "200 OK".into();
-                    response_body = BodyTypes::File(file);
-                    response_headers.push("Content-Type: application/octet-stream".into());
+            match request.get("method").unwrap().as_str() {
+                "GET" => {
+                    let maybe_file = File::open(file_path).await;
+                    match maybe_file {
+                        Ok(file) => {
+                            response_status = "200 OK".into();
+                            response_body = BodyTypes::File(file);
+                            response_headers.push("Content-Type: application/octet-stream".into());
+                        },
+                        Err(_) => {
+                            response_status = "404 Not Found".into();
+                            response_body = BodyTypes::String("".into());
+                        }
+                    }
                 },
-                Err(_) => {
-                    response_status = "404 Not Found".into();
-                    response_body = BodyTypes::String("".into());
-                }
+                "POST" => {
+                    let file = File::create(file_path).await;
+                    match file {
+                        Ok(mut f) => {
+                            f.write(request.get("body").unwrap().as_bytes()).await.unwrap();
+                            response_status = "201 Created".into();
+                            response_body = BodyTypes::String("".into());
+                        },
+                        Err(_) => {
+                            response_body = BodyTypes::String("500 INTERNAL SERVER ERROR".into());
+                            response_status = "".into()
+                        }
+                    }
+                },
+                _ => unreachable!() // not actually unreachable, but please don't kill our server thank you with pretty puppies on top <3
             }
         },
         _ => {