jsonrpc_async/
error.rs

1// Rust JSON-RPC Library
2// Written in 2015 by
3//     Andrew Poelstra <apoelstra@wpsoftware.net>
4//
5// To the extent possible under law, the author(s) have dedicated all
6// copyright and related and neighboring rights to this software to
7// the public domain worldwide. This software is distributed without
8// any warranty.
9//
10// You should have received a copy of the CC0 Public Domain Dedication
11// along with this software.
12// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
13//
14
15//! # Error handling
16//!
17//! Some useful methods for creating Error objects
18//!
19
20use std::{error, fmt};
21
22use serde::{Deserialize, Serialize};
23use serde_derive::*;
24use serde_json;
25
26use super::Response;
27
28/// A library error
29#[derive(Debug)]
30pub enum Error {
31    /// A transport error
32    Transport(Box<dyn error::Error + Send + Sync>),
33    /// Json error
34    Json(serde_json::Error),
35    /// Error response
36    Rpc(RpcError),
37    /// Response to a request did not have the expected nonce
38    NonceMismatch,
39    /// Response to a request had a jsonrpc field other than "2.0"
40    VersionMismatch,
41    /// Batches can't be empty
42    EmptyBatch,
43    /// Too many responses returned in batch
44    WrongBatchResponseSize,
45    /// Batch response contained a duplicate ID
46    BatchDuplicateResponseId(serde_json::Value),
47    /// Batch response contained an ID that didn't correspond to any request ID
48    WrongBatchResponseId(serde_json::Value),
49}
50
51impl From<serde_json::Error> for Error {
52    fn from(e: serde_json::Error) -> Error {
53        Error::Json(e)
54    }
55}
56
57impl From<RpcError> for Error {
58    fn from(e: RpcError) -> Error {
59        Error::Rpc(e)
60    }
61}
62
63impl fmt::Display for Error {
64    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65        match *self {
66            Error::Transport(ref e) => write!(f, "transport error: {}", e),
67            Error::Json(ref e) => write!(f, "JSON decode error: {}", e),
68            Error::Rpc(ref r) => write!(f, "RPC error response: {:?}", r),
69            Error::BatchDuplicateResponseId(ref v) => {
70                write!(f, "duplicate RPC batch response ID: {}", v)
71            }
72            Error::WrongBatchResponseId(ref v) => write!(f, "wrong RPC batch response ID: {}", v),
73            Error::NonceMismatch => write!(f, "Nonce of response did not match nonce of request"),
74            Error::VersionMismatch => write!(f, "`jsonrpc` field set to non-\"2.0\""),
75            Error::EmptyBatch => write!(f, "batches can't be empty"),
76            Error::WrongBatchResponseSize => write!(f, "too many responses returned in batch"),
77        }
78    }
79}
80
81impl error::Error for Error {
82    fn cause(&self) -> Option<&dyn error::Error> {
83        match *self {
84            Error::Transport(ref e) => Some(&**e),
85            Error::Json(ref e) => Some(e),
86            _ => None,
87        }
88    }
89}
90
91/// Standard error responses, as described at at
92/// http://www.jsonrpc.org/specification#error_object
93///
94/// # Documentation Copyright
95/// Copyright (C) 2007-2010 by the JSON-RPC Working Group
96///
97/// This document and translations of it may be used to implement JSON-RPC, it
98/// may be copied and furnished to others, and derivative works that comment
99/// on or otherwise explain it or assist in its implementation may be prepared,
100/// copied, published and distributed, in whole or in part, without restriction
101/// of any kind, provided that the above copyright notice and this paragraph
102/// are included on all such copies and derivative works. However, this document
103/// itself may not be modified in any way.
104///
105/// The limited permissions granted above are perpetual and will not be revoked.
106///
107/// This document and the information contained herein is provided "AS IS" and
108/// ALL WARRANTIES, EXPRESS OR IMPLIED are DISCLAIMED, INCLUDING BUT NOT LIMITED
109/// TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY
110/// RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
111/// PARTICULAR PURPOSE.
112///
113#[derive(Debug)]
114pub enum StandardError {
115    /// Invalid JSON was received by the server.
116    /// An error occurred on the server while parsing the JSON text.
117    ParseError,
118    /// The JSON sent is not a valid Request object.
119    InvalidRequest,
120    /// The method does not exist / is not available.
121    MethodNotFound,
122    /// Invalid method parameter(s).
123    InvalidParams,
124    /// Internal JSON-RPC error.
125    InternalError,
126}
127
128#[derive(Clone, Debug, Deserialize, Serialize)]
129/// A JSONRPC error object
130pub struct RpcError {
131    /// The integer identifier of the error
132    pub code: i32,
133    /// A string describing the error
134    pub message: String,
135    /// Additional data specific to the error
136    pub data: Option<Box<serde_json::value::RawValue>>,
137}
138
139/// Create a standard error responses
140pub fn standard_error(
141    code: StandardError,
142    data: Option<Box<serde_json::value::RawValue>>,
143) -> RpcError {
144    match code {
145        StandardError::ParseError => RpcError {
146            code: -32700,
147            message: "Parse error".to_string(),
148            data: data,
149        },
150        StandardError::InvalidRequest => RpcError {
151            code: -32600,
152            message: "Invalid Request".to_string(),
153            data: data,
154        },
155        StandardError::MethodNotFound => RpcError {
156            code: -32601,
157            message: "Method not found".to_string(),
158            data: data,
159        },
160        StandardError::InvalidParams => RpcError {
161            code: -32602,
162            message: "Invalid params".to_string(),
163            data: data,
164        },
165        StandardError::InternalError => RpcError {
166            code: -32603,
167            message: "Internal error".to_string(),
168            data: data,
169        },
170    }
171}
172
173/// Converts a Rust `Result` to a JSONRPC response object
174pub fn result_to_response(
175    result: Result<serde_json::Value, RpcError>,
176    id: serde_json::Value,
177) -> Response {
178    match result {
179        Ok(data) => Response {
180            result: Some(
181                serde_json::value::RawValue::from_string(serde_json::to_string(&data).unwrap())
182                    .unwrap(),
183            ),
184            error: None,
185            id: id,
186            jsonrpc: Some(String::from("2.0")),
187        },
188        Err(err) => Response {
189            result: None,
190            error: Some(err),
191            id: id,
192            jsonrpc: Some(String::from("2.0")),
193        },
194    }
195}
196
197#[cfg(test)]
198mod tests {
199    use super::StandardError::{
200        InternalError, InvalidParams, InvalidRequest, MethodNotFound, ParseError,
201    };
202    use super::{result_to_response, standard_error};
203    use serde_json;
204
205    #[test]
206    fn test_parse_error() {
207        let resp = result_to_response(Err(standard_error(ParseError, None)), From::from(1));
208        assert!(resp.result.is_none());
209        assert!(resp.error.is_some());
210        assert_eq!(resp.id, serde_json::Value::from(1));
211        assert_eq!(resp.error.unwrap().code, -32700);
212    }
213
214    #[test]
215    fn test_invalid_request() {
216        let resp = result_to_response(Err(standard_error(InvalidRequest, None)), From::from(1));
217        assert!(resp.result.is_none());
218        assert!(resp.error.is_some());
219        assert_eq!(resp.id, serde_json::Value::from(1));
220        assert_eq!(resp.error.unwrap().code, -32600);
221    }
222
223    #[test]
224    fn test_method_not_found() {
225        let resp = result_to_response(Err(standard_error(MethodNotFound, None)), From::from(1));
226        assert!(resp.result.is_none());
227        assert!(resp.error.is_some());
228        assert_eq!(resp.id, serde_json::Value::from(1));
229        assert_eq!(resp.error.unwrap().code, -32601);
230    }
231
232    #[test]
233    fn test_invalid_params() {
234        let resp = result_to_response(Err(standard_error(InvalidParams, None)), From::from("123"));
235        assert!(resp.result.is_none());
236        assert!(resp.error.is_some());
237        assert_eq!(resp.id, serde_json::Value::from("123"));
238        assert_eq!(resp.error.unwrap().code, -32602);
239    }
240
241    #[test]
242    fn test_internal_error() {
243        let resp = result_to_response(Err(standard_error(InternalError, None)), From::from(-1));
244        assert!(resp.result.is_none());
245        assert!(resp.error.is_some());
246        assert_eq!(resp.id, serde_json::Value::from(-1));
247        assert_eq!(resp.error.unwrap().code, -32603);
248    }
249}