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}