Fixed a bug where names with square brackets tripped routing

This commit is contained in:
Antoine Gersant 2018-10-28 15:13:34 -07:00
parent 5d0ead96e4
commit 84507e4d86
4 changed files with 50 additions and 29 deletions

View file

@ -430,7 +430,7 @@ fn browse(request: &mut Request, db: &DB) -> IronResult<Response> {
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<Response> {
};
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,

View file

@ -537,15 +537,16 @@ fn virtualize_directory(vfs: &VFS, mut directory: Directory) -> Option<Directory
Some(directory)
}
pub fn browse<T>(db: &T, virtual_path: &Path) -> Result<Vec<CollectionFile>, errors::Error>
pub fn browse<T, P>(db: &T, virtual_path: P) -> Result<Vec<CollectionFile>, errors::Error>
where
T: ConnectionSource + VFSSource,
P: AsRef<Path>,
{
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<Directory> = directories::table
.filter(directories::parent.is_null())
@ -581,15 +582,16 @@ where
Ok(output)
}
pub fn flatten<T>(db: &T, virtual_path: &Path) -> Result<Vec<Song>, errors::Error>
pub fn flatten<T, P>(db: &T, virtual_path: P) -> Result<Vec<Song>, errors::Error>
where
T: ConnectionSource + VFSSource,
P: AsRef<Path>,
{
use self::songs::dsl::*;
let vfs = db.get_vfs()?;
let connection = db.get_connection();
let real_songs: Vec<Song> = if virtual_path.parent() != None {
let real_songs: Vec<Song> = 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

View file

@ -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<rocket::Route> {
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<Self, Self::Error> {
let decoded_path = param.percent_decode_lossy();
Ok(VFSPathBuf{
path_buf: PathBuf::from(decoded_path.into_owned())
})
}
}
impl From<VFSPathBuf> 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<DB>,
_auth: Auth,
) -> Result<Json<Vec<index::CollectionFile>>, errors::Error> {
let result = index::browse::<DB>(&db, &PathBuf::new())?;
let result = index::browse(db.deref(), &PathBuf::new())?;
Ok(Json(result))
}
#[get("/browse/<path..>")]
#[get("/browse/<path>")]
fn browse(
db: State<DB>,
_auth: Auth,
path: PathBuf,
path: VFSPathBuf,
) -> Result<Json<Vec<index::CollectionFile>>, errors::Error> {
let result = index::browse::<DB>(&db, &path)?;
let result = index::browse(db.deref(), &path.into() as &PathBuf)?;
Ok(Json(result))
}
#[get("/flatten")]
fn flatten_root(db: State<DB>, _auth: Auth) -> Result<Json<Vec<index::Song>>, errors::Error> {
let result = index::flatten::<DB>(&db, &PathBuf::new())?;
let result = index::flatten(db.deref(), &PathBuf::new())?;
Ok(Json(result))
}
#[get("/flatten/<path..>")]
#[get("/flatten/<path>")]
fn flatten(
db: State<DB>,
_auth: Auth,
path: PathBuf,
path: VFSPathBuf,
) -> Result<Json<Vec<index::Song>>, errors::Error> {
let result = index::flatten::<DB>(&db, &path)?;
let result = index::flatten(db.deref(), &path.into() as &PathBuf)?;
Ok(Json(result))
}
#[get("/random")]
fn random(db: State<DB>, _auth: Auth) -> Result<Json<Vec<index::Directory>>, errors::Error> {
let result = index::get_random_albums::<DB>(&db, 20)?;
let result = index::get_random_albums(db.deref(), 20)?;
Ok(Json(result))
}
#[get("/recent")]
fn recent(db: State<DB>, _auth: Auth) -> Result<Json<Vec<index::Directory>>, errors::Error> {
let result = index::get_recent_albums::<DB>(&db, 20)?;
let result = index::get_recent_albums(db.deref(), 20)?;
Ok(Json(result))
}
#[get("/search")]
fn search_root(db: State<DB>, _auth: Auth) -> Result<Json<Vec<index::CollectionFile>>, errors::Error> {
let result = index::search::<DB>(&db, "")?;
let result = index::search(db.deref(), "")?;
Ok(Json(result))
}
#[get("/search/<query>")]
fn search(db: State<DB>, _auth: Auth, query: String) -> Result<Json<Vec<index::CollectionFile>>, errors::Error> {
let result = index::search::<DB>(&db, &query)?;
let result = index::search(db.deref(), &query)?;
Ok(Json(result))
}
#[get("/serve/<path..>")]
fn serve(db: State<DB>, _auth: Auth, path: PathBuf) -> Result<serve::RangeResponder<File>, errors::Error> {
#[get("/serve/<path>")]
fn serve(db: State<DB>, _auth: Auth, path: VFSPathBuf) -> Result<serve::RangeResponder<File>, 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)?

View file

@ -51,9 +51,9 @@ impl VFS {
Ok(())
}
pub fn real_to_virtual(&self, real_path: &Path) -> Result<PathBuf> {
pub fn real_to_virtual<P: AsRef<Path>>(&self, real_path: P) -> Result<PathBuf> {
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<PathBuf> {
pub fn virtual_to_real<P: AsRef<Path>>(&self, virtual_path: P) -> Result<PathBuf> {
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 {