1use std::{error::Error as StdError, fmt};
2
3use serde::Deserialize;
4use serde_json::{Map, Value};
5
6#[derive(Debug)]
13#[non_exhaustive]
14pub enum Error {
15 Http(HttpError),
17 Server(ServerError),
20 Parse(ParseError),
22}
23
24impl fmt::Display for Error {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 match self {
27 Error::Http(error) => error.fmt(f),
28 Error::Server(error) => error.fmt(f),
29 Error::Parse(error) => error.fmt(f),
30 }
31 }
32}
33
34impl StdError for Error {
35 fn source(&self) -> Option<&(dyn StdError + 'static)> {
36 match self {
37 Error::Http(error) => Some(error),
38 Error::Server(error) => Some(error),
39 Error::Parse(error) => Some(error),
40 }
41 }
42}
43
44#[derive(Debug)]
47pub struct HttpError(pub(crate) HttpErrorKind);
48
49#[derive(Debug)]
50pub(crate) enum HttpErrorKind {
51 #[cfg(feature = "reqwest")]
52 Reqwest(reqwest::Error),
53}
54
55impl fmt::Display for HttpError {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 let _ = f;
58 match self.0 {
59 #[cfg(feature = "reqwest")]
60 HttpErrorKind::Reqwest(ref error) => write!(f, "http request failed: {error}"),
61 }
62 }
63}
64
65impl StdError for HttpError {
66 fn source(&self) -> Option<&(dyn StdError + 'static)> {
67 match self.0 {
68 #[cfg(feature = "reqwest")]
69 HttpErrorKind::Reqwest(ref error) => Some(error),
70 }
71 }
72}
73
74#[derive(Debug)]
77pub struct ServerError {
78 code: ErrorCode,
79 description: Option<String>,
80 uri: Option<String>,
81 status: u16,
82 extra: Map<String, Value>,
83}
84
85impl ServerError {
86 pub fn code(&self) -> &ErrorCode {
88 &self.code
89 }
90
91 pub fn description(&self) -> Option<&str> {
93 self.description.as_deref()
94 }
95
96 pub fn uri(&self) -> Option<&str> {
98 self.uri.as_deref()
99 }
100
101 pub fn status(&self) -> u16 {
103 self.status
104 }
105
106 pub fn extra_field<T: serde::de::DeserializeOwned>(&self, key: &str) -> Option<T> {
108 let value = self.extra.get(key)?;
109 serde_json::from_value(value.clone()).ok()
110 }
111}
112
113impl fmt::Display for ServerError {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 write!(
116 f,
117 "server returned error \"{}\" (status {})",
118 self.code, self.status
119 )?;
120 if let Some(description) = &self.description {
121 write!(f, ": {description}")?;
122 }
123 Ok(())
124 }
125}
126
127impl StdError for ServerError {}
128
129#[derive(Debug, Clone, PartialEq, Eq)]
131#[non_exhaustive]
132pub enum ErrorCode {
133 InvalidRequest,
134 InvalidClient,
135 InvalidGrant,
136 UnauthorizedClient,
137 UnsupportedGrantType,
138 InvalidScope,
139 Other(String),
141}
142
143impl ErrorCode {
144 pub fn as_str(&self) -> &str {
146 match self {
147 ErrorCode::InvalidRequest => "invalid_request",
148 ErrorCode::InvalidClient => "invalid_client",
149 ErrorCode::InvalidGrant => "invalid_grant",
150 ErrorCode::UnauthorizedClient => "unauthorized_client",
151 ErrorCode::UnsupportedGrantType => "unsupported_grant_type",
152 ErrorCode::InvalidScope => "invalid_scope",
153 ErrorCode::Other(code) => code,
154 }
155 }
156
157 fn from_wire(code: String) -> Self {
158 match code.as_str() {
159 "invalid_request" => ErrorCode::InvalidRequest,
160 "invalid_client" => ErrorCode::InvalidClient,
161 "invalid_grant" => ErrorCode::InvalidGrant,
162 "unauthorized_client" => ErrorCode::UnauthorizedClient,
163 "unsupported_grant_type" => ErrorCode::UnsupportedGrantType,
164 "invalid_scope" => ErrorCode::InvalidScope,
165 _ => ErrorCode::Other(code),
166 }
167 }
168}
169
170impl fmt::Display for ErrorCode {
171 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172 f.write_str(self.as_str())
173 }
174}
175
176#[derive(Deserialize)]
178pub(crate) struct ServerErrorWire {
179 error: String,
180 #[serde(default)]
181 error_description: Option<String>,
182 #[serde(default)]
183 error_uri: Option<String>,
184 #[serde(flatten)]
185 extra: Map<String, Value>,
186}
187
188impl ServerErrorWire {
189 pub(crate) fn into_server_error(self, status: u16) -> ServerError {
190 ServerError {
191 code: ErrorCode::from_wire(self.error),
192 description: self.error_description,
193 uri: self.error_uri,
194 status,
195 extra: self.extra,
196 }
197 }
198}
199
200pub struct ParseError {
207 pub(crate) url: String,
208 pub(crate) status: u16,
209 pub(crate) content_type: Option<String>,
210 pub(crate) body: Vec<u8>,
211 pub(crate) source: serde_json::Error,
212}
213
214impl ParseError {
215 pub fn url(&self) -> &str {
217 &self.url
218 }
219
220 pub fn status(&self) -> u16 {
222 self.status
223 }
224
225 pub fn content_type(&self) -> Option<&str> {
227 self.content_type.as_deref()
228 }
229
230 pub fn body(&self) -> &[u8] {
232 &self.body
233 }
234}
235
236impl fmt::Debug for ParseError {
237 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
238 f.debug_struct("ParseError")
239 .field("url", &self.url)
240 .field("status", &self.status)
241 .field("content_type", &self.content_type)
242 .field(
243 "body",
244 &format_args!("[redacted, {} bytes]", self.body.len()),
245 )
246 .field("source", &self.source)
247 .finish()
248 }
249}
250
251impl fmt::Display for ParseError {
252 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253 write!(
254 f,
255 "could not parse response from \"{}\" (status {}, content-type {}, {} bytes): {}",
256 self.url,
257 self.status,
258 self.content_type.as_deref().unwrap_or("unknown"),
259 self.body.len(),
260 self.source
261 )
262 }
263}
264
265impl StdError for ParseError {
266 fn source(&self) -> Option<&(dyn StdError + 'static)> {
267 Some(&self.source)
268 }
269}