index : static-web-server.git

ascending towards madness

author Jose Quintana <joseluisquintana20@gmail.com> 2021-07-11 19:56:02.0 +00:00:00
committer Jose Quintana <joseluisquintana20@gmail.com> 2021-07-11 19:56:02.0 +00:00:00
commit
c9e7222fb0b6fb04d50a6b9336569883730a1ab7 [patch]
tree
f96b1d928b5a3396036790abc5e7aa92ff52c895
parent
962595deff69345e60c4fbdb9540c87fef94feb9
download
c9e7222fb0b6fb04d50a6b9336569883730a1ab7.tar.gz

refactor: cross-platform ctrl-c signal handling



Diff

 .gitignore            |  1 +-
 Cargo.lock            | 70 ++++++++++++++++++++--------------------------------
 Cargo.toml            |  5 +----
 src/lib.rs            |  5 +----
 src/server.rs         | 23 +----------------
 src/signal_manager.rs | 56 +------------------------------------------
 src/signals.rs        | 18 +++++++++++++-
 7 files changed, 51 insertions(+), 127 deletions(-)

diff --git a/.gitignore b/.gitignore
index f2cf8f1..69030d7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,7 @@
**/*.data*
**/*.perf*
**/*.out*
**/*.zst
release
.vscode
TODO
diff --git a/Cargo.lock b/Cargo.lock
index ad8d21c..63de1e7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -56,12 +56,6 @@ checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"

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

[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
@@ -121,7 +115,17 @@ 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]]
name = "ctrlc"
version = "3.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "232295399409a8b7ae41276757b5a1cc21032848d42bff2352261f958b3ca29a"
dependencies = [
 "nix",
 "winapi",
]

[[package]]
@@ -139,7 +143,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",
@@ -178,7 +182,7 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
 "cfg-if 1.0.0",
 "cfg-if",
 "libc",
 "wasi",
]
@@ -328,9 +332,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"

[[package]]
name = "libc"
version = "0.2.97"
version = "0.2.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"

[[package]]
name = "log"
@@ -347,7 +351,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]]
@@ -413,15 +417,14 @@ dependencies = [

[[package]]
name = "nix"
version = "0.14.1"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce"
checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a"
dependencies = [
 "bitflags",
 "cc",
 "cfg-if 0.1.10",
 "cfg-if",
 "libc",
 "void",
]

[[package]]
@@ -466,7 +469,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "549430950c79ae24e6d02e0b7404534ecf311d94cc9f861e9e4020187d13d885"
dependencies = [
 "bitflags",
 "cfg-if 1.0.0",
 "cfg-if",
 "foreign-types",
 "libc",
 "once_cell",
@@ -852,16 +855,6 @@ dependencies = [
]

[[package]]
name = "signal"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f6ce83b159ab6984d2419f495134972b48754d13ff2e3f8c998339942b56ed9"
dependencies = [
 "libc",
 "nix",
]

[[package]]
name = "siphasher"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -872,6 +865,7 @@ name = "static-web-server"
version = "1.17.1"
dependencies = [
 "chrono",
 "ctrlc",
 "env_logger",
 "flate2",
 "humansize",
@@ -884,10 +878,8 @@ dependencies = [
 "log 0.4.14",
 "mime",
 "mime_guess",
 "nix",
 "openssl",
 "percent-encoding 2.1.0",
 "signal",
 "structopt",
 "tempfile",
 "time",
@@ -896,9 +888,9 @@ dependencies = [

[[package]]
name = "structopt"
version = "0.3.21"
version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c"
checksum = "69b041cdcb67226aca307e6e7be44c8806423d83e018bd662360a93dabce4d71"
dependencies = [
 "clap",
 "lazy_static",
@@ -907,9 +899,9 @@ dependencies = [

[[package]]
name = "structopt-derive"
version = "0.4.14"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90"
checksum = "7813934aecf5f51a54775e00068c237de98489463968231a51746bbbc03f9c10"
dependencies = [
 "heck",
 "proc-macro-error",
@@ -935,7 +927,7 @@ version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
dependencies = [
 "cfg-if 1.0.0",
 "cfg-if",
 "libc",
 "rand 0.8.4",
 "redox_syscall",
@@ -1027,9 +1019,9 @@ dependencies = [

[[package]]
name = "unicode-segmentation"
version = "1.7.1"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"

[[package]]
name = "unicode-width"
@@ -1091,12 +1083,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"

[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"

[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 1f5ffaf..baa400b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -39,11 +39,8 @@ structopt = { version = "0.3", default-features = false }
time = "0.1"
url = "1.4"
percent-encoding = "2.1"
ctrlc = { version = "3.1", features = ["termination"] }

[target.'cfg(not(windows))'.dependencies.nix]
version = "0.14"
[target.'cfg(not(windows))'.dependencies.signal]
version = "0.7"
[target.'cfg(all(target_env = "musl", target_pointer_width = "64"))'.dependencies.jemallocator]
version = "0.3"

diff --git a/src/lib.rs b/src/lib.rs
index b0eea07..ee21821 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -13,10 +13,7 @@ pub mod gzip;
pub mod helpers;
pub mod logger;
pub mod server;

#[cfg(not(windows))]
pub mod signal_manager;

pub mod signals;
pub mod staticfile_middleware;
pub mod staticfiles;

diff --git a/src/server.rs b/src/server.rs
index d9d94af..4fc435c 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -3,7 +3,7 @@ use iron::{Chain, Iron, Listening};

use crate::staticfile_middleware::HttpToHttpsRedirect;
use crate::staticfiles::*;
use crate::{config::Options, logger};
use crate::{config::Options, logger, signals};

/// Struct for holding a reference to a running iron server instance
#[derive(Debug)]
@@ -102,24 +102,5 @@ fn on_server_running(server_name: &str, running_servers: &[RunningServer]) {
        ))
    });

    handle_signals()
}

#[cfg(not(windows))]
fn handle_signals() {
    use crate::signal_manager;

    // Wait for incoming signals (E.g Ctrl+C (SIGINT), SIGTERM, etc
    signal_manager::wait_for_signal(|sig: signal::Signal| {
        let code = signal_manager::signal_to_int(sig);

        println!();
        warn!("Signal {} caught. Server execution exited.", code);
        std::process::exit(code)
    })
}

#[cfg(windows)]
fn handle_signals() {
    // TODO: Windows signals...
    signals::wait_for_ctrl_c()
}
diff --git a/src/signal_manager.rs b/src/signal_manager.rs
deleted file mode 100644
index 06be40c..0000000
--- a/src/signal_manager.rs
+++ /dev/null
@@ -1,56 +0,0 @@
use nix::errno::Errno;
use nix::libc::c_int;
use nix::sys::signal::{SIGCHLD, SIGINT, SIGTERM};
use nix::sys::wait::WaitStatus::{Exited, Signaled, StillAlive};
use nix::sys::wait::{waitpid, WaitPidFlag};
use nix::Error;
use signal::trap::Trap;

/// It waits for an incoming Termination Signal like Ctrl+C (SIGINT), SIGTERM, etc
pub fn wait_for_signal<F>(f: F)
where
    F: Fn(signal::Signal),
{
    let signal_trap = Trap::trap(&[SIGTERM, SIGINT, SIGCHLD]);

    for sig in signal_trap {
        match sig {
            SIGCHLD => {
                // Current std::process::Command ip does not have a way to find
                // process id, so we just wait until we have no children
                loop {
                    match waitpid(None, Some(WaitPidFlag::WNOHANG)) {
                        Ok(Exited(pid, status)) => {
                            println!("{} exited with status {}", pid, status);
                            continue;
                        }
                        Ok(Signaled(pid, sig, _)) => {
                            println!("{} killed by {}", pid, sig as c_int);
                            continue;
                        }
                        Ok(StillAlive) => {
                            break;
                        }
                        Ok(status) => {
                            println!("Temporary status {:?}", status);
                            continue;
                        }
                        Err(Error::Sys(Errno::ECHILD)) => {
                            return;
                        }
                        Err(e) => {
                            panic!("Error {:?}", e);
                        }
                    }
                }
            }

            sig => f(sig),
        }
    }
}

/// It casts a `signal::Signal` to `i32`
pub fn signal_to_int(sig: signal::Signal) -> i32 {
    sig as c_int
}
diff --git a/src/signals.rs b/src/signals.rs
new file mode 100644
index 0000000..289b206
--- /dev/null
+++ b/src/signals.rs
@@ -0,0 +1,18 @@
use ctrlc;
use std::{process, sync::mpsc::channel};

/// It waits for a `Ctrl-C` incoming signal.
pub fn wait_for_ctrl_c() {
    let (tx, rx) = channel();

    ctrlc::set_handler(move || tx.send(()).expect("could not send signal on channel"))
        .expect("error setting Ctrl-C handler");

    info!("press Ctrl+C to shutdown the server");

    rx.recv().expect("could not receive signal from channel");

    warn!("Ctrl+C signal caught, shutting down the server execution");

    process::exit(1)
}