jsonrpc/
error.rs

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