Skip to main content

mini_static/
error.rs

1use std::fmt;
2
3/// Errors that can occur during static file serving.
4///
5/// This error type is non-exhaustive and may gain new variants in future releases.
6///
7/// # Variants
8///
9/// - `NotFound`: The requested path does not exist.
10/// - `Traversal`: The requested path attempts to escape the server root.
11/// - `Io`: An I/O error occurred (file read, permission denied, etc.).
12/// - `Config`: A builder was given a value it cannot accept, reported at configuration
13///   time rather than per request.
14#[derive(Debug)]
15#[non_exhaustive]
16pub enum StaticError {
17    /// Requested path does not exist.
18    NotFound(String),
19    /// Path traversal attempt detected.
20    Traversal(String),
21    /// I/O error from the filesystem.
22    Io(std::io::Error),
23    /// A builder was given a value it cannot accept — reported when the server is
24    /// configured, not when a request arrives.
25    Config(String),
26}
27
28impl fmt::Display for StaticError {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        match self {
31            StaticError::NotFound(path) => write!(f, "not found: {path}"),
32            StaticError::Traversal(path) => write!(f, "path traversal denied: {path}"),
33            StaticError::Io(e) => write!(f, "io error: {e}"),
34            StaticError::Config(msg) => write!(f, "invalid configuration: {msg}"),
35        }
36    }
37}
38
39impl std::error::Error for StaticError {
40    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
41        match self {
42            StaticError::Io(e) => Some(e),
43            _ => None,
44        }
45    }
46}
47
48impl StaticError {
49    /// Returns a user-safe error message for use in HTTP responses.
50    ///
51    /// Traversal errors return "not found" to avoid leaking information about
52    /// the filesystem structure. I/O errors return "internal server error".
53    pub fn user_message(&self) -> &'static str {
54        match self {
55            StaticError::NotFound(_) | StaticError::Traversal(_) => "not found",
56            StaticError::Io(_) | StaticError::Config(_) => "internal server error",
57        }
58    }
59}
60
61impl From<std::io::Error> for StaticError {
62    fn from(e: std::io::Error) -> Self {
63        StaticError::Io(e)
64    }
65}
66
67#[cfg(test)]
68#[path = "../tests/unit/error.rs"]
69mod tests;