parquet_format_safe/thrift/
errors.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::collections::TryReserveError;
19use std::convert::{From, Into};
20use std::convert::{Infallible, TryFrom};
21use std::fmt::{Debug, Display, Formatter};
22use std::{error, fmt, io, string};
23
24use crate::thrift::protocol::{
25    TFieldIdentifier, TInputProtocol, TOutputProtocol, TStructIdentifier, TType,
26};
27
28// FIXME: should all my error structs impl error::Error as well?
29// FIXME: should all fields in TransportError, ProtocolError and ApplicationError be optional?
30
31/// Error type returned by all runtime library functions.
32///
33/// `thrift::Error` is used throughout this crate as well as in auto-generated
34/// Rust code. It consists of four variants defined by convention across Thrift
35/// implementations:
36///
37/// 1. `Transport`: errors encountered while operating on I/O channels
38/// 2. `Protocol`: errors encountered during runtime-library processing
39/// 3. `Application`: errors encountered within auto-generated code
40/// 4. `User`: IDL-defined exception structs
41///
42/// The `Application` variant also functions as a catch-all: all handler errors
43/// are automatically turned into application errors.
44///
45/// All error variants except `Error::User` take an eponymous struct with two
46/// required fields:
47///
48/// 1. `kind`: variant-specific enum identifying the error sub-type
49/// 2. `message`: human-readable error info string
50///
51/// `kind` is defined by convention while `message` is freeform. If none of the
52/// enumerated kinds are suitable use `Unknown`.
53///
54/// To simplify error creation convenience constructors are defined for all
55/// variants, and conversions from their structs (`thrift::TransportError`,
56/// `thrift::ProtocolError` and `thrift::ApplicationError` into `thrift::Error`.
57pub enum Error {
58    /// Errors encountered while operating on I/O channels.
59    ///
60    /// These include *connection closed* and *bind failure*.
61    Transport(TransportError),
62    /// Errors encountered during runtime-library processing.
63    ///
64    /// These include *message too large* and *unsupported protocol version*.
65    Protocol(ProtocolError),
66    /// Errors encountered within auto-generated code, or when incoming
67    /// or outgoing messages violate the Thrift spec.
68    ///
69    /// These include *out-of-order messages* and *missing required struct
70    /// fields*.
71    ///
72    /// This variant also functions as a catch-all: errors from handler
73    /// functions are automatically returned as an `ApplicationError`.
74    Application(ApplicationError),
75}
76
77impl Error {
78    /// Create an `ApplicationError` from its wire representation.
79    ///
80    /// Application code **should never** call this method directly.
81    pub fn read_application_error_from_in_protocol<T: TInputProtocol>(
82        i: &mut T,
83    ) -> crate::thrift::Result<ApplicationError> {
84        let mut message = "general remote error".to_owned();
85        let mut kind = ApplicationErrorKind::Unknown;
86
87        i.read_struct_begin()?;
88
89        loop {
90            let field_ident = i.read_field_begin()?;
91
92            if field_ident.field_type == TType::Stop {
93                break;
94            }
95
96            let id = field_ident
97                .id
98                .expect("sender should always specify id for non-STOP field");
99
100            match id {
101                1 => {
102                    let remote_message = i.read_string()?;
103                    i.read_field_end()?;
104                    message = remote_message;
105                }
106                2 => {
107                    let remote_type_as_int = i.read_i32()?;
108                    let remote_kind: ApplicationErrorKind = TryFrom::try_from(remote_type_as_int)
109                        .unwrap_or(ApplicationErrorKind::Unknown);
110                    i.read_field_end()?;
111                    kind = remote_kind;
112                }
113                _ => {
114                    i.skip(field_ident.field_type)?;
115                }
116            }
117        }
118
119        i.read_struct_end()?;
120
121        Ok(ApplicationError { kind, message })
122    }
123
124    /// Convert an `ApplicationError` into its wire representation and write
125    /// it to the remote.
126    ///
127    /// Application code **should never** call this method directly.
128    pub fn write_application_error_to_out_protocol(
129        e: &ApplicationError,
130        o: &mut dyn TOutputProtocol,
131    ) -> crate::thrift::Result<()> {
132        o.write_struct_begin(&TStructIdentifier {
133            name: "TApplicationException".to_owned(),
134        })?;
135
136        let message_field = TFieldIdentifier::new("message", TType::String, 1);
137        let type_field = TFieldIdentifier::new("type", TType::I32, 2);
138
139        o.write_field_begin(&message_field)?;
140        o.write_string(&e.message)?;
141        o.write_field_end()?;
142
143        o.write_field_begin(&type_field)?;
144        o.write_i32(e.kind as i32)?;
145        o.write_field_end()?;
146
147        o.write_field_stop()?;
148        o.write_struct_end()?;
149
150        o.flush()
151    }
152}
153
154impl error::Error for Error {}
155
156impl Debug for Error {
157    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
158        match *self {
159            Error::Transport(ref e) => Debug::fmt(e, f),
160            Error::Protocol(ref e) => Debug::fmt(e, f),
161            Error::Application(ref e) => Debug::fmt(e, f),
162        }
163    }
164}
165
166impl Display for Error {
167    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
168        match *self {
169            Error::Transport(ref e) => Display::fmt(e, f),
170            Error::Protocol(ref e) => Display::fmt(e, f),
171            Error::Application(ref e) => Display::fmt(e, f),
172        }
173    }
174}
175
176impl From<String> for Error {
177    fn from(s: String) -> Self {
178        Error::Application(ApplicationError {
179            kind: ApplicationErrorKind::Unknown,
180            message: s,
181        })
182    }
183}
184
185impl<'a> From<&'a str> for Error {
186    fn from(s: &'a str) -> Self {
187        Error::Application(ApplicationError {
188            kind: ApplicationErrorKind::Unknown,
189            message: String::from(s),
190        })
191    }
192}
193
194impl From<TransportError> for Error {
195    fn from(e: TransportError) -> Self {
196        Error::Transport(e)
197    }
198}
199
200impl From<ProtocolError> for Error {
201    fn from(e: ProtocolError) -> Self {
202        Error::Protocol(e)
203    }
204}
205
206impl From<ApplicationError> for Error {
207    fn from(e: ApplicationError) -> Self {
208        Error::Application(e)
209    }
210}
211
212/// Create a new `Error` instance of type `Transport` that wraps a
213/// `TransportError`.
214pub fn new_transport_error<S: Into<String>>(kind: TransportErrorKind, message: S) -> Error {
215    Error::Transport(TransportError::new(kind, message))
216}
217
218/// Information about I/O errors.
219#[derive(Debug, Eq, PartialEq)]
220pub struct TransportError {
221    /// I/O error variant.
222    ///
223    /// If a specific `TransportErrorKind` does not apply use
224    /// `TransportErrorKind::Unknown`.
225    pub kind: TransportErrorKind,
226    /// Human-readable error message.
227    pub message: String,
228}
229
230impl TransportError {
231    /// Create a new `TransportError`.
232    pub fn new<S: Into<String>>(kind: TransportErrorKind, message: S) -> TransportError {
233        TransportError {
234            kind,
235            message: message.into(),
236        }
237    }
238}
239
240/// I/O error categories.
241///
242/// This list may grow, and it is not recommended to match against it.
243#[non_exhaustive]
244#[derive(Clone, Copy, Eq, Debug, PartialEq)]
245pub enum TransportErrorKind {
246    /// Catch-all I/O error.
247    Unknown = 0,
248    /// An I/O operation was attempted when the transport channel was not open.
249    NotOpen = 1,
250    /// The transport channel cannot be opened because it was opened previously.
251    AlreadyOpen = 2,
252    /// An I/O operation timed out.
253    TimedOut = 3,
254    /// A read could not complete because no bytes were available.
255    EndOfFile = 4,
256    /// An invalid (buffer/message) size was requested or received.
257    NegativeSize = 5,
258    /// Too large a buffer or message size was requested or received.
259    SizeLimit = 6,
260}
261
262impl Display for TransportError {
263    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
264        let error_text = match self.kind {
265            TransportErrorKind::Unknown => "transport error",
266            TransportErrorKind::NotOpen => "not open",
267            TransportErrorKind::AlreadyOpen => "already open",
268            TransportErrorKind::TimedOut => "timed out",
269            TransportErrorKind::EndOfFile => "end of file",
270            TransportErrorKind::NegativeSize => "negative size message",
271            TransportErrorKind::SizeLimit => "message too long",
272        };
273
274        write!(f, "{}", error_text)
275    }
276}
277
278impl TryFrom<i32> for TransportErrorKind {
279    type Error = Error;
280    fn try_from(from: i32) -> Result<Self, Self::Error> {
281        match from {
282            0 => Ok(TransportErrorKind::Unknown),
283            1 => Ok(TransportErrorKind::NotOpen),
284            2 => Ok(TransportErrorKind::AlreadyOpen),
285            3 => Ok(TransportErrorKind::TimedOut),
286            4 => Ok(TransportErrorKind::EndOfFile),
287            5 => Ok(TransportErrorKind::NegativeSize),
288            6 => Ok(TransportErrorKind::SizeLimit),
289            _ => Err(Error::Protocol(ProtocolError {
290                kind: ProtocolErrorKind::Unknown,
291                message: format!("cannot convert {} to TransportErrorKind", from),
292            })),
293        }
294    }
295}
296
297impl From<io::Error> for Error {
298    fn from(err: io::Error) -> Self {
299        match err.kind() {
300            io::ErrorKind::ConnectionReset
301            | io::ErrorKind::ConnectionRefused
302            | io::ErrorKind::NotConnected => Error::Transport(TransportError {
303                kind: TransportErrorKind::NotOpen,
304                message: err.to_string(),
305            }),
306            io::ErrorKind::AlreadyExists => Error::Transport(TransportError {
307                kind: TransportErrorKind::AlreadyOpen,
308                message: err.to_string(),
309            }),
310            io::ErrorKind::TimedOut => Error::Transport(TransportError {
311                kind: TransportErrorKind::TimedOut,
312                message: err.to_string(),
313            }),
314            io::ErrorKind::UnexpectedEof => Error::Transport(TransportError {
315                kind: TransportErrorKind::EndOfFile,
316                message: err.to_string(),
317            }),
318            _ => {
319                Error::Transport(TransportError {
320                    kind: TransportErrorKind::Unknown,
321                    message: err.to_string(), // FIXME: use io error's debug string
322                })
323            }
324        }
325    }
326}
327
328impl From<string::FromUtf8Error> for Error {
329    fn from(err: string::FromUtf8Error) -> Self {
330        Error::Protocol(ProtocolError {
331            kind: ProtocolErrorKind::InvalidData,
332            message: err.to_string(), // FIXME: use fmt::Error's debug string
333        })
334    }
335}
336
337impl From<std::num::TryFromIntError> for Error {
338    fn from(err: std::num::TryFromIntError) -> Self {
339        Error::Protocol(ProtocolError {
340            kind: ProtocolErrorKind::InvalidData,
341            message: err.to_string(),
342        })
343    }
344}
345
346impl From<TryReserveError> for Error {
347    fn from(err: TryReserveError) -> Self {
348        Error::Protocol(ProtocolError {
349            kind: ProtocolErrorKind::SizeLimit,
350            message: err.to_string(),
351        })
352    }
353}
354
355impl From<Infallible> for Error {
356    fn from(err: Infallible) -> Self {
357        Error::Protocol(ProtocolError {
358            kind: ProtocolErrorKind::InvalidData,
359            message: err.to_string(),
360        })
361    }
362}
363
364/// Create a new `Error` instance of type `Protocol` that wraps a
365/// `ProtocolError`.
366pub fn new_protocol_error<S: Into<String>>(kind: ProtocolErrorKind, message: S) -> Error {
367    Error::Protocol(ProtocolError::new(kind, message))
368}
369
370/// Information about errors that occur in the runtime library.
371#[derive(Debug, Eq, PartialEq)]
372pub struct ProtocolError {
373    /// Protocol error variant.
374    ///
375    /// If a specific `ProtocolErrorKind` does not apply use
376    /// `ProtocolErrorKind::Unknown`.
377    pub kind: ProtocolErrorKind,
378    /// Human-readable error message.
379    pub message: String,
380}
381
382impl ProtocolError {
383    /// Create a new `ProtocolError`.
384    pub fn new<S: Into<String>>(kind: ProtocolErrorKind, message: S) -> ProtocolError {
385        ProtocolError {
386            kind,
387            message: message.into(),
388        }
389    }
390}
391
392/// Runtime library error categories.
393///
394/// This list may grow, and it is not recommended to match against it.
395#[non_exhaustive]
396#[derive(Clone, Copy, Eq, Debug, PartialEq)]
397pub enum ProtocolErrorKind {
398    /// Catch-all runtime-library error.
399    Unknown = 0,
400    /// An invalid argument was supplied to a library function, or invalid data
401    /// was received from a Thrift endpoint.
402    InvalidData = 1,
403    /// An invalid size was received in an encoded field.
404    NegativeSize = 2,
405    /// Thrift message or field was too long.
406    SizeLimit = 3,
407    /// Unsupported or unknown Thrift protocol version.
408    BadVersion = 4,
409    /// Unsupported Thrift protocol, server or field type.
410    NotImplemented = 5,
411    /// Reached the maximum nested depth to which an encoded Thrift field could
412    /// be skipped.
413    DepthLimit = 6,
414}
415
416impl Display for ProtocolError {
417    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
418        let error_text = match self.kind {
419            ProtocolErrorKind::Unknown => "protocol error",
420            ProtocolErrorKind::InvalidData => "bad data",
421            ProtocolErrorKind::NegativeSize => "negative message size",
422            ProtocolErrorKind::SizeLimit => "message too long",
423            ProtocolErrorKind::BadVersion => "invalid thrift version",
424            ProtocolErrorKind::NotImplemented => "not implemented",
425            ProtocolErrorKind::DepthLimit => "maximum skip depth reached",
426        };
427
428        write!(f, "{}", error_text)
429    }
430}
431
432impl TryFrom<i32> for ProtocolErrorKind {
433    type Error = Error;
434    fn try_from(from: i32) -> Result<Self, Self::Error> {
435        match from {
436            0 => Ok(ProtocolErrorKind::Unknown),
437            1 => Ok(ProtocolErrorKind::InvalidData),
438            2 => Ok(ProtocolErrorKind::NegativeSize),
439            3 => Ok(ProtocolErrorKind::SizeLimit),
440            4 => Ok(ProtocolErrorKind::BadVersion),
441            5 => Ok(ProtocolErrorKind::NotImplemented),
442            6 => Ok(ProtocolErrorKind::DepthLimit),
443            _ => Err(Error::Protocol(ProtocolError {
444                kind: ProtocolErrorKind::Unknown,
445                message: format!("cannot convert {} to ProtocolErrorKind", from),
446            })),
447        }
448    }
449}
450
451/// Create a new `Error` instance of type `Application` that wraps an
452/// `ApplicationError`.
453pub fn new_application_error<S: Into<String>>(kind: ApplicationErrorKind, message: S) -> Error {
454    Error::Application(ApplicationError::new(kind, message))
455}
456
457/// Information about errors in auto-generated code or in user-implemented
458/// service handlers.
459#[derive(Debug, Eq, PartialEq)]
460pub struct ApplicationError {
461    /// Application error variant.
462    ///
463    /// If a specific `ApplicationErrorKind` does not apply use
464    /// `ApplicationErrorKind::Unknown`.
465    pub kind: ApplicationErrorKind,
466    /// Human-readable error message.
467    pub message: String,
468}
469
470impl ApplicationError {
471    /// Create a new `ApplicationError`.
472    pub fn new<S: Into<String>>(kind: ApplicationErrorKind, message: S) -> ApplicationError {
473        ApplicationError {
474            kind,
475            message: message.into(),
476        }
477    }
478}
479
480/// Auto-generated or user-implemented code error categories.
481///
482/// This list may grow, and it is not recommended to match against it.
483#[non_exhaustive]
484#[derive(Clone, Copy, Debug, Eq, PartialEq)]
485pub enum ApplicationErrorKind {
486    /// Catch-all application error.
487    Unknown = 0,
488    /// Made service call to an unknown service method.
489    UnknownMethod = 1,
490    /// Received an unknown Thrift message type. That is, not one of the
491    /// `thrift::protocol::TMessageType` variants.
492    InvalidMessageType = 2,
493    /// Method name in a service reply does not match the name of the
494    /// receiving service method.
495    WrongMethodName = 3,
496    /// Received an out-of-order Thrift message.
497    BadSequenceId = 4,
498    /// Service reply is missing required fields.
499    MissingResult = 5,
500    /// Auto-generated code failed unexpectedly.
501    InternalError = 6,
502    /// Thrift protocol error. When possible use `Error::ProtocolError` with a
503    /// specific `ProtocolErrorKind` instead.
504    ProtocolError = 7,
505    /// *Unknown*. Included only for compatibility with existing Thrift implementations.
506    InvalidTransform = 8, // ??
507    /// Thrift endpoint requested, or is using, an unsupported encoding.
508    InvalidProtocol = 9, // ??
509    /// Thrift endpoint requested, or is using, an unsupported auto-generated client type.
510    UnsupportedClientType = 10, // ??
511}
512
513impl Display for ApplicationError {
514    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
515        let error_text = match self.kind {
516            ApplicationErrorKind::Unknown => "service error",
517            ApplicationErrorKind::UnknownMethod => "unknown service method",
518            ApplicationErrorKind::InvalidMessageType => "wrong message type received",
519            ApplicationErrorKind::WrongMethodName => "unknown method reply received",
520            ApplicationErrorKind::BadSequenceId => "out of order sequence id",
521            ApplicationErrorKind::MissingResult => "missing method result",
522            ApplicationErrorKind::InternalError => "remote service threw exception",
523            ApplicationErrorKind::ProtocolError => "protocol error",
524            ApplicationErrorKind::InvalidTransform => "invalid transform",
525            ApplicationErrorKind::InvalidProtocol => "invalid protocol requested",
526            ApplicationErrorKind::UnsupportedClientType => "unsupported protocol client",
527        };
528
529        write!(f, "{}", error_text)
530    }
531}
532
533impl TryFrom<i32> for ApplicationErrorKind {
534    type Error = Error;
535    fn try_from(from: i32) -> Result<Self, Self::Error> {
536        match from {
537            0 => Ok(ApplicationErrorKind::Unknown),
538            1 => Ok(ApplicationErrorKind::UnknownMethod),
539            2 => Ok(ApplicationErrorKind::InvalidMessageType),
540            3 => Ok(ApplicationErrorKind::WrongMethodName),
541            4 => Ok(ApplicationErrorKind::BadSequenceId),
542            5 => Ok(ApplicationErrorKind::MissingResult),
543            6 => Ok(ApplicationErrorKind::InternalError),
544            7 => Ok(ApplicationErrorKind::ProtocolError),
545            8 => Ok(ApplicationErrorKind::InvalidTransform),
546            9 => Ok(ApplicationErrorKind::InvalidProtocol),
547            10 => Ok(ApplicationErrorKind::UnsupportedClientType),
548            _ => Err(Error::Application(ApplicationError {
549                kind: ApplicationErrorKind::Unknown,
550                message: format!("cannot convert {} to ApplicationErrorKind", from),
551            })),
552        }
553    }
554}