Treat deserialization failure as a validation failure.

If a ruma-events type fails deserialization, but the input was valid
JSON, this should be treated as a validation failure instead of a
deserialization failure. In this case, attempt to deserialize the json
into a `serde_json::Value`, and only return a deserialization error if
that fails.
This commit is contained in:
Jimmy Cuadra 2019-07-08 03:29:47 -07:00
parent 733dfa7ef3
commit c25d76e20f
2 changed files with 54 additions and 7 deletions

View File

@ -365,7 +365,20 @@ impl ToTokens for RumaEvent {
/// Attempt to create `Self` from parsing a string of JSON data. /// Attempt to create `Self` from parsing a string of JSON data.
fn from_str(json: &str) -> Result<Self, Self::Err> { fn from_str(json: &str) -> Result<Self, Self::Err> {
let raw = serde_json::from_str::<raw::#content_name>(json)?; let raw = match serde_json::from_str::<raw::#content_name>(json) {
Ok(raw) => raw,
Err(error) => match serde_json::from_str::<serde_json::Value>(json) {
Ok(value) => {
return Err(crate::InvalidEvent(crate::InnerInvalidEvent::Validation {
json: value,
message: error.to_string(),
}));
}
Err(error) => {
return Err(crate::InvalidEvent(crate::InnerInvalidEvent::Deserialization { error }));
}
},
};
Ok(Self { Ok(Self {
#(#content_field_values)* #(#content_field_values)*
@ -400,7 +413,20 @@ impl ToTokens for RumaEvent {
/// Attempt to create `Self` from parsing a string of JSON data. /// Attempt to create `Self` from parsing a string of JSON data.
fn from_str(json: &str) -> Result<Self, Self::Err> { fn from_str(json: &str) -> Result<Self, Self::Err> {
let raw = serde_json::from_str::<raw::#name>(json)?; let raw = match serde_json::from_str::<raw::#name>(json) {
Ok(raw) => raw,
Err(error) => match serde_json::from_str::<serde_json::Value>(json) {
Ok(value) => {
return Err(crate::InvalidEvent(crate::InnerInvalidEvent::Validation {
json: value,
message: error.to_string(),
}));
}
Err(error) => {
return Err(crate::InvalidEvent(crate::InnerInvalidEvent::Deserialization { error }));
}
},
};
Ok(Self { Ok(Self {
#(#try_from_field_values)* #(#try_from_field_values)*

View File

@ -126,13 +126,34 @@ pub trait StateEvent: RoomEvent {
fn state_key(&self) -> &str; fn state_key(&self) -> &str;
} }
/// An event that is malformed or otherwise invalid.
///
/// When attempting to create an event from a string of JSON data, an error in the input data may
/// cause deserialization to fail, or the JSON structure may not corresponded to ruma-events's
/// strict definition of the event's schema. If deserialization completely fails, this type will
/// provide a message with details about the deserialization error. If deserialization succeeds but
/// the event is otherwise invalid, a similar message will be provided, as well as a
/// `serde_json::Value` containing the raw JSON data as it was deserialized.
#[derive(Debug)] #[derive(Debug)]
pub struct InvalidEvent; pub struct InvalidEvent(InnerInvalidEvent);
impl From<serde_json::Error> for InvalidEvent { /// An event that is malformed or otherwise invalid.
fn from(_: serde_json::Error) -> Self { #[derive(Debug)]
Self enum InnerInvalidEvent {
} /// An event that failed to deserialize from JSON.
Deserialization {
/// The deserialization error returned by serde.
error: serde_json::Error,
},
/// An event that deserialized but failed validation.
Validation {
/// The raw `serde_json::Value` representation of the invalid event.
json: serde_json::Value,
/// An message describing why the event was invalid.
message: String,
},
} }
// See note about wrapping macro expansion in a module from `src/lib.rs` // See note about wrapping macro expansion in a module from `src/lib.rs`