index : static-web-server.git

ascending towards madness

author Jose Quintana <joseluisquintana20@gmail.com> 2021-07-12 21:40:15.0 +00:00:00
committer Jose Quintana <joseluisquintana20@gmail.com> 2021-07-12 21:40:32.0 +00:00:00
commit
157ade1c85d746584baf9ca7c0ac184b6a8600dd [patch]
tree
b744a605709e012ab5d652489458282cab52c56d
parent
18de7fd485717efa3fc04a9f0a6a12464541461f
download
157ade1c85d746584baf9ca7c0ac184b6a8600dd.tar.gz

refactor: decrease allocations during 404/50x error page responses



Diff

 Cargo.lock        | 40 +++++++++++++++-------------------------
 Cargo.toml        |  1 -
 src/error_page.rs | 47 ++++++++++++++++++++---------------------------
 src/handler.rs    | 18 ++++++++++++++++--
 src/server.rs     | 12 +++++-------
 5 files changed, 56 insertions(+), 62 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 2c68a75..5c13a4a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -34,9 +34,9 @@ dependencies = [

[[package]]
name = "anyhow"
version = "1.0.41"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15af2628f6890fe2609a3b91bef4c83450512802e59489f9c1cb1fa5df064a61"
checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486"

[[package]]
name = "async-compression"
@@ -114,15 +114,9 @@ checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"

[[package]]
name = "cc"
version = "1.0.68"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"

[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"

[[package]]
name = "cfg-if"
@@ -168,7 +162,7 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
dependencies = [
 "cfg-if 1.0.0",
 "cfg-if",
]

[[package]]
@@ -202,7 +196,7 @@ version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0"
dependencies = [
 "cfg-if 1.0.0",
 "cfg-if",
 "crc32fast",
 "libc",
 "miniz_oxide",
@@ -492,9 +486,9 @@ checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"

[[package]]
name = "listenfd"
version = "0.3.3"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "492158e732f2e2de81c592f0a2427e57e12cd3d59877378fe7af624b6bbe0ca1"
checksum = "809e514e2cb8a9624701346ea3e694c1766d76778e343e537d873c1c366e79a7"
dependencies = [
 "libc",
 "uuid",
@@ -507,7 +501,7 @@ version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
 "cfg-if 1.0.0",
 "cfg-if",
]

[[package]]
@@ -581,7 +575,7 @@ checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a"
dependencies = [
 "bitflags",
 "cc",
 "cfg-if 1.0.0",
 "cfg-if",
 "libc",
]

@@ -807,7 +801,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c4cfa741c5832d0ef7fab46cabed29c2aae926db0b11bb2069edd8db5e64e16"
dependencies = [
 "block-buffer",
 "cfg-if 1.0.0",
 "cfg-if",
 "cpufeatures",
 "digest",
 "opaque-debug",
@@ -867,7 +861,6 @@ dependencies = [
 "listenfd",
 "mime_guess",
 "num_cpus",
 "once_cell",
 "percent-encoding",
 "pin-project",
 "structopt",
@@ -1008,7 +1001,7 @@ version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d"
dependencies = [
 "cfg-if 1.0.0",
 "cfg-if",
 "pin-project-lite",
 "tracing-attributes",
 "tracing-core",
@@ -1124,12 +1117,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"

[[package]]
name = "uuid"
version = "0.6.5"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363"
dependencies = [
 "cfg-if 0.1.10",
]
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"

[[package]]
name = "version_check"
@@ -1159,7 +1149,7 @@ version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
dependencies = [
 "cfg-if 1.0.0",
 "cfg-if",
 "wasm-bindgen-macro",
]

diff --git a/Cargo.toml b/Cargo.toml
index 45e40a6..5603020 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -40,7 +40,6 @@ bytes = "1.0"
percent-encoding = "2.1"
structopt = { version = "0.3", default-features = false }
num_cpus = { version = "1.13" }
once_cell = "1.7"
pin-project = "1.0"
tokio-rustls = { version = "0.22" }
humansize = "1.1"
diff --git a/src/error_page.rs b/src/error_page.rs
index b3853ec..193bec3 100644
--- a/src/error_page.rs
+++ b/src/error_page.rs
@@ -1,15 +1,16 @@
use headers::{AcceptRanges, ContentLength, ContentType, HeaderMapExt, HeaderValue};
use http::header::CONTENT_TYPE;
use hyper::{Body, Method, Response, StatusCode};
use once_cell::sync::OnceCell;

use crate::Result;

pub static PAGE_404: OnceCell<String> = OnceCell::new();
pub static PAGE_50X: OnceCell<String> = OnceCell::new();

/// It returns a HTTP error response which also handles available `404` or `50x` HTML content.
pub fn error_response(method: &Method, status_code: &StatusCode) -> Result<Response<Body>> {
pub fn error_response(
    method: &Method,
    status_code: &StatusCode,
    page404: &str,
    page50x: &str,
) -> Result<Response<Body>> {
    tracing::warn!(method = ?method, status = status_code.as_u16(), error = ?status_code.to_owned());

    // Check for 4xx/50x status codes and handle their corresponding HTML content
@@ -36,15 +37,7 @@ pub fn error_response(method: &Method, status_code: &StatusCode) -> Result<Respo
        | &StatusCode::EXPECTATION_FAILED => {
            // Extra check for 404 status code and its HTML content
            if status_code == &StatusCode::NOT_FOUND {
                error_page_content = match PAGE_404.get() {
                    Some(s) => s.to_owned(),
                    None => {
                        tracing::error!(
                            "404 error page content is not accessible or `PAGE_404` uninitialized"
                        );
                        String::new()
                    }
                };
                error_page_content = page404.to_owned();
            }
            status_code
        }
@@ -59,15 +52,7 @@ pub fn error_response(method: &Method, status_code: &StatusCode) -> Result<Respo
        | &StatusCode::INSUFFICIENT_STORAGE
        | &StatusCode::LOOP_DETECTED => {
            // HTML content check for status codes 50x
            error_page_content = match PAGE_50X.get() {
                Some(s) => s.to_owned(),
                None => {
                    tracing::error!(
                        "50x error page content is not accessible or `PAGE_50X` uninitialized"
                    );
                    String::new()
                }
            };
            error_page_content = page50x.to_owned();
            status_code
        }
        // other status codes
@@ -75,10 +60,18 @@ pub fn error_response(method: &Method, status_code: &StatusCode) -> Result<Respo
    };

    if error_page_content.is_empty() {
        error_page_content = format!(
            "<html><head><title>{}</title></head><body><center><h1>{}</h1></center></body></html>",
            status_code, status_code
        );
        error_page_content = [
            "<html><head><title>",
            status_code.as_str(),
            " ",
            status_code.canonical_reason().unwrap_or_default(),
            "</title></head><body><center><h1>",
            status_code.as_str(),
            " ",
            status_code.canonical_reason().unwrap_or_default(),
            "</h1></center></body></html>",
        ]
        .concat();
    }

    let mut body = Body::empty();
diff --git a/src/handler.rs b/src/handler.rs
index f182e10..c0282bb 100644
--- a/src/handler.rs
+++ b/src/handler.rs
@@ -12,6 +12,8 @@ pub struct RequestHandlerOpts {
    pub dir_listing: bool,
    pub cors: Option<Arc<cors::Configured>>,
    pub security_headers: bool,
    pub page404: Arc<str>,
    pub page50x: Arc<str>,
}

/// It defines the main request handler used by the Hyper service request.
@@ -42,7 +44,12 @@ impl RequestHandler {
                    }
                    Err(e) => {
                        tracing::debug!("cors error kind: {:?}", e);
                        return error_page::error_response(method, &StatusCode::FORBIDDEN);
                        return error_page::error_response(
                            method,
                            &StatusCode::FORBIDDEN,
                            self.opts.page404.as_ref(),
                            self.opts.page50x.as_ref(),
                        );
                    }
                };
            }
@@ -59,6 +66,8 @@ impl RequestHandler {
                                return error_page::error_response(
                                    method,
                                    &StatusCode::INTERNAL_SERVER_ERROR,
                                    self.opts.page404.as_ref(),
                                    self.opts.page50x.as_ref(),
                                );
                            }
                        };
@@ -75,7 +84,12 @@ impl RequestHandler {

                    Ok(resp)
                }
                Err(status) => error_page::error_response(method, &status),
                Err(status) => error_page::error_response(
                    method,
                    &status,
                    self.opts.page404.as_ref(),
                    self.opts.page50x.as_ref(),
                ),
            }
        }
    }
diff --git a/src/server.rs b/src/server.rs
index 01a1f1f..b3950af 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -8,7 +8,7 @@ use structopt::StructOpt;
use crate::handler::{RequestHandler, RequestHandlerOpts};
use crate::tls::{TlsAcceptor, TlsConfigBuilder};
use crate::{config::Config, service::RouterService, Result};
use crate::{cors, error_page, helpers, logger, signals};
use crate::{cors, helpers, logger, signals};

/// Define a multi-thread HTTP or HTTP/2 web server.
pub struct Server {
@@ -81,12 +81,8 @@ impl Server {
        let root_dir = Arc::new(helpers::get_valid_dirpath(&opts.root)?);

        // Custom error pages content
        error_page::PAGE_404
            .set(helpers::read_file_content(opts.page404.as_ref()))
            .expect("page 404 is not initialized");
        error_page::PAGE_50X
            .set(helpers::read_file_content(opts.page50x.as_ref()))
            .expect("page 50x is not initialized");
        let page404 = Arc::from(helpers::read_file_content(opts.page404.as_ref()).as_str());
        let page50x = Arc::from(helpers::read_file_content(opts.page50x.as_ref()).as_str());

        // Number of worker threads option
        let threads = self.threads;
@@ -115,6 +111,8 @@ impl Server {
                dir_listing,
                cors,
                security_headers,
                page404,
                page50x,
            },
        });