1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use interrupt_support::Interrupted;
use rc_crypto::hawk;
use std::string;
use std::time::SystemTime;
use sync15_traits::request::UnacceptableBaseUrl;
#[derive(Debug, Clone)]
pub enum ErrorResponse {
NotFound { route: String },
Unauthorized { route: String },
PreconditionFailed { route: String },
ServerError { route: String, status: u16 },
RequestFailed { route: String, status: u16 },
}
#[derive(Debug, thiserror::Error)]
pub enum ErrorKind {
#[error("Key {0} had wrong length, got {1}, expected {2}")]
BadKeyLength(&'static str, usize, usize),
#[error("SHA256 HMAC Mismatch error")]
HmacMismatch,
#[error("HTTP status {0} when requesting a token from the tokenserver")]
TokenserverHttpError(u16),
#[error("HTTP storage error: {0:?}")]
StorageHttpError(ErrorResponse),
#[error("Server requested backoff. Retry after {0:?}")]
BackoffError(SystemTime),
#[error("Outgoing record is too large to upload")]
RecordTooLargeError,
#[error("Not all records were successfully uploaded")]
RecordUploadFailed,
#[error("The server has reset the storage for this account")]
StorageResetError,
#[error("Unacceptable URL: {0}")]
UnacceptableUrl(String),
#[error("Missing server timestamp header in request")]
MissingServerTimestamp,
#[error("Unexpected server behavior during batch upload: {0}")]
ServerBatchProblem(&'static str),
#[error("It appears some other client is also trying to setup storage; try again later")]
SetupRace,
#[error("Client upgrade required; server storage version too new")]
ClientUpgradeRequired,
#[error("Our storage needs setting up and we can't currently do it")]
SetupRequired,
#[error("Store error: {0}")]
StoreError(#[from] anyhow::Error),
#[error("Crypto/NSS error: {0}")]
CryptoError(#[from] rc_crypto::Error),
#[error("Base64 decode error: {0}")]
Base64Decode(#[from] base64::DecodeError),
#[error("JSON error: {0}")]
JsonError(#[from] serde_json::Error),
#[error("Bad cleartext UTF8: {0}")]
BadCleartextUtf8(#[from] string::FromUtf8Error),
#[error("Network error: {0}")]
RequestError(#[from] viaduct::Error),
#[error("Unexpected HTTP status: {0}")]
UnexpectedStatus(#[from] viaduct::UnexpectedStatus),
#[error("HAWK error: {0}")]
HawkError(#[from] hawk::Error),
#[error("URL parse error: {0}")]
MalformedUrl(#[from] url::ParseError),
#[error("The operation was interrupted.")]
Interrupted(#[from] Interrupted),
}
error_support::define_error! {
ErrorKind {
(CryptoError, rc_crypto::Error),
(Base64Decode, base64::DecodeError),
(JsonError, serde_json::Error),
(BadCleartextUtf8, std::string::FromUtf8Error),
(RequestError, viaduct::Error),
(UnexpectedStatus, viaduct::UnexpectedStatus),
(MalformedUrl, url::ParseError),
(StoreError, anyhow::Error),
(Interrupted, Interrupted),
(HawkError, hawk::Error),
}
}
impl From<UnacceptableBaseUrl> for ErrorKind {
fn from(e: UnacceptableBaseUrl) -> ErrorKind {
ErrorKind::UnacceptableUrl(e.to_string())
}
}
impl From<UnacceptableBaseUrl> for Error {
fn from(e: UnacceptableBaseUrl) -> Self {
Error::from(ErrorKind::from(e))
}
}
impl Error {
pub(crate) fn get_backoff(&self) -> Option<SystemTime> {
if let ErrorKind::BackoffError(time) = self.kind() {
Some(*time)
} else {
None
}
}
}