1 use crate::codec::{SendError, UserError};
2 use crate::frame::StreamId;
3 use crate::proto::{self, Initiator};
4 
5 use bytes::Bytes;
6 use std::{error, fmt, io};
7 
8 pub use crate::frame::Reason;
9 
10 /// Represents HTTP/2 operation errors.
11 ///
12 /// `Error` covers error cases raised by protocol errors caused by the
13 /// peer, I/O (transport) errors, and errors caused by the user of the library.
14 ///
15 /// If the error was caused by the remote peer, then it will contain a
16 /// [`Reason`] which can be obtained with the [`reason`] function.
17 ///
18 /// [`Reason`]: struct.Reason.html
19 /// [`reason`]: #method.reason
20 #[derive(Debug)]
21 pub struct Error {
22     kind: Kind,
23 }
24 
25 #[derive(Debug)]
26 enum Kind {
27     /// A RST_STREAM frame was received or sent.
28     Reset(StreamId, Reason, Initiator),
29 
30     /// A GO_AWAY frame was received or sent.
31     GoAway(Bytes, Reason, Initiator),
32 
33     /// The user created an error from a bare Reason.
34     Reason(Reason),
35 
36     /// An error resulting from an invalid action taken by the user of this
37     /// library.
38     User(UserError),
39 
40     /// An `io::Error` occurred while trying to read or write.
41     Io(io::Error),
42 }
43 
44 // ===== impl Error =====
45 
46 impl Error {
47     /// If the error was caused by the remote peer, the error reason.
48     ///
49     /// This is either an error received by the peer or caused by an invalid
50     /// action taken by the peer (i.e. a protocol error).
reason(&self) -> Option<Reason>51     pub fn reason(&self) -> Option<Reason> {
52         match self.kind {
53             Kind::Reset(_, reason, _) | Kind::GoAway(_, reason, _) | Kind::Reason(reason) => {
54                 Some(reason)
55             }
56             _ => None,
57         }
58     }
59 
60     /// Returns the true if the error is an io::Error
is_io(&self) -> bool61     pub fn is_io(&self) -> bool {
62         match self.kind {
63             Kind::Io(_) => true,
64             _ => false,
65         }
66     }
67 
68     /// Returns the error if the error is an io::Error
get_io(&self) -> Option<&io::Error>69     pub fn get_io(&self) -> Option<&io::Error> {
70         match self.kind {
71             Kind::Io(ref e) => Some(e),
72             _ => None,
73         }
74     }
75 
76     /// Returns the error if the error is an io::Error
into_io(self) -> Option<io::Error>77     pub fn into_io(self) -> Option<io::Error> {
78         match self.kind {
79             Kind::Io(e) => Some(e),
80             _ => None,
81         }
82     }
83 
from_io(err: io::Error) -> Self84     pub(crate) fn from_io(err: io::Error) -> Self {
85         Error {
86             kind: Kind::Io(err),
87         }
88     }
89 }
90 
91 impl From<proto::Error> for Error {
from(src: proto::Error) -> Error92     fn from(src: proto::Error) -> Error {
93         use crate::proto::Error::*;
94 
95         Error {
96             kind: match src {
97                 Reset(stream_id, reason, initiator) => Kind::Reset(stream_id, reason, initiator),
98                 GoAway(debug_data, reason, initiator) => {
99                     Kind::GoAway(debug_data, reason, initiator)
100                 }
101                 Io(kind, inner) => {
102                     Kind::Io(inner.map_or_else(|| kind.into(), |inner| io::Error::new(kind, inner)))
103                 }
104             },
105         }
106     }
107 }
108 
109 impl From<Reason> for Error {
from(src: Reason) -> Error110     fn from(src: Reason) -> Error {
111         Error {
112             kind: Kind::Reason(src),
113         }
114     }
115 }
116 
117 impl From<SendError> for Error {
from(src: SendError) -> Error118     fn from(src: SendError) -> Error {
119         match src {
120             SendError::User(e) => e.into(),
121             SendError::Connection(e) => e.into(),
122         }
123     }
124 }
125 
126 impl From<UserError> for Error {
from(src: UserError) -> Error127     fn from(src: UserError) -> Error {
128         Error {
129             kind: Kind::User(src),
130         }
131     }
132 }
133 
134 impl fmt::Display for Error {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result135     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
136         let debug_data = match self.kind {
137             Kind::Reset(_, reason, Initiator::User) => {
138                 return write!(fmt, "stream error sent by user: {}", reason)
139             }
140             Kind::Reset(_, reason, Initiator::Library) => {
141                 return write!(fmt, "stream error detected: {}", reason)
142             }
143             Kind::Reset(_, reason, Initiator::Remote) => {
144                 return write!(fmt, "stream error received: {}", reason)
145             }
146             Kind::GoAway(ref debug_data, reason, Initiator::User) => {
147                 write!(fmt, "connection error sent by user: {}", reason)?;
148                 debug_data
149             }
150             Kind::GoAway(ref debug_data, reason, Initiator::Library) => {
151                 write!(fmt, "connection error detected: {}", reason)?;
152                 debug_data
153             }
154             Kind::GoAway(ref debug_data, reason, Initiator::Remote) => {
155                 write!(fmt, "connection error received: {}", reason)?;
156                 debug_data
157             }
158             Kind::Reason(reason) => return write!(fmt, "protocol error: {}", reason),
159             Kind::User(ref e) => return write!(fmt, "user error: {}", e),
160             Kind::Io(ref e) => return e.fmt(fmt),
161         };
162 
163         if !debug_data.is_empty() {
164             write!(fmt, " ({:?})", debug_data)?;
165         }
166 
167         Ok(())
168     }
169 }
170 
171 impl error::Error for Error {}
172 
173 #[cfg(test)]
174 mod tests {
175     use super::Error;
176     use crate::Reason;
177 
178     #[test]
error_from_reason()179     fn error_from_reason() {
180         let err = Error::from(Reason::HTTP_1_1_REQUIRED);
181         assert_eq!(err.reason(), Some(Reason::HTTP_1_1_REQUIRED));
182     }
183 }
184