diff --git a/src/main.rs b/src/main.rs index 52a7f27..1331867 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,72 +16,118 @@ struct StartLine { } impl StartLine { - pub fn new(input: String) -> Self { - let input_array = input.trim().split(" ").collect::>(); - + pub fn new() -> Self { Self { - method: input_array[0].to_owned(), - target: input_array[1].to_owned(), - version: input_array[2].to_owned(), + method: String::new(), + target: String::new(), + version: String::new(), } } - pub fn is_valid_method(input: &StartLine) -> bool { - if input.method.is_empty() { + pub fn is_valid_method(method: &String) -> bool { + if method.trim().is_empty() { return false; } - let method: &str = input.method.as_str(); + let tmp = method.as_str(); - if VALID_METHODS.contains(&method) { + if VALID_METHODS.contains(&tmp) { return true; } else { return false; } } + + pub fn is_valid_target(target: &String) -> bool { + if target.trim().is_empty() { + return false; + } + + return true; + } + + pub fn is_valid_version(version: &String) -> bool { + if version.trim().is_empty() { + return false; + } + + return true; + } +} + +fn parse_start_line(input: String) -> Option { + let mut start_line = StartLine::new(); + let vec = input.trim().split(" ").collect::>(); + + if vec.len() != 3 { + return None; + } + + let method = String::from(vec[0]); + if StartLine::is_valid_method(&method) { + start_line.method = method; + } + + let target = String::from(vec[1]); + if StartLine::is_valid_target(&target) { + start_line.target = target; + } + + let version = String::from(vec[2]); + if StartLine::is_valid_version(&version) { + start_line.version = version; + } + + return Some(start_line); } fn handle_request(mut stream: TcpStream) { + let mut line = String::new(); let mut reader = BufReader::new(&mut stream); + reader.read_line(&mut line).unwrap(); - let mut start_line = String::new(); - reader.read_line(&mut start_line).unwrap(); + let mut counter = 0; + let max_preceding_empty_lines = 1000; - // I will not support ignoring the CR - if !start_line.ends_with("\r\n") { - stream - .write_all(b"HTTP/1.1 400 Bad Request\r\n\r\nLines must end with CRLF") - .unwrap(); - return; - } - - // Request can have one or many empty lines preceding the request-line and I will ignore these + // Request can have one or many empty lines preceding the start-line and I will ignore these + // I will also for now only allow up to 1000 of these empty lines before I abort loop { - if !start_line.trim().is_empty() { + if counter > max_preceding_empty_lines { + stream + .write_all( + b"HTTP/1.1 400 Bad Request\r\n\r\nReceived too many preceding empty lines", + ) + .unwrap(); + return; + } + + // I will not support ignoring the CR + if !line.ends_with("\r\n") { + stream + .write_all(b"HTTP/1.1 400 Bad Request\r\n\r\nLines must end with CRLF") + .unwrap(); + return; + } + line = line.trim().into(); + + if !line.is_empty() { break; } - reader.read_line(&mut start_line).unwrap(); + reader.read_line(&mut line).unwrap(); + counter += 1; } - if start_line.trim().is_empty() { - reader.read_line(&mut start_line).unwrap(); - } - if start_line.trim().is_empty() { - stream - .write_all(b"HTTP/1.1 400 Bad Request\r\n\r\nReceived too many preceding empty lines") - .unwrap(); - return; - } + let start_line = match parse_start_line(line) { + Some(val) => val, + None => { + stream + .write_all(b"HTTP/1.1 400 Bad Request\r\n\r\nInvalid start-line") + .unwrap(); + return; + } + }; - let start_line = StartLine::new(start_line); dbg!(&start_line); - if !StartLine::is_valid_method(&start_line) { - stream - .write_all(b"HTTP/1.1 400 Bad Request\r\n\r\nInvalid request method") - .unwrap(); - return; - } - if start_line.method != "GET" { stream .write_all(b"HTTP/1.1 501 Not Implemented\r\n\r\nServer currently only supports GET") @@ -95,7 +141,7 @@ fn handle_request(mut stream: TcpStream) { loop { let mut line = String::new(); reader.read_line(&mut line).unwrap(); - print!("{line}"); + // print!("{line}"); if line.starts_with(" ") { if !is_first_line { @@ -107,6 +153,7 @@ fn handle_request(mut stream: TcpStream) { return; } + // I will not support ignoring the CR if !line.ends_with("\r\n") { stream .write_all(b"HTTP/1.1 400 Bad Request\r\n\r\nLines must end with CRLF") @@ -127,7 +174,7 @@ fn handle_request(mut stream: TcpStream) { dbg!(&field_lines); stream - .write_all(b"HTTP/1.1 200 OK\r\n\r\nHello, World!") + .write_all(b"HTTP/1.1 200 OK\r\n\r\nHello, World!\r\n") .unwrap(); }