1//! Variations on our message types used to give better diagnostics for
2//! unparsable requests.
34use tor_rpcbase as rpc;
56use super::{ReqMeta, RequestId};
7use crate::err::RequestParseError;
89/// 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.
20id: Option<Possibly<RequestId>>,
21/// The object that was passed in, if any.
22obj: Option<Possibly<rpc::ObjectId>>,
23/// The metadata that was passed in, if any.
24meta: Option<Possibly<ReqMeta>>,
25/// The method that was passed in, if any.
26method: Option<Possibly<String>>,
27/// The params that were passed in, if any.
28params: Option<serde_json::Value>,
29}
3031/// 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.
36Good(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
39Bad(serde_json::Value),
40}
4142impl InvalidRequest {
43/// Return the ID for this request, if it has one.
44pub(crate) fn id(&self) -> Option<&RequestId> {
45match &self.id {
46Some(Possibly::Good(id)) => Some(id),
47_ => None,
48 }
49 }
5051/// Return an error explaining why this wasn't a valid request.
52pub(crate) fn error(&self) -> RequestParseError {
53use Possibly::*;
54use RequestParseError as E;
5556match self.id {
57None => return E::IdMissing,
58Some(Bad(_)) => return E::IdType,
59_ => {}
60 }
6162match self.obj {
63None => return E::ObjMissing,
64Some(Bad(_)) => return E::ObjType,
65_ => {}
66 }
6768match &self.method {
69None => return E::MethodMissing,
70Some(Bad(_)) => return E::MethodType,
71Some(Good(name)) if !rpc::is_method_name(name) => return E::NoSuchMethod,
72_ => {}
73 }
7475if matches!(self.meta, Some(Bad(_))) {
76return E::MetaType;
77 }
7879if self.params.is_none() {
80return E::MissingParams;
81 }
8283 E::ParamType
84 }
85}