indexflow_sitemap/error.rs
1use thiserror::Error;
2
3/// Errors produced by sitemap download, decompression, or (strict) expansion.
4///
5/// Streaming XML parse itself is **fault-tolerant** and does not surface as an
6/// error: malformed documents yield a partial [`crate::ParsedSitemap`] instead.
7#[derive(Debug, Error)]
8pub enum SitemapError {
9 /// Underlying `quick-xml` tokenizer failure (reserved for strict parsers).
10 #[error("XML parser error: {0}")]
11 Xml(#[from] quick_xml::Error),
12
13 /// Gzip inflate failed (truncated stream, CRC mismatch, …).
14 #[error("Decompression error: {0}")]
15 Decompression(String),
16
17 /// Inflated payload exceeded the configured uncompressed-size cap.
18 ///
19 /// This is the primary defence against gzip/deflate bombs.
20 #[error("decompression bomb: inflated size exceeds {limit} bytes")]
21 DecompressionBomb { limit: usize },
22
23 /// HTTP response body (or declared `Content-Length`) exceeded the download cap.
24 #[error("payload too large: {size} bytes exceeds limit {limit}")]
25 PayloadTooLarge { size: u64, limit: u64 },
26
27 /// Byte stream could not be decoded as UTF-8 / UTF-16.
28 #[error("encoding error: {0}")]
29 Encoding(String),
30
31 /// A URL failed to parse (kept for callers that validate locs strictly).
32 #[error("Invalid URL: {0}")]
33 InvalidUrl(#[from] url::ParseError),
34
35 /// Local I/O failure while reading decompressed bytes.
36 #[error("I/O error: {0}")]
37 Io(#[from] std::io::Error),
38
39 /// HTTP transport error from `reqwest`.
40 #[cfg(feature = "fetch")]
41 #[error("Network error: {0}")]
42 Network(#[from] reqwest::Error),
43
44 /// Non-success HTTP status from the sitemap origin.
45 #[error("HTTP response error with status: {0}")]
46 HttpStatus(u16),
47
48 /// Recursive expansion exceeded the caller-supplied depth budget.
49 ///
50 /// `expand_all` isolates this per-child (it skips instead of failing the
51 /// whole tree). Exposed so strict callers can treat it as fatal.
52 #[error("Max recursive depth exceeded ({0})")]
53 MaxDepthExceeded(u8),
54
55 /// A sitemap index loc pointed at an already-visited ancestor (cycle).
56 ///
57 /// `expand_all` isolates this per-child. Exposed so strict callers can
58 /// treat it as fatal.
59 #[error("Circular reference detected for sitemap: {0}")]
60 CircularReference(String),
61}