Skip to main content

slim_config/errors/
native.rs

1// Copyright AGNTCY Contributors (https://github.com/agntcy)
2// SPDX-License-Identifier: Apache-2.0
3
4//! Native configuration errors covering gRPC/TLS/auth/native-WebSocket. The
5//! browser build uses the smaller [`super::ConfigError`] in `errors/wasm.rs`.
6
7use crate::auth::ConfigAuthError;
8use slim_auth::errors::AuthError;
9use thiserror::Error;
10
11/// Errors for Config.
12/// This is a custom error type for handling configuration-related errors.
13/// It is used to provide more context to the error messages.
14#[derive(Error, Debug)]
15pub enum ConfigError {
16    // Configuration / required fields
17    #[error("missing the grpc server service")]
18    MissingServices,
19    #[error("missing grpc endpoint")]
20    MissingEndpoint,
21
22    // Address / parsing
23    #[error("endpoint parse error")]
24    EndpointParse(#[from] std::net::AddrParseError),
25    #[error("URI parse error")]
26    UriParse(#[from] http::uri::InvalidUri),
27    #[error("invalid endpoint scheme")]
28    InvalidEndpointScheme,
29    #[error("websocket transport requires endpoint scheme ws:// or wss://")]
30    InvalidWebSocketEndpointScheme,
31    #[error("websocket client builder requires websocket transport")]
32    WebSocketClientUnsupportedTransport,
33    #[error("websocket server builder requires websocket transport")]
34    WebSocketServerUnsupportedTransport,
35    #[error("websocket transport TLS configuration is invalid")]
36    WebSocketTlsConfiguration,
37    #[error("websocket server TLS is required but no TLS configuration was provided")]
38    WebSocketServerTlsMissing,
39    #[error("HTTPS proxy URL requires a TLS configuration but none was provided")]
40    ProxyTlsMissing,
41    #[error("websocket server TLS configuration is set but endpoint scheme is not wss://")]
42    WebSocketServerTlsUnexpected,
43    #[error("websocket server SNI / certificate name is invalid")]
44    WebSocketInvalidServerName,
45    #[error("websocket TLS handshake error")]
46    WebSocketTlsHandshake(#[source] std::io::Error),
47    #[error("websocket TLS handshake timed out")]
48    WebSocketTlsHandshakeTimeout,
49    #[error("websocket protocol upgrade timed out")]
50    WebSocketHandshakeTimeout,
51    #[error("websocket handshake returned non-101 status: {0}")]
52    WebSocketHandshakeStatus(http::StatusCode),
53    #[error("websocket handshake response missing Sec-WebSocket-Accept header")]
54    WebSocketMissingAcceptHeader,
55    #[error("websocket handshake response Sec-WebSocket-Accept did not match the sent key")]
56    WebSocketAcceptMismatch,
57    #[error("websocket client send error")]
58    WebSocketClientSend(#[source] Box<dyn std::error::Error + Send + Sync>),
59
60    // Network / transport
61    #[error("transport error")]
62    TransportError(#[from] tonic::transport::Error),
63    #[error("gRPC channel builder does not support websocket transport")]
64    GrpcChannelUnsupportedTransport,
65    #[error("gRPC server builder does not support websocket transport")]
66    GrpcServerUnsupportedTransport,
67    #[error("bind error")]
68    Bind(#[from] std::io::Error),
69    #[error("websocket connection error")]
70    WebSocketConnection(#[source] std::io::Error),
71    #[error("websocket handshake error")]
72    WebSocketHandshake(#[source] fastwebsockets::WebSocketError),
73    #[error("websocket request error")]
74    WebSocketRequest(#[source] http::Error),
75
76    // Unix domain sockets
77    #[error("unix domain sockets are unsupported on this platform")]
78    UnixSocketUnsupported,
79    #[error("unix domain socket endpoint requires a socket path")]
80    UnixSocketMissingPath,
81    #[error("unix domain sockets require tls.insecure=true")]
82    UnixSocketTlsUnsupported,
83    #[error("invalid unix domain socket path")]
84    UnixSocketInvalidPath(#[source] http::Error),
85
86    #[cfg(target_family = "unix")]
87    #[error("failed to connect to unix domain socket")]
88    UnixSocketConnect(#[source] std::io::Error),
89
90    // Header parsing
91    #[error("header name parse error")]
92    HeaderNameParse(#[from] http::header::InvalidHeaderName),
93    #[error("header value parse error")]
94    HeaderValueParse(#[from] http::header::InvalidHeaderValue),
95
96    // Rate limiting
97    #[error("rate limit parse error")]
98    RateLimitParse(#[from] std::num::ParseIntError),
99
100    // TLS configuration
101    #[error("TLS config error")]
102    TlsConfig(#[from] crate::tls::errors::ConfigError),
103
104    // Authentication
105    #[error("auth error")]
106    AuthError(#[from] AuthError),
107    #[error("auth config error")]
108    AuthConfigError(#[from] ConfigAuthError),
109
110    // Resolution / operational
111    #[error("resolution error")]
112    ResolutionError,
113
114    // ServerHandler routing
115    #[error("server handler does not provide gRPC routes, but transport is gRPC")]
116    HandlerMissingGrpcSupport,
117    #[error("server handler does not provide a websocket callback, but transport is websocket")]
118    HandlerMissingWebSocketSupport,
119
120    // Unknown / catch-all
121    #[error("unknown error")]
122    Unknown,
123}
124
125impl ConfigError {
126    /// True if this error came from a transient transport-level failure that
127    /// a connect attempt could plausibly recover from on retry (TCP refused,
128    /// TLS handshake hiccup, websocket upgrade race, etc.). Used by the
129    /// shared connect-retry helper to decide whether to keep retrying.
130    ///
131    /// Add new variants here when introducing a transport — that's the single
132    /// switch that opts a new transport into the shared retry policy.
133    pub fn is_retryable_connect_error(&self) -> bool {
134        match self {
135            // gRPC / tonic
136            ConfigError::TransportError(_) => true,
137
138            // Unix domain socket
139            #[cfg(target_family = "unix")]
140            ConfigError::UnixSocketConnect(_) => true,
141
142            // WebSocket
143            ConfigError::WebSocketConnection(_)
144            | ConfigError::WebSocketTlsHandshake(_)
145            | ConfigError::WebSocketTlsHandshakeTimeout
146            | ConfigError::WebSocketHandshake(_)
147            | ConfigError::WebSocketHandshakeTimeout
148            | ConfigError::WebSocketHandshakeStatus(_)
149            | ConfigError::WebSocketMissingAcceptHeader
150            | ConfigError::WebSocketAcceptMismatch
151            | ConfigError::WebSocketClientSend(_) => true,
152
153            _ => false,
154        }
155    }
156}