From b49395adc47afa3334fa3292964c7ddec46cf5ec Mon Sep 17 00:00:00 2001 From: Jose Quintana <1700322+joseluisq@users.noreply.github.com> Date: Wed, 25 May 2022 00:14:51 +0200 Subject: [PATCH] Merge pull request #112 from joseluisq/feature/remote_address_logging feat: log request file with its remote address if available via new `--log-remote-address` boolean option --- docs/content/configuration/config-file.md | 10 ++++++++++ src/handler.rs | 18 +++++++++++++++++- src/server.rs | 5 +++++ src/service.rs | 17 ++++++++++------- src/settings/cli.rs | 9 +++++++++ src/settings/file.rs | 2 ++ src/settings/mod.rs | 5 +++++ tests/toml/config.toml | 15 ++++++++++++++- 8 files changed, 72 insertions(+), 9 deletions(-) diff --git a/docs/content/configuration/config-file.md b/docs/content/configuration/config-file.md index 8346e08..9d827e7 100644 --- a/docs/content/configuration/config-file.md +++ b/docs/content/configuration/config-file.md @@ -60,6 +60,16 @@ grace-period = 0 #### Page fallback for 404s # page-fallback = "some_page.html" +#### Log request Remote Address if available +log-remote-address = false + + +### Windows Only + +#### Run the web server as a Windows Service +# windows-service = false + + [advanced] diff --git a/src/handler.rs b/src/handler.rs index a9ab4f7..dbb7905 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -1,5 +1,5 @@ use hyper::{header::WWW_AUTHENTICATE, Body, Method, Request, Response, StatusCode}; -use std::{future::Future, path::PathBuf, sync::Arc}; +use std::{future::Future, net::SocketAddr, path::PathBuf, sync::Arc}; use crate::{ basic_auth, compression, control_headers, cors, custom_headers, error_page, fallback_page, @@ -20,6 +20,7 @@ pub struct RequestHandlerOpts { pub page50x: Vec, pub page_fallback: Vec, pub basic_auth: String, + pub log_remote_address: bool, // Advanced options pub advanced_opts: Option, @@ -35,6 +36,7 @@ impl RequestHandler { pub fn handle<'a>( &'a self, req: &'a mut Request, + remote_addr: Option, ) -> impl Future, Error>> + Send + 'a { let method = req.method(); let headers = req.headers(); @@ -45,9 +47,23 @@ impl RequestHandler { let uri_query = uri.query(); let dir_listing = self.opts.dir_listing; let dir_listing_order = self.opts.dir_listing_order; + let log_remote_addr = self.opts.log_remote_address; let mut cors_headers: Option = None; + // Log request information with its remote address if available + let mut remote_addr_str = String::new(); + if log_remote_addr { + remote_addr_str.push_str(" remote_addr="); + remote_addr_str.push_str(&remote_addr.map_or("".to_owned(), |v| v.to_string())); + } + tracing::info!( + "incoming request: method={} uri={}{}", + method, + uri, + remote_addr_str, + ); + async move { // Check for disallowed HTTP methods and reject request accordently if !(method == Method::GET || method == Method::HEAD || method == Method::OPTIONS) { diff --git a/src/server.rs b/src/server.rs index 77f469b..4b4d650 100644 --- a/src/server.rs +++ b/src/server.rs @@ -162,6 +162,10 @@ impl Server { !general.basic_auth.is_empty() ); + // Log remote address option + let log_remote_address = general.log_remote_address; + tracing::info!("log remote address: enabled={}", log_remote_address); + // Grace period option let grace_period = general.grace_period; tracing::info!("grace period before graceful shutdown: {}s", grace_period); @@ -180,6 +184,7 @@ impl Server { page50x, page_fallback, basic_auth, + log_remote_address, advanced_opts, }), }); diff --git a/src/service.rs b/src/service.rs index 7f5aa8b..315fd16 100644 --- a/src/service.rs +++ b/src/service.rs @@ -1,12 +1,12 @@ use hyper::{service::Service, Body, Request, Response}; use std::convert::Infallible; use std::future::{ready, Future, Ready}; +use std::net::SocketAddr; use std::pin::Pin; use std::sync::Arc; use std::task::{Context, Poll}; -use crate::handler::RequestHandler; -use crate::Error; +use crate::{handler::RequestHandler, transport::Transport, Error}; /// It defines the router service which is the main entry point for Hyper Server. pub struct RouterService { @@ -21,7 +21,7 @@ impl RouterService { } } -impl Service for RouterService { +impl Service<&T> for RouterService { type Response = RequestService; type Error = Infallible; type Future = Ready>; @@ -30,14 +30,15 @@ impl Service for RouterService { Poll::Ready(Ok(())) } - fn call(&mut self, _: T) -> Self::Future { - ready(Ok(self.builder.build())) + fn call(&mut self, conn: &T) -> Self::Future { + ready(Ok(self.builder.build(conn.remote_addr()))) } } /// It defines a Hyper service request which delegates a request handler. pub struct RequestService { handler: Arc, + remote_addr: Option, } impl Service> for RequestService { @@ -51,7 +52,8 @@ impl Service> for RequestService { fn call(&mut self, mut req: Request) -> Self::Future { let handler = self.handler.clone(); - Box::pin(async move { handler.handle(&mut req).await }) + let remote_addr = self.remote_addr; + Box::pin(async move { handler.handle(&mut req, remote_addr).await }) } } @@ -67,9 +69,10 @@ impl RequestServiceBuilder { } } - pub fn build(&self) -> RequestService { + pub fn build(&self, remote_addr: Option) -> RequestService { RequestService { handler: self.handler.clone(), + remote_addr, } } } diff --git a/src/settings/cli.rs b/src/settings/cli.rs index 9f2a033..f062165 100644 --- a/src/settings/cli.rs +++ b/src/settings/cli.rs @@ -170,6 +170,15 @@ pub struct General { /// Server TOML configuration file path. pub config_file: Option, + #[structopt( + long, + parse(try_from_str), + default_value = "false", + env = "SERVER_LOG_REMOTE_ADDRESS" + )] + /// Log incoming requests information along with its remote address if available using the `info` log level. + pub log_remote_address: bool, + // // Windows specific arguments and commands // diff --git a/src/settings/file.rs b/src/settings/file.rs index d0b565c..22be141 100644 --- a/src/settings/file.rs +++ b/src/settings/file.rs @@ -96,6 +96,8 @@ pub struct General { pub grace_period: Option, pub page_fallback: Option, + + pub log_remote_address: Option, } /// Full server configuration diff --git a/src/settings/mod.rs b/src/settings/mod.rs index dcb3707..4b793de 100644 --- a/src/settings/mod.rs +++ b/src/settings/mod.rs @@ -61,6 +61,7 @@ impl Settings { let mut threads_multiplier = opts.threads_multiplier; let mut grace_period = opts.grace_period; let mut page_fallback = opts.page_fallback; + let mut log_remote_address = opts.log_remote_address; // Define the advanced file options let mut settings_advanced: Option = None; @@ -145,6 +146,9 @@ impl Settings { if let Some(v) = general.page_fallback { page_fallback = Some(v) } + if let Some(v) = general.log_remote_address { + log_remote_address = v + } } // Prepare the "advanced" options @@ -206,6 +210,7 @@ impl Settings { threads_multiplier, grace_period, page_fallback, + log_remote_address, // NOTE: // Windows-only options and commands diff --git a/tests/toml/config.toml b/tests/toml/config.toml index 51de796..47ff090 100644 --- a/tests/toml/config.toml +++ b/tests/toml/config.toml @@ -45,6 +45,19 @@ grace-period = 0 #### Page fallback for 404s page-fallback = "" +#### Page fallback for 404s +page-fallback = "" + +#### Log request Remote Address if available +log-remote-address = false + + +### Windows Only + +#### Run the web server as a Windows Service +# windows-service = false + + [advanced] #### HTTP Headers customization @@ -56,7 +69,7 @@ headers = { Access-Control-Allow-Origin = "*", X-XSS-PROTECTION = "1; mode=block # #### b. Multiline version [[advanced.headers]] -source = "index.html" +source = "/index.html" [advanced.headers.headers] Cache-Control = "public, max-age=36000" Content-Security-Policy = "frame-ancestors 'self'" -- libgit2 1.7.2