Skip to content

Commit 6c7c8ec

Browse files
committed
[#259] Fix handling of payload format
The UMessage::extract_protobuf function has still handled both UPAYLOAD_FORMAT_PROTOBUF_WRAPPED_IN_ANY and UPAYLOAD_FORMAT_UNSPECIFIED synonymously. This has been changed to only support the former payload format as well as UPAYLOAD_FORMAT_PROTOBUF when extracting protobuf payload. Fixes #259
1 parent 9599739 commit 6c7c8ec

File tree

1 file changed

+32
-43
lines changed

1 file changed

+32
-43
lines changed

src/umessage.rs

Lines changed: 32 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ mod umessagebuilder;
1515
mod umessagetype;
1616

1717
use bytes::Bytes;
18-
use protobuf::{well_known_types::any::Any, Message, MessageFull};
18+
use protobuf::{well_known_types::any::Any, Enum, Message, MessageFull};
1919

2020
pub use umessagebuilder::*;
2121

@@ -345,54 +345,46 @@ impl UMessage {
345345
.is_some_and(|attribs| attribs.is_notification())
346346
}
347347

348-
/// If `UMessage` payload is available, deserialize it as a protobuf `Message`.
349-
///
350-
/// This function is used to extract strongly-typed data from a `UMessage` object,
351-
/// taking into account the payload format (will only succeed if payload format is
352-
/// `UPayloadFormat::UPAYLOAD_FORMAT_PROTOBUF` or `UPayloadFormat::UPAYLOAD_FORMAT_PROTOBUF_WRAPPED_IN_ANY`)
348+
/// Deserializes this message's protobuf payload into a type.
353349
///
354350
/// # Type Parameters
355351
///
356352
/// * `T`: The target type of the data to be unpacked.
357353
///
358-
/// # Returns
359-
///
360-
/// * `Ok(T)`: The deserialized protobuf message contained in the payload.
361-
///
362354
/// # Errors
363355
///
364-
/// * Err(`UMessageError`) if the unpacking process fails, for example if the payload could
365-
/// not be deserialized into the target type `T`.
356+
/// Returns an error if the message payload format is neither [UPayloadFormat::UPAYLOAD_FORMAT_PROTOBUF]
357+
/// nor [UPayloadFormat::UPAYLOAD_FORMAT_PROTOBUF_WRAPPED_IN_ANY] or if the bytes in the
358+
/// payload cannot be deserialized into the target type.
366359
pub fn extract_protobuf<T: MessageFull + Default>(&self) -> Result<T, UMessageError> {
367-
if let Some(payload) = &self.payload {
360+
if let Some(payload) = self.payload.as_ref() {
368361
let payload_format = self.attributes.payload_format.enum_value_or_default();
369362
deserialize_protobuf_bytes(payload, &payload_format)
370363
} else {
371364
Err(UMessageError::PayloadError(
372-
"No embedded payload".to_string(),
365+
"Message has no payload".to_string(),
373366
))
374367
}
375368
}
376369
}
377370

378371
/// Deserializes a protobuf message from a byte array.
379372
///
373+
/// # Type Parameters
374+
///
375+
/// * `T`: The target type of the data to be unpacked.
376+
///
380377
/// # Arguments
381378
///
382379
/// * `payload` - The payload data.
383380
/// * `payload_format` - The format/encoding of the data. Must be one of
384381
/// - `UPayloadFormat::UPAYLOAD_FORMAT_PROTOBUF`
385382
/// - `UPayloadFormat::UPAYLOAD_FORMAT_PROTOBUF_WRAPPED_IN_ANY`
386-
/// - `UPayloadFormat::UPAYLOAD_FORMAT_UNSPECIFIED`
387-
///
388-
/// `UPayloadFormat::UPAYLOAD_FORMAT_UNSPECIFIED` is interpreted as
389-
/// `UPayloadFormat::UPAYLOAD_FORMAT_PROTOBUF_WRAPPED_IN_ANY` according to the uProtocol
390-
/// specification.
391383
///
392384
/// # Errors
393385
///
394-
/// Returns an error if the payload format is unsupported or if the data is can not be deserialized
395-
/// based on the given format.
386+
/// Returns an error if the payload format is unsupported or if the data can not be deserialized
387+
/// into the target type based on the given format.
396388
pub(crate) fn deserialize_protobuf_bytes<T: MessageFull + Default>(
397389
payload: &Bytes,
398390
payload_format: &UPayloadFormat,
@@ -401,22 +393,24 @@ pub(crate) fn deserialize_protobuf_bytes<T: MessageFull + Default>(
401393
UPayloadFormat::UPAYLOAD_FORMAT_PROTOBUF => {
402394
T::parse_from_tokio_bytes(payload).map_err(UMessageError::DataSerializationError)
403395
}
404-
UPayloadFormat::UPAYLOAD_FORMAT_PROTOBUF_WRAPPED_IN_ANY
405-
| UPayloadFormat::UPAYLOAD_FORMAT_UNSPECIFIED => Any::parse_from_tokio_bytes(payload)
406-
.map_err(UMessageError::DataSerializationError)
407-
.and_then(|any| match any.unpack() {
408-
Ok(Some(v)) => Ok(v),
409-
Ok(None) => Err(UMessageError::PayloadError(
410-
"cannot deserialize payload, message type mismatch".to_string(),
411-
)),
412-
Err(e) => Err(UMessageError::DataSerializationError(e)),
413-
}),
414-
_ => Err(UMessageError::from(format!(
415-
"Unknown/invalid/unsupported payload format: {}",
416-
payload_format
417-
.to_media_type()
418-
.unwrap_or("unknown".to_string())
419-
))),
396+
UPayloadFormat::UPAYLOAD_FORMAT_PROTOBUF_WRAPPED_IN_ANY => {
397+
Any::parse_from_tokio_bytes(payload)
398+
.map_err(UMessageError::DataSerializationError)
399+
.and_then(|any| match any.unpack() {
400+
Ok(Some(v)) => Ok(v),
401+
Ok(None) => Err(UMessageError::PayloadError(
402+
"cannot deserialize payload, message type mismatch".to_string(),
403+
)),
404+
Err(e) => Err(UMessageError::DataSerializationError(e)),
405+
})
406+
}
407+
_ => {
408+
let detail_msg = payload_format.to_media_type().map_or_else(
409+
|| format!("Unknown payload format: {}", payload_format.value()),
410+
|mt| format!("Invalid/unsupported payload format: {mt}"),
411+
);
412+
Err(UMessageError::from(detail_msg))
413+
}
420414
}
421415
}
422416

@@ -438,12 +432,6 @@ mod test {
438432
let any = Any::pack(&data.clone()).unwrap();
439433
let buf: Bytes = any.write_to_bytes().unwrap().into();
440434

441-
let result = deserialize_protobuf_bytes::<StringValue>(
442-
&buf,
443-
&UPayloadFormat::UPAYLOAD_FORMAT_UNSPECIFIED,
444-
);
445-
assert!(result.is_ok_and(|v| v.value == *"hello world"));
446-
447435
let result = deserialize_protobuf_bytes::<StringValue>(
448436
&buf,
449437
&UPayloadFormat::UPAYLOAD_FORMAT_PROTOBUF_WRAPPED_IN_ANY,
@@ -476,6 +464,7 @@ mod test {
476464
#[test_case(UPayloadFormat::UPAYLOAD_FORMAT_SOMEIP; "SOMEIP format")]
477465
#[test_case(UPayloadFormat::UPAYLOAD_FORMAT_SOMEIP_TLV; "SOMEIP TLV format")]
478466
#[test_case(UPayloadFormat::UPAYLOAD_FORMAT_TEXT; "TEXT format")]
467+
#[test_case(UPayloadFormat::UPAYLOAD_FORMAT_UNSPECIFIED; "UNSPECIFIED format")]
479468
fn test_deserialize_protobuf_bytes_fails_for_(format: UPayloadFormat) {
480469
let result = deserialize_protobuf_bytes::<UStatus>(&"hello".into(), &format);
481470
assert!(result.is_err_and(|e| matches!(e, UMessageError::PayloadError(_))));

0 commit comments

Comments
 (0)