Skip to main content

apollo_http_client/
error.rs

1use apollo_errors::Error;
2use apollo_errors::miette;
3use tower::BoxError;
4
5/// Errors produced by the HTTP client.
6#[non_exhaustive]
7#[derive(Debug, Error, miette::Diagnostic)]
8pub enum HttpClientError {
9    /// The HTTP client could not be constructed.
10    #[error("failed to build HTTP client")]
11    #[diagnostic(code(http_client::build_failed))]
12    Build {
13        /// The underlying error.
14        #[from]
15        source: rustls::Error,
16    },
17
18    /// `tls.certificate_authorities` could not be parsed as PEM.
19    #[error("failed to parse `tls.certificate_authorities` as PEM")]
20    #[diagnostic(code(http_client::tls_certificate_authorities_invalid))]
21    TlsCertificateAuthoritiesInvalid {
22        /// The underlying error.
23        #[source]
24        source: rustls_pki_types::pem::Error,
25    },
26
27    /// `tls.certificate_authorities` contained no PEM certificate blocks.
28    #[error("`tls.certificate_authorities` contained no certificates")]
29    #[diagnostic(code(http_client::tls_certificate_authorities_empty))]
30    TlsCertificateAuthoritiesEmpty,
31
32    /// TLS verification is enabled but no trust anchors are configured.
33    #[error(
34        "TLS has no trust anchors: set `tls.certificate_authorities`, enable \
35         `tls.use_native_certificate_store`, or set `tls.danger_accept_invalid_certs` \
36         for development only"
37    )]
38    #[diagnostic(code(http_client::tls_no_trust_anchors))]
39    TlsNoTrustAnchors,
40
41    /// `tls.client_authentication.certificate_chain` could not be parsed as PEM.
42    #[error("failed to parse `tls.client_authentication.certificate_chain` as PEM")]
43    #[diagnostic(code(http_client::tls_client_certificate_chain_invalid))]
44    TlsClientCertificateChainInvalid {
45        /// The underlying error.
46        #[source]
47        source: rustls_pki_types::pem::Error,
48    },
49
50    /// `tls.client_authentication.certificate_chain` contained no certificates.
51    #[error("`tls.client_authentication.certificate_chain` contained no certificates")]
52    #[diagnostic(code(http_client::tls_client_certificate_chain_empty))]
53    TlsClientCertificateChainEmpty,
54
55    /// `tls.client_authentication.key` could not be parsed as PEM.
56    #[error("failed to parse `tls.client_authentication.key` as PEM")]
57    #[diagnostic(code(http_client::tls_client_key_invalid))]
58    TlsClientKeyInvalid {
59        /// The underlying error.
60        #[source]
61        source: rustls_pki_types::pem::Error,
62    },
63
64    /// `tls.client_authentication.key` contained no recognised private key block.
65    #[error(
66        "`tls.client_authentication.key` contained no PKCS#1, PKCS#8, or SEC1 private key block"
67    )]
68    #[diagnostic(code(http_client::tls_client_key_missing))]
69    TlsClientKeyMissing,
70
71    /// `tls.client_authentication.key` is encrypted. Encrypted keys are not supported.
72    #[error(
73        "`tls.client_authentication.key` is encrypted; only unencrypted private keys are supported"
74    )]
75    #[diagnostic(code(http_client::tls_client_key_encrypted))]
76    TlsClientKeyEncrypted,
77
78    /// `tls.client_authentication` was rejected by rustls — typically because
79    /// the private key is not usable as a TLS signer or does not match the
80    /// leaf certificate's public key.
81    ///
82    /// Cert/key pair mismatches that pass the build but fail the handshake
83    /// surface as [`Transport`](Self::Transport).
84    #[error(
85        "failed to configure TLS client authentication from `tls.client_authentication` \
86         — verify `certificate_chain` and `key` are from the same key pair"
87    )]
88    #[diagnostic(code(http_client::tls_client_auth))]
89    TlsClientAuth {
90        /// The underlying error.
91        #[source]
92        source: rustls::Error,
93    },
94
95    /// The request URI could not be constructed from its components.
96    #[error("invalid request URI")]
97    #[diagnostic(code(http_client::invalid_uri))]
98    InvalidUri {
99        /// The underlying error.
100        #[source]
101        source: http::Error,
102    },
103
104    /// The connection timed out before being established.
105    #[error("connection timed out")]
106    #[diagnostic(code(http_client::connection_timeout))]
107    ConnectionTimeout,
108
109    /// A TCP or TLS transport error.
110    #[error("transport error")]
111    #[diagnostic(code(http_client::transport_error))]
112    Transport {
113        /// The underlying error.
114        #[source]
115        source: BoxError,
116    },
117
118    /// The HTTP/1.1 or HTTP/2 handshake failed.
119    #[error("HTTP handshake failed")]
120    #[diagnostic(code(http_client::handshake_failed))]
121    Handshake {
122        /// The underlying error.
123        #[source]
124        source: hyper::Error,
125    },
126
127    /// Sending or receiving the HTTP request failed.
128    #[error("HTTP request failed")]
129    #[diagnostic(code(http_client::request_failed))]
130    Request {
131        /// The underlying error.
132        #[source]
133        source: hyper::Error,
134    },
135
136    /// The proxy returned a non-200 response to a CONNECT request.
137    #[error("proxy CONNECT rejected with status {status}")]
138    #[diagnostic(code(http_client::proxy_connect_rejected))]
139    ProxyTunnel {
140        /// The HTTP status code returned by the proxy.
141        status: http::StatusCode,
142    },
143
144    /// The configuration failed validation.
145    ///
146    /// `apollo_configuration::parse_yaml` runs validation before returning, so
147    /// this only fires when the config reached [`HttpClient::new`] through a
148    /// path that bypassed it.
149    ///
150    /// [`HttpClient::new`]: crate::HttpClient::new
151    #[error("invalid HTTP client configuration")]
152    #[diagnostic(code(http_client::invalid_config))]
153    InvalidConfig {
154        /// The collected validation errors.
155        #[source]
156        source: apollo_configuration::ValidationErrors,
157    },
158
159    /// A `unix://` URI's authority could not be hex-decoded into a socket path.
160    #[cfg(unix)]
161    #[error("invalid Unix socket path in URI authority")]
162    #[diagnostic(code(http_client::invalid_unix_socket_path))]
163    InvalidUnixSocketPath {
164        /// The underlying decoding error.
165        #[source]
166        source: hex::FromHexError,
167    },
168
169    /// A `unix://` URI's authority decoded to bytes that are not valid UTF-8.
170    ///
171    /// Non-UTF-8 socket paths are not supported.
172    #[cfg(unix)]
173    #[error("Unix socket path is not valid UTF-8")]
174    #[diagnostic(code(http_client::non_utf8_unix_socket_path))]
175    NonUtf8UnixSocketPath {
176        /// The underlying UTF-8 decoding error.
177        #[source]
178        source: std::string::FromUtf8Error,
179    },
180
181    /// The request URI's scheme is not supported on this platform.
182    #[error("unsupported URI scheme: {scheme:?}")]
183    #[diagnostic(code(http_client::unsupported_scheme))]
184    UnsupportedScheme {
185        /// The scheme from the request URI.
186        scheme: String,
187    },
188}