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
//! Types for handling errors.
//!
//! This crate uses [`error_chain`][1] for its error handling.
//!
//! [1]: https://docs.rs/error-chain

use std::fmt;
use std::error::Error as StdError;
use reqwest::StatusCode;

use reqwest::Error as ReqwestError;
use serde_json::Error as SerdeJsonError;
use serde::de::value::Error as ValueError;

error_chain! {
    foreign_links {
        Http(ReqwestError) #[doc = "An error from the `reqwest` crate."];
        
        Json(SerdeJsonError) #[doc = "An error from the `serde_json` crate."];
        
        Parse(ValueError) #[doc = "An error from the `serde::de` module."];
        
        Rest(RestError) #[doc = "An error from the ExtraHop appliance"];
    }
    
    errors {
        #[doc = "A string was provided that did not parse as a complete Authorization header, including the scheme and prefix"]
        ApiKeyParseError {
            description("The provided string was not a complete API key header including `ExtraHop apikey=`. Did you mean ApiKey::from?")
        }

        #[doc = "A query time string was provided that doesn't match the supported format in [`QueryTime`](../enum.QueryTime.html)."]
        QueryTimeParseError {
            description("The provided string was not a unitized time expression understood by the ExtraHop platform")
        }
    }
}

/// A 4xx or 5xx response from the ExtraHop appliance.
#[derive(Debug, Clone, PartialEq)]
pub struct RestError {
    status: StatusCode,
    body: Option<ErrorBody>,
}

impl RestError {
    /// Create a new REST API error.
    pub fn new<B: Into<Option<ErrorBody>>>(status: StatusCode, body: B) -> Self {
        RestError {
            status: status,
            body: body.into(),
        }
    }
    
    /// Gets the HTTP status code of the error.
    pub fn status(&self) -> StatusCode {
        self.status
    }
    
    /// Gets the body of the error, if one was provided in well-formed JSON.
    pub fn body(&self) -> Option<&ErrorBody> {
        self.body.as_ref()
    }
}

impl StdError for RestError {
    fn description(&self) -> &str {
        "ExtraHop appliance returned an error"
    }
    
    fn cause(&self) -> Option<&StdError> {
        None
    }
}

impl fmt::Display for RestError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}, {:?}", self.status, self.body)
    }
}

/// The body of an HTTP error response from the appliance.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ErrorBody {
    error_message: String,
}

impl ErrorBody {
    /// Gets the human-friendly message returned by the appliance.
    pub fn message(&self) -> &str {
        &self.error_message
    }
}