tokio_jsonrpc/
message.rs

1// Copyright 2017 tokio-jsonrpc Developers
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8//! JSON-RPC 2.0 messages.
9//!
10//! The main entrypoint here is the [Message](enum.Message.html). The others are just building
11//! blocks and you should generally work with `Message` instead.
12
13use std::fmt::{Formatter, Result as FmtResult};
14
15use serde::ser::{Serialize, SerializeStruct, Serializer};
16use serde::de::{Deserialize, Deserializer, Error, Unexpected, Visitor};
17use serde_json::{to_value, Result as JsonResult, Value};
18use uuid::Uuid;
19
20#[derive(Debug, Clone, PartialEq, Eq, Hash)]
21struct Version;
22
23impl Serialize for Version {
24    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
25        serializer.serialize_str("2.0")
26    }
27}
28
29impl<'de> Deserialize<'de> for Version {
30    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
31        struct VersionVisitor;
32        impl<'de> Visitor<'de> for VersionVisitor {
33            type Value = Version;
34
35            fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
36                formatter.write_str("a version string")
37            }
38
39            fn visit_str<E: Error>(self, value: &str) -> Result<Version, E> {
40                match value {
41                    "2.0" => Ok(Version),
42                    _ => Err(E::invalid_value(Unexpected::Str(value), &"value 2.0")),
43                }
44            }
45        }
46        deserializer.deserialize_str(VersionVisitor)
47    }
48}
49
50/// An RPC request.
51#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
52#[serde(deny_unknown_fields)]
53pub struct Request {
54    jsonrpc: Version,
55    pub method: String,
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub params: Option<Value>,
58    pub id: Value,
59}
60
61impl Request {
62    /// Answer the request with a (positive) reply.
63    ///
64    /// The ID is taken from the request.
65    pub fn reply(&self, reply: Value) -> Message {
66        Message::Response(Response {
67            jsonrpc: Version,
68            result: Ok(reply),
69            id: self.id.clone(),
70        })
71    }
72    /// Answer the request with an error.
73    pub fn error(&self, error: RpcError) -> Message {
74        Message::Response(Response {
75            jsonrpc: Version,
76            result: Err(error),
77            id: self.id.clone(),
78        })
79    }
80}
81
82/// An error code.
83#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
84#[serde(deny_unknown_fields)]
85pub struct RpcError {
86    pub code: i64,
87    pub message: String,
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub data: Option<Value>,
90}
91
92impl RpcError {
93    /// A generic constructor.
94    ///
95    /// Mostly for completeness, doesn't do anything but filling in the corresponding fields.
96    pub fn new(code: i64, message: String, data: Option<Value>) -> Self {
97        RpcError {
98            code,
99            message,
100            data,
101        }
102    }
103    /// Create an Invalid Param error.
104    pub fn invalid_params(msg: Option<String>) -> Self {
105        RpcError::new(-32_602, "Invalid params".to_owned(), msg.map(Value::String))
106    }
107    /// Create a server error.
108    pub fn server_error<E: Serialize>(e: Option<E>) -> Self {
109        RpcError::new(
110            -32_000,
111            "Server error".to_owned(),
112            e.map(|v| to_value(v).expect("Must be representable in JSON")),
113        )
114    }
115    /// Create an invalid request error.
116    pub fn invalid_request() -> Self {
117        RpcError::new(-32_600, "Invalid request".to_owned(), None)
118    }
119    /// Create a parse error.
120    pub fn parse_error(e: String) -> Self {
121        RpcError::new(-32_700, "Parse error".to_owned(), Some(Value::String(e)))
122    }
123    /// Create a method not found error.
124    pub fn method_not_found(method: String) -> Self {
125        RpcError::new(
126            -32_601,
127            "Method not found".to_owned(),
128            Some(Value::String(method)),
129        )
130    }
131}
132
133/// A response to an RPC.
134///
135/// It is created by the methods on [Request](struct.Request.html).
136#[derive(Debug, Clone, PartialEq)]
137pub struct Response {
138    jsonrpc: Version,
139    pub result: Result<Value, RpcError>,
140    pub id: Value,
141}
142
143impl Serialize for Response {
144    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
145        let mut sub = serializer.serialize_struct("Response", 3)?;
146        sub.serialize_field("jsonrpc", &self.jsonrpc)?;
147        match self.result {
148            Ok(ref value) => sub.serialize_field("result", value),
149            Err(ref err) => sub.serialize_field("error", err),
150        }?;
151        sub.serialize_field("id", &self.id)?;
152        sub.end()
153    }
154}
155
156/// Deserializer for `Option<Value>` that produces `Some(Value::Null)`.
157///
158/// The usual one produces None in that case. But we need to know the difference between
159/// `{x: null}` and `{}`.
160fn some_value<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Option<Value>, D::Error> {
161    Deserialize::deserialize(deserializer).map(Some)
162}
163
164/// A helper trick for deserialization.
165#[derive(Deserialize)]
166#[serde(deny_unknown_fields)]
167struct WireResponse {
168    // It is actually used to eat and sanity check the deserialized text
169    #[allow(dead_code)]
170    jsonrpc: Version,
171    // Make sure we accept null as Some(Value::Null), instead of going to None
172    #[serde(default, deserialize_with = "some_value")]
173    result: Option<Value>,
174    error: Option<RpcError>,
175    id: Value,
176}
177
178// Implementing deserialize is hard. We sidestep the difficulty by deserializing a similar
179// structure that directly corresponds to whatever is on the wire and then convert it to our more
180// convenient representation.
181impl<'de> Deserialize<'de> for Response {
182    #[allow(unreachable_code)] // For that unreachable below
183    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
184        let wr: WireResponse = Deserialize::deserialize(deserializer)?;
185        let result = match (wr.result, wr.error) {
186            (Some(res), None) => Ok(res),
187            (None, Some(err)) => Err(err),
188            _ => {
189                let err = D::Error::custom("Either 'error' or 'result' is expected, but not both");
190                return Err(err);
191            },
192        };
193        Ok(Response {
194            jsonrpc: Version,
195            result,
196            id: wr.id,
197        })
198    }
199}
200
201/// A notification (doesn't expect an answer).
202#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
203#[serde(deny_unknown_fields)]
204pub struct Notification {
205    jsonrpc: Version,
206    pub method: String,
207    #[serde(skip_serializing_if = "Option::is_none")]
208    pub params: Option<Value>,
209}
210
211/// One message of the JSON RPC protocol.
212///
213/// One message, directly mapped from the structures of the protocol. See the
214/// [specification](http://www.jsonrpc.org/specification) for more details.
215///
216/// Since the protocol allows one endpoint to be both client and server at the same time, the
217/// message can decode and encode both directions of the protocol.
218///
219/// The `Batch` variant is supposed to be created directly, without a constructor.
220///
221/// The `UnmatchedSub` variant is used when a request is an array and some of the subrequests
222/// aren't recognized as valid json rpc 2.0 messages. This is never returned as a top-level
223/// element, it is returned as `Err(Broken::Unmatched)`.
224#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
225#[serde(untagged)]
226pub enum Message {
227    /// An RPC request.
228    Request(Request),
229    /// A response to a Request.
230    Response(Response),
231    /// A notification.
232    Notification(Notification),
233    /// A batch of more requests or responses.
234    ///
235    /// The protocol allows bundling multiple requests, notifications or responses to a single
236    /// message.
237    ///
238    /// This variant has no direct constructor and is expected to be constructed manually.
239    Batch(Vec<Message>),
240    /// An unmatched sub entry in a `Batch`.
241    ///
242    /// When there's a `Batch` and an element doesn't comform to the JSONRPC 2.0 format, that one
243    /// is represented by this. This is never produced as a top-level value when parsing, the
244    /// `Err(Broken::Unmatched)` is used instead. It is not possible to serialize.
245    #[serde(skip_serializing)]
246    UnmatchedSub(Value),
247}
248
249impl Message {
250    /// A constructor for a request.
251    ///
252    /// The ID is auto-generated.
253    pub fn request(method: String, params: Option<Value>) -> Self {
254        Message::Request(Request {
255            jsonrpc: Version,
256            method,
257            params,
258            id: Value::String(Uuid::new_v4().hyphenated().to_string()),
259        })
260    }
261    /// Create a top-level error (without an ID).
262    pub fn error(error: RpcError) -> Self {
263        Message::Response(Response {
264            jsonrpc: Version,
265            result: Err(error),
266            id: Value::Null,
267        })
268    }
269    /// A constructor for a notification.
270    pub fn notification(method: String, params: Option<Value>) -> Self {
271        Message::Notification(Notification {
272            jsonrpc: Version,
273            method,
274            params,
275        })
276    }
277}
278
279/// A broken message.
280///
281/// Protocol-level errors.
282#[derive(Debug, Clone, PartialEq, Deserialize)]
283#[serde(untagged)]
284pub enum Broken {
285    /// It was valid JSON, but doesn't match the form of a JSONRPC 2.0 message.
286    Unmatched(Value),
287    /// Invalid JSON.
288    #[serde(skip_deserializing)]
289    SyntaxError(String),
290}
291
292impl Broken {
293    /// Generate an appropriate error message.
294    ///
295    /// The error message for these things are specified in the RFC, so this just creates an error
296    /// with the right values.
297    pub fn reply(&self) -> Message {
298        match *self {
299            Broken::Unmatched(_) => Message::error(RpcError::invalid_request()),
300            Broken::SyntaxError(ref e) => Message::error(RpcError::parse_error(e.clone())),
301        }
302    }
303}
304
305/// A trick to easily deserialize and detect valid JSON, but invalid Message.
306#[derive(Deserialize)]
307#[serde(untagged)]
308pub(crate) enum WireMessage {
309    Message(Message),
310    Broken(Broken),
311}
312
313pub(crate) fn decoded_to_parsed(res: JsonResult<WireMessage>) -> Parsed {
314    match res {
315        Ok(WireMessage::Message(Message::UnmatchedSub(value))) => Err(Broken::Unmatched(value)),
316        Ok(WireMessage::Message(m)) => Ok(m),
317        Ok(WireMessage::Broken(b)) => Err(b),
318        Err(e) => Err(Broken::SyntaxError(format!("{}", e))),
319    }
320}
321
322pub type Parsed = Result<Message, Broken>;
323
324/// Read a [Message](enum.Message.html) from a slice.
325///
326/// Invalid JSON or JSONRPC messages are reported as [Broken](enum.Broken.html).
327pub fn from_slice(s: &[u8]) -> Parsed {
328    decoded_to_parsed(::serde_json::de::from_slice(s))
329}
330
331/// Read a [Message](enum.Message.html) from a string.
332///
333/// Invalid JSON or JSONRPC messages are reported as [Broken](enum.Broken.html).
334pub fn from_str(s: &str) -> Parsed {
335    from_slice(s.as_bytes())
336}
337
338impl Into<String> for Message {
339    fn into(self) -> String {
340        ::serde_json::ser::to_string(&self).unwrap()
341    }
342}
343
344impl Into<Vec<u8>> for Message {
345    fn into(self) -> Vec<u8> {
346        ::serde_json::ser::to_vec(&self).unwrap()
347    }
348}
349
350#[cfg(test)]
351mod tests {
352    use super::*;
353    use serde_json::Value;
354    use serde_json::ser::to_vec;
355    use serde_json::de::from_slice;
356
357    /// Test serialization and deserialization of the Message
358    ///
359    /// We first deserialize it from a string. That way we check deserialization works.
360    /// But since serialization doesn't have to produce the exact same result (order, spaces, …),
361    /// we then serialize and deserialize the thing again and check it matches.
362    #[test]
363    fn message_serde() {
364        // A helper for running one message test
365        fn one(input: &str, expected: &Message) {
366            let parsed: Message = from_str(input).unwrap();
367            assert_eq!(*expected, parsed);
368            let serialized = to_vec(&parsed).unwrap();
369            let deserialized: Message = from_slice(&serialized).unwrap();
370            assert_eq!(parsed, deserialized);
371        }
372
373        // A request without parameters
374        one(
375            r#"{"jsonrpc": "2.0", "method": "call", "id": 1}"#,
376            &Message::Request(Request {
377                jsonrpc: Version,
378                method: "call".to_owned(),
379                params: None,
380                id: json!(1),
381            }),
382        );
383        // A request with parameters
384        one(
385            r#"{"jsonrpc": "2.0", "method": "call", "params": [1, 2, 3], "id": 2}"#,
386            &Message::Request(Request {
387                jsonrpc: Version,
388                method: "call".to_owned(),
389                params: Some(json!([1, 2, 3])),
390                id: json!(2),
391            }),
392        );
393        // A notification (with parameters)
394        one(
395            r#"{"jsonrpc": "2.0", "method": "notif", "params": {"x": "y"}}"#,
396            &Message::Notification(Notification {
397                jsonrpc: Version,
398                method: "notif".to_owned(),
399                params: Some(json!({"x": "y"})),
400            }),
401        );
402        // A successful response
403        one(
404            r#"{"jsonrpc": "2.0", "result": 42, "id": 3}"#,
405            &Message::Response(Response {
406                jsonrpc: Version,
407                result: Ok(json!(42)),
408                id: json!(3),
409            }),
410        );
411        // A successful response
412        one(
413            r#"{"jsonrpc": "2.0", "result": null, "id": 3}"#,
414            &Message::Response(Response {
415                jsonrpc: Version,
416                result: Ok(Value::Null),
417                id: json!(3),
418            }),
419        );
420        // An error
421        one(
422            r#"{"jsonrpc": "2.0", "error": {"code": 42, "message": "Wrong!"}, "id": null}"#,
423            &Message::Response(Response {
424                jsonrpc: Version,
425                result: Err(RpcError::new(42, "Wrong!".to_owned(), None)),
426                id: Value::Null,
427            }),
428        );
429        // A batch
430        one(
431            r#"[
432                {"jsonrpc": "2.0", "method": "notif"},
433                {"jsonrpc": "2.0", "method": "call", "id": 42}
434            ]"#,
435            &Message::Batch(vec![
436                Message::Notification(Notification {
437                    jsonrpc: Version,
438                    method: "notif".to_owned(),
439                    params: None,
440                }),
441                Message::Request(Request {
442                    jsonrpc: Version,
443                    method: "call".to_owned(),
444                    params: None,
445                    id: json!(42),
446                }),
447            ]),
448        );
449        // Some handling of broken messages inside a batch
450        let parsed = from_str(
451            r#"[
452                {"jsonrpc": "2.0", "method": "notif"},
453                {"jsonrpc": "2.0", "method": "call", "id": 42},
454                true
455            ]"#,
456        ).unwrap();
457        assert_eq!(
458            Message::Batch(vec![
459                Message::Notification(Notification {
460                    jsonrpc: Version,
461                    method: "notif".to_owned(),
462                    params: None,
463                }),
464                Message::Request(Request {
465                    jsonrpc: Version,
466                    method: "call".to_owned(),
467                    params: None,
468                    id: json!(42),
469                }),
470                Message::UnmatchedSub(Value::Bool(true)),
471            ]),
472            parsed
473        );
474        to_vec(&Message::UnmatchedSub(Value::Null)).unwrap_err();
475    }
476
477    /// A helper for the `broken` test.
478    ///
479    /// Check that the given JSON string parses, but is not recognized as a valid RPC message.
480
481    /// Test things that are almost but not entirely JSONRPC are rejected
482    ///
483    /// The reject is done by returning it as Unmatched.
484    #[test]
485    fn broken() {
486        // A helper with one test
487        fn one(input: &str) {
488            let msg = from_str(input);
489            match msg {
490                Err(Broken::Unmatched(_)) => (),
491                _ => panic!("{} recognized as an RPC message: {:?}!", input, msg),
492            }
493        }
494
495        // Missing the version
496        one(r#"{"method": "notif"}"#);
497        // Wrong version
498        one(r#"{"jsonrpc": 2.0, "method": "notif"}"#);
499        // A response with both result and error
500        one(r#"{"jsonrpc": "2.0", "result": 42, "error": {"code": 42, "message": "!"}, "id": 1}"#);
501        // A response without an id
502        one(r#"{"jsonrpc": "2.0", "result": 42}"#);
503        // An extra field
504        one(r#"{"jsonrpc": "2.0", "method": "weird", "params": 42, "others": 43, "id": 2}"#);
505        // Something completely different
506        one(r#"{"x": [1, 2, 3]}"#);
507
508        match from_str(r#"{]"#) {
509            Err(Broken::SyntaxError(_)) => (),
510            other => panic!("Something unexpected: {:?}", other),
511        };
512    }
513
514    /// Test some non-trivial aspects of the constructors
515    ///
516    /// This doesn't have a full coverage, because there's not much to actually test there.
517    /// Most of it is related to the ids.
518    #[test]
519    fn constructors() {
520        let msg1 = Message::request("call".to_owned(), Some(json!([1, 2, 3])));
521        let msg2 = Message::request("call".to_owned(), Some(json!([1, 2, 3])));
522        // They differ, even when created with the same parameters
523        assert_ne!(msg1, msg2);
524        // And, specifically, they differ in the ID's
525        let (req1, req2) = if let (Message::Request(req1), Message::Request(req2)) = (msg1, msg2) {
526            assert_ne!(req1.id, req2.id);
527            assert!(req1.id.is_string());
528            assert!(req2.id.is_string());
529            (req1, req2)
530        } else {
531            panic!("Non-request received");
532        };
533        let id1 = req1.id.clone();
534        // When we answer a message, we get the same ID
535        if let Message::Response(ref resp) = req1.reply(json!([1, 2, 3])) {
536            assert_eq!(
537                *resp,
538                Response {
539                    jsonrpc: Version,
540                    result: Ok(json!([1, 2, 3])),
541                    id: id1,
542                }
543            );
544        } else {
545            panic!("Not a response");
546        }
547        let id2 = req2.id.clone();
548        // The same with an error
549        if let Message::Response(ref resp) =
550            req2.error(RpcError::new(42, "Wrong!".to_owned(), None))
551        {
552            assert_eq!(
553                *resp,
554                Response {
555                    jsonrpc: Version,
556                    result: Err(RpcError::new(42, "Wrong!".to_owned(), None)),
557                    id: id2,
558                }
559            );
560        } else {
561            panic!("Not a response");
562        }
563        // When we have unmatched, we generate a top-level error with Null id.
564        if let Message::Response(ref resp) =
565            Message::error(RpcError::new(43, "Also wrong!".to_owned(), None))
566        {
567            assert_eq!(
568                *resp,
569                Response {
570                    jsonrpc: Version,
571                    result: Err(RpcError::new(43, "Also wrong!".to_owned(), None)),
572                    id: Value::Null,
573                }
574            );
575        } else {
576            panic!("Not a response");
577        }
578    }
579}