use crate::authenticators::Authenticate;
use crate::back::dispatcher::Dispatcher;
use crate::front::listener::Connection;
use derivative::Derivative;
use log::{info, trace};
use parsec_interface::requests::AuthType;
use parsec_interface::requests::ResponseStatus;
use parsec_interface::requests::{Request, Response};
use std::collections::HashMap;
use std::io::{Error, ErrorKind, Result};
#[derive(Derivative)]
#[derivative(Debug)]
pub struct FrontEndHandler {
dispatcher: Dispatcher,
#[derivative(Debug = "ignore")]
authenticators: HashMap<AuthType, Box<dyn Authenticate + Send + Sync>>,
body_len_limit: usize,
}
impl FrontEndHandler {
pub fn handle_request(&self, mut connection: Connection) {
trace!("handle_request ingress");
let request = match Request::read_from_stream(&mut connection.stream, self.body_len_limit) {
Ok(request) => request,
Err(status) => {
format_error!("Failed to read request", status);
let response = Response::from_status(status);
if response.header.status != ResponseStatus::Success {
format_error!("Sending back an error", response.header.status);
}
if let Err(status) = response.write_to_stream(&mut connection.stream) {
format_error!("Failed to write response", status);
}
return;
}
};
let (app, err_response) = if AuthType::NoAuth == request.header.auth_type {
(None, None)
} else if let Some(authenticator) = self.authenticators.get(&request.header.auth_type) {
match authenticator.authenticate(&request.auth, connection.metadata) {
Ok(app) => (Some(app), None),
Err(status) => (
None,
Some(Response::from_request_header(request.header, status)),
),
}
} else {
(
None,
Some(Response::from_request_header(
request.header,
ResponseStatus::AuthenticatorNotRegistered,
)),
)
};
let response = if let Some(err_response) = err_response {
err_response
} else {
if crate::utils::GlobalConfig::log_error_details() {
if let Some(app) = &app.as_ref() {
info!(
"New request received from application name \"{}\"",
app.identity().name()
)
} else {
info!("New request received without authentication")
}
};
let response = self.dispatcher.dispatch_request(request, app.clone());
trace!("dispatch_request egress");
response
};
match response.write_to_stream(&mut connection.stream) {
Ok(_) => {
if crate::utils::GlobalConfig::log_error_details() {
if let Some(app) = app {
info!(
"Response for application name \"{}\" sent back",
app.identity().name()
);
} else {
info!("Response sent back from request without authentication");
}
}
}
Err(err) => format_error!("Failed to send response", err),
}
}
}
#[derive(Default, Derivative)]
#[derivative(Debug)]
pub struct FrontEndHandlerBuilder {
dispatcher: Option<Dispatcher>,
#[derivative(Debug = "ignore")]
authenticators: Option<HashMap<AuthType, Box<dyn Authenticate + Send + Sync>>>,
body_len_limit: Option<usize>,
}
impl FrontEndHandlerBuilder {
pub fn new() -> Self {
FrontEndHandlerBuilder {
dispatcher: None,
authenticators: None,
body_len_limit: None,
}
}
pub fn with_dispatcher(mut self, dispatcher: Dispatcher) -> Self {
self.dispatcher = Some(dispatcher);
self
}
pub fn with_authenticator(
mut self,
auth_type: AuthType,
authenticator: Box<dyn Authenticate + Send + Sync>,
) -> Self {
match &mut self.authenticators {
Some(authenticators) => {
let _ = authenticators.insert(auth_type, authenticator);
}
None => {
let mut map = HashMap::new();
let _ = map.insert(auth_type, authenticator);
self.authenticators = Some(map);
}
};
self
}
pub fn with_body_len_limit(mut self, body_len_limit: usize) -> Self {
self.body_len_limit = Some(body_len_limit);
self
}
pub fn build(self) -> Result<FrontEndHandler> {
Ok(FrontEndHandler {
dispatcher: self
.dispatcher
.ok_or_else(|| Error::new(ErrorKind::InvalidData, "dispatcher is missing"))?,
authenticators: self
.authenticators
.ok_or_else(|| Error::new(ErrorKind::InvalidData, "authenticators is missing"))?,
body_len_limit: self
.body_len_limit
.ok_or_else(|| Error::new(ErrorKind::InvalidData, "body_len_limit is missing"))?,
})
}
}