1use std::error;
4use std::fmt;
5
6use reqwest;
7use reqwest::StatusCode;
8use serde::{Deserialize, Serialize};
9
10pub type Result<T> = std::result::Result<T, FirebaseError>;
12
13#[derive(Debug)]
17pub enum FirebaseError {
18 Generic(&'static str),
20 UnexpectedResponse(&'static str, reqwest::StatusCode, String, String),
24 APIError(usize, String, String),
30 Request(reqwest::Error),
34 JWT(biscuit::errors::Error),
37 JWTValidation(biscuit::errors::ValidationError),
38 Ser {
40 doc: Option<String>,
41 ser: serde_json::Error,
42 },
43 SerdeVerbose {
45 doc: Option<String>,
46 input_doc: String,
47 ser: serde_json::Error,
48 },
49 RSA(ring::error::KeyRejected),
51 IO(std::io::Error),
53}
54
55impl std::convert::From<std::io::Error> for FirebaseError {
56 fn from(error: std::io::Error) -> Self {
57 FirebaseError::IO(error)
58 }
59}
60
61impl std::convert::From<ring::error::KeyRejected> for FirebaseError {
62 fn from(error: ring::error::KeyRejected) -> Self {
63 FirebaseError::RSA(error)
64 }
65}
66
67impl std::convert::From<serde_json::Error> for FirebaseError {
68 fn from(error: serde_json::Error) -> Self {
69 FirebaseError::Ser { doc: None, ser: error }
70 }
71}
72
73impl std::convert::From<biscuit::errors::Error> for FirebaseError {
74 fn from(error: biscuit::errors::Error) -> Self {
75 FirebaseError::JWT(error)
76 }
77}
78
79impl std::convert::From<biscuit::errors::ValidationError> for FirebaseError {
80 fn from(error: biscuit::errors::ValidationError) -> Self {
81 FirebaseError::JWTValidation(error)
82 }
83}
84
85impl std::convert::From<reqwest::Error> for FirebaseError {
86 fn from(error: reqwest::Error) -> Self {
87 FirebaseError::Request(error)
88 }
89}
90
91impl fmt::Display for FirebaseError {
92 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93 match self {
94 FirebaseError::Generic(m) => write!(f, "{}", m),
95 FirebaseError::APIError(code, m, context) => {
96 write!(f, "API Error! Code {} - {}. Context: {}", code, m, context)
97 }
98 FirebaseError::UnexpectedResponse(m, status, text, source) => {
99 writeln!(f, "{} - {}", &m, status)?;
100 writeln!(f, "{}", text)?;
101 writeln!(f, "{}", source)?;
102 Ok(())
103 }
104 FirebaseError::Request(e) => e.fmt(f),
105 FirebaseError::JWT(e) => e.fmt(f),
106 FirebaseError::JWTValidation(e) => e.fmt(f),
107 FirebaseError::RSA(e) => e.fmt(f),
108 FirebaseError::IO(e) => e.fmt(f),
109 FirebaseError::Ser { doc, ser } => {
110 if let Some(doc) = doc {
111 writeln!(f, "{} in document {}", ser, doc)
112 } else {
113 ser.fmt(f)
114 }
115 }
116 FirebaseError::SerdeVerbose { doc, input_doc, ser } => {
117 let doc = doc.clone().unwrap_or("Unknown document".to_string());
118 writeln!(
119 f,
120 "Serde deserialization failed for document '{}' with error '{}' on input: '{}'",
121 doc, ser, input_doc
122 )
123 }
124 }
125 }
126}
127
128impl error::Error for FirebaseError {
129 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
130 match *self {
131 FirebaseError::Generic(ref _m) => None,
132 FirebaseError::UnexpectedResponse(_, _, _, _) => None,
133 FirebaseError::APIError(_, _, _) => None,
134 FirebaseError::Request(ref e) => Some(e),
135 FirebaseError::JWT(ref e) => Some(e),
136 FirebaseError::JWTValidation(ref e) => Some(e),
137 FirebaseError::RSA(_) => None,
138 FirebaseError::IO(ref e) => Some(e),
139 FirebaseError::Ser { ref ser, .. } => Some(ser),
140 FirebaseError::SerdeVerbose { ref ser, .. } => Some(ser),
141 }
142 }
143}
144
145#[derive(Default, Serialize, Deserialize)]
146struct GoogleRESTApiError {
147 pub message: String,
148 pub domain: String,
149 pub reason: String,
150}
151
152#[derive(Default, Serialize, Deserialize)]
153struct GoogleRESTApiErrorInfo {
154 pub code: usize,
155 pub message: String,
156 pub errors: Option<Vec<GoogleRESTApiError>>,
157}
158
159#[derive(Default, Serialize, Deserialize)]
160struct GoogleRESTApiErrorWrapper {
161 pub error: Option<GoogleRESTApiErrorInfo>,
162}
163
164pub(crate) fn extract_google_api_error(
172 response: reqwest::blocking::Response,
173 context: impl Fn() -> String,
174) -> Result<reqwest::blocking::Response> {
175 if response.status() == 200 {
176 return Ok(response);
177 }
178
179 Err(extract_google_api_error_intern(
180 response.status().clone(),
181 response.text()?,
182 context,
183 ))
184}
185
186pub(crate) async fn extract_google_api_error_async(
194 response: reqwest::Response,
195 context: impl Fn() -> String,
196) -> Result<reqwest::Response> {
197 if response.status() == 200 {
198 return Ok(response);
199 }
200
201 Err(extract_google_api_error_intern(
202 response.status().clone(),
203 response.text().await?,
204 context,
205 ))
206}
207
208fn extract_google_api_error_intern(
209 status: StatusCode,
210 http_body: String,
211 context: impl Fn() -> String,
212) -> FirebaseError {
213 let google_api_error_wrapper: std::result::Result<GoogleRESTApiErrorWrapper, serde_json::Error> =
214 serde_json::from_str(&http_body);
215 if let Ok(google_api_error_wrapper) = google_api_error_wrapper {
216 if let Some(google_api_error) = google_api_error_wrapper.error {
217 return FirebaseError::APIError(google_api_error.code, google_api_error.message.to_owned(), context());
218 }
219 };
220
221 FirebaseError::UnexpectedResponse("", status, http_body, context())
222}