cargo clippy and proper HTTP codes in parse_start_line

This commit is contained in:
2025-03-21 10:17:06 +01:00
parent bb2e683f20
commit 6472b0a278

View File

@ -12,9 +12,9 @@ use std::{
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
enum RequestMethods {
NULL = -1, // This is only to initialise the struct
GET,
HEAD,
Null = -1, // This is only to initialise the struct
Get,
Head,
}
#[derive(Debug)]
@ -27,7 +27,7 @@ struct StartLine {
impl StartLine {
pub fn new() -> Self {
Self {
method: RequestMethods::NULL,
method: RequestMethods::Null,
target: String::new(),
version: String::new(),
}
@ -73,7 +73,7 @@ impl StartLine {
return true;
}
return false;
false
}
pub fn is_valid_version(version: &str) -> bool {
@ -102,14 +102,10 @@ impl StartLine {
}
};
if major <= 9 && minor <= 9 {
return true;
} else {
return false;
}
} else {
return false;
return major <= 9 && minor <= 9;
}
false
}
}
@ -135,7 +131,7 @@ fn parse_start_line(input: &str) -> Result<StartLine, Vec<u8>> {
response_field_lines.insert(String::from("Content-Type"), String::from("text/plain"));
return Err(response_builder(
RequestMethods::GET,
RequestMethods::Get,
"HTTP/1.1 400 ",
Some(response_field_lines),
Some(response_body),
@ -146,31 +142,64 @@ fn parse_start_line(input: &str) -> Result<StartLine, Vec<u8>> {
let target = vec[1];
let version = vec[2];
if StartLine::is_valid_method(&method)
&& StartLine::is_valid_target(&target)
&& StartLine::is_valid_version(&version)
{
// start_line.method will remain RequestMethods::NULL if it is not supported.
match method {
"GET" => start_line.method = RequestMethods::GET,
"HEAD" => start_line.method = RequestMethods::HEAD,
_ => start_line.method = RequestMethods::NULL,
}
start_line.target = target.to_string();
if version == "HTTP/1.1" || version == "HTTP/1.0" {
start_line.version = version.to_string();
}
} else {
if !StartLine::is_valid_method(method) {
return Err(response_builder(
RequestMethods::HEAD,
RequestMethods::Head,
"HTTP/1.1 501 ",
None,
None,
));
}
// start_line.method will remain RequestMethods::NULL if it is not supported.
match method {
"GET" => start_line.method = RequestMethods::Get,
"HEAD" => start_line.method = RequestMethods::Head,
_ => start_line.method = RequestMethods::Null,
}
if !StartLine::is_valid_version(version) {
return Err(response_builder(
RequestMethods::Head,
"HTTP/1.1 400 ",
None,
None,
));
}
if version != "HTTP/1.1" && version != "HTTP/1.0" {
"Server only supports major version 1 of HTTP"
.as_bytes()
.iter()
.for_each(|byte| response_body.push(*byte));
response_field_lines.insert(
String::from("Content-Length"),
response_body.len().to_string(),
);
response_field_lines.insert(String::from("Content-Type"), String::from("text/plain"));
return Err(response_builder(
RequestMethods::Head,
"HTTP/1.1 505 ",
Some(response_field_lines),
Some(response_body),
));
}
start_line.version = version.to_string();
if !StartLine::is_valid_target(target) {
return Err(response_builder(
RequestMethods::Head,
"HTTP/1.1 400 ",
None,
None,
));
}
start_line.target = target.to_string();
Ok(start_line)
}
@ -199,7 +228,7 @@ fn parse_field_lines(
response_field_lines.insert(String::from("Content-Type"), String::from("text/plain"));
return Err(response_builder(
RequestMethods::GET,
RequestMethods::Get,
"HTTP/1.1 400 ",
Some(response_field_lines),
Some(response_body),
@ -226,7 +255,7 @@ fn parse_field_lines(
.insert(String::from("Content-Type"), String::from("text/plain"));
return Err(response_builder(
RequestMethods::GET,
RequestMethods::Get,
"HTTP/1.1 400 ",
Some(response_field_lines),
Some(response_body),
@ -250,14 +279,14 @@ fn parse_field_lines(
response_field_lines.insert(String::from("Content-Type"), String::from("text/plain"));
return Err(response_builder(
RequestMethods::GET,
RequestMethods::Get,
"HTTP/1.1 400 ",
Some(response_field_lines),
Some(response_body),
));
}
return Ok(field_lines);
Ok(field_lines)
}
fn response_builder(
@ -275,47 +304,41 @@ fn response_builder(
response.push(b'\r');
response.push(b'\n');
match field_lines {
Some(val) => {
for field_line in val.iter() {
field_line
.0
.as_bytes()
.iter()
.for_each(|byte| response.push(*byte));
if let Some(val) = field_lines {
for field_line in val.iter() {
field_line
.0
.as_bytes()
.iter()
.for_each(|byte| response.push(*byte));
response.push(b':');
response.push(b' ');
response.push(b':');
response.push(b' ');
field_line
.1
.as_bytes()
.iter()
.for_each(|byte| response.push(*byte));
field_line
.1
.as_bytes()
.iter()
.for_each(|byte| response.push(*byte));
response.push(b'\r');
response.push(b'\n');
}
response.push(b'\r');
response.push(b'\n');
}
None => (),
}
// Mandatory empty line between header and body
response.push(b'\r');
response.push(b'\n');
if method != RequestMethods::HEAD {
match body {
Some(val) => {
val.iter().for_each(|byte| response.push(*byte));
response.push(b'\r');
response.push(b'\n');
}
None => (),
if method != RequestMethods::Head {
if let Some(val) = body {
val.iter().for_each(|byte| response.push(*byte));
response.push(b'\r');
response.push(b'\n');
}
}
return response;
response
}
fn try_get_file(start_line: &StartLine, _field_lines: &HashMap<String, String>) -> Vec<u8> {
@ -387,7 +410,7 @@ fn handle_request(mut stream: TcpStream) -> Result<(), Box<dyn Error>> {
response_field_lines.insert(String::from("Content-Type"), String::from("text/plain"));
let response = response_builder(
RequestMethods::GET,
RequestMethods::Get,
"HTTP/1.1 400 ",
Some(response_field_lines),
Some(response_body),
@ -419,7 +442,7 @@ fn handle_request(mut stream: TcpStream) -> Result<(), Box<dyn Error>> {
let response = match start_line.target.as_str() {
// For docker healtcheck. If the server can properly respond, then it must be healthy.
"/server-health" => response_builder(RequestMethods::HEAD, "HTTP/1.1 200 ", None, None),
"/server-health" => response_builder(RequestMethods::Head, "HTTP/1.1 200 ", None, None),
"/server-stats" => response_builder(start_line.method, "HTTP/1.1 404 ", None, None),
"/server-info" => response_builder(start_line.method, "HTTP/1.1 404 ", None, None),
_ => try_get_file(&start_line, &field_lines),
@ -434,7 +457,7 @@ fn main() -> Result<(), Box<dyn Error>> {
// TODO: Gracefully shutdown server
thread::spawn(move || {
for sig in signals.forever() {
if let Some(sig) = signals.forever().next() {
println!("Received signal {:?}", sig);
println!("Shutting down");
exit(1);