improve HTTPResponse to include custom HTTPMessage

This commit is contained in:
landrigun 2022-10-13 12:20:30 +00:00
parent 808cd3ee77
commit 7073a4b88e
5 changed files with 70 additions and 21 deletions

View File

@ -33,10 +33,27 @@ impl TryInto<json::JsonValue> for HTTPMessage {
}
impl HTTPMessage {
fn put(&mut self, key: &str, value: &str) {
pub fn put(&mut self, key: &str, value: &str) {
self.message.insert(key.to_string(), value.to_string());
}
/// associated function to build an HTTPMessage error
pub fn error(message: &str) -> Option<json::JsonValue> {
let mut http_message = HTTPMessage::default();
http_message.put("error", message);
match message.try_into() {
Ok(m) => Some(m),
Err(e) => {
eprintln!(
"unable to parse the message: {} into JSON, err={}",
message, e
);
return None;
}
}
}
/// loops over all the HashMap keys, builds a JSON key value for each one and join them with `JSON_DELIMITER`
fn build_json(self) -> String {
let unstruct: Vec<String> = self

View File

@ -6,6 +6,6 @@ pub mod response;
pub mod router;
pub use message::HTTPMessage;
pub use request::HTTPRequest;
pub use request::{HTTPRequest, HTTPVersion};
pub use response::{HTTPResponse, HTTPStatusCode};
pub use router::ROUTER;

View File

@ -2,7 +2,7 @@
//! 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 crate::http::request::HTTPVersion;
use super::{HTTPMessage, HTTPVersion};
use json;
#[derive(Debug, PartialEq, Clone)]
@ -92,13 +92,19 @@ impl Into<String> for HTTPResponse {
}
impl HTTPResponse {
pub fn as_500() -> Self {
pub fn as_500(message: Option<json::JsonValue>) -> Self {
let mut response = Self::default();
response
.status_line
.set_status_code(HTTPStatusCode::Http500);
response.body = json::parse(r#"{"error": "unexpected error occurred"}"#).unwrap();
response.body = {
match message {
Some(m) => m,
None => json::parse(r#"{"error": "unexpected error occurred"}"#).unwrap(),
}
};
response
}
@ -119,9 +125,11 @@ impl HTTPResponse {
status_line: HTTPStatusLine::default(),
body: json::parse(r#"{"error": "invalid credentials"}"#).unwrap(),
};
response
.status_line
.set_status_code(HTTPStatusCode::Http403);
response
}
@ -130,16 +138,35 @@ impl HTTPResponse {
Self::default()
}
// TODO: need to be adjust to accept `json::JsonValue`
pub fn as_200(token: String) -> Self {
pub fn as_200(message: Option<json::JsonValue>) -> Self {
let mut response = Self::default();
response
.status_line
.set_status_code(HTTPStatusCode::Http200);
response.body = json::parse(format!(r#"{{"token": "{}"}}"#, token).as_str()).unwrap();
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))
}
}

View File

@ -1,7 +1,7 @@
//! router aims to handle correctly the request corresponding to the target
//! it implements all the logic to build an `HTTPResponse`
use super::{HTTPRequest, HTTPResponse};
use super::{HTTPMessage, HTTPRequest, HTTPResponse};
use crate::config::Config;
use crate::stores::FileStore;
use crate::stores::Store;
@ -36,10 +36,11 @@ fn handle_get(request: HTTPRequest, config: Config) -> FuturePinned<HTTPResponse
let jwt_key = {
match RS384KeyPair::from_pem(priv_key_content.as_str()) {
Ok(k) => k,
// TODO: set error in the message body
Err(e) => {
eprintln!("error occurred while getting private key err={}", e);
return HTTPResponse::as_500();
let message: Option<json::JsonValue> = HTTPMessage::error(
format!("unable to load the private key, err={}", e).as_str(),
);
return HTTPResponse::as_500(message);
}
}
};
@ -47,11 +48,12 @@ fn handle_get(request: HTTPRequest, config: Config) -> FuturePinned<HTTPResponse
claims.issuer = Some(config.jwt_issuer);
match jwt_key.sign(claims) {
Ok(token) => HTTPResponse::as_200(token),
// TODO: set the error in the message body
Ok(token) => HTTPResponse::send_token(&token),
Err(e) => {
eprintln!("error occurred while signing the token err={}", e);
return HTTPResponse::as_500();
let message: Option<json::JsonValue> = HTTPMessage::error(
format!("unable to sign the token, err={}", e).as_str(),
);
return HTTPResponse::as_500(message);
}
}
}
@ -67,7 +69,7 @@ fn handle_validate(request: HTTPRequest, _config: Config) -> FuturePinned<HTTPRe
match &request.body {
Some(ref _b) => {
// TODO: impl the JWT validation
HTTPResponse::as_200("header.payload.signature".to_string())
HTTPResponse::send_token("header.payload.signature")
}
None => HTTPResponse::as_400(),
}

View File

@ -46,10 +46,13 @@ async fn main() {
}
};
let router_config: Config = if let Ok(c) = Config::try_from(config) {
c
} else {
std::process::exit(1);
let router_config: Config = {
match Config::try_from(config) {
Ok(c) => c,
Err(_e) => {
std::process::exit(1);
}
}
};
loop {