improv: add a logger (#18) + log client IP (#19)

This commit is contained in:
2022-11-07 10:28:58 +00:00
parent 74e8d58b5c
commit 45c9112af2
5 changed files with 163 additions and 28 deletions
+13 -9
View File
@@ -143,10 +143,7 @@ impl TryFrom<String> for HTTPBody {
let body = body.replace(NULL_CHAR, "");
match json::parse(&body) {
Ok(v) => Ok(HTTPBody::new(v)),
Err(e) => Err(format!(
"error occurred during request body parsing err={}",
e
)),
Err(e) => Err(format!("during request body parsing details={}", e)),
}
}
}
@@ -156,6 +153,8 @@ impl TryFrom<String> for HTTPBody {
pub struct HTTPRequest {
pub start_line: HTTPStartLine,
pub body: Option<HTTPBody>,
// includes the client IP + port (should be in the headers)
pub addr: String,
}
impl HTTPRequest {
@@ -190,19 +189,19 @@ impl HTTPRequest {
let start_line = HTTPStartLine::parse(&rp.0);
match start_line {
Ok(v) => request.start_line = v,
Err(e) => eprintln!("error occurred while parsing start_line err={}", e),
Err(e) => log::error!("while parsing start_line details={}", e),
}
let body = HTTPBody::try_from(rp.2);
match body {
Ok(v) => request.body = Some(v),
Err(e) => eprintln!("error occurred during body parsing err={}", e),
Err(e) => log::error!("{}", e),
}
return Ok(request);
}
Err(e) => {
return Err(format!("error occurred getting request parts err={}", e));
return Err(e);
}
}
}
@@ -222,6 +221,10 @@ impl HTTPRequest {
pub fn is_valid(&self) -> bool {
return self.start_line.is_valid();
}
pub fn set_addr(&mut self, addr: String) {
self.addr = addr;
}
}
impl Default for HTTPRequest {
@@ -229,6 +232,7 @@ impl Default for HTTPRequest {
HTTPRequest {
start_line: HTTPStartLine::default(),
body: None,
addr: "".to_string(),
}
}
}
@@ -237,8 +241,8 @@ impl From<&str> for HTTPRequest {
fn from(request: &str) -> Self {
match Self::parse(request) {
Ok(v) => v,
Err(v) => {
eprintln!("{}", format!("[ERR]: {v}"));
Err(e) => {
log::error!("{}", e);
return HTTPRequest::default();
}
}
+4 -2
View File
@@ -90,8 +90,10 @@ async fn handle_validate(request: HTTPRequest, config: Config) -> HTTPResponse {
pub struct Router;
impl Router {
pub async fn route(&self, request_str: &str, config: Config) -> HTTPResponse {
let request = HTTPRequest::from(request_str);
pub async fn route(&self, request_str: &str, addr: String, config: Config) -> HTTPResponse {
let mut request = HTTPRequest::from(request_str);
request.set_addr(addr);
let target = request.start_line.get_target();
match target.as_str() {
+16 -10
View File
@@ -24,13 +24,14 @@ struct Cli {
#[tokio::main]
async fn main() {
simple_logger::init_with_level(log::Level::Info).unwrap();
let args = Cli::parse();
let mut config = Ini::new();
match config.load(args.config) {
Ok(c) => c,
Err(e) => {
eprintln!("error while loading the config file, err={}", e);
log::error!("error while loading the config file details={}", e);
std::process::exit(1);
}
};
@@ -39,11 +40,11 @@ async fn main() {
let listener = {
match TcpListener::bind(&server_url).await {
Ok(t) => {
println!("server is listening on '{}'", server_url);
log::info!("server is listening on '{}'", server_url);
t
}
Err(e) => {
eprintln!("error occurred while initializing tcp listener err={}", e);
log::error!("while initializing tcp listener details={}", e);
std::process::exit(1);
}
}
@@ -52,28 +53,31 @@ async fn main() {
let router_config: Config = {
match Config::try_from(config) {
Ok(c) => c,
Err(_e) => {
Err(e) => {
log::error!("unable to load the configuration details={}", e);
std::process::exit(1);
}
}
};
loop {
let (stream, _) = listener.accept().await.unwrap();
let (stream, addr) = listener.accept().await.unwrap();
let conf = router_config.clone();
tokio::spawn(handle_connection(stream, conf.clone()));
tokio::spawn(handle_connection(stream, addr.to_string(), conf.clone()));
}
}
/// parses the incoming request (partial spec implementation) and build an HTTP response
async fn handle_connection(mut stream: TcpStream, config: Config) {
async fn handle_connection(mut stream: TcpStream, addr: String, config: Config) {
log::info!("client connected: {}", addr);
let mut message = vec![];
let mut buffer: [u8; 1024] = [0; 1024];
let duration = Duration::from_micros(500);
let duration = Duration::from_millis(5);
// loop until the message is read
// the stream can be fragmented so, using a timeout (500um should be enough) for the future for completion
// the stream can be fragmented so, using a timeout (5ms should be far enough) for the future for completion
// after the timeout, the message is "considered" as entirely read
loop {
match timeout(duration, stream.read(&mut buffer)).await {
@@ -86,9 +90,11 @@ async fn handle_connection(mut stream: TcpStream, config: Config) {
}
let request_string = std::str::from_utf8(&message).unwrap();
let response = ROUTER.route(request_string, config).await;
let response = ROUTER.route(request_string, addr.clone(), config).await;
let response_str: String = response.into();
stream.write(response_str.as_bytes()).await.unwrap();
stream.flush().await.unwrap();
log::info!("connection closed: {}", addr);
}