index : static-web-server.git

ascending towards madness

author Jose Quintana <1700322+joseluisq@users.noreply.github.com> 2023-06-26 19:59:29.0 +00:00:00
committer GitHub <noreply@github.com> 2023-06-26 19:59:29.0 +00:00:00
commit
06955e9061413b14f39aee7c24259f51463e0d78 [patch]
tree
5d7facede641580bac47bd08bfb409e80b6e45a5
parent
506f54ede4d523a56d854bcf6c94ea1cf239b68b
download
06955e9061413b14f39aee7c24259f51463e0d78.tar.gz

feat: `redirect` option for url rewrites feature (#231)

the values can be:

- `301` for "Moved Permanently"
- `302` for "Found" (Temporary Redirect)

example:

```toml
[[advanced.rewrites]]
source = "**/*.{jpg,jpeg}"
destination = "/images/generic.png"
redirect = 301
```

Diff

 docs/content/features/url-rewrites.md | 14 ++++++++++++--
 src/handler.rs                        | 28 +++++++++++++++++++++++++---
 src/rewrites.rs                       |  4 ++--
 src/settings/file.rs                  |  4 +++-
 src/settings/mod.rs                   |  5 +++++
 tests/toml/config.toml                |  5 +++--
 6 files changed, 50 insertions(+), 10 deletions(-)

diff --git a/docs/content/features/url-rewrites.md b/docs/content/features/url-rewrites.md
index 47d99ea..9e23ef1 100644
--- a/docs/content/features/url-rewrites.md
+++ b/docs/content/features/url-rewrites.md
@@ -1,6 +1,6 @@
# URL Rewrites 

**SWS** provides the ability to rewrite request URLs with pattern matching support.
**SWS** provides the ability to rewrite request URLs with pattern-matching support.

URI rewrites are particularly useful with pattern matching ([globs]https://en.wikipedia.org/wiki/Glob_(programming)), as the server can accept any URL that matches the pattern and let the client-side code decide what to display.

@@ -12,6 +12,7 @@ Each table entry should have two key/value pairs:

- One `source` key containing a string _glob pattern_.
- One `destination` string containing the local file path.
- Optional `redirect` number containing the HTTP response code.

!!! info "Note"
    The incoming request(s) will reach the `destination` only if the request(s) URI matches the `source` pattern.
@@ -22,7 +23,15 @@ The source is a [Glob pattern](https://en.wikipedia.org/wiki/Glob_(programming))

### Destination

A local file path which must exist. It has to look something like `/some/directory/file.html`. It is worth noting that the `/` at the beginning indicates the server's root directory.
A local file path must exist. It has to look something like `/some/directory/file.html`. It is worth noting that the `/` at the beginning indicates the server's root directory.

### Redirect

An optional number that indicates the HTTP response code (redirect).
The values can be:

- `301` for "Moved Permanently"
- `302` for "Found" (Temporary Redirect)

## Examples

@@ -38,4 +47,5 @@ destination = "/assets/generic1.png"
[[advanced.rewrites]]
source = "**/*.{jpg,jpeg}"
destination = "/images/generic2.png"
redirect = 302
```
diff --git a/src/handler.rs b/src/handler.rs
index b13932c..d5abf44 100644
--- a/src/handler.rs
+++ b/src/handler.rs
@@ -23,7 +23,7 @@ use crate::{
    control_headers, cors, custom_headers, error_page,
    exts::http::MethodExt,
    redirects, rewrites, security_headers,
    settings::Advanced,
    settings::{file::RedirectsKind, Advanced},
    static_files::{self, HandleOpts},
    Error, Result,
};
@@ -232,8 +232,30 @@ impl RequestHandler {
                }

                // Rewrites
                if let Some(uri) = rewrites::rewrite_uri_path(uri_path, &advanced.rewrites) {
                    uri_path = uri
                if let Some(rewrite) = rewrites::rewrite_uri_path(uri_path, &advanced.rewrites) {
                    uri_path = rewrite.destination.as_str();
                    if let Some(redirect_type) = &rewrite.redirect {
                        let loc = match HeaderValue::from_str(uri_path) {
                            Ok(val) => val,
                            Err(err) => {
                                tracing::error!("invalid header value from current uri: {:?}", err);
                                return error_page::error_response(
                                    uri,
                                    method,
                                    &StatusCode::INTERNAL_SERVER_ERROR,
                                    &self.opts.page404,
                                    &self.opts.page50x,
                                );
                            }
                        };
                        let mut resp = Response::new(Body::empty());
                        resp.headers_mut().insert(hyper::header::LOCATION, loc);
                        *resp.status_mut() = match redirect_type {
                            RedirectsKind::Permanent => StatusCode::MOVED_PERMANENTLY,
                            RedirectsKind::Temporary => StatusCode::FOUND,
                        };
                        return Ok(resp);
                    }
                }
            }

diff --git a/src/rewrites.rs b/src/rewrites.rs
index 66e5550..ebff85a 100644
--- a/src/rewrites.rs
+++ b/src/rewrites.rs
@@ -13,12 +13,12 @@ use crate::settings::Rewrites;
pub fn rewrite_uri_path<'a>(
    uri_path: &'a str,
    rewrites_opts_vec: &'a Option<Vec<Rewrites>>,
) -> Option<&'a str> {
) -> Option<&'a Rewrites> {
    if let Some(rewrites_vec) = rewrites_opts_vec {
        for rewrites_entry in rewrites_vec.iter() {
            // Match source glob pattern against request uri path
            if rewrites_entry.source.is_match(uri_path) {
                return Some(rewrites_entry.destination.as_str());
                return Some(rewrites_entry);
            }
        }
    }
diff --git a/src/settings/file.rs b/src/settings/file.rs
index 5651050..3feee8d 100644
--- a/src/settings/file.rs
+++ b/src/settings/file.rs
@@ -74,7 +74,7 @@ pub struct Redirects {
    pub source: String,
    /// Redirect destination.
    pub destination: String,
    /// Redirect type.
    /// Redirect type either 301 (Moved Permanently) or 302 (Found).
    pub kind: RedirectsKind,
}

@@ -86,6 +86,8 @@ pub struct Rewrites {
    pub source: String,
    /// Rewrite destination.
    pub destination: String,
    /// Optional redirect type either 301 (Moved Permanently) or 302 (Found).
    pub redirect: Option<RedirectsKind>,
}

/// Advanced server options only available in configuration file mode.
diff --git a/src/settings/mod.rs b/src/settings/mod.rs
index 6ee58d6..b259bf3 100644
--- a/src/settings/mod.rs
+++ b/src/settings/mod.rs
@@ -21,6 +21,8 @@ pub use cli::Commands;

use cli::General;

use self::file::RedirectsKind;

/// The `headers` file options.
pub struct Headers {
    /// Source pattern glob matcher
@@ -35,6 +37,8 @@ pub struct Rewrites {
    pub source: GlobMatcher,
    /// A local file that must exist
    pub destination: String,
    /// Optional redirect type either 301 (Moved Permanently) or 302 (Found).
    pub redirect: Option<RedirectsKind>,
}

/// The `Redirects` file options.
@@ -327,6 +331,7 @@ impl Settings {
                                rewrites_vec.push(Rewrites {
                                    source,
                                    destination: rewrites_entry.destination.to_owned(),
                                    redirect: rewrites_entry.redirect.to_owned(),
                                });
                            }
                            Some(rewrites_vec)
diff --git a/tests/toml/config.toml b/tests/toml/config.toml
index f59a6db..1043890 100644
--- a/tests/toml/config.toml
+++ b/tests/toml/config.toml
@@ -109,9 +109,10 @@ kind = 302
### URL Rewrites

[[advanced.rewrites]]
source = "**/*.{png,ico,gif}"
source = "**/*.{png,gif}"
destination = "/assets/favicon.ico"
# redirect = 301

[[advanced.rewrites]]
source = "**/*.{jpg,jpeg}"
destination = "/images/nomad.png"
destination = "/assets/favicon.ico"