Add add/remove_path_prefix fields to domain settings
This commit is contained in:
parent
edadaab792
commit
188ebaa30b
@ -252,7 +252,12 @@ impl Manager for ManagerImpl {
|
|||||||
return Err(unexpected::Error::from("origin is proxy, can't serve file").into());
|
return Err(unexpected::Error::from("origin is proxy, can't serve file").into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let f = self.origin_store.get_file(&settings.origin_descr, path)?;
|
let path = settings.process_path(path);
|
||||||
|
|
||||||
|
let f = self
|
||||||
|
.origin_store
|
||||||
|
.get_file(&settings.origin_descr, path.as_ref())?;
|
||||||
|
|
||||||
Ok(f)
|
Ok(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
use crate::error::unexpected::{self, Mappable};
|
use crate::error::unexpected::{self, Mappable};
|
||||||
use crate::origin;
|
use crate::origin;
|
||||||
|
|
||||||
|
use std::borrow;
|
||||||
|
|
||||||
use hex::ToHex;
|
use hex::ToHex;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
@ -11,6 +13,9 @@ use sha2::{Digest, Sha256};
|
|||||||
pub struct Settings {
|
pub struct Settings {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub origin_descr: origin::Descr,
|
pub origin_descr: origin::Descr,
|
||||||
|
|
||||||
|
pub remove_path_prefix: Option<String>,
|
||||||
|
pub add_path_prefix: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Settings {
|
impl Settings {
|
||||||
@ -19,4 +24,104 @@ impl Settings {
|
|||||||
serde_json::to_writer(&mut h, self).or_unexpected()?;
|
serde_json::to_writer(&mut h, self).or_unexpected()?;
|
||||||
Ok(h.finalize().encode_hex::<String>())
|
Ok(h.finalize().encode_hex::<String>())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remove_path_prefix<'path, 'prefix>(
|
||||||
|
path: borrow::Cow<'path, str>,
|
||||||
|
prefix: &'prefix str,
|
||||||
|
) -> borrow::Cow<'path, str> {
|
||||||
|
if prefix.len() == 0 {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut prefix = prefix.trim_end_matches('/');
|
||||||
|
prefix = prefix.trim_start_matches('/');
|
||||||
|
|
||||||
|
let mut stripped_path = path.trim_start_matches('/');
|
||||||
|
|
||||||
|
if !stripped_path.starts_with(prefix) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
stripped_path = stripped_path.strip_prefix(prefix).unwrap();
|
||||||
|
if stripped_path.len() == 0 {
|
||||||
|
return borrow::Cow::Borrowed("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
borrow::Cow::Owned(stripped_path.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_path_prefix<'path, 'prefix>(
|
||||||
|
path: borrow::Cow<'path, str>,
|
||||||
|
prefix: &'prefix str,
|
||||||
|
) -> borrow::Cow<'path, str> {
|
||||||
|
if prefix.len() == 0 {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut prefix = prefix.trim_end_matches('/');
|
||||||
|
prefix = prefix.trim_start_matches('/');
|
||||||
|
|
||||||
|
let mut prefixed_path = String::with_capacity(1 + prefix.len() + path.len());
|
||||||
|
|
||||||
|
prefixed_path.push('/');
|
||||||
|
prefixed_path.push_str(prefix);
|
||||||
|
prefixed_path.push_str(path.as_ref());
|
||||||
|
|
||||||
|
borrow::Cow::Owned(prefixed_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_path<'a>(&self, path: &'a str) -> borrow::Cow<'a, str> {
|
||||||
|
let mut path = borrow::Cow::Borrowed(path);
|
||||||
|
|
||||||
|
if let Some(ref prefix) = self.remove_path_prefix {
|
||||||
|
path = Self::remove_path_prefix(path, prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref prefix) = self.add_path_prefix {
|
||||||
|
path = Self::add_path_prefix(path, prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::borrow;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn remove_path_prefix() {
|
||||||
|
let assert_remove = |want: &str, path: &str, prefix: &str| {
|
||||||
|
assert_eq!(
|
||||||
|
want,
|
||||||
|
Settings::remove_path_prefix(borrow::Cow::Borrowed(path), prefix).as_ref(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_remove("/bar", "/foo/bar", "/foo");
|
||||||
|
assert_remove("/foo/bar", "/foo/bar", "/baz");
|
||||||
|
assert_remove("/bar", "/foo/bar", "/foo/");
|
||||||
|
assert_remove("/bar", "/foo/bar", "/foo///");
|
||||||
|
assert_remove("/", "/", "/");
|
||||||
|
assert_remove("/", "/foo/bar/", "/foo/bar");
|
||||||
|
assert_remove("/", "/foo/bar", "/foo/bar");
|
||||||
|
assert_remove("/", "/foo/bar", "/foo/bar///");
|
||||||
|
assert_remove("/bar", "/bar", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_path_prefix() {
|
||||||
|
let assert_add = |want: &str, path: &str, prefix: &str| {
|
||||||
|
assert_eq!(
|
||||||
|
want,
|
||||||
|
Settings::add_path_prefix(borrow::Cow::Borrowed(path), prefix).as_ref(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_add("/foo/bar", "/bar", "/foo");
|
||||||
|
assert_add("/foo/", "/", "/foo");
|
||||||
|
assert_add("/foo/", "/", "/foo///");
|
||||||
|
assert_add("/bar", "/bar", "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,6 +181,8 @@ mod tests {
|
|||||||
url: "bar".to_string(),
|
url: "bar".to_string(),
|
||||||
branch_name: "baz".to_string(),
|
branch_name: "baz".to_string(),
|
||||||
},
|
},
|
||||||
|
remove_path_prefix: None,
|
||||||
|
add_path_prefix: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
@ -203,6 +205,8 @@ mod tests {
|
|||||||
url: "BAR".to_string(),
|
url: "BAR".to_string(),
|
||||||
branch_name: "BAZ".to_string(),
|
branch_name: "BAZ".to_string(),
|
||||||
},
|
},
|
||||||
|
remove_path_prefix: None,
|
||||||
|
add_path_prefix: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
store.set(&domain, &new_settings).expect("set");
|
store.set(&domain, &new_settings).expect("set");
|
||||||
|
@ -30,7 +30,7 @@ pub async fn serve_http_request(
|
|||||||
mut req: hyper::Request<hyper::Body>,
|
mut req: hyper::Request<hyper::Body>,
|
||||||
req_is_https: bool,
|
req_is_https: bool,
|
||||||
) -> unexpected::Result<hyper::Response<hyper::Body>> {
|
) -> unexpected::Result<hyper::Response<hyper::Body>> {
|
||||||
let (proxy_url, request_http_headers) = if let origin::Descr::Proxy {
|
let (url, request_http_headers) = if let origin::Descr::Proxy {
|
||||||
ref url,
|
ref url,
|
||||||
ref request_http_headers,
|
ref request_http_headers,
|
||||||
} = settings.origin_descr
|
} = settings.origin_descr
|
||||||
@ -67,12 +67,12 @@ pub async fn serve_http_request(
|
|||||||
.insert("x-forwarded-proto", HeaderValue::from_static("https"));
|
.insert("x-forwarded-proto", HeaderValue::from_static("https"));
|
||||||
}
|
}
|
||||||
|
|
||||||
match hyper_reverse_proxy::call(client_ip, proxy_url, req).await {
|
match hyper_reverse_proxy::call(client_ip, url, req).await {
|
||||||
Ok(res) => Ok(res),
|
Ok(res) => Ok(res),
|
||||||
// ProxyError doesn't actually implement Error :facepalm: so we have to format the error
|
// ProxyError doesn't actually implement Error :facepalm: so we have to format the error
|
||||||
// manually
|
// manually
|
||||||
Err(e) => Err(unexpected::Error::from(
|
Err(e) => Err(unexpected::Error::from(
|
||||||
format!("error while proxying to {proxy_url}: {e:?}").as_str(),
|
format!("error while proxying to {url}: {e:?}").as_str(),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ struct BasePresenter<'a, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct DomainGetArgs {
|
struct DomainArgs {
|
||||||
domain: domain::Name,
|
domain: domain::Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,7 +246,7 @@ impl<'svc> Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn domain_get(&self, args: DomainGetArgs) -> Response<Body> {
|
fn domain(&self, args: DomainArgs) -> Response<Body> {
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct Data {
|
struct Data {
|
||||||
domain: domain::Name,
|
domain: domain::Name,
|
||||||
@ -485,10 +485,8 @@ impl<'svc> Service {
|
|||||||
self.render_page("/index.html", ())
|
self.render_page("/index.html", ())
|
||||||
}
|
}
|
||||||
(form_method, "/domain.html") if form_method == config_form_method => {
|
(form_method, "/domain.html") if form_method == config_form_method => {
|
||||||
self.with_query_req(&req, body, |args: DomainGetArgs| async {
|
self.with_query_req(&req, body, |args: DomainArgs| async { self.domain(args) })
|
||||||
self.domain_get(args)
|
.await
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
(form_method, "/domain_init.html") if form_method == config_form_method => {
|
(form_method, "/domain_init.html") if form_method == config_form_method => {
|
||||||
self.with_query_req(&req, body, |args: DomainInitArgs| async {
|
self.with_query_req(&req, body, |args: DomainInitArgs| async {
|
||||||
|
@ -49,6 +49,31 @@ automatically updated too!</p>
|
|||||||
</p>
|
</p>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Advanced Settings</legend>
|
||||||
|
<p>
|
||||||
|
<label>
|
||||||
|
Prefix to remove from URL paths:
|
||||||
|
<input name="domain_setting_remove_path_prefix"
|
||||||
|
type="text"
|
||||||
|
placeholder="/foo/bar"
|
||||||
|
value="{{ data.settings.remove_path_prefix }}"
|
||||||
|
required />
|
||||||
|
</label>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<label>
|
||||||
|
Prefix to add to URL paths:
|
||||||
|
<input name="domain_setting_add_path_prefix"
|
||||||
|
type="text"
|
||||||
|
placeholder="/foo/bar"
|
||||||
|
value="{{ data.settings.add_path_prefix }}"
|
||||||
|
required />
|
||||||
|
</label>
|
||||||
|
</p>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<input type="submit" value="Next" />
|
<input type="submit" value="Next" />
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_with::{serde_as, NoneAsEmptyString};
|
||||||
|
|
||||||
use crate::{domain, error::unexpected, origin};
|
use crate::{domain, error::unexpected, origin};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Default)]
|
#[serde_as]
|
||||||
|
#[derive(Serialize, Deserialize, Default, Debug)]
|
||||||
pub struct FlatDomainSettings {
|
pub struct FlatDomainSettings {
|
||||||
domain_setting_origin_descr_kind: String,
|
domain_setting_origin_descr_kind: String,
|
||||||
|
|
||||||
@ -12,6 +14,14 @@ pub struct FlatDomainSettings {
|
|||||||
domain_setting_origin_descr_git_branch_name: Option<String>,
|
domain_setting_origin_descr_git_branch_name: Option<String>,
|
||||||
|
|
||||||
domain_setting_origin_descr_proxy_url: Option<String>,
|
domain_setting_origin_descr_proxy_url: Option<String>,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
#[serde_as(as = "NoneAsEmptyString")]
|
||||||
|
domain_setting_remove_path_prefix: Option<String>,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
#[serde_as(as = "NoneAsEmptyString")]
|
||||||
|
domain_setting_add_path_prefix: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<FlatDomainSettings> for domain::Settings {
|
impl TryFrom<FlatDomainSettings> for domain::Settings {
|
||||||
@ -31,7 +41,11 @@ impl TryFrom<FlatDomainSettings> for domain::Settings {
|
|||||||
_ => Err("invalid domain_setting_origin_descr_kind".to_string()),
|
_ => Err("invalid domain_setting_origin_descr_kind".to_string()),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
Ok(Self { origin_descr })
|
Ok(Self {
|
||||||
|
origin_descr,
|
||||||
|
remove_path_prefix: v.domain_setting_remove_path_prefix,
|
||||||
|
add_path_prefix: v.domain_setting_add_path_prefix,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,6 +68,9 @@ impl TryFrom<domain::Settings> for FlatDomainSettings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
res.domain_setting_remove_path_prefix = v.remove_path_prefix;
|
||||||
|
res.domain_setting_add_path_prefix = v.add_path_prefix;
|
||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user