diff --git a/src/status.rs b/src/status.rs index eec1ab1..2f817fb 100644 --- a/src/status.rs +++ b/src/status.rs @@ -1,7 +1,10 @@ +//! Response status code representation + use crate::error::LibError; use num_enum::{IntoPrimitive, TryFromPrimitive}; +/// Handy representation of a Gemini response status code #[derive(Debug, Clone, Copy)] pub struct Status { status_code: StatusCode, @@ -9,46 +12,76 @@ pub struct Status { second_digit: u8, } +/// Type of a Gemini response defined by the first digit of a status code #[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] #[num_enum(error_type(name = LibError, constructor = LibError::status_out_of_range))] #[repr(u8)] pub enum ReplyType { + /// User input in a query argument is expected for this path Input = 1, + /// Request has been processed successfully, content is served Success, + /// Server redirects to another URL Redirect, + /// Temporary failure, try again later TempFail, + /// Permanent failure, request is incorrect PermFail, + /// Server requires authorization via client certificates to access this resource Auth, } +/// 2-digit status code enum; all the codes defined in Gemini spec are listed #[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] #[num_enum(error_type(name = LibError, constructor = LibError::status_out_of_range))] #[repr(u8)] pub enum StatusCode { + /// User input is expected Input = 10, + /// User input with sensitive data such as password is expected InputSensitive = 11, + /// Request has been processed successfully, content is served Success = 20, + /// Temporary redirection to another URL TempRedirect = 30, + /// Permanent redirection to another URL PermRedirect = 31, + /// General status code for temporary failures TempFail = 40, + /// Server is unavailable due to overload or maintenance ServerUnavailable = 41, + /// CGI process returned an error or timed out CgiError = 42, + /// Request to a remote host was not successful ProxyError = 43, + /// Client must slow down requests (some kind of ratelimit) SlowDown = 44, + /// General status code for permanent failures PermFail = 50, + /// Requested resource was not found NotFound = 51, + /// Requested resource is no longer available Gone = 52, + /// Given URL is not meant to be processed by this server + /// (host does not match, scheme is not `gemini://`, etc.), + /// but the server does not accept proxy requests ProxyRequestRefused = 53, + /// Server is unable to parse the request BadRequest = 59, + /// Client certificate is required to access the content ClientCerts = 60, + /// Provided certificate is not authorized for accessing this resource CertNotAuthorized = 61, + /// Provided certificate is not valid: violates X.509 standard, + /// has invalid signature or expiry date CertNotValid = 62, + /// Undefined status code between 10 and 69 inclusive // 1..6 first digit range check is still // covered by conversion into ReplyType // (see Status::parse_status) @@ -59,6 +92,8 @@ pub enum StatusCode { const ASCII_ZERO: u8 = 48; // '0' impl Status { + /// Take first two bytes from the buffer and parse them as a status code, + /// returning [`Status`] on success or [`LibError::StatusOutOfRange`] on error pub fn parse_status(buf: &[u8]) -> Result { // simple decimal digit conversion // '2' - '0' = 50 - 48 = 2 (from byte '2' to uint 2) @@ -77,18 +112,22 @@ impl Status { }) } + /// Get the 2-digit status code as a [`StatusCode`] enum item pub fn status_code(&self) -> StatusCode { self.status_code } + /// Get this status code as a number pub fn num(&self) -> u8 { self.status_code.into() } + /// Get the response type (the first digit) as a [`ReplyType`] enum item pub fn reply_type(&self) -> ReplyType { self.reply_type } + /// Get the second digit of this status code pub fn second_digit(&self) -> u8 { self.second_digit }