Skip to main content

oxibrowser_core/
error.rs

1//! Error types for oxibrowser-core.
2
3use thiserror::Error;
4
5// Re-export intercept types from network module (single source of truth)
6pub use crate::network::{InterceptedBody, InterceptedResponse};
7
8/// Either a real HTTP response or a synthetic intercepted response.
9#[derive(Debug)]
10pub enum FetchResult {
11    /// Real HTTP response from reqwest.
12    Real(reqwest::Response),
13    /// Synthetic response from Fetch.fulfillRequest.
14    Intercepted(InterceptedResponse),
15}
16
17/// Core error type.
18#[derive(Error, Debug)]
19pub enum CoreError {
20    #[error("navigation failed: {0}")]
21    NavigationFailed(String),
22
23    #[error("network error: {0}")]
24    NetworkError(String),
25
26    #[error("DNS resolution failed: {0}")]
27    DnsError(String),
28
29    #[error("connection timeout: {0}")]
30    ConnectionTimeout(String),
31
32    #[error("HTTP {status}: {message}")]
33    HttpError { status: u16, message: String },
34
35    #[error("JavaScript evaluation error: {0}")]
36    JsError(String),
37
38    #[error("JS execution timed out after {0}ms")]
39    JsTimeout(u64),
40
41    #[error("JS runtime limit exceeded: {0}")]
42    JsRuntimeLimit(String),
43
44    #[error("page not loaded")]
45    PageNotLoaded,
46
47    #[error("page error: {0}")]
48    PageError(String),
49
50    #[error("session error: {0}")]
51    SessionError(String),
52
53    #[error("session closed")]
54    SessionClosed,
55
56    #[error("browser closed")]
57    BrowserClosed,
58
59    #[error("invalid URL: {0}")]
60    InvalidUrl(String),
61
62    #[error("timeout: {0}")]
63    Timeout(String),
64
65    #[error("DOM error: {0}")]
66    DomError(String),
67
68    /// Intercepted response from Fetch.fulfillRequest (synthetic response).
69    #[error("intercepted response")]
70    InterceptedResponse(InterceptedResponse),
71
72    #[error("screenshot error: {0}")]
73    ScreenshotError(String),
74}
75
76/// Convenience Result alias.
77pub type Result<T> = std::result::Result<T, CoreError>;
78
79impl From<url::ParseError> for CoreError {
80    fn from(e: url::ParseError) -> Self {
81        CoreError::InvalidUrl(e.to_string())
82    }
83}
84
85impl From<reqwest::Error> for CoreError {
86    fn from(e: reqwest::Error) -> Self {
87        if e.is_timeout() {
88            return CoreError::ConnectionTimeout(e.to_string());
89        }
90        if e.is_connect() {
91            let msg = e.to_string();
92            if msg.contains("dns")
93                || msg.contains("resolve")
94                || msg.contains("getaddrinfo")
95                || msg.contains("Name or service not known")
96                || msg.contains("nodename nor servname")
97            {
98                return CoreError::DnsError(msg);
99            }
100            return CoreError::NetworkError(msg);
101        }
102        CoreError::NetworkError(e.to_string())
103    }
104}