1
//! Internal: Declare an Error type for tor-bytes
2

            
3
use std::borrow::Cow;
4
use std::num::NonZeroUsize;
5

            
6
use derive_deftly::{Deftly, define_derive_deftly};
7
use safelog::Sensitive;
8
use thiserror::Error;
9
use tor_error::{Bug, into_internal};
10

            
11
define_derive_deftly! {
12
    /// `impl PartialEq for Error`
13
    PartialEqForError expect items:
14

            
15
    impl PartialEq for $ttype {
16
2513
        fn eq(&self, other: &Self) -> bool {
17
            match (self, other) {
18
              $(
19
                ${when not(vmeta(never_eq))}
20
                #[allow(deprecated)]
21
                (${vpat fprefix=a_}, ${vpat fprefix=b_}) => {
22
                  $(
23
                    if $<a_ $fname> != $<b_ $fname> { return false; }
24
                  )
25
                    return true;
26
                },
27
              )
28
                (_, _) => false,
29
            }
30
        }
31
    }
32
}
33

            
34
/// Error type for decoding Tor objects from bytes.
35
//
36
// TODO(nickm): This error type could use a redesign: it doesn't do a good job
37
// of preserving context.  At the least it should say what kind of object it
38
// found any given problem in.
39
#[derive(Error, Debug, Clone, Deftly)]
40
#[derive_deftly(PartialEqForError)]
41
#[non_exhaustive]
42
pub enum Error {
43
    /// Something was truncated
44
    ///
45
    /// It might be an inner data structure, or the outer message being parsed.
46
    #[deprecated(since = "0.22.0", note = "Use Reader::incomplete_error instead.")]
47
    #[error("something was truncated (maybe inner structure, maybe outer message)")]
48
    Truncated,
49
    /// Tried to read something, but we didn't find enough bytes.
50
    ///
51
    /// This can means that the outer object is truncated.
52
    /// Possibly we need to read more and try again,
53
    ///
54
    /// This error is only returned by [`Reader`](crate::Reader)s created with
55
    /// [`from_possibly_incomplete_slice`](crate::Reader::from_possibly_incomplete_slice).
56
    ///
57
    /// # Do not directly construct this variant
58
    ///
59
    /// It is usually a bug to explicitly construct this variant.
60
    /// Use [`Reader::incomplete_error`](crate::Reader::incomplete_error) instead.
61
    ///
62
    /// In tests using
63
    /// [`Reader::from_slice_for_test`](crate::Reader::from_slice_for_test),
64
    /// use [`Error::new_incomplete_for_test`].
65
    #[error("Object truncated (or not fully present), at least {deficit} more bytes needed")]
66
    Incomplete {
67
        /// Lower bound on number of additional bytes needed
68
        deficit: Sensitive<NonZeroUsize>,
69
    },
70
    /// Called Reader::should_be_exhausted(), but found bytes anyway.
71
    #[error("Extra bytes at end of object")]
72
    ExtraneousBytes,
73
    /// Invalid length value
74
    #[error("Object length too large to represent as usize")]
75
    BadLengthValue,
76
    /// An attempt to parse an object failed for some reason related to its
77
    /// contents.
78
    #[deprecated(since = "0.6.2", note = "Use InvalidMessage instead.")]
79
    #[error("Bad object: {0}")]
80
    BadMessage(&'static str),
81
    /// An attempt to parse an object failed for some reason related to its
82
    /// contents.
83
    ///
84
    /// # General case, more specific variants also exist
85
    ///
86
    /// This variant is used when encountering parsing trouble
87
    /// for which there is no more specific variant.
88
    ///
89
    /// Other variants can occur when deserialising malformed messages.
90
    /// for example (but not necessarily only):
91
    /// [`ExtraneousBytes`](Error::ExtraneousBytes),
92
    /// [`MissingData`](Error::MissingData), and
93
    /// [`BadLengthValue`](Error::BadLengthValue).
94
    #[error("Bad object: {0}")]
95
    InvalidMessage(Cow<'static, str>),
96
    /// The message contains data which is too short (perhaps in an inner counted section)
97
    ///
98
    /// # Usually, do not directly construct this variant
99
    ///
100
    /// It is often a bug to explicitly construct this variant.
101
    /// Consider [`Reader::incomplete_error`](crate::Reader::incomplete_error) instead.
102
    ///
103
    /// (It can be appropriate in test cases,
104
    /// or during bespoke parsing of an inner substructure.)
105
    #[error("message (or inner portion) too short")]
106
    MissingData,
107
    /// A parsing error that should never happen.
108
    ///
109
    /// We use this one in lieu of calling assert() and expect() and
110
    /// unwrap() from within parsing code.
111
    #[error("Internal error")]
112
    #[deftly(never_eq)] // an internal error is equal to nothing, not even itself.
113
    Bug(#[from] tor_error::Bug),
114
    /// Using for reader.rs::take_until_with_limit
115
    /// If we reach the limit before finding the terminator, we return this error.
116
    #[error("Reached limit of {limit} bytes while searching for terminator 0x{terminator:02x}")]
117
    LimitExceeded {
118
        /// Maximum number of bytes that were allowed to read
119
        limit: usize,
120
        /// The terminator byte we were looking for
121
        terminator: u8,
122
    },
123
}
124

            
125
impl Error {
126
    /// Make an [`Error::Incomplete`] with a specified deficit
127
    ///
128
    /// Suitable for use in tests.
129
    ///
130
    /// # Panics
131
    ///
132
    /// Panics if the specified `deficit` is zero.
133
626
    pub fn new_incomplete_for_test(deficit: usize) -> Self {
134
626
        let deficit = NonZeroUsize::new(deficit)
135
626
            .expect("zero deficit in assert!")
136
626
            .into();
137
626
        Error::Incomplete { deficit }
138
626
    }
139
}
140

            
141
/// Error type for encoding Tor objects to bytes.
142
#[derive(Error, Debug, Clone)]
143
#[non_exhaustive]
144
pub enum EncodeError {
145
    /// We tried to encode an object with an attached length, but the length was
146
    /// too large to encode in the available space.
147
    #[error("Object length too large to encode")]
148
    BadLengthValue,
149
    /// A parsing error that should never happen.
150
    ///
151
    /// We use this variant instead of calling assert() and expect() and
152
    /// unwrap() from within encoding implementations.
153
    #[error("Internal error")]
154
    Bug(#[from] Bug),
155
}
156

            
157
impl EncodeError {
158
    /// Converts this error into a [`Bug`]
159
    ///
160
    /// Use when any encoding error is a bug.
161
    //
162
    // TODO: should this be a `From` impl or would that be too error-prone?
163
    #[deprecated(note = "please use the `From<EncodeError>` trait for `Bug` instead")]
164
    pub fn always_bug(self) -> Bug {
165
        match self {
166
            EncodeError::Bug(bug) => bug,
167
            EncodeError::BadLengthValue => into_internal!("EncodingError")(self),
168
        }
169
    }
170
}
171

            
172
// This trait is used to convert any encoding error into a bug
173
impl From<EncodeError> for Bug {
174
    fn from(error: EncodeError) -> Bug {
175
        match error {
176
            EncodeError::Bug(bug) => bug,
177
            EncodeError::BadLengthValue => into_internal!("EncodingError")(error),
178
        }
179
    }
180
}