fix: demote path-not-exists validation errors to debug

The /image cross-library fallback tries the resolved library first and falls
back to any library holding the rel_path. The first attempt emitted error-level
noise on every grid tile in union mode. Split the validation error so only
traversal attempts log at error; missing-file cases log at debug.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cameron
2026-04-18 18:18:57 -04:00
committed by cameron
parent 2c8de8dcc6
commit b04dd8b601

View File

@@ -1,6 +1,6 @@
use ::anyhow; use ::anyhow;
use actix::{Handler, Message}; use actix::{Handler, Message};
use anyhow::{Context, anyhow}; use anyhow::Context;
use std::collections::HashSet; use std::collections::HashSet;
use std::fmt::Debug; use std::fmt::Debug;
use std::fs::read_dir; use std::fs::read_dir;
@@ -1024,33 +1024,58 @@ pub fn is_valid_full_path<P: AsRef<Path> + Debug + AsRef<std::ffi::OsStr>>(
match is_path_above_base_dir(base, &mut path, new_file) { match is_path_above_base_dir(base, &mut path, new_file) {
Ok(path) => Some(path), Ok(path) => Some(path),
Err(e) => { Err(PathValidationError::DoesNotExist(p)) => {
debug!("Path does not exist under base {:?}: {:?}", base, p);
None
}
Err(PathValidationError::AboveBase(p)) => {
error!("Path above base directory {:?}: {:?}", base, p);
None
}
Err(PathValidationError::Other(e)) => {
error!("{}", e); error!("{}", e);
None None
} }
} }
} }
#[derive(Debug)]
enum PathValidationError {
DoesNotExist(PathBuf),
AboveBase(PathBuf),
Other(anyhow::Error),
}
impl std::fmt::Display for PathValidationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PathValidationError::DoesNotExist(p) => write!(f, "Path does not exist: {:?}", p),
PathValidationError::AboveBase(p) => write!(f, "Path above base directory: {:?}", p),
PathValidationError::Other(e) => write!(f, "{}", e),
}
}
}
fn is_path_above_base_dir<P: AsRef<Path> + Debug>( fn is_path_above_base_dir<P: AsRef<Path> + Debug>(
base: P, base: P,
full_path: &mut PathBuf, full_path: &mut PathBuf,
new_file: bool, new_file: bool,
) -> anyhow::Result<PathBuf> { ) -> Result<PathBuf, PathValidationError> {
full_path match full_path.absolutize() {
.absolutize() Err(e) => Err(PathValidationError::Other(
.with_context(|| format!("Unable to resolve absolute path: {:?}", full_path)) anyhow::Error::new(e)
.map_or_else( .context(format!("Unable to resolve absolute path: {:?}", full_path)),
|e| Err(anyhow!(e)), )),
|p| { Ok(p) => {
if p.starts_with(base) && (new_file || p.exists()) { if p.starts_with(base) && (new_file || p.exists()) {
Ok(p.into_owned()) Ok(p.into_owned())
} else if !p.exists() { } else if !p.exists() {
Err(anyhow!("Path does not exist: {:?}", p)) Err(PathValidationError::DoesNotExist(p.into_owned()))
} else { } else {
Err(anyhow!("Path above base directory")) Err(PathValidationError::AboveBase(p.into_owned()))
} }
}, }
) }
} }
/// Handler for GPS summary endpoint /// Handler for GPS summary endpoint
@@ -1289,6 +1314,7 @@ impl Handler<RefreshThumbnailsMessage> for StreamActor {
mod tests { mod tests {
use super::*; use super::*;
use crate::database::DbError; use crate::database::DbError;
use ::anyhow::anyhow;
use std::collections::HashMap; use std::collections::HashMap;
use std::env; use std::env;
use std::fs::File; use std::fs::File;