Skip to content

Commit 73b3854

Browse files
committed
fix and test site prefix normalization
1 parent cee0cd4 commit 73b3854

File tree

1 file changed

+35
-14
lines changed

1 file changed

+35
-14
lines changed

src/app_config.rs

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use anyhow::Context;
22
use config::Config;
3+
use percent_encoding::AsciiSet;
34
use serde::de::Error;
45
use serde::{Deserialize, Deserializer};
56
use std::net::{SocketAddr, ToSocketAddrs};
@@ -152,21 +153,41 @@ fn deserialize_socket_addr<'de, D: Deserializer<'de>>(
152153
.transpose()
153154
}
154155

155-
/// The site prefix should always start and end with a `/`.
156156
fn deserialize_site_prefix<'de, D: Deserializer<'de>>(deserializer: D) -> Result<String, D::Error> {
157-
let prefix: Option<String> = Deserialize::deserialize(deserializer)?;
158-
Ok(prefix.map_or_else(
159-
|| '/'.to_string(),
160-
|h| {
161-
std::iter::once("/")
162-
.chain(percent_encoding::utf8_percent_encode(
163-
&h,
164-
percent_encoding::NON_ALPHANUMERIC,
165-
))
166-
.chain(std::iter::once("/"))
167-
.collect::<String>()
168-
},
169-
))
157+
let prefix: String = Deserialize::deserialize(deserializer)?;
158+
Ok(normalize_site_prefix(prefix.as_str()))
159+
}
160+
161+
/// We standardize the site prefix to always be stored with both leading and trailing slashes.
162+
/// We also percent-encode special characters in the prefix, but allow it to contain slashes (to allow
163+
/// hosting on a sub-sub-path).
164+
fn normalize_site_prefix(prefix: &str) -> String {
165+
const TO_ENCODE: AsciiSet = percent_encoding::NON_ALPHANUMERIC.remove(b'/');
166+
167+
let prefix = prefix.trim_start_matches('/').trim_end_matches('/');
168+
if prefix.is_empty() {
169+
return default_site_prefix();
170+
}
171+
let encoded_prefix = percent_encoding::percent_encode(prefix.as_bytes(), &TO_ENCODE);
172+
173+
std::iter::once("/")
174+
.chain(encoded_prefix)
175+
.chain(std::iter::once("/"))
176+
.collect::<String>()
177+
}
178+
179+
#[test]
180+
fn test_normalize_site_prefix() {
181+
assert_eq!(normalize_site_prefix(""), "/");
182+
assert_eq!(normalize_site_prefix("/"), "/");
183+
assert_eq!(normalize_site_prefix("a"), "/a/");
184+
assert_eq!(normalize_site_prefix("a/"), "/a/");
185+
assert_eq!(normalize_site_prefix("/a"), "/a/");
186+
assert_eq!(normalize_site_prefix("a/b"), "/a/b/");
187+
assert_eq!(normalize_site_prefix("a/b/"), "/a/b/");
188+
assert_eq!(normalize_site_prefix("a/b/c"), "/a/b/c/");
189+
assert_eq!(normalize_site_prefix("a b"), "/a%20b/");
190+
assert_eq!(normalize_site_prefix("a b/c"), "/a%20b/c/");
170191
}
171192

172193
fn default_site_prefix() -> String {

0 commit comments

Comments
 (0)