Repository: static-web-server/static-web-server (language: rust)

Issue:
Publish to crates.io to allow use as a library
Hello @joseluisq

In one of our projects we would like to use this project as a library and programmatically call the [`fn run_server_on_rt`](https://github.com/static-web-server/static-web-server/blob/master/src/server.rs#L64) function from our own rust-wrapper.

However, we could not find this project published on [crates.io](https://crates.io/).

Maybe @Absolucy , who controls the "[sws](https://crates.io/crates/sws)" name, or @NoahJelen who controls the "[simple-web-server](https://crates.io/crates/simple-web-server)" name could offer to transfer the ownership to you for this project.

This would make lots of sense for our particular use-case, so we would prefer not to use a script: https://github.com/torrust/torrust-index-frontend/pull/68

Kind Regards,
Cameron.


Discussion / hints:
In fact, I was thinking about this idea a couple of times in the past.
I'm aware that it can help people like you and others embed SWS with ease and even opt-in/out features on demand to do their own stuff.

So, why not.
However, I probably will need some help regarding how to make SWS modules library-wise like what API parts expose, better structure, refactorings, docs, setup, etc. Which definitely will take time.

Regarding the name, I think will be not a big deal, we could even go with something like `libsws`.

So, If you would like to help, more than welcome!
Just to clarify #189 is one of the steps forward to make `libsws` happen.

FYI, I will take care of preparing the API for the library, doing the refactorings needed as well as adding proper documentation for the API exposed.

Fix patch:
diff --git a/.github/workflows/release.crate.yml b/.github/workflows/release.crate.yml
index 1781b10f..6010d916 100644
--- a/.github/workflows/release.crate.yml
+++ b/.github/workflows/release.crate.yml
@@ -9,7 +9,7 @@ on:
 jobs:
   check-secret:
     runs-on: ubuntu-latest
-    environment: crates-io-libsws
+    environment: crates-io-static-web-server
     outputs:
       publish: ${{ steps.check.outputs.publish }}
     steps:
@@ -205,7 +205,7 @@ jobs:
     needs: test
     if: needs.check-secret.outputs.publish == 'true'
     runs-on: ubuntu-latest
-    environment: crates-io-libsws
+    environment: crates-io-static-web-server
     steps:
       - name: Checkout
         uses: actions/checkout@v3
@@ -217,6 +217,6 @@ jobs:
 
       - name: Publish workspace packages
         run: |
-          cargo publish -p libsws
+          cargo publish -p static-web-server
         env:
           CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_TOKEN }}
diff --git a/Cargo.toml b/Cargo.toml
index 8a9d33d8..da76d607 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,26 +6,44 @@ license = "MIT OR Apache-2.0"
 description = "A cross-platform, high-performance and asynchronous web server for static files-serving."
 repository = "https://github.com/static-web-server/static-web-server"
 readme = "README.md"
+homepage = "https://static-web-server.net"
 keywords = [
     "static-web-server",
     "file-server",
     "http-server",
-    "docker-image",
     "musl-libc",
     "x86",
     "x86-64",
+    "arm",
     "arm64",
     "linux",
     "darwin",
+    "freebsd",
     "windows",
 ]
 categories = ["network-programming", "web-programming::http-server"]
 edition = "2021"
-include = ["src/**/*", "Cargo.toml", "Cargo.lock"]
+include = [
+    "src/**/*.rs",
+    "Cargo.toml",
+    "README.md",
+    "LICENSE-MIT",
+    "LICENSE-APACHE"
+]
+autotests = true
+autoexamples = true
+
+[package.metadata.docs.rs]
+all-features = true
+
+[lib]
+name = "static_web_server"
+path = "src/lib.rs"
 
 [[bin]]
 name = "static-web-server"
 path = "src/bin/server.rs"
+doc = false
 
 [features]
 default = ["http2"]
diff --git a/Makefile b/Makefile
index 574b7da9..ccfa8d85 100644
--- a/Makefile
+++ b/Makefile
@@ -247,6 +247,17 @@ docs-dev:
 	@docker-compose -f docs/docker-compose.yml up --build
 .PHONY: docs-dev
 
+crate-docs:
+	@cargo doc --no-deps
+.PHONY: crate-docs
+
+crate-docs-dev:
+	@cargo doc --no-deps
+	@echo "Crate documentation: http://localhost:8787/static_web_server"
+	@static-web-server -p 8787 -d target/doc/ \
+		& watchman-make -p 'src/**/*.rs' --run 'cargo doc'
+.PHONY: crate-docs-dev
+
 docs-deploy:
 	@git stash
 	@rm -rf /tmp/docs
diff --git a/src/basic_auth.rs b/src/basic_auth.rs
index 34c13b6c..9daada86 100644
--- a/src/basic_auth.rs
+++ b/src/basic_auth.rs
@@ -1,3 +1,6 @@
+//! Basic HTTP Authorization Schema module.
+//!
+
 use bcrypt::verify as bcrypt_verify;
 use headers::{authorization::Basic, Authorization, HeaderMapExt};
 use hyper::StatusCode;
diff --git a/src/compression.rs b/src/compression.rs
index 349f567c..a39b1c18 100644
--- a/src/compression.rs
+++ b/src/compression.rs
@@ -1,5 +1,7 @@
-// Compression handler that compress the body of a response.
-// -> Part of the file is borrowed from https://github.com/seanmonstar/warp/pull/513
+//! Auto-compression module to compress responses body.
+//!
+
+// Part of the file is borrowed from <https://github.com/seanmonstar/warp/pull/513>*
 
 use async_compression::tokio::bufread::{BrotliEncoder, DeflateEncoder, GzipEncoder};
 use bytes::Bytes;
@@ -158,8 +160,8 @@ pub fn create_encoding_header(existing: Option<HeaderValue>, coding: ContentCodi
     coding.into()
 }
 
-/// A wrapper around any type that implements [`Stream`](futures::Stream) to be
-/// compatible with async_compression's Stream based encoders.
+/// A wrapper around any type that implements [`Stream`](futures_util::Stream) to be
+/// compatible with async_compression's `Stream` based encoders.
 #[pin_project]
 #[derive(Debug)]
 pub struct CompressableBody<S, E>
diff --git a/src/compression_static.rs b/src/compression_static.rs
index e4dfb8db..85578b2c 100644
--- a/src/compression_static.rs
+++ b/src/compression_static.rs
@@ -1,3 +1,6 @@
+//! Compression static module to serve compressed files directly from the file system.
+//!
+
 use headers::{ContentCoding, HeaderMap, HeaderValue};
 use std::{
     ffi::OsStr,
@@ -9,8 +12,11 @@ use crate::{compression, static_files::file_metadata};
 
 /// It defines the pre-compressed file variant metadata of a particular file path.
 pub struct CompressedFileVariant<'a> {
+    /// Current file path.
     pub file_path: PathBuf,
+    /// The metadata of the current file.
     pub metadata: Metadata,
+    /// The file extension.
     pub extension: &'a str,
 }
 
diff --git a/src/control_headers.rs b/src/control_headers.rs
index 9b1adefd..aadf5068 100644
--- a/src/control_headers.rs
+++ b/src/control_headers.rs
@@ -1,4 +1,6 @@
-// An arbitrary `Cache-Control` headers functionality for incoming requests based on a set of file types.
+//! It provides an arbitrary `Cache-Control` headers functionality
+//! for incoming requests based on a set of file types.
+//!
 
 use headers::{CacheControl, HeaderMapExt};
 use hyper::{Body, Response};
diff --git a/src/cors.rs b/src/cors.rs
index c326e3fd..77d2ab0e 100644
--- a/src/cors.rs
+++ b/src/cors.rs
@@ -1,5 +1,7 @@
-// CORS handler for incoming requests.
-// -> Part of the file is borrowed from https://github.com/seanmonstar/warp/blob/master/src/filters/cors.rs
+//! CORS module to handle incoming requests.
+//!
+
+// Part of the file is borrowed from https://github.com/seanmonstar/warp/blob/master/src/filters/cors.rs
 
 use headers::{
     AccessControlAllowHeaders, AccessControlAllowMethods, AccessControlExposeHeaders, HeaderMapExt,
@@ -139,13 +141,6 @@ impl Cors {
         self
     }
 
-    /// Sets the `Access-Control-Max-Age` header.
-    /// TODO: we could enable this in the future.
-    pub fn max_age(mut self, seconds: impl Seconds) -> Self {
-        self.max_age = Some(seconds.seconds());
-        self
-    }
-
     /// Adds multiple headers to the list of allowed request headers.
     ///
     /// **Note**: These should match the values the browser sends via `Access-Control-Request-Headers`, e.g.`content-type`.
@@ -211,6 +206,7 @@ impl Default for Cors {
 }
 
 #[derive(Clone, Debug)]
+/// CORS is configurated.
 pub struct Configured {
     cors: Cors,
     allowed_headers: AccessControlAllowHeaders,
@@ -219,16 +215,24 @@ pub struct Configured {
 }
 
 #[derive(Debug)]
+/// Validated CORS request.
 pub enum Validated {
+    /// Validated as preflight.
     Preflight(HeaderValue),
+    /// Validated as simple.
     Simple(HeaderValue),
+    /// Validated as not cors.
     NotCors,
 }
 
 #[derive(Debug)]
+/// Forbidden errors.
 pub enum Forbidden {
+    /// Forbidden error origin.
     Origin,
+    /// Forbidden error method.
     Method,
+    /// Forbidden error header.
     Header,
 }
 
@@ -239,6 +243,7 @@ impl Default for Forbidden {
 }
 
 impl Configured {
+    /// Check for the incoming CORS request.
     pub fn check_request(
         &self,
         method: &http::Method,
@@ -299,19 +304,19 @@ impl Configured {
         }
     }
 
-    pub fn is_method_allowed(&self, header: &HeaderValue) -> bool {
+    fn is_method_allowed(&self, header: &HeaderValue) -> bool {
         http::Method::from_bytes(header.as_bytes())
             .map(|method| self.cors.allowed_methods.contains(&method))
             .unwrap_or(false)
     }
 
-    pub fn is_header_allowed(&self, header: &str) -> bool {
+    fn is_header_allowed(&self, header: &str) -> bool {
         HeaderName::from_bytes(header.as_bytes())
             .map(|header| self.cors.allowed_headers.contains(&header))
             .unwrap_or(false)
     }
 
-    pub fn is_origin_allowed(&self, origin: &HeaderValue) -> bool {
+    fn is_origin_allowed(&self, origin: &HeaderValue) -> bool {
         if let Some(ref allowed) = self.cors.origins {
             allowed.contains(origin)
         } else {
@@ -330,23 +335,9 @@ impl Configured {
     }
 }
 
-pub trait Seconds {
-    fn seconds(self) -> u64;
-}
-
-impl Seconds for u32 {
-    fn seconds(self) -> u64 {
-        self.into()
-    }
-}
-
-impl Seconds for ::std::time::Duration {
-    fn seconds(self) -> u64 {
-        self.as_secs()
-    }
-}
-
+/// Cast values into the origin header.
 pub trait IntoOrigin {
+    /// Cast actual value into an origin header.
     fn into_origin(self) -> Origin;
 }
 
diff --git a/src/custom_headers.rs b/src/custom_headers.rs
index 1cb42097..e972a57e 100644
--- a/src/custom_headers.rs
+++ b/src/custom_headers.rs
@@ -1,3 +1,6 @@
+//! Module to append custom HTTP headers via TOML config file.
+//!
+
 use hyper::{Body, Response};
 
 use crate::settings::Headers;
diff --git a/src/directory_listing.rs b/src/directory_listing.rs
index dab33992..73886972 100644
--- a/src/directory_listing.rs
+++ b/src/directory_listing.rs
@@ -1,3 +1,8 @@
+//! It provides directory listig and auto-index support.
+//!
+
+#![allow(missing_docs)]
+
 use chrono::{DateTime, Local, NaiveDateTime, Utc};
 use futures_util::future::Either;
 use futures_util::{future, FutureExt};
diff --git a/src/error.rs b/src/error.rs
index 83512fa6..3902eb6b 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,3 +1,6 @@
+//! Useful error type re-exports based on [anyhow][mod@anyhow].
+//!
+
 /// Just a `anyhow::Result` type alias.
 pub type Result<T = (), E = anyhow::Error> = anyhow::Result<T, E>;
 
diff --git a/src/error_page.rs b/src/error_page.rs
index fd2f783c..6beb9475 100644
--- a/src/error_page.rs
+++ b/src/error_page.rs
@@ -1,3 +1,6 @@
+//! Error page module to compose an HTML page response.
+//!
+
 use headers::{AcceptRanges, ContentLength, ContentType, HeaderMapExt};
 use hyper::{Body, Method, Response, StatusCode, Uri};
 use mime_guess::mime;
diff --git a/src/exts/http.rs b/src/exts/http.rs
index 1322d530..9ea932b2 100644
--- a/src/exts/http.rs
+++ b/src/exts/http.rs
@@ -7,9 +7,13 @@ pub const HTTP_SUPPORTED_METHODS: &[Method; 3] = &[Method::OPTIONS, Method::HEAD
 
 /// SWS HTTP Method extensions trait.
 pub trait MethodExt {
+    /// If method is allowed.
     fn is_allowed(&self) -> bool;
+    /// If method is `GET`.
     fn is_get(&self) -> bool;
+    /// If method is `HEAD`.
     fn is_head(&self) -> bool;
+    /// If method is `OPTIONS`.
     fn is_options(&self) -> bool;
 }
 
diff --git a/src/exts/path.rs b/src/exts/path.rs
index 30628c9a..ce17e494 100644
--- a/src/exts/path.rs
+++ b/src/exts/path.rs
@@ -4,6 +4,7 @@ use std::path::{Component, Path};
 
 /// SWS Path extensions trait.
 pub trait PathExt {
+    /// If file path is hidden.
     fn is_hidden(&self) -> bool;
 }
 
diff --git a/src/fallback_page.rs b/src/fallback_page.rs
index 67c5ab68..9b1370eb 100644
--- a/src/fallback_page.rs
+++ b/src/fallback_page.rs
@@ -1,3 +1,6 @@
+//! Fallback page module useful for a custom page default.
+//!
+
 use headers::{AcceptRanges, ContentLength, ContentType, HeaderMapExt};
 use hyper::{Body, Response, StatusCode};
 use mime_guess::mime;
diff --git a/src/handler.rs b/src/handler.rs
index b7410b4f..bc8831d9 100644
--- a/src/handler.rs
+++ b/src/handler.rs
@@ -1,3 +1,6 @@
+//! Request handler module intended to manage incoming HTTP requests.
+//!
+
 use headers::HeaderValue;
 use hyper::{header::WWW_AUTHENTICATE, Body, Request, Response, StatusCode};
 use std::{future::Future, net::IpAddr, net::SocketAddr, path::PathBuf, sync::Arc};
@@ -16,29 +19,46 @@ use crate::{
 /// It defines options for a request handler.
 pub struct RequestHandlerOpts {
     // General options
+    /// Root directory of static files.
     pub root_dir: PathBuf,
+    /// Compression feature.
     pub compression: bool,
+    /// Compression static feature.
     pub compression_static: bool,
+    /// Directory listing feature.
     pub dir_listing: bool,
+    /// Directory listing order feature.
     pub dir_listing_order: u8,
+    /// Directory listing format feature.
     pub dir_listing_format: DirListFmt,
+    /// CORS feature.
     pub cors: Option<cors::Configured>,
+    /// Security headers feature.
     pub security_headers: bool,
+    /// Cache control headers feature.
     pub cache_control_headers: bool,
+    /// Page for 404 errors.
     pub page404: Vec<u8>,
+    /// Page for 50x errors.
     pub page50x: Vec<u8>,
+    /// Page fallback feature.
     pub page_fallback: Vec<u8>,
+    /// Basic auth feature.
     pub basic_auth: String,
+    /// Log remote address feature.
     pub log_remote_address: bool,
+    /// Redirect trailing slash feature.
     pub redirect_trailing_slash: bool,
+    /// Ignore hidden files feature.
     pub ignore_hidden_files: bool,
 
-    // Advanced options
+    /// Advanced options from the config file.
     pub advanced_opts: Option<Advanced>,
 }
 
 /// It defines the main request handler used by the Hyper service request.
 pub struct RequestHandler {
+    /// Request handler options.
     pub opts: Arc<RequestHandlerOpts>,
 }
 
diff --git a/src/helpers.rs b/src/helpers.rs
index 5862ba42..866e2007 100644
--- a/src/helpers.rs
+++ b/src/helpers.rs
@@ -15,21 +15,6 @@ where
     }
 }
 
-/// Get the directory name of a valid directory path.
-pub fn get_dirname<P: AsRef<Path>>(path: P) -> Result<String>
-where
-    PathBuf: From<P>,
-{
-    let path = get_valid_dirpath(path)?;
-    match path.iter().last() {
-        Some(v) => Ok(v.to_str().unwrap().to_owned()),
-        _ => bail!(
-            "directory name for path {} was not determined",
-            path.display()
-        ),
-    }
-}
-
 /// Read the entire contents of a file into a bytes vector.
 pub fn read_bytes(path: &Path) -> Result<Vec<u8>> {
     fs::read(path).with_context(|| format!("failed to read file `{}`", path.display()))
@@ -75,13 +60,13 @@ pub fn stringify(dst: &mut String, path: &serde_ignored::Path<'_>) {
 
 #[cfg(unix)]
 /// In Unix-like systems it just casts the `PathBuf` into an string.
-pub fn adjust_canonicalization(p: PathBuf) -> String {
+pub fn adjust_canonicalization(p: &Path) -> String {
     p.display().to_string()
 }
 
 #[cfg(windows)]
 /// In Windows systems it adjusts the `PathBuf` stripping its `\\?\` prefix.
-pub fn adjust_canonicalization(p: PathBuf) -> String {
+pub fn adjust_canonicalization(p: &Path) -> String {
     const VERBATIM_PREFIX: &str = r#"\\?\"#;
     let p = p.to_str().unwrap_or_default();
     let p = if p.starts_with(VERBATIM_PREFIX) {
diff --git a/src/lib.rs b/src/lib.rs
index f3954859..ba63e994 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,14 +1,81 @@
+//! # Static Web Server (SWS)
+//!
+//! SWS is a cross-platform, high-performance and asynchronous web server for static files-serving.
+//!
+//! **Considerations:**
+//!
+//! This crate was published to make it possible for users to embed SWS with ease instead of working around it via forks.
+//! For example, allowing users to turn off default features like `tls` and so on.
+//!
+//! **However**, because the library is highly coupled with the SWS binary project at this point,
+//! users might be limited by the exposed APIs, implementations, missing functionality, or dependencies.
+//!
+//! In the future, we will eventually plan to make SWS library independent from the binary project.
+//!
+//! That said, if fine-grained control and flexibility are needed then you could want to look at other alternatives like HTTP libraries or frameworks.
+//!
+//! **Pre-compile binaries:**
+//!
+//! This is the official SWS crate.
+//! If you are looking for platform pre-compile binaries then
+//! take a look at [static-web-server.net/download-and-install](https://static-web-server.net/download-and-install).
+//!
+//! ## Overview
+//!
+//! **Static Web Server** (or **`SWS`** abbreviated) is a very small and fast production-ready web server suitable to serve static web files or assets.
+//!
+//! It is focused on **lightness and easy-to-use** principles while keeping [high performance and safety](https://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html) powered by [The Rust Programming Language](https://rust-lang.org).
+//!
+//! Written on top of [Hyper](https://github.com/hyperium/hyper) and [Tokio](https://github.com/tokio-rs/tokio) runtime. It provides [concurrent and asynchronous networking abilities](https://rust-lang.github.io/async-book/01_getting_started/02_why_async.html) as well as the latest HTTP/1 - HTTP/2 implementations.
+//!
+//! It's cross-platform and available for `Linux`, `macOS`, `Windows` and `FreeBSD` (`x86`/`x86_64`,  `ARM`/`ARM64`) as well as `Docker`.
+//!
+//! ![static-web-server](https://user-images.githubusercontent.com/1700322/152613820-658f025c-d0a4-46b3-aa6d-bdc7f638ce77.png)
+//!
+//! ## Features
+//!
+//! - Built with [Rust](https://rust-lang.org) which is focused on [safety, speed and concurrency](https://kornel.ski/rust-c-speed).
+//! - Memory safe and very reduced CPU and RAM overhead.
+//! - Blazing fast static files-serving and asynchronous powered by latest [Hyper](https://github.com/hyperium/hyper/), [Tokio](https://github.com/tokio-rs/tokio) and a set of [awesome crates](https://github.com/static-web-server/static-web-server/blob/master/Cargo.toml).
+//! - Single __4MB__ (uncompressed) and fully static binary with no dependencies ([Musl libc](https://doc.rust-lang.org/edition-guide/rust-2018/platform-and-target-support/musl-support-for-fully-static-binaries.html)). Suitable for running on [any Linux distro](https://en.wikipedia.org/wiki/Linux_distribution) or [Docker container](https://hub.docker.com/r/joseluisq/static-web-server/tags).
+//! - Optional GZip, Deflate or Brotli compression for text-based web files only.
+//! - Compression on-demand via [Accept-Encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding) header.
+//! - [Partial Content Delivery](https://en.wikipedia.org/wiki/Byte_serving) support for byte-serving of large files.
+//! - Optional [Cache-Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) headers for assets.
+//! - [Termination signal](https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html) handling with [graceful shutdown](https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-terminating-with-grace) ability and grace period.
+//! - [HTTP/2](https://tools.ietf.org/html/rfc7540) and TLS support.
+//! - [Security headers](https://web.dev/security-headers/) for HTTP/2 by default.
+//! - [HEAD](https://tools.ietf.org/html/rfc7231#section-4.3.2) responses.
+//! - Lightweight and configurable logging via [tracing](https://github.com/tokio-rs/tracing) crate.
+//! - Customizable number of worker threads.
+//! - Optional directory listing.
+//! - [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) support.
+//! - Basic HTTP Authentication.
+//! - Customizable HTTP response headers for specific file requests via glob patterns.
+//! - Fallback pages for 404 errors, useful for Single-page applications.
+//! - Run the server as a [Windows Service](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc783643(v=ws.10)).
+//! - Configurable using CLI arguments, environment variables or a TOML file.
+//! - Default and custom error pages.
+//! - Custom URL rewrites and redirects via glob patterns.
+//! - Support for serving pre-compressed (Gzip/Brotli) files.
+//! - First-class [Docker](https://docs.docker.com/get-started/overview/) support. [Scratch](https://hub.docker.com/_/scratch) and latest [Alpine Linux](https://hub.docker.com/_/alpine) Docker images.
+//! - Ability to accept a socket listener as a file descriptor for use in sandboxing and on-demand applications (E.g [systemd](http://0pointer.de/blog/projects/socket-activation.html)).
+//! - Cross-platform. Pre-compiled binaries for Linux, macOS, Windows and FreeBSD (`x86`,`x86_64`,`ARM`,`ARM64`).
+//!
+
+#![deny(missing_docs)]
 #![forbid(unsafe_code)]
 #![deny(warnings)]
 #![deny(rust_2018_idioms)]
 #![deny(dead_code)]
 
+// Extern crates
 #[macro_use]
 extern crate anyhow;
-
 #[macro_use]
 extern crate serde;
 
+// Public modules
 pub mod basic_auth;
 pub mod compression;
 pub mod compression_static;
@@ -20,7 +87,6 @@ pub mod error_page;
 pub mod exts;
 pub mod fallback_page;
 pub mod handler;
-pub mod helpers;
 pub mod logger;
 pub mod redirects;
 pub mod rewrites;
@@ -34,13 +100,15 @@ pub mod static_files;
 #[cfg(feature = "tls")]
 pub mod tls;
 pub mod transport;
-
 #[cfg(windows)]
 pub mod winservice;
-
 #[macro_use]
 pub mod error;
 
+// Private modules
+mod helpers;
+
+// Re-exports
 pub use error::*;
 pub use server::Server;
 pub use settings::Settings;
diff --git a/src/logger.rs b/src/logger.rs
index ac666bf3..c27786bc 100644
--- a/src/logger.rs
+++ b/src/logger.rs
@@ -1,3 +1,6 @@
+//! Provides logging initialization for the web server.
+//!
+
 use tracing::Level;
 use tracing_subscriber::fmt::format::FmtSpan;
 
diff --git a/src/redirects.rs b/src/redirects.rs
index d51f5913..bf886169 100644
--- a/src/redirects.rs
+++ b/src/redirects.rs
@@ -1,3 +1,6 @@
+//! Redirection module to handle config redirect URLs with pattern matching support.
+//!
+
 use hyper::StatusCode;
 
 use crate::settings::Redirects;
diff --git a/src/rewrites.rs b/src/rewrites.rs
index b007b360..1b4a3207 100644
--- a/src/rewrites.rs
+++ b/src/rewrites.rs
@@ -1,3 +1,6 @@
+//! Module that allows to rewrite request URLs with pattern matching support.
+//!
+
 use crate::settings::Rewrites;
 
 /// It returns a rewrite's destination path if the current request uri
diff --git a/src/security_headers.rs b/src/security_headers.rs
index 73ff7bbc..eb35376c 100644
--- a/src/security_headers.rs
+++ b/src/security_headers.rs
@@ -1,3 +1,6 @@
+//! The module provides several HTTP security headers support.
+//!
+
 use http::header::{
     CONTENT_SECURITY_POLICY, STRICT_TRANSPORT_SECURITY, X_CONTENT_TYPE_OPTIONS, X_FRAME_OPTIONS,
     X_XSS_PROTECTION,
diff --git a/src/server.rs b/src/server.rs
index ef19deb0..79f71e87 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -1,3 +1,6 @@
+//! Server module intended to construct a multi-thread HTTP or HTTP/2 web server.
+//!
+
 #[allow(unused_imports)]
 use hyper::server::conn::AddrIncoming;
 #[allow(unused_imports)]
@@ -43,7 +46,8 @@ impl Server {
         })
     }
 
-    /// Build and run the multi-thread `Server` as standalone.
+    /// Run the multi-thread `Server` as standalone.
+    /// It is a top-level function of [run_server_on_rt](#method.run_server_on_rt).
     pub fn run_standalone(self) -> Result {
         // Logging system initialization
         logger::init(&self.opts.general.log_level)?;
@@ -51,7 +55,8 @@ impl Server {
         self.run_server_on_rt(None, || {})
     }
 
-    /// Build and run the multi-thread `Server` which will be used by a Windows service.
+    /// Run the multi-thread `Server` which will be used by a Windows service.
+    /// It is a top-level function of [run_server_on_rt](#method.run_server_on_rt).
     #[cfg(windows)]
     pub fn run_as_service<F>(self, cancel: Option<Receiver<()>>, cancel_fn: F) -> Result
     where
@@ -60,8 +65,8 @@ impl Server {
         self.run_server_on_rt(cancel, cancel_fn)
     }
 
-    /// Build and run the multi-thread `Server` on Tokio runtime.
-    fn run_server_on_rt<F>(self, cancel_recv: Option<Receiver<()>>, cancel_fn: F) -> Result
+    /// Build and run the multi-thread `Server` on the Tokio runtime.
+    pub fn run_server_on_rt<F>(self, cancel_recv: Option<Receiver<()>>, cancel_fn: F) -> Result
     where
         F: FnOnce(),
     {
@@ -100,7 +105,7 @@ impl Server {
 
         // Config file option
         if let Some(config_file) = general.config_file {
-            let config_file = helpers::adjust_canonicalization(config_file);
+            let config_file = helpers::adjust_canonicalization(&config_file);
             tracing::info!("config file: {}", config_file);
         }
 
diff --git a/src/service.rs b/src/service.rs
index 315fd161..9161c98e 100644
--- a/src/service.rs
+++ b/src/service.rs
@@ -1,3 +1,6 @@
+//! The module provides a custom [Hyper service](hyper::service::Service).
+//!
+
 use hyper::{service::Service, Body, Request, Response};
 use std::convert::Infallible;
 use std::future::{ready, Future, Ready};
@@ -14,6 +17,7 @@ pub struct RouterService {
 }
 
 impl RouterService {
+    /// Creates a new router service.
     pub fn new(handler: RequestHandler) -> Self {
         Self {
             builder: RequestServiceBuilder::new(handler),
@@ -63,12 +67,14 @@ pub struct RequestServiceBuilder {
 }
 
 impl RequestServiceBuilder {
+    /// Initializes a new request service buider.
     pub fn new(handler: RequestHandler) -> Self {
         Self {
             handler: Arc::new(handler),
         }
     }
 
+    /// Build a new request service.
     pub fn build(&self, remote_addr: Option<SocketAddr>) -> RequestService {
         RequestService {
             handler: self.handler.clone(),
diff --git a/src/settings/cli.rs b/src/settings/cli.rs
index 166c9c53..d21c52eb 100644
--- a/src/settings/cli.rs
+++ b/src/settings/cli.rs
@@ -281,11 +281,13 @@ pub struct General {
     // Windows commands
     #[cfg(windows)]
     #[structopt(subcommand)]
+    /// Subcommands to install or uninstall the SWS Windows Service.
     pub commands: Option<Commands>,
 }
 
 #[cfg(windows)]
 #[derive(Debug, StructOpt)]
+/// Subcommands to install or uninstall the SWS Windows Service.
 pub enum Commands {
     /// Install a Windows Service for the web server.
     #[structopt(name = "install")]
diff --git a/src/settings/file.rs b/src/settings/file.rs
index 6b8c4ccd..06685f2b 100644
--- a/src/settings/file.rs
+++ b/src/settings/file.rs
@@ -11,15 +11,22 @@ use crate::{helpers, Context, Result};
 
 #[derive(Debug, Serialize, Deserialize, Clone)]
 #[serde(rename_all = "kebab-case")]
+/// Log level variants.
 pub enum LogLevel {
+    /// Error log level.
     Error,
+    /// Warn log level.
     Warn,
+    /// Info log level.
     Info,
+    /// Debug log level.
     Debug,
+    /// Trace log level.
     Trace,
 }
 
 impl LogLevel {
+    /// Get log level name.
     pub fn name(&self) -> &'static str {
         match self {
             LogLevel::Error => "error",
@@ -33,14 +40,18 @@ impl LogLevel {
 
 #[derive(Debug, Serialize, Deserialize, Clone)]
 #[serde(rename_all = "kebab-case")]
+/// Represents an HTTP headers map.
 pub struct Headers {
+    /// Header source.
     pub source: String,
     #[serde(rename(deserialize = "headers"), with = "http_serde::header_map")]
+    /// headers list.
     pub headers: HeaderMap,
 }
 
 #[derive(Debug, Serialize_repr, Deserialize_repr, Clone)]
 #[repr(u16)]
+/// Represents redirects types.
 pub enum RedirectsKind {
     /// Moved Permanently
     Permanent = 301,
@@ -50,16 +61,23 @@ pub enum RedirectsKind {
 
 #[derive(Debug, Serialize, Deserialize, Clone)]
 #[serde(rename_all = "kebab-case")]
+/// Represents redirects types.
 pub struct Redirects {
+    /// Source of the redirect.
     pub source: String,
+    /// Redirect destination.
     pub destination: String,
+    /// Redirect type.
     pub kind: RedirectsKind,
 }
 
 #[derive(Debug, Serialize, Deserialize, Clone)]
 #[serde(rename_all = "kebab-case")]
+/// Represents rewrites types.
 pub struct Rewrites {
+    /// Source of the rewrite.
     pub source: String,
+    /// Rewrite destination.
     pub destination: String,
 }
 
@@ -67,11 +85,11 @@ pub struct Rewrites {
 #[derive(Debug, Serialize, Deserialize, Clone)]
 #[serde(rename_all = "kebab-case")]
 pub struct Advanced {
-    // Headers
+    /// Headers
     pub headers: Option<Vec<Headers>>,
-    // Rewrites
+    /// Rewrites
     pub rewrites: Option<Vec<Rewrites>>,
-    // Redirects
+    /// Redirects
     pub redirects: Option<Vec<Redirects>>,
 }
 
@@ -80,70 +98,86 @@ pub struct Advanced {
 #[derive(Debug, Serialize, Deserialize, Clone)]
 #[serde(rename_all = "kebab-case")]
 pub struct General {
-    // Address & Root dir
+    /// Server address.
     pub host: Option<String>,
+    /// Server port.
     pub port: Option<u16>,
+    /// Root directory path.
     pub root: Option<PathBuf>,
 
-    // Logging
+    /// Logging.
     pub log_level: Option<LogLevel>,
 
-    // Cache Control headers
+    /// Cache Control headers.
     pub cache_control_headers: Option<bool>,
 
-    // Compression
+    /// Compression.
     pub compression: Option<bool>,
 
-    // Check for a pre-compressed file on disk
+    /// Check for a pre-compressed file on disk.
     pub compression_static: Option<bool>,
 
-    // Error pages
+    /// Error 404 pages.
     pub page404: Option<PathBuf>,
+    /// Error 50x pages.
     pub page50x: Option<PathBuf>,
 
-    // HTTP/2 + TLS
+    /// HTTP/2 + TLS.
     #[cfg(feature = "http2")]
     pub http2: Option<bool>,
+    /// Http2 tls certificate feature.
     #[cfg(feature = "http2")]
     pub http2_tls_cert: Option<PathBuf>,
+    /// Http2 tls key feature.
     #[cfg(feature = "http2")]
     pub http2_tls_key: Option<PathBuf>,
 
-    // Security headers
+    /// Security headers.
     pub security_headers: Option<bool>,
 
-    // CORS
+    /// Cors allow origins feature.
     pub cors_allow_origins: Option<String>,
+    /// Cors allow headers feature.
     pub cors_allow_headers: Option<String>,
+    /// Cors expose headers feature.
     pub cors_expose_headers: Option<String>,
 
-    // Directory listing
+    /// Directory listing feature.
     pub directory_listing: Option<bool>,
+    /// Directory listing order feature.
     pub directory_listing_order: Option<u8>,
+    /// Directory listing format feature.
     pub directory_listing_format: Option<DirListFmt>,
 
-    // Basich Authentication
+    /// Basich Authentication feature.
     pub basic_auth: Option<String>,
 
-    // File descriptor binding
+    /// File descriptor binding feature.
     pub fd: Option<usize>,
 
-    // Worker threads
+    /// Worker threads.
     pub threads_multiplier: Option<usize>,
 
+    /// Max blocking threads feature.
     pub max_blocking_threads: Option<usize>,
 
+    /// Grace period feature.
     pub grace_period: Option<u8>,
 
+    /// Page fallback feature.
     pub page_fallback: Option<PathBuf>,
 
+    /// Log remote address feature.
     pub log_remote_address: Option<bool>,
 
+    /// Redirect trailing slash feature.
     pub redirect_trailing_slash: Option<bool>,
 
+    /// Ignore hidden files feature.
     pub ignore_hidden_files: Option<bool>,
 
     #[cfg(windows)]
+    /// windows service feature.
     pub windows_service: Option<bool>,
 }
 
@@ -151,7 +185,9 @@ pub struct General {
 #[derive(Debug, Serialize, Deserialize, Clone)]
 #[serde(rename_all = "kebab-case")]
 pub struct Settings {
+    /// General settings.
     pub general: Option<General>,
+    /// Advanced settings.
     pub advanced: Option<Advanced>,
 }
 
diff --git a/src/settings/mod.rs b/src/settings/mod.rs
index 8bd577f0..7aa3c05f 100644
--- a/src/settings/mod.rs
+++ b/src/settings/mod.rs
@@ -1,3 +1,6 @@
+//! Module that provides all settings of SWS.
+//!
+
 use globset::{Glob, GlobMatcher};
 use headers::HeaderMap;
 use hyper::StatusCode;
@@ -41,8 +44,11 @@ pub struct Redirects {
 
 /// The `advanced` file options.
 pub struct Advanced {
+    /// Headers list.
     pub headers: Option<Vec<Headers>>,
+    /// Rewrites list.
     pub rewrites: Option<Vec<Rewrites>>,
+    /// Redirects list.
     pub redirects: Option<Vec<Redirects>>,
 }
 
diff --git a/src/signals.rs b/src/signals.rs
index d3d6d817..f28c8ba4 100644
--- a/src/signals.rs
+++ b/src/signals.rs
@@ -1,3 +1,6 @@
+//! The module provides signals support like `SIGTERM`, `SIGINT` and `SIGQUIT`.
+//!
+
 use tokio::time::{sleep, Duration};
 
 #[cfg(unix)]
diff --git a/src/static_files.rs b/src/static_files.rs
index bdeaf3f9..04319383 100644
--- a/src/static_files.rs
+++ b/src/static_files.rs
@@ -1,7 +1,8 @@
-//! Static File handler
+//! The static file module which powers the web server.
 //!
-//! Part of the file is borrowed and adapted at a convenience from
-//! https://github.com/seanmonstar/warp/blob/master/src/filters/fs.rs
+
+// Part of the file is borrowed and adapted at a convenience from
+// https://github.com/seanmonstar/warp/blob/master/src/filters/fs.rs
 
 use bytes::{Bytes, BytesMut};
 use futures_util::future::{Either, Future};
@@ -27,20 +28,31 @@ use crate::{compression_static, directory_listing, Result};
 
 /// Defines all options needed by the static-files handler.
 pub struct HandleOpts<'a> {
+    /// Request method.
     pub method: &'a Method,
+    /// Request headers.
     pub headers: &'a HeaderMap<HeaderValue>,
+    /// Request base path.
     pub base_path: &'a PathBuf,
+    /// Request base path.
     pub uri_path: &'a str,
+    /// Request URI query.
     pub uri_query: Option<&'a str>,
+    /// Directory listing feature.
     pub dir_listing: bool,
+    /// Directory listing order feature.
     pub dir_listing_order: u8,
+    /// Directory listing format feature.
     pub dir_listing_format: &'a DirListFmt,
+    /// Redirect trailing slash feature.
     pub redirect_trailing_slash: bool,
+    /// Compression static feature.
     pub compression_static: bool,
+    /// Ignore hidden files feature.
     pub ignore_hidden_files: bool,
 }
 
-/// Entry point to handle incoming requests which map to specific files
+/// The server entry point to handle incoming requests which map to specific files
 /// on file system and return a file response.
 pub async fn handle<'a>(opts: &HandleOpts<'a>) -> Result<(Response<Body>, bool), StatusCode> {
     let method = opts.method;
@@ -472,7 +484,7 @@ const READ_BUF_SIZE: usize = 4_096;
 const READ_BUF_SIZE: usize = 8_192;
 
 #[derive(Debug)]
-pub struct FileStream<T> {
+struct FileStream<T> {
     reader: T,
 }
 
diff --git a/src/tls.rs b/src/tls.rs
index aaebec98..6a200326 100644
--- a/src/tls.rs
+++ b/src/tls.rs
@@ -1,5 +1,7 @@
-// Handles requests over TLS
-// -> Most of the file is borrowed from https://github.com/seanmonstar/warp/blob/master/src/tls.rs
+//! The module handles requests over TLS via [Rustls](tokio_rustls::rustls).
+//!
+
+// Most of the file is borrowed from https://github.com/seanmonstar/warp/blob/master/src/tls.rs
 
 use futures_util::ready;
 use hyper::server::accept::Accept;
@@ -23,6 +25,7 @@ use crate::transport::Transport;
 /// Represents errors that can occur building the TlsConfig
 #[derive(Debug)]
 pub enum TlsConfigError {
+    /// Error type for I/O operations
     Io(io::Error),
     /// An Error parsing the Certificate
     CertParseError,
@@ -168,6 +171,7 @@ impl TlsConfigBuilder {
         self
     }
 
+    /// Builds TLS configuration.
     pub fn build(mut self) -> Result<ServerConfig, TlsConfigError> {
         let mut cert_rdr = BufReader::new(self.cert);
         let cert = rustls_pemfile::certs(&mut cert_rdr)
@@ -284,9 +288,10 @@ enum State {
     Streaming(tokio_rustls::server::TlsStream<AddrStream>),
 }
 
-// tokio_rustls::server::TlsStream doesn't expose constructor methods,
-// so we have to TlsAcceptor::accept and handshake to have access to it
-// TlsStream implements AsyncRead/AsyncWrite handshaking tokio_rustls::Accept first
+/// TlsStream implements AsyncRead/AsyncWrite handshaking tokio_rustls::Accept first.
+///
+/// tokio_rustls::server::TlsStream doesn't expose constructor methods,
+/// so we have to TlsAcceptor::accept and handshake to have access to it.
 pub struct TlsStream {
     state: State,
     remote_addr: SocketAddr,
@@ -359,12 +364,14 @@ impl AsyncWrite for TlsStream {
     }
 }
 
+/// Type to intercept Tls incoming connections.
 pub struct TlsAcceptor {
     config: Arc<ServerConfig>,
     incoming: AddrIncoming,
 }
 
 impl TlsAcceptor {
+    /// Creates a new Tls interceptor.
     pub fn new(config: ServerConfig, incoming: AddrIncoming) -> TlsAcceptor {
         TlsAcceptor {
             config: Arc::new(config),
diff --git a/src/transport.rs b/src/transport.rs
index 7f52ed7a..e372e895 100644
--- a/src/transport.rs
+++ b/src/transport.rs
@@ -1,5 +1,7 @@
-// Handles requests over TLS
-// -> Most of the file is borrowed from https://github.com/seanmonstar/warp/blob/master/src/transport.rs
+//! Async transport module.
+//!
+
+// Most of the file is borrowed from https://github.com/seanmonstar/warp/blob/master/src/transport.rs
 
 use std::io;
 use std::net::SocketAddr;
@@ -9,7 +11,9 @@ use std::task::{Context, Poll};
 use hyper::server::conn::AddrStream;
 use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
 
+/// Transport trait that supports the remote (peer) address.
 pub trait Transport: AsyncRead + AsyncWrite {
+    /// Returns the remote (peer) address of this connection.
     fn remote_addr(&self) -> Option<SocketAddr>;
 }
 
@@ -19,6 +23,7 @@ impl Transport for AddrStream {
     }
 }
 
+/// Type to support `Transport`, `AsyncRead` and `AsyncWrite`.
 pub struct LiftIo<T>(pub T);
 
 impl<T: AsyncRead + Unpin> AsyncRead for LiftIo<T> {
diff --git a/src/winservice.rs b/src/winservice.rs
index 652fcdcc..e197986d 100644
--- a/src/winservice.rs
+++ b/src/winservice.rs
@@ -1,4 +1,5 @@
 //! Module that lets SWS to run in a "Windows Service" context
+//!
 
 use std::ffi::OsString;
 use std::thread;
@@ -181,7 +182,7 @@ pub fn install_service(config_file: Option<PathBuf>) -> Result {
 
     // Append a `--config-file` path to the binary arguments if present
     if let Some(f) = config_file {
-        let f = helpers::adjust_canonicalization(f);
+        let f = helpers::adjust_canonicalization(&f);
         if !f.is_empty() {
             service_binary_arguments.push(OsString::from(["--config-file=", &f].concat()));
         }


Test patch: