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
Diff
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(-)
@@ -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]
@@ -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<u8>,
pub page_fallback: Vec<u8>,
pub basic_auth: String,
pub log_remote_address: bool,
pub advanced_opts: Option<Advanced>,
@@ -35,6 +36,7 @@ impl RequestHandler {
pub fn handle<'a>(
&'a self,
req: &'a mut Request<Body>,
remote_addr: Option<SocketAddr>,
) -> impl Future<Output = Result<Response<Body>, 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<http::HeaderMap> = None;
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 {
if !(method == Method::GET || method == Method::HEAD || method == Method::OPTIONS) {
@@ -162,6 +162,10 @@ impl Server {
!general.basic_auth.is_empty()
);
let log_remote_address = general.log_remote_address;
tracing::info!("log remote address: enabled={}", log_remote_address);
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,
}),
});
@@ -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};
pub struct RouterService {
@@ -21,7 +21,7 @@ impl RouterService {
}
}
impl<T> Service<T> for RouterService {
impl<T: Transport + Send + 'static> Service<&T> for RouterService {
type Response = RequestService;
type Error = Infallible;
type Future = Ready<Result<Self::Response, Self::Error>>;
@@ -30,14 +30,15 @@ impl<T> Service<T> 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())))
}
}
pub struct RequestService {
handler: Arc<RequestHandler>,
remote_addr: Option<SocketAddr>,
}
impl Service<Request<Body>> for RequestService {
@@ -51,7 +52,8 @@ impl Service<Request<Body>> for RequestService {
fn call(&mut self, mut req: Request<Body>) -> 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<SocketAddr>) -> RequestService {
RequestService {
handler: self.handler.clone(),
remote_addr,
}
}
}
@@ -170,6 +170,15 @@ pub struct General {
pub config_file: Option<PathBuf>,
#[structopt(
long,
parse(try_from_str),
default_value = "false",
env = "SERVER_LOG_REMOTE_ADDRESS"
)]
pub log_remote_address: bool,
@@ -96,6 +96,8 @@ pub struct General {
pub grace_period: Option<u8>,
pub page_fallback: Option<PathBuf>,
pub log_remote_address: Option<bool>,
}
@@ -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;
let mut settings_advanced: Option<Advanced> = 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
}
}
@@ -206,6 +210,7 @@ impl Settings {
threads_multiplier,
grace_period,
page_fallback,
log_remote_address,
@@ -45,6 +45,19 @@ grace-period = 0
page-fallback = ""
page-fallback = ""
log-remote-address = false
[advanced]
@@ -56,7 +69,7 @@ headers = { Access-Control-Allow-Origin = "*", X-XSS-PROTECTION = "1; mode=block
[[advanced.headers]]
source = "index.html"
source = "/index.html"
[advanced.headers.headers]
Cache-Control = "public, max-age=36000"
Content-Security-Policy = "frame-ancestors 'self'"