diff --git a/src/api.rs b/src/api.rs index 50450e2..a48591d 100644 --- a/src/api.rs +++ b/src/api.rs @@ -430,7 +430,7 @@ fn browse(request: &mut Request, db: &DB) -> IronResult { Err(e) => return Err(IronError::new(e, status::BadRequest)), Ok(p) => p, }; - let browse_result = index::browse(db, &path)?; + let browse_result = index::browse(db, path)?; let result_json = serde_json::to_string(&browse_result); let result_json = match result_json { @@ -504,7 +504,7 @@ fn serve(request: &mut Request, db: &DB) -> IronResult { }; let vfs = db.get_vfs()?; - let real_path = vfs.virtual_to_real(&virtual_path); + let real_path = vfs.virtual_to_real(virtual_path); let real_path = match real_path { Err(e) => return Err(IronError::new(e, status::NotFound)), Ok(p) => p, diff --git a/src/index.rs b/src/index.rs index 8e69680..ebb1e9e 100644 --- a/src/index.rs +++ b/src/index.rs @@ -537,15 +537,16 @@ fn virtualize_directory(vfs: &VFS, mut directory: Directory) -> Option(db: &T, virtual_path: &Path) -> Result, errors::Error> +pub fn browse(db: &T, virtual_path: P) -> Result, errors::Error> where T: ConnectionSource + VFSSource, + P: AsRef, { let mut output = Vec::new(); let vfs = db.get_vfs()?; let connection = db.get_connection(); - if virtual_path.components().count() == 0 { + if virtual_path.as_ref().components().count() == 0 { // Browse top-level let real_directories: Vec = directories::table .filter(directories::parent.is_null()) @@ -581,15 +582,16 @@ where Ok(output) } -pub fn flatten(db: &T, virtual_path: &Path) -> Result, errors::Error> +pub fn flatten(db: &T, virtual_path: P) -> Result, errors::Error> where T: ConnectionSource + VFSSource, + P: AsRef, { use self::songs::dsl::*; let vfs = db.get_vfs()?; let connection = db.get_connection(); - let real_songs: Vec = if virtual_path.parent() != None { + let real_songs: Vec = if virtual_path.as_ref().parent() != None { let real_path = vfs.virtual_to_real(virtual_path)?; let like_path = real_path.as_path().to_string_lossy().into_owned() + "%"; songs diff --git a/src/rocket_api.rs b/src/rocket_api.rs index b8c514d..38b7c47 100644 --- a/src/rocket_api.rs +++ b/src/rocket_api.rs @@ -1,5 +1,5 @@ -use rocket::http::{Cookie, Cookies, Status}; -use rocket::request::{self, FromRequest, Request}; +use rocket::http::{Cookie, Cookies, RawStr, Status}; +use rocket::request::{self, FromParam, FromRequest, Request}; use rocket::{Outcome, State}; use rocket_contrib::json::Json; use std::fs::File; @@ -21,8 +21,6 @@ const CURRENT_MAJOR_VERSION: i32 = 2; const CURRENT_MINOR_VERSION: i32 = 2; const SESSION_FIELD_USERNAME: &str = "username"; -// TODO every path.. argument breaks when the path contains square brackets. Needs URLencoding back!! - pub fn get_routes() -> Vec { routes![ version, @@ -85,6 +83,27 @@ impl<'a, 'r> FromRequest<'a, 'r> for AdminRights { } } +struct VFSPathBuf { + path_buf: PathBuf, +} + +impl<'r> FromParam<'r> for VFSPathBuf { + type Error = &'r RawStr; + + fn from_param(param: &'r RawStr) -> Result { + let decoded_path = param.percent_decode_lossy(); + Ok(VFSPathBuf{ + path_buf: PathBuf::from(decoded_path.into_owned()) + }) + } +} + +impl From for PathBuf { + fn from(vfs_path_buf: VFSPathBuf) -> Self { + vfs_path_buf.path_buf.clone() + } +} + #[derive(Serialize)] struct Version { major: i32, @@ -172,65 +191,65 @@ fn browse_root( db: State, _auth: Auth, ) -> Result>, errors::Error> { - let result = index::browse::(&db, &PathBuf::new())?; + let result = index::browse(db.deref(), &PathBuf::new())?; Ok(Json(result)) } -#[get("/browse/")] +#[get("/browse/")] fn browse( db: State, _auth: Auth, - path: PathBuf, + path: VFSPathBuf, ) -> Result>, errors::Error> { - let result = index::browse::(&db, &path)?; + let result = index::browse(db.deref(), &path.into() as &PathBuf)?; Ok(Json(result)) } #[get("/flatten")] fn flatten_root(db: State, _auth: Auth) -> Result>, errors::Error> { - let result = index::flatten::(&db, &PathBuf::new())?; + let result = index::flatten(db.deref(), &PathBuf::new())?; Ok(Json(result)) } -#[get("/flatten/")] +#[get("/flatten/")] fn flatten( db: State, _auth: Auth, - path: PathBuf, + path: VFSPathBuf, ) -> Result>, errors::Error> { - let result = index::flatten::(&db, &path)?; + let result = index::flatten(db.deref(), &path.into() as &PathBuf)?; Ok(Json(result)) } #[get("/random")] fn random(db: State, _auth: Auth) -> Result>, errors::Error> { - let result = index::get_random_albums::(&db, 20)?; + let result = index::get_random_albums(db.deref(), 20)?; Ok(Json(result)) } #[get("/recent")] fn recent(db: State, _auth: Auth) -> Result>, errors::Error> { - let result = index::get_recent_albums::(&db, 20)?; + let result = index::get_recent_albums(db.deref(), 20)?; Ok(Json(result)) } #[get("/search")] fn search_root(db: State, _auth: Auth) -> Result>, errors::Error> { - let result = index::search::(&db, "")?; + let result = index::search(db.deref(), "")?; Ok(Json(result)) } #[get("/search/")] fn search(db: State, _auth: Auth, query: String) -> Result>, errors::Error> { - let result = index::search::(&db, &query)?; + let result = index::search(db.deref(), &query)?; Ok(Json(result)) } -#[get("/serve/")] -fn serve(db: State, _auth: Auth, path: PathBuf) -> Result, errors::Error> { +#[get("/serve/")] +fn serve(db: State, _auth: Auth, path: VFSPathBuf) -> Result, errors::Error> { let db: &DB = db.deref(); let vfs = db.get_vfs()?; - let real_path = vfs.virtual_to_real(&path)?; + let real_path = vfs.virtual_to_real(&path.into() as &PathBuf)?; let serve_path = if utils::is_image(&real_path) { thumbnails::get_thumbnail(&real_path, 400)? diff --git a/src/vfs.rs b/src/vfs.rs index 8469c2b..9af661a 100644 --- a/src/vfs.rs +++ b/src/vfs.rs @@ -51,9 +51,9 @@ impl VFS { Ok(()) } - pub fn real_to_virtual(&self, real_path: &Path) -> Result { + pub fn real_to_virtual>(&self, real_path: P) -> Result { for (name, target) in &self.mount_points { - if let Ok(p) = real_path.strip_prefix(target) { + if let Ok(p) = real_path.as_ref().strip_prefix(target) { let mount_path = Path::new(&name); return if p.components().count() == 0 { Ok(mount_path.to_path_buf()) @@ -65,10 +65,10 @@ impl VFS { bail!("Real path has no match in VFS") } - pub fn virtual_to_real(&self, virtual_path: &Path) -> Result { + pub fn virtual_to_real>(&self, virtual_path: P) -> Result { for (name, target) in &self.mount_points { let mount_path = Path::new(&name); - if let Ok(p) = virtual_path.strip_prefix(mount_path) { + if let Ok(p) = virtual_path.as_ref().strip_prefix(mount_path) { return if p.components().count() == 0 { Ok(target.clone()) } else {