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/// - `PipelineSetup`: A configured CSS/JS tool's binary is missing from `PATH`,
13/// discovered at server startup (or [`crate::Server::build`]) before any build runs.
14/// - `Build`: A configured build pipeline (CSS/JS tool or asset folder) failed to
15/// produce output.
16#[derive(Debug)]
17#[non_exhaustive]
18pub enum StaticError {
19 /// Requested path does not exist.
20 NotFound(String),
21 /// Path traversal attempt detected.
22 Traversal(String),
23 /// I/O error from the filesystem.
24 Io(std::io::Error),
25 /// A configured build-pipeline tool could not be found or validated at startup.
26 PipelineSetup(String),
27 /// A configured build pipeline ran but failed to produce output.
28 Build(String),
29}
30
31impl fmt::Display for StaticError {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 match self {
34 StaticError::NotFound(path) => write!(f, "not found: {path}"),
35 StaticError::Traversal(path) => write!(f, "path traversal denied: {path}"),
36 StaticError::Io(e) => write!(f, "io error: {e}"),
37 StaticError::PipelineSetup(msg) => write!(f, "pipeline setup failed: {msg}"),
38 StaticError::Build(msg) => write!(f, "build failed: {msg}"),
39 }
40 }
41}
42
43impl std::error::Error for StaticError {
44 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
45 match self {
46 StaticError::Io(e) => Some(e),
47 _ => None,
48 }
49 }
50}
51
52impl StaticError {
53 /// Returns a user-safe error message for use in HTTP responses.
54 ///
55 /// Traversal errors return "not found" to avoid leaking information about
56 /// the filesystem structure. I/O errors return "internal server error".
57 pub fn user_message(&self) -> &'static str {
58 match self {
59 StaticError::NotFound(_) | StaticError::Traversal(_) => "not found",
60 StaticError::Io(_) | StaticError::PipelineSetup(_) | StaticError::Build(_) => {
61 "internal server error"
62 }
63 }
64 }
65}
66
67impl From<std::io::Error> for StaticError {
68 fn from(e: std::io::Error) -> Self {
69 StaticError::Io(e)
70 }
71}