arti_rpcserver/msgs/invalid.rs
1//! Variations on our message types used to give better diagnostics for
2//! unparsable requests.
3
4use tor_rpcbase as rpc;
5
6use super::{ReqMeta, RequestId};
7use crate::err::RequestParseError;
8
9/// An invalid approximation of a request.
10///
11/// If we can't deserialize a [`Request`](super::Request) properly,
12/// we try to deserialize it into
13/// _this_ structure so we can explain what was wrong with it.
14#[derive(Debug, serde::Deserialize)]
15pub(crate) struct InvalidRequest {
16 /// Possibly, an ID field.
17 ///
18 /// If we can't parse this, then there's no hope of giving back a cogent
19 /// response.
20 id: Option<Possibly<RequestId>>,
21 /// The object that was passed in, if any.
22 obj: Option<Possibly<rpc::ObjectId>>,
23 /// The metadata that was passed in, if any.
24 meta: Option<Possibly<ReqMeta>>,
25 /// The method that was passed in, if any.
26 method: Option<Possibly<String>>,
27 /// The params that were passed in, if any.
28 params: Option<serde_json::Value>,
29}
30
31/// Either a "good" value that we could deserialize as a `T`, or some "Bad" value that we couldn't.
32#[derive(Debug, serde::Deserialize)]
33#[serde(untagged)]
34enum Possibly<T> {
35 /// The value was deserialized as expected.
36 Good(T),
37 /// The value could not be deserialized as expected.
38 #[allow(dead_code)] // deserialize the Value; we may use it for error reporting some day
39 Bad(serde_json::Value),
40}
41
42impl InvalidRequest {
43 /// Return the ID for this request, if it has one.
44 pub(crate) fn id(&self) -> Option<&RequestId> {
45 match &self.id {
46 Some(Possibly::Good(id)) => Some(id),
47 _ => None,
48 }
49 }
50
51 /// Return an error explaining why this wasn't a valid request.
52 pub(crate) fn error(&self) -> RequestParseError {
53 use Possibly::*;
54 use RequestParseError as E;
55
56 match self.id {
57 None => return E::IdMissing,
58 Some(Bad(_)) => return E::IdType,
59 _ => {}
60 }
61
62 match self.obj {
63 None => return E::ObjMissing,
64 Some(Bad(_)) => return E::ObjType,
65 _ => {}
66 }
67
68 match &self.method {
69 None => return E::MethodMissing,
70 Some(Bad(_)) => return E::MethodType,
71 Some(Good(name)) if !rpc::is_method_name(name) => return E::NoSuchMethod,
72 _ => {}
73 }
74
75 if matches!(self.meta, Some(Bad(_))) {
76 return E::MetaType;
77 }
78
79 if self.params.is_none() {
80 return E::MissingParams;
81 }
82
83 E::ParamType
84 }
85}