/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use interrupt_support::Interrupted; /// This enum is to discriminate `StorageHttpError`, and not used as an error. #[cfg(feature = "sync-client")] #[derive(Debug, Clone)] pub enum ErrorResponse { NotFound { route: String }, // 401 Unauthorized { route: String }, // 412 PreconditionFailed { route: String }, // 5XX ServerError { route: String, status: u16 }, // TODO: info for "retry-after" and backoff handling etc here. // Other HTTP responses. RequestFailed { route: String, status: u16 }, } pub type Result = std::result::Result; #[derive(Debug, thiserror::Error)] pub enum Error { #[cfg(feature = "crypto")] #[error("Key {0} had wrong length, got {1}, expected {2}")] BadKeyLength(&'static str, usize, usize), #[cfg(feature = "crypto")] #[error("SHA256 HMAC Mismatch error")] HmacMismatch, #[cfg(feature = "crypto")] #[error("Crypto/NSS error: {0}")] CryptoError(#[from] rc_crypto::Error), #[cfg(feature = "crypto")] #[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] std::string::FromUtf8Error), #[cfg(feature = "crypto")] #[error("HAWK error: {0}")] HawkError(#[from] rc_crypto::hawk::Error), // // Errors specific to this module. // #[cfg(feature = "sync-client")] #[error("HTTP status {0} when requesting a token from the tokenserver")] TokenserverHttpError(u16), #[cfg(feature = "sync-client")] #[error("HTTP storage error: {0:?}")] StorageHttpError(ErrorResponse), #[cfg(feature = "sync-client")] #[error("Server requested backoff. Retry after {0:?}")] BackoffError(std::time::SystemTime), #[cfg(feature = "sync-client")] #[error("Outgoing record is too large to upload")] RecordTooLargeError, // Do we want to record the concrete problems? #[cfg(feature = "sync-client")] #[error("Not all records were successfully uploaded")] RecordUploadFailed, /// Used for things like a node reassignment or an unexpected syncId /// implying the app needs to "reset" its understanding of remote storage. #[cfg(feature = "sync-client")] #[error("The server has reset the storage for this account")] StorageResetError, #[cfg(feature = "sync-client")] #[error("Unacceptable URL: {0}")] UnacceptableUrl(String), #[cfg(feature = "sync-client")] #[error("Missing server timestamp header in request")] MissingServerTimestamp, #[cfg(feature = "sync-client")] #[error("Unexpected server behavior during batch upload: {0}")] ServerBatchProblem(&'static str), #[cfg(feature = "sync-client")] #[error("It appears some other client is also trying to setup storage; try again later")] SetupRace, #[cfg(feature = "sync-client")] #[error("Client upgrade required; server storage version too new")] ClientUpgradeRequired, // This means that our global state machine needs to enter a state (such as // "FreshStartNeeded", but the allowed_states don't include that state.) // It typically means we are trying to do a "fast" or "read-only" sync. #[cfg(feature = "sync-client")] #[error("Our storage needs setting up and we can't currently do it")] SetupRequired, #[cfg(feature = "sync-client")] #[error("Store error: {0}")] StoreError(#[from] anyhow::Error), #[cfg(feature = "sync-client")] #[error("Network error: {0}")] RequestError(#[from] viaduct::Error), #[cfg(feature = "sync-client")] #[error("Unexpected HTTP status: {0}")] UnexpectedStatus(#[from] viaduct::UnexpectedStatus), #[cfg(feature = "sync-client")] #[error("URL parse error: {0}")] MalformedUrl(#[from] url::ParseError), #[error("The operation was interrupted.")] Interrupted(#[from] Interrupted), } #[cfg(feature = "sync-client")] impl Error { pub(crate) fn get_backoff(&self) -> Option { if let Error::BackoffError(time) = self { Some(*time) } else { None } } }