feat: improve hidden to support glob (#108)

This commit is contained in:
sigoden 2022-07-19 20:37:14 +08:00 committed by GitHub
parent f148817c52
commit b791549ec7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 69 additions and 10 deletions

View file

@ -159,7 +159,7 @@ pub struct Args {
pub path_is_file: bool, pub path_is_file: bool,
pub path_prefix: String, pub path_prefix: String,
pub uri_prefix: String, pub uri_prefix: String,
pub hidden: String, pub hidden: Vec<String>,
pub auth_method: AuthMethod, pub auth_method: AuthMethod,
pub auth: AccessControl, pub auth: AccessControl,
pub allow_upload: bool, pub allow_upload: bool,
@ -199,9 +199,9 @@ impl Args {
} else { } else {
format!("/{}/", &encode_uri(&path_prefix)) format!("/{}/", &encode_uri(&path_prefix))
}; };
let hidden: String = matches let hidden: Vec<String> = matches
.value_of("hidden") .value_of("hidden")
.map(|v| format!(",{},", v)) .map(|v| v.split(',').map(|x| x.to_string()).collect())
.unwrap_or_default(); .unwrap_or_default();
let enable_cors = matches.is_present("enable-cors"); let enable_cors = matches.is_present("enable-cors");
let auth: Vec<&str> = matches let auth: Vec<&str> = matches

View file

@ -1,5 +1,5 @@
use crate::streamer::Streamer; use crate::streamer::Streamer;
use crate::utils::{decode_uri, encode_uri, get_file_name, try_get_file_name}; use crate::utils::{decode_uri, encode_uri, get_file_name, glob, try_get_file_name};
use crate::{Args, BoxResult}; use crate::{Args, BoxResult};
use walkdir::WalkDir; use walkdir::WalkDir;
use xml::escape::escape_str_pcdata; use xml::escape::escape_str_pcdata;
@ -366,7 +366,8 @@ impl Server {
) -> BoxResult<()> { ) -> BoxResult<()> {
let mut paths: Vec<PathItem> = vec![]; let mut paths: Vec<PathItem> = vec![];
let path_buf = path.to_path_buf(); let path_buf = path.to_path_buf();
let hidden = self.args.hidden.to_string(); let hidden = Arc::new(self.args.hidden.to_vec());
let hidden = hidden.clone();
let running = self.running.clone(); let running = self.running.clone();
let search = search.to_lowercase(); let search = search.to_lowercase();
let search_paths = tokio::task::spawn_blocking(move || { let search_paths = tokio::task::spawn_blocking(move || {
@ -1065,12 +1066,12 @@ fn res_multistatus(res: &mut Response, content: &str) {
async fn zip_dir<W: AsyncWrite + Unpin>( async fn zip_dir<W: AsyncWrite + Unpin>(
writer: &mut W, writer: &mut W,
dir: &Path, dir: &Path,
hidden: &str, hidden: &[String],
running: Arc<AtomicBool>, running: Arc<AtomicBool>,
) -> BoxResult<()> { ) -> BoxResult<()> {
let mut writer = ZipFileWriter::new(writer); let mut writer = ZipFileWriter::new(writer);
let hidden = Arc::new(hidden.to_string()); let hidden = Arc::new(hidden.to_vec());
let hidden = hidden.to_string(); let hidden = hidden.clone();
let dir_path_buf = dir.to_path_buf(); let dir_path_buf = dir.to_path_buf();
let zip_paths = tokio::task::spawn_blocking(move || { let zip_paths = tokio::task::spawn_blocking(move || {
let mut it = WalkDir::new(&dir_path_buf).into_iter(); let mut it = WalkDir::new(&dir_path_buf).into_iter();
@ -1170,8 +1171,8 @@ fn status_no_content(res: &mut Response) {
*res.status_mut() = StatusCode::NO_CONTENT; *res.status_mut() = StatusCode::NO_CONTENT;
} }
fn is_hidden(hidden: &str, file_name: &str) -> bool { fn is_hidden(hidden: &[String], file_name: &str) -> bool {
hidden.contains(&format!(",{},", file_name)) hidden.iter().any(|v| glob(v, file_name))
} }
fn set_webdav_headers(res: &mut Response) { fn set_webdav_headers(res: &mut Response) {

View file

@ -23,3 +23,61 @@ pub fn try_get_file_name(path: &Path) -> BoxResult<&str> {
.and_then(|v| v.to_str()) .and_then(|v| v.to_str())
.ok_or_else(|| format!("Failed to get file name of `{}`", path.display()).into()) .ok_or_else(|| format!("Failed to get file name of `{}`", path.display()).into())
} }
pub fn glob(source: &str, target: &str) -> bool {
let ss: Vec<char> = source.chars().collect();
let mut iter = target.chars();
let mut i = 0;
'outer: while i < ss.len() {
let s = ss[i];
match s {
'*' => match ss.get(i + 1) {
Some(s_next) => {
for t in iter.by_ref() {
if t == *s_next {
i += 2;
continue 'outer;
}
}
return true;
}
None => return true,
},
'?' => match iter.next() {
Some(_) => {
i += 1;
continue;
}
None => return false,
},
_ => match iter.next() {
Some(t) => {
if s == t {
i += 1;
continue;
}
return false;
}
None => return false,
},
}
}
iter.next().is_none()
}
#[test]
fn test_glob_key() {
assert!(glob("", ""));
assert!(glob(".*", ".git"));
assert!(glob("abc", "abc"));
assert!(glob("a*c", "abc"));
assert!(glob("a?c", "abc"));
assert!(glob("a*c", "abbc"));
assert!(glob("*c", "abc"));
assert!(glob("a*", "abc"));
assert!(glob("?c", "bc"));
assert!(glob("a?", "ab"));
assert!(!glob("abc", "adc"));
assert!(!glob("abc", "abcd"));
assert!(!glob("a?c", "abbc"));
}