index : static-web-server.git

ascending towards madness

author Paul Hennig <OZpmaz7h_G5Y7DqmfE658ya_u17Ttf3WP4OT83Y_@y.gy> 2022-03-15 20:01:24.0 +00:00:00
committer GitHub <noreply@github.com> 2022-03-15 20:01:24.0 +00:00:00
commit
cba4a8337da7b149f185d564c4f218fb46e94e99 [patch]
tree
d6070668c9f6a73a88fb952f05060e6651fd4718
parent
7b6fc0b8999a0092f9fe62bc16d69189a2c69776
download
cba4a8337da7b149f185d564c4f218fb46e94e99.tar.gz

Add fallback page option (#91)

feat: fallback page option via `--page-fallback` argument

Diff

 docs/content/features/error-pages.md | 15 ++++++++++++++-
 src/config.rs                        |  8 ++++++--
 src/fallback_page.rs                 | 19 +++++++++++++++++++
 src/handler.rs                       | 25 ++++++++++++++++++-------
 src/lib.rs                           |  1 +
 src/server.rs                        |  4 ++++
 6 files changed, 62 insertions(+), 10 deletions(-)

diff --git a/docs/content/features/error-pages.md b/docs/content/features/error-pages.md
index 5c270da..b772cfb 100644
--- a/docs/content/features/error-pages.md
+++ b/docs/content/features/error-pages.md
@@ -5,7 +5,7 @@
This feature is enabled by default and can be controlled either by the string `--page404` ([SERVER_ERROR_PAGE_404]./../configuration/environment-variables.md#server_error_page_404) or the `--page50x` ([SERVER_ERROR_PAGE_50X]./../configuration/environment-variables.md#server_error_page_50x) arguments.

!!! info "Tip"
    Either `--page404` and `--page50x` have defaults (optional values) so they can be specified or omitted as required.
Either `--page404` and `--page50x` have defaults (optional values) so they can be specified or omitted as required.

Below an example of how to customize those HTML pages.

@@ -16,3 +16,16 @@ static-web-server \
    --page404 ./my-page-404.html \
    --page50x ./my-page-50x.html
```

## Fallback Page for use with Client Routers

HTML file path that is used for GET requests when the requested path doesn't exist. The fallback page is served with a 200 status code, useful when using client routers like `React Router` or similar. If the path is not specified or simply doesn't exist then this feature will not be active.

It can be set with the `SERVER_FALLBACK_PAGE` environment variable or with the cli argument `--page-fallback`.

```sh
static-web-server \
    --port 8787 \
    --root ./my-public-dir \
    --page-fallback ./my-public-dir/index.html
```
diff --git a/src/config.rs b/src/config.rs
index 5126d9b..e04d838 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -47,7 +47,7 @@ pub struct Config {
        default_value = "./public/50x.html",
        env = "SERVER_ERROR_PAGE_50X"
    )]
    /// HTML file path for 50x errors. If path is not specified or simply don't exists then server will use a generic HTML error message.
    /// HTML file path for 50x errors. If the path is not specified or simply doesn't exist then the server will use a generic HTML error message.
    pub page50x: String,

    #[structopt(
@@ -55,9 +55,13 @@ pub struct Config {
        default_value = "./public/404.html",
        env = "SERVER_ERROR_PAGE_404"
    )]
    /// HTML file path for 404 errors. If path is not specified or simply don't exists then server will use a generic HTML error message.
    /// HTML file path for 404 errors. If the path is not specified or simply doesn't exist then the server will use a generic HTML error message.
    pub page404: String,

    #[structopt(long, default_value = "", env = "SERVER_FALLBACK_PAGE")]
    /// HTML file path that is used for GET requests when the requested path doesn't exist. The fallback page is served with a 200 status code, useful when using client routers. If the path is not specified or simply doesn't exist then this feature will not be active.
    pub page_fallback: String,

    #[structopt(long, short = "g", default_value = "error", env = "SERVER_LOG_LEVEL")]
    /// Specify a logging level in lower case. Values: error, warn, info, debug or trace
    pub log_level: String,
diff --git a/src/fallback_page.rs b/src/fallback_page.rs
new file mode 100644
index 0000000..79528b5
--- /dev/null
+++ b/src/fallback_page.rs
@@ -0,0 +1,19 @@
use headers::{AcceptRanges, ContentLength, ContentType, HeaderMapExt};
use hyper::{Body, Response, StatusCode};
use mime_guess::mime;
/// Checks if a fallback response can be generated, i.e. if it is a GET request that would result in a 404 error and a fallback page is configured.
/// If a response can be generated, it is returned, else `None` is returned.
pub fn fallback_response(page_fallback: &str) -> Response<Body> {
    let body = Body::from(page_fallback.to_owned());
    let len = page_fallback.len() as u64;

    let mut resp = Response::new(body);
    *resp.status_mut() = StatusCode::OK;

    resp.headers_mut().typed_insert(ContentLength(len));
    resp.headers_mut()
        .typed_insert(ContentType::from(mime::TEXT_HTML_UTF_8));
    resp.headers_mut().typed_insert(AcceptRanges::bytes());

    resp
}
diff --git a/src/handler.rs b/src/handler.rs
index bbae8f5..9870485 100644
--- a/src/handler.rs
+++ b/src/handler.rs
@@ -2,7 +2,8 @@ use hyper::{header::WWW_AUTHENTICATE, Body, Method, Request, Response, StatusCod
use std::{future::Future, path::PathBuf, sync::Arc};

use crate::{
    basic_auth, compression, control_headers, cors, error_page, security_headers, static_files,
    basic_auth, compression, control_headers, cors, error_page, fallback_page, security_headers,
    static_files,
};
use crate::{Error, Result};

@@ -17,6 +18,7 @@ pub struct RequestHandlerOpts {
    pub cache_control_headers: bool,
    pub page404: String,
    pub page50x: String,
    pub page_fallback: String,
    pub basic_auth: String,
}

@@ -154,12 +156,21 @@ impl RequestHandler {

                    Ok(resp)
                }
                Err(status) => error_page::error_response(
                    method,
                    &status,
                    &self.opts.page404,
                    &self.opts.page50x,
                ),
                Err(status) => {
                    if !self.opts.page_fallback.is_empty()
                        && (status == StatusCode::NOT_FOUND)
                        && (method == Method::GET)
                    {
                        Ok(fallback_page::fallback_response(&self.opts.page_fallback))
                    } else {
                        error_page::error_response(
                            method,
                            &status,
                            &self.opts.page404,
                            &self.opts.page50x,
                        )
                    }
                }
            }
        }
    }
diff --git a/src/lib.rs b/src/lib.rs
index 3969b8d..2cb08e1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -12,6 +12,7 @@ pub mod config;
pub mod control_headers;
pub mod cors;
pub mod error_page;
pub mod fallback_page;
pub mod handler;
pub mod helpers;
pub mod logger;
diff --git a/src/server.rs b/src/server.rs
index 3d937c5..a46fb66 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -95,6 +95,9 @@ impl Server {
        let page404 = helpers::read_file_content(&opts.page404);
        let page50x = helpers::read_file_content(&opts.page50x);

        // Fallback page content
        let page_fallback = helpers::read_file_content(&opts.page_fallback);

        // Number of worker threads option
        let threads = self.threads;
        tracing::info!("runtime worker threads: {}", self.threads);
@@ -148,6 +151,7 @@ impl Server {
                cache_control_headers,
                page404,
                page50x,
                page_fallback,
                basic_auth,
            }),
        });