Import upstream v0.16.22, stripped
Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f Enterprise-only files removed or emptied: 63 Enterprise-only snippets removed: 117 in 50 files Dangling module declarations removed: 5 Cargo edits turning enterprise off: 14 Verification: clean Enterprise feature gates left for rebuilt features: 19 in 18 files Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
This commit is contained in:
@@ -0,0 +1,948 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use super::{
|
||||
Call, Request, RequestMethod,
|
||||
method::{MethodFunction, MethodName, MethodObject},
|
||||
};
|
||||
use crate::request::{
|
||||
CopyRequestMethod, GetRequestMethod, ParseRequestMethod, QueryChangesRequestMethod,
|
||||
QueryRequestMethod, SetRequestMethod, deserialize::DeserializeArguments,
|
||||
};
|
||||
use serde::{
|
||||
Deserialize, Deserializer,
|
||||
de::{self, SeqAccess, Visitor},
|
||||
};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
impl<'x> Request<'x> {
|
||||
pub fn parse(json: &'x [u8], max_calls: usize, max_size: usize) -> trc::Result<Self> {
|
||||
if json.len() <= max_size {
|
||||
match serde_json::from_slice::<Request>(json) {
|
||||
Ok(request) => {
|
||||
if request.method_calls.len() <= max_calls {
|
||||
Ok(request)
|
||||
} else {
|
||||
Err(trc::LimitEvent::CallsIn.into_err())
|
||||
}
|
||||
}
|
||||
Err(err) => Err(trc::JmapEvent::NotRequest
|
||||
.into_err()
|
||||
.reason(err.to_string())
|
||||
.details(String::from_utf8_lossy(json).into_owned())),
|
||||
}
|
||||
} else {
|
||||
Err(trc::LimitEvent::SizeRequest.into_err())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> DeserializeArguments<'de> for Request<'de> {
|
||||
fn deserialize_argument<A>(&mut self, key: &str, map: &mut A) -> Result<(), A::Error>
|
||||
where
|
||||
A: serde::de::MapAccess<'de>,
|
||||
{
|
||||
hashify::fnc_map!(key.as_bytes(),
|
||||
b"using" => {
|
||||
self.using = map.next_value()?;
|
||||
},
|
||||
b"methodCalls" => {
|
||||
self.method_calls = map.next_value()?;
|
||||
},
|
||||
b"createdIds" => {
|
||||
self.created_ids = map.next_value()?;
|
||||
},
|
||||
_ => {
|
||||
let _ = map.next_value::<serde::de::IgnoredAny>()?;
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct CallVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for CallVisitor {
|
||||
type Value = Call<RequestMethod<'de>>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("an array with 3 elements")
|
||||
}
|
||||
|
||||
fn visit_seq<V>(self, mut seq: V) -> Result<Call<RequestMethod<'de>>, V::Error>
|
||||
where
|
||||
V: SeqAccess<'de>,
|
||||
{
|
||||
let method_name = seq
|
||||
.next_element::<std::borrow::Cow<str>>()?
|
||||
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
|
||||
let name = match MethodName::parse(method_name.as_ref()) {
|
||||
Some(name) => name,
|
||||
None => {
|
||||
// Ignore the rest of the call
|
||||
let _ = seq
|
||||
.next_element::<serde::de::IgnoredAny>()?
|
||||
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
|
||||
let id = seq
|
||||
.next_element::<String>()?
|
||||
.ok_or_else(|| de::Error::invalid_length(2, &self))?;
|
||||
|
||||
return Ok(Call {
|
||||
id,
|
||||
method: RequestMethod::Error(
|
||||
trc::JmapEvent::UnknownMethod
|
||||
.into_err()
|
||||
.details(method_name.to_string()),
|
||||
),
|
||||
name: MethodName::error(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let method = match (&name.fnc, &name.obj) {
|
||||
(MethodFunction::Get, MethodObject::Email) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Email(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Get, MethodObject::Mailbox) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Mailbox(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Get, MethodObject::Thread) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Thread(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Get, MethodObject::Identity) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Identity(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Get, MethodObject::EmailSubmission) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::EmailSubmission(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Get, MethodObject::PushSubscription) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::PushSubscription(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Get, MethodObject::VacationResponse) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::VacationResponse(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Get, MethodObject::SieveScript) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Sieve(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Get, MethodObject::Principal) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Principal(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Get, MethodObject::Quota) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Quota(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Get, MethodObject::Blob) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Blob(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Get, MethodObject::Calendar) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Calendar(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Get, MethodObject::CalendarEvent) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::CalendarEvent(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Get, MethodObject::CalendarEventNotification) => {
|
||||
match seq.next_element() {
|
||||
Ok(Some(value)) => {
|
||||
RequestMethod::Get(GetRequestMethod::CalendarEventNotification(value))
|
||||
}
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
}
|
||||
}
|
||||
(MethodFunction::Get, MethodObject::ParticipantIdentity) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::ParticipantIdentity(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Get, MethodObject::AddressBook) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::AddressBook(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Get, MethodObject::ContactCard) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::ContactCard(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Get, MethodObject::FileNode) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::FileNode(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Get, MethodObject::ShareNotification) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::ShareNotification(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Get, MethodObject::SearchSnippet) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::SearchSnippet(value),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Get, MethodObject::Registry(_)) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Get(GetRequestMethod::Registry(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Set, MethodObject::Email) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::Email(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Set, MethodObject::Mailbox) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::Mailbox(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Set, MethodObject::Identity) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::Identity(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Set, MethodObject::EmailSubmission) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::EmailSubmission(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Set, MethodObject::PushSubscription) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::PushSubscription(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Set, MethodObject::VacationResponse) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::VacationResponse(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Set, MethodObject::SieveScript) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::Sieve(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Set, MethodObject::Calendar) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::Calendar(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Set, MethodObject::CalendarEvent) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::CalendarEvent(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Set, MethodObject::CalendarEventNotification) => {
|
||||
match seq.next_element() {
|
||||
Ok(Some(value)) => {
|
||||
RequestMethod::Set(SetRequestMethod::CalendarEventNotification(value))
|
||||
}
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
}
|
||||
}
|
||||
(MethodFunction::Set, MethodObject::ParticipantIdentity) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::ParticipantIdentity(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Set, MethodObject::AddressBook) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::AddressBook(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Set, MethodObject::ContactCard) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::ContactCard(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Set, MethodObject::FileNode) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::FileNode(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Set, MethodObject::ShareNotification) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::ShareNotification(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Set, MethodObject::Registry(_)) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Set(SetRequestMethod::Registry(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Query, MethodObject::Email) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::Email(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Query, MethodObject::Mailbox) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::Mailbox(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Query, MethodObject::EmailSubmission) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::EmailSubmission(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Query, MethodObject::SieveScript) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::Sieve(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Query, MethodObject::Principal) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::Principal(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Query, MethodObject::Quota) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::Quota(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Query, MethodObject::Calendar) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::Calendar(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Query, MethodObject::CalendarEvent) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::CalendarEvent(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Query, MethodObject::CalendarEventNotification) => {
|
||||
match seq.next_element() {
|
||||
Ok(Some(value)) => {
|
||||
RequestMethod::Query(QueryRequestMethod::CalendarEventNotification(value))
|
||||
}
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
}
|
||||
}
|
||||
(MethodFunction::Query, MethodObject::AddressBook) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::AddressBook(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Query, MethodObject::ContactCard) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::ContactCard(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Query, MethodObject::FileNode) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::FileNode(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Query, MethodObject::ShareNotification) => match seq.next_element() {
|
||||
Ok(Some(value)) => {
|
||||
RequestMethod::Query(QueryRequestMethod::ShareNotification(value))
|
||||
}
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Query, MethodObject::Registry(_)) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Query(QueryRequestMethod::Registry(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::QueryChanges, MethodObject::Email) => match seq.next_element() {
|
||||
Ok(Some(value)) => {
|
||||
RequestMethod::QueryChanges(QueryChangesRequestMethod::Email(value))
|
||||
}
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::QueryChanges, MethodObject::Mailbox) => match seq.next_element() {
|
||||
Ok(Some(value)) => {
|
||||
RequestMethod::QueryChanges(QueryChangesRequestMethod::Mailbox(value))
|
||||
}
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::QueryChanges, MethodObject::EmailSubmission) => {
|
||||
match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::QueryChanges(
|
||||
QueryChangesRequestMethod::EmailSubmission(value),
|
||||
),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
}
|
||||
}
|
||||
(MethodFunction::QueryChanges, MethodObject::Principal) => match seq.next_element() {
|
||||
Ok(Some(value)) => {
|
||||
RequestMethod::QueryChanges(QueryChangesRequestMethod::Principal(value))
|
||||
}
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::QueryChanges, MethodObject::Quota) => match seq.next_element() {
|
||||
Ok(Some(value)) => {
|
||||
RequestMethod::QueryChanges(QueryChangesRequestMethod::Quota(value))
|
||||
}
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::QueryChanges, MethodObject::CalendarEvent) => match seq.next_element()
|
||||
{
|
||||
Ok(Some(value)) => {
|
||||
RequestMethod::QueryChanges(QueryChangesRequestMethod::CalendarEvent(value))
|
||||
}
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::QueryChanges, MethodObject::CalendarEventNotification) => {
|
||||
match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::QueryChanges(
|
||||
QueryChangesRequestMethod::CalendarEventNotification(value),
|
||||
),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
}
|
||||
}
|
||||
(MethodFunction::QueryChanges, MethodObject::ContactCard) => match seq.next_element() {
|
||||
Ok(Some(value)) => {
|
||||
RequestMethod::QueryChanges(QueryChangesRequestMethod::ContactCard(value))
|
||||
}
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::QueryChanges, MethodObject::FileNode) => match seq.next_element() {
|
||||
Ok(Some(value)) => {
|
||||
RequestMethod::QueryChanges(QueryChangesRequestMethod::FileNode(value))
|
||||
}
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::QueryChanges, MethodObject::ShareNotification) => {
|
||||
match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::QueryChanges(
|
||||
QueryChangesRequestMethod::ShareNotification(value),
|
||||
),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
}
|
||||
}
|
||||
(MethodFunction::Changes, _) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Changes(value),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Copy, MethodObject::Email) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Copy(CopyRequestMethod::Email(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Copy, MethodObject::Blob) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Copy(CopyRequestMethod::Blob(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Copy, MethodObject::CalendarEvent) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Copy(CopyRequestMethod::CalendarEvent(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Copy, MethodObject::ContactCard) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Copy(CopyRequestMethod::ContactCard(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Copy, MethodObject::FileNode) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Copy(CopyRequestMethod::FileNode(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Lookup, MethodObject::Blob) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::LookupBlob(value),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Upload, MethodObject::Blob) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::UploadBlob(value),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Import, MethodObject::Email) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::ImportEmail(value),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Parse, MethodObject::Email) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Parse(ParseRequestMethod::Email(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Parse, MethodObject::CalendarEvent) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Parse(ParseRequestMethod::CalendarEvent(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Parse, MethodObject::ContactCard) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Parse(ParseRequestMethod::ContactCard(value)),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::GetAvailability, MethodObject::Principal) => {
|
||||
match seq.next_element() {
|
||||
Ok(Some(value)) => {
|
||||
RequestMethod::Get(GetRequestMethod::PrincipalAvailability(value))
|
||||
}
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
}
|
||||
}
|
||||
(MethodFunction::Validate, MethodObject::SieveScript) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::ValidateScript(value),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
(MethodFunction::Echo, MethodObject::Core) => match seq.next_element() {
|
||||
Ok(Some(value)) => RequestMethod::Echo(value),
|
||||
Err(err) => RequestMethod::invalid(err),
|
||||
Ok(None) => {
|
||||
return Err(de::Error::invalid_length(1, &self));
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
return Err(de::Error::custom(format!(
|
||||
"Invalid method function/object combination: {}",
|
||||
method_name
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
let id = seq
|
||||
.next_element::<String>()?
|
||||
.ok_or_else(|| de::Error::invalid_length(2, &self))?;
|
||||
|
||||
Ok(Call { id, method, name })
|
||||
}
|
||||
}
|
||||
|
||||
impl RequestMethod<'_> {
|
||||
fn invalid(err: impl Display) -> Self {
|
||||
RequestMethod::Error(
|
||||
trc::JmapEvent::InvalidArguments
|
||||
.into_err()
|
||||
.details(err.to_string()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Request<'de> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct RequestVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for RequestVisitor {
|
||||
type Value = Request<'de>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a JMAP request object")
|
||||
}
|
||||
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: de::MapAccess<'de>,
|
||||
{
|
||||
let mut target = Request::default();
|
||||
let mut has_using = false;
|
||||
let mut has_method_calls = false;
|
||||
|
||||
while let Some(key) = map.next_key::<&str>()? {
|
||||
match key {
|
||||
"using" => has_using = true,
|
||||
"methodCalls" => has_method_calls = true,
|
||||
_ => {}
|
||||
}
|
||||
target
|
||||
.deserialize_argument(key, &mut map)
|
||||
.map_err(de::Error::custom)?;
|
||||
}
|
||||
|
||||
if !has_using || !has_method_calls {
|
||||
return Err(de::Error::custom(
|
||||
"Request is missing the \"using\" or \"methodCalls\" property.",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(target)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_map(RequestVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Call<RequestMethod<'de>> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_seq(CallVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::request::Request;
|
||||
|
||||
const TEST: &str = r#"
|
||||
{
|
||||
"using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail" ],
|
||||
"methodCalls": [
|
||||
[ "method1", {
|
||||
"arg1": "arg1data",
|
||||
"arg2": "arg2data"
|
||||
}, "c1" ],
|
||||
[ "Core/echo", {
|
||||
"hello": true,
|
||||
"high": 5
|
||||
}, "c2" ],
|
||||
[ "method3", {"hello": [{"a": {"b": true}}]}, "c3" ]
|
||||
],
|
||||
"createdIds": {
|
||||
"c1": "m1",
|
||||
"c2": "m2"
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
const TEST1: &str = r#"
|
||||
{
|
||||
"using": [
|
||||
"urn:ietf:params:jmap:core",
|
||||
"urn:ietf:params:jmap:mail"
|
||||
],
|
||||
"methodCalls": [
|
||||
[
|
||||
"Email/query",
|
||||
{
|
||||
"accountId": "0",
|
||||
"filter": { "conditions": [ { "hasKeyword": "music", "maxSize": 455 }, { "hasKeyword": "video" }, { "operator": "AND", "conditions": [ { "subject": "test" }, { "minSize": 100 } ] } ], "operator": "OR" },
|
||||
"sort": [
|
||||
{
|
||||
"property": "subject",
|
||||
"isAscending": true
|
||||
},
|
||||
{
|
||||
"property": "allInThreadHaveKeyword",
|
||||
"isAscending": false,
|
||||
"keyword": "$seen"
|
||||
},
|
||||
{
|
||||
"keyword": "$junk",
|
||||
"property": "someInThreadHaveKeyword",
|
||||
"collation": "i;octet",
|
||||
"isAscending": false
|
||||
}
|
||||
],
|
||||
"position": 0,
|
||||
"limit": 10
|
||||
},
|
||||
"c1"
|
||||
]
|
||||
],
|
||||
"createdIds": {}
|
||||
}
|
||||
"#;
|
||||
|
||||
const TEST2: &str = r##"
|
||||
{
|
||||
"using": [
|
||||
"urn:ietf:params:jmap:submission",
|
||||
"urn:ietf:params:jmap:mail",
|
||||
"urn:ietf:params:jmap:core"
|
||||
],
|
||||
"methodCalls": [
|
||||
[
|
||||
"Email/set",
|
||||
{
|
||||
"accountId": "c",
|
||||
"create": {
|
||||
"c37ee58b-e224-4799-88e6-1d7484e3b782": {
|
||||
"mailboxIds": {
|
||||
"9": true
|
||||
},
|
||||
"subject": "test",
|
||||
"from": [
|
||||
{
|
||||
"name": "Foo",
|
||||
"email": "[email protected]"
|
||||
}
|
||||
],
|
||||
"to": [
|
||||
{
|
||||
"name": null,
|
||||
"email": "[email protected]"
|
||||
}
|
||||
],
|
||||
"cc": [],
|
||||
"bcc": [],
|
||||
"replyTo": [
|
||||
{
|
||||
"name": null,
|
||||
"email": "[email protected]"
|
||||
}
|
||||
],
|
||||
"htmlBody": [
|
||||
{
|
||||
"partId": "c37ee58b-e224-4799-88e6-1d7484e3b782",
|
||||
"type": "text/html"
|
||||
}
|
||||
],
|
||||
"bodyValues": {
|
||||
"c37ee58b-e224-4799-88e6-1d7484e3b782": {
|
||||
"value": "<p>test email<br></p>",
|
||||
"isEncodingProblem": false,
|
||||
"isTruncated": false
|
||||
}
|
||||
},
|
||||
"header:User-Agent:asText": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"c0"
|
||||
],
|
||||
[
|
||||
"EmailSubmission/set",
|
||||
{
|
||||
"accountId": "c",
|
||||
"create": {
|
||||
"c37ee58b-e224-4799-88e6-1d7484e3b782": {
|
||||
"identityId": "a",
|
||||
"emailId": "#c37ee58b-e224-4799-88e6-1d7484e3b782",
|
||||
"envelope": {
|
||||
"mailFrom": {
|
||||
"email": "[email protected]"
|
||||
},
|
||||
"rcptTo": [
|
||||
{
|
||||
"email": "[email protected]"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"onSuccessUpdateEmail": {
|
||||
"#c37ee58b-e224-4799-88e6-1d7484e3b782": {
|
||||
"mailboxIds/d": true,
|
||||
"mailboxIds/9": null,
|
||||
"keywords/$seen": true,
|
||||
"keywords/$draft": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"c1"
|
||||
]
|
||||
]
|
||||
}
|
||||
"##;
|
||||
|
||||
const TEST_ESCAPED_SOLIDUS: &str = r#"
|
||||
{
|
||||
"using": [ "urn:ietf:params:jmap:core" ],
|
||||
"methodCalls": [
|
||||
[ "Core\/echo", { "hello": true }, "c1" ]
|
||||
]
|
||||
}
|
||||
"#;
|
||||
|
||||
#[test]
|
||||
fn parse_request() {
|
||||
println!("{:#?}", Request::parse(TEST.as_bytes(), 10, 10240));
|
||||
println!("{:#?}", Request::parse(TEST1.as_bytes(), 10, 10240));
|
||||
println!("{:#?}", Request::parse(TEST2.as_bytes(), 10, 10240));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_method_name_with_escaped_solidus() {
|
||||
let request = Request::parse(TEST_ESCAPED_SOLIDUS.as_bytes(), 10, 10240)
|
||||
.expect("escaped solidus in method name must parse");
|
||||
assert_eq!(request.method_calls.len(), 1);
|
||||
assert!(matches!(
|
||||
request.method_calls[0].method,
|
||||
super::RequestMethod::Echo(_)
|
||||
));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user