diff --git a/src/http.rs b/src/http.rs index 0e401f4..0bef40c 100644 --- a/src/http.rs +++ b/src/http.rs @@ -11,8 +11,9 @@ pub enum StatusCode { OK, BadRequest, NotFound, + ImATeapot, InternalServerError, - // ImATeapot, + BadGateway, } impl StatusCode { @@ -21,8 +22,9 @@ impl StatusCode { StatusCode::OK => 200, StatusCode::BadRequest => 400, StatusCode::NotFound => 404, - // StatusCode::ImATeapot => 418, + StatusCode::ImATeapot => 418, StatusCode::InternalServerError => 500, + StatusCode::BadGateway => 502, } } diff --git a/src/main.rs b/src/main.rs index 5bd96c2..9a1d9b9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -53,6 +53,23 @@ fn parse_address(address: &str) -> Result { } } +fn query_error_to_user_response(err: &Error, query_address: &String, address: &SocketAddr) -> (StatusCode, String) { + match err.kind() { + ErrorKind::HostUnreachable => + (StatusCode::BadGateway, format!( + "Host unreachable: {} ({})\n", + query_address, address)), + ErrorKind::InvalidData => + (StatusCode::BadGateway, format!( + "Server returned invalid data: {} ({})\n", + query_address, address)), + _ => + (StatusCode::InternalServerError, format!( + "Failed to connect: {} ({}).\n", + query_address, address)), + } +} + fn handle_html_request(request: &Request, response: &mut Response, verbose: bool) -> Result { let content = include_str!("views/index.html"); response.set_header("Content-Type", "text/html".to_string()); @@ -75,19 +92,16 @@ fn handle_html_request(request: &Request, response: &mut Response, verbose: bool match MinecraftStatus::fetch(&address, verbose) { Err(err) => { println!( - "Failed to connect to {} ({}): {}", + "Failed to query {} ({}): {}", query_address, address, err); - response.body(format!( - "Failed to connect to {} ({}).\n", - query_address, address)); - response.status(StatusCode::InternalServerError); + let (code, msg) = query_error_to_user_response(&err, query_address, &address); + + response.status(code); query_response = format!( "

Server Details

-
Failed to connect to {} ({}).
", - sanitize_html(query_address), - sanitize_html(&address.to_string()), +
{msg}
", ); } Ok(status) => { @@ -155,10 +169,10 @@ fn handle_json_request(request: &Request, response: &mut Response, verbose: bool "Failed to connect to {} ({}): {}", query_address, address, err); - response.status(StatusCode::InternalServerError); - response.body(format!( - "Failed to connect to {} ({}).\n", - query_address, address)); + let (code, msg) = query_error_to_user_response(&err, query_address, &address); + + response.status(code); + response.body(msg); } Ok(status) => { let minecraft_status = MinecraftStatusResponse{ @@ -241,7 +255,7 @@ fn main() -> Result<()> { Err (e) => { return Err(Error::new( ErrorKind::Other, - format!("Failed to fetch status: {}", e))); + format!("Failed to query server: {}", e))); } }; } diff --git a/src/status.rs b/src/status.rs index 8e1185d..343350e 100644 --- a/src/status.rs +++ b/src/status.rs @@ -128,10 +128,16 @@ impl MinecraftStatus { } } - let data = std::str::from_utf8(&data[offset..]).expect("Failed to parse UTF-8 data"); + let data = match std::str::from_utf8(&data[offset..]) { + Ok(data) => data, + Err(err) => return Err(Error::new(ErrorKind::InvalidData, format!("Failed to parse UTF-8 data: {err}"))) + }; let sanitised: String = data.chars().filter( |&c| c >= '\u{20}' || c == '\n' || c == '\r' || c == '\t').collect(); - let status: MinecraftStatus = serde_json::from_str(&sanitised).expect("Failed to parse JSON"); + let status: MinecraftStatus = match serde_json::from_str(&sanitised) { + Ok(status) => status, + Err(err) => return Err(Error::new(ErrorKind::InvalidData, format!("Failed to parse JSON: {err}"))), + }; Ok(status) }