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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use hyper;

use std::error::Error;
use std::fmt;

use hyper_utils::{client_error, server_error};

/// An `Error` which can occur during the execution of a function. Depending on
/// which kind of error it is, it could signify that the function runtime is
/// compromised or it could just represent an issue with the way the caller
/// provided input data.
#[derive(Debug)]
pub struct FunctionError {
    kind: FunctionErrorKind,
    error: Box<Error + Send + Sync>,
}

impl FunctionError {
    fn new<E>(kind: FunctionErrorKind, error: E) -> FunctionError
    where
        E: Into<Box<Error + Send + Sync>>,
    {
        FunctionError {
            kind: kind,
            error: error.into(),
        }
    }

    /// Create a new error signifying that the input provided to the function
    /// was genuinely invalid.
    pub fn invalid_input<E>(error: E) -> FunctionError
    where
        E: Into<Box<Error + Send + Sync>>,
    {
        FunctionError::new(FunctionErrorKind::InvalidInput, error)
    }

    /// Create a new error signifying that the request provided to the function
    /// was genuinely bad (for example, headers or data were missing).
    pub fn bad_request<E>(error: E) -> FunctionError
    where
        E: Into<Box<Error + Send + Sync>>,
    {
        FunctionError::new(FunctionErrorKind::BadRequest, error)
    }

    /// Create a new error signifying that the initializer code for the function
    /// has failed; this error compromises the function runtime.
    pub fn initialization<E>(error: E) -> FunctionError
    where
        E: Into<Box<Error + Send + Sync>>,
    {
        FunctionError::new(FunctionErrorKind::InitializationError, error)
    }

    /// Create a new error signifying that the input/output coercion code has
    /// encountered an unrecoverable problem; this error compromises the
    /// function runtime.
    pub fn coercion<E>(error: E) -> FunctionError
    where
        E: Into<Box<Error + Send + Sync>>,
    {
        FunctionError::new(FunctionErrorKind::CoercionError, error)
    }

    /// Create a new error signifying that an i/o error has occurred while
    /// reading or writing the i/o streams; this error compromises the function
    /// runtime.
    pub fn io<E>(error: E) -> FunctionError
    where
        E: Into<Box<Error + Send + Sync>>,
    {
        FunctionError::new(FunctionErrorKind::IOError, error)
    }

    /// Create a new error representing a totally unexpected situation; this
    /// error compromises the function runtime.
    pub fn other<E>(error: E) -> FunctionError
    where
        E: Into<Box<Error + Send + Sync>>,
    {
        FunctionError::new(FunctionErrorKind::OtherError, error)
    }

    /// Returns true if the error can be reported to the user as a client error
    /// (a 400-series http error).
    pub fn is_user_error(&self) -> bool {
        self.kind.is_user_error()
    }
}

impl fmt::Display for FunctionError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self.error.fmt(fmt)
    }
}

impl Error for FunctionError {
    fn description(&self) -> &str {
        self.error.description()
    }

    fn cause(&self) -> Option<&Error> {
        self.error.cause()
    }
}

impl Into<hyper::Response> for FunctionError {
    fn into(self) -> hyper::Response {
        if self.is_user_error() {
            client_error(format!("{}", self.error).into_bytes())
        } else {
            server_error(format!("{}", self.error).into_bytes())
        }
    }
}

fn _assert_error_is_sync_send() {
    fn _is_sync_send<T: Sync + Send>() {}
    _is_sync_send::<FunctionError>();
}

/// A kind for function errors. Some of these errors can be reported to the
/// caller without compromising the function runtime, while others represent
/// situations in which the function runtime is compromised and must be shut
/// down.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
enum FunctionErrorKind {
    // User errors which can be reported without compromising the function
    /// Genuinely invalid input from the caller
    InvalidInput,
    /// Generic bad request
    BadRequest,

    // Internal errors which compromise the integrity of the function
    /// Unrecoverable error during initialization of the function
    InitializationError,
    /// Unrecoverable error during input/output coercion
    CoercionError,
    /// Unrecoverable error on input/output streams
    IOError,
    /// Unrecoverable generic error
    OtherError,
}

impl FunctionErrorKind {
    /// True if the error is a user error and can be reported as such.
    pub fn is_user_error(&self) -> bool {
        match *self {
            FunctionErrorKind::InvalidInput |
            FunctionErrorKind::BadRequest => true,
            _ => false,
        }
    }
}