//! response handles the incoming request parsed `HTTPRequest` //! it will build an HTTPResponse corresponding to the HTTP message specs. see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages //! NOTE: only few parts of the specification has been implemented use super::{HTTPMessage, HTTPVersion}; use json; #[derive(Debug, PartialEq, Clone)] pub enum HTTPStatusCode { Http200, Http400, Http403, Http404, Http500, } impl Into for HTTPStatusCode { fn into(self) -> String { match self { Self::Http200 => "200".to_string(), Self::Http400 => "400".to_string(), Self::Http404 => "404".to_string(), Self::Http403 => "403".to_string(), Self::Http500 => "500".to_string(), } } } pub struct HTTPStatusLine { version: HTTPVersion, status_code: HTTPStatusCode, } impl Default for HTTPStatusLine { fn default() -> HTTPStatusLine { HTTPStatusLine { version: HTTPVersion::Http1_1, status_code: HTTPStatusCode::Http400, } } } impl Into for HTTPStatusLine { fn into(self) -> String { let version: String = self.version.into(); let status_code: String = self.status_code.into(); format! {"{} {}", version, status_code} } } impl HTTPStatusLine { pub fn set_status_code(&mut self, code: HTTPStatusCode) { self.status_code = code; } #[allow(dead_code)] pub fn get_status_code(&self) -> HTTPStatusCode { self.status_code.clone() } } /// represents an HTTP response (headers are not parsed) /// NOTE: for simplicity, only JSON body are accepted pub struct HTTPResponse { pub status_line: HTTPStatusLine, body: json::JsonValue, } impl Default for HTTPResponse { fn default() -> Self { HTTPResponse { status_line: HTTPStatusLine::default(), body: json::parse(r#"{"error": "the incoming request is not valid"}"#).unwrap(), } } } impl Into for HTTPResponse { fn into(self) -> String { // move `self.body` into a new var let b = self.body; let body: String = json::stringify(b); let status_line: String = self.status_line.into(); format!( "{}\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{}", status_line, body.len(), body ) } } impl HTTPResponse { pub fn as_500(message: Option) -> Self { let mut response = Self::default(); response .status_line .set_status_code(HTTPStatusCode::Http500); response.body = { match message { Some(m) => m, None => json::parse(r#"{"error": "unexpected error occurred"}"#).unwrap(), } }; response } pub fn as_404() -> Self { let mut response = Self::default(); response .status_line .set_status_code(HTTPStatusCode::Http404); response.body = json::parse(r#"{"error": "the url requested does not exist"}"#).unwrap(); response } pub fn as_403() -> Self { let mut response = HTTPResponse { status_line: HTTPStatusLine::default(), body: json::parse(r#"{"error": "invalid credentials"}"#).unwrap(), }; response .status_line .set_status_code(HTTPStatusCode::Http403); response } /// wrap the `Self::default()` associated func (not really clear) pub fn as_400() -> Self { Self::default() } pub fn as_200(message: Option) -> Self { let mut response = Self::default(); response .status_line .set_status_code(HTTPStatusCode::Http200); response.body = { match message { Some(m) => m, None => json::parse(r#"{"status": "ok"}"#).unwrap(), } }; response } /// build and HTTP 200 response with the generated JWT pub fn send_token(token: &str) -> Self { let mut http_message = HTTPMessage::default(); http_message.put("token", token); let message = { match http_message.try_into() { Ok(m) => m, Err(_e) => json::parse(r#"{"token": "error.generation.token"}"#).unwrap(), } }; HTTPResponse::as_200(Some(message)) } }