feat: make --path-prefix works on serving single file (#102)

This commit is contained in:
sigoden 2022-07-08 19:30:05 +08:00 committed by GitHub
parent 4e84e6c532
commit 4e823e8bba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 88 additions and 26 deletions

View file

@ -10,6 +10,7 @@ use crate::auth::AccessControl;
use crate::auth::AuthMethod; use crate::auth::AuthMethod;
#[cfg(feature = "tls")] #[cfg(feature = "tls")]
use crate::tls::{load_certs, load_private_key}; use crate::tls::{load_certs, load_private_key};
use crate::utils::encode_uri;
use crate::BoxResult; use crate::BoxResult;
pub fn build_cli() -> Command<'static> { pub fn build_cli() -> Command<'static> {
@ -196,7 +197,7 @@ impl Args {
let uri_prefix = if path_prefix.is_empty() { let uri_prefix = if path_prefix.is_empty() {
"/".to_owned() "/".to_owned()
} else { } else {
format!("/{}/", &path_prefix) format!("/{}/", &encode_uri(&path_prefix))
}; };
let hidden: String = matches let hidden: String = matches
.value_of("hidden") .value_of("hidden")

View file

@ -45,15 +45,30 @@ const BUF_SIZE: usize = 65536;
pub struct Server { pub struct Server {
args: Arc<Args>, args: Arc<Args>,
assets_prefix: String, assets_prefix: String,
single_file_req_paths: Vec<String>,
running: Arc<AtomicBool>, running: Arc<AtomicBool>,
} }
impl Server { impl Server {
pub fn new(args: Arc<Args>, running: Arc<AtomicBool>) -> Self { pub fn new(args: Arc<Args>, running: Arc<AtomicBool>) -> Self {
let assets_prefix = format!("{}__dufs_v{}_", args.uri_prefix, env!("CARGO_PKG_VERSION")); let assets_prefix = format!("{}__dufs_v{}_", args.uri_prefix, env!("CARGO_PKG_VERSION"));
let single_file_req_paths = if args.path_is_file {
vec![
args.uri_prefix.to_string(),
args.uri_prefix[0..args.uri_prefix.len() - 1].to_string(),
encode_uri(&format!(
"{}{}",
&args.uri_prefix,
get_file_name(&args.path)
)),
]
} else {
vec![]
};
Self { Self {
args, args,
running, running,
single_file_req_paths,
assets_prefix, assets_prefix,
} }
} }
@ -118,8 +133,16 @@ impl Server {
let head_only = method == Method::HEAD; let head_only = method == Method::HEAD;
if self.args.path_is_file { if self.args.path_is_file {
self.handle_send_file(&self.args.path, headers, head_only, &mut res) if self
.await?; .single_file_req_paths
.iter()
.any(|v| v.as_str() == req_path)
{
self.handle_send_file(&self.args.path, headers, head_only, &mut res)
.await?;
} else {
status_not_found(&mut res);
}
return Ok(res); return Ok(res);
} }

View file

@ -3,11 +3,8 @@
mod fixtures; mod fixtures;
mod utils; mod utils;
use assert_cmd::prelude::*; use fixtures::{server, Error, TestServer};
use assert_fs::fixture::TempDir;
use fixtures::{port, server, tmpdir, wait_for_port, Error, TestServer};
use rstest::rstest; use rstest::rstest;
use std::process::{Command, Stdio};
#[rstest] #[rstest]
fn path_prefix_index(#[with(&["--path-prefix", "xyz"])] server: TestServer) -> Result<(), Error> { fn path_prefix_index(#[with(&["--path-prefix", "xyz"])] server: TestServer) -> Result<(), Error> {
@ -33,22 +30,3 @@ fn path_prefix_propfind(
assert!(text.contains("<D:href>/xyz/</D:href>")); assert!(text.contains("<D:href>/xyz/</D:href>"));
Ok(()) Ok(())
} }
#[rstest]
#[case("index.html")]
fn serve_single_file(tmpdir: TempDir, port: u16, #[case] file: &str) -> Result<(), Error> {
let mut child = Command::cargo_bin("dufs")?
.arg(tmpdir.path().join(file))
.arg("-p")
.arg(port.to_string())
.stdout(Stdio::piped())
.spawn()?;
wait_for_port(port);
let resp = reqwest::blocking::get(format!("http://localhost:{}/index.html", port))?;
assert_eq!(resp.text()?, "This is index.html");
child.kill()?;
Ok(())
}

60
tests/single_file.rs Normal file
View file

@ -0,0 +1,60 @@
//! Run file server with different args
mod fixtures;
mod utils;
use assert_cmd::prelude::*;
use assert_fs::fixture::TempDir;
use fixtures::{port, tmpdir, wait_for_port, Error};
use rstest::rstest;
use std::process::{Command, Stdio};
#[rstest]
#[case("index.html")]
fn single_file(tmpdir: TempDir, port: u16, #[case] file: &str) -> Result<(), Error> {
let mut child = Command::cargo_bin("dufs")?
.arg(tmpdir.path().join(file))
.arg("-p")
.arg(port.to_string())
.stdout(Stdio::piped())
.spawn()?;
wait_for_port(port);
let resp = reqwest::blocking::get(format!("http://localhost:{}", port))?;
assert_eq!(resp.text()?, "This is index.html");
let resp = reqwest::blocking::get(format!("http://localhost:{}/", port))?;
assert_eq!(resp.text()?, "This is index.html");
let resp = reqwest::blocking::get(format!("http://localhost:{}/index.html", port))?;
assert_eq!(resp.text()?, "This is index.html");
child.kill()?;
Ok(())
}
#[rstest]
#[case("index.html")]
fn path_prefix_single_file(tmpdir: TempDir, port: u16, #[case] file: &str) -> Result<(), Error> {
let mut child = Command::cargo_bin("dufs")?
.arg(tmpdir.path().join(file))
.arg("-p")
.arg(port.to_string())
.arg("--path-prefix")
.arg("xyz")
.stdout(Stdio::piped())
.spawn()?;
wait_for_port(port);
let resp = reqwest::blocking::get(format!("http://localhost:{}/xyz", port))?;
assert_eq!(resp.text()?, "This is index.html");
let resp = reqwest::blocking::get(format!("http://localhost:{}/xyz/", port))?;
assert_eq!(resp.text()?, "This is index.html");
let resp = reqwest::blocking::get(format!("http://localhost:{}/xyz/index.html", port))?;
assert_eq!(resp.text()?, "This is index.html");
let resp = reqwest::blocking::get(format!("http://localhost:{}", port))?;
assert_eq!(resp.status(), 404);
child.kill()?;
Ok(())
}