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(-)
@@ -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
```
@@ -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 {
}
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);
}
}
}
@@ -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() {
if rewrites_entry.source.is_match(uri_path) {
return Some(rewrites_entry.destination.as_str());
return Some(rewrites_entry);
}
}
}
@@ -74,7 +74,7 @@ pub struct Redirects {
pub source: String,
pub destination: String,
pub kind: RedirectsKind,
}
@@ -86,6 +86,8 @@ pub struct Rewrites {
pub source: String,
pub destination: String,
pub redirect: Option<RedirectsKind>,
}
@@ -21,6 +21,8 @@ pub use cli::Commands;
use cli::General;
use self::file::RedirectsKind;
pub struct Headers {
@@ -35,6 +37,8 @@ pub struct Rewrites {
pub source: GlobMatcher,
pub destination: String,
pub redirect: Option<RedirectsKind>,
}
@@ -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)
@@ -109,9 +109,10 @@ kind = 302
[[advanced.rewrites]]
source = "**/*.{png,ico,gif}"
source = "**/*.{png,gif}"
destination = "/assets/favicon.ico"
[[advanced.rewrites]]
source = "**/*.{jpg,jpeg}"
destination = "/images/nomad.png"
destination = "/assets/favicon.ico"