From 92068236b7405ba3cae1262fb7baf34bf41610dc Mon Sep 17 00:00:00 2001 From: Michiel De Backker Date: Sun, 25 Jan 2026 10:51:42 +0100 Subject: [PATCH 1/3] Fix: message type key encoding to use RFC 9000 varint Type keys were incorrectly encoded as CBOR array [type, body]. Spec requires: [varint type key][CBOR body] --- openscreen-network/Cargo.toml | 1 + openscreen-network/src/messages.rs | 194 ++++++++++++++++------------- 2 files changed, 107 insertions(+), 88 deletions(-) diff --git a/openscreen-network/Cargo.toml b/openscreen-network/Cargo.toml index ef945e4..db55f08 100644 --- a/openscreen-network/Cargo.toml +++ b/openscreen-network/Cargo.toml @@ -12,6 +12,7 @@ heapless = "0.8" minicbor = { version = "0.25", default-features = false, features = ["half"] } log = "0.4" subtle = { version = "2.6", default-features = false } +bytes = { version = "1", default-features = false } [dev-dependencies] openscreen-crypto-rustcrypto = { path = "../openscreen-crypto-rustcrypto" } diff --git a/openscreen-network/src/messages.rs b/openscreen-network/src/messages.rs index 0bd46cd..c7ecad3 100644 --- a/openscreen-network/src/messages.rs +++ b/openscreen-network/src/messages.rs @@ -17,10 +17,16 @@ //! This module implements CBOR encoding/decoding for OpenScreen Network Protocol messages //! (authentication) based on the W3C specification's CDDL definitions. //! +//! Message format per spec: +//! 1. Type key encoded as RFC 9000 variable-length integer +//! 2. Message body encoded as CBOR +//! //! Reference: ref/w3c_ref/messages_appendix.cddl +use bytes::Buf; use heapless::Vec; use minicbor::{Decoder, Encoder}; +use openscreen_common::quinn_varint::{Codec, VarInt}; use openscreen_common::MessageError; /// A wrapper around heapless::Vec that implements minicbor's Write trait @@ -45,6 +51,39 @@ impl<'a, const N: usize> minicbor::encode::Write for VecWriter<'a, N> { } } +/// Encode a type key as RFC 9000 variable-length integer into a heapless::Vec +fn encode_type_key( + type_key: u16, + buf: &mut Vec, +) -> Result<(), MessageError> { + let varint = VarInt::from(type_key); + let size = varint.size(); + + // Ensure we have space + if buf.len() + size > N { + return Err(MessageError::BufferFull); + } + + // Encode varint to a small stack buffer, then copy + let mut temp = [0u8; 8]; + varint.encode(&mut temp.as_mut_slice()); + buf.extend_from_slice(&temp[..size]) + .map_err(|_| MessageError::BufferFull) +} + +/// Decode a type key as RFC 9000 variable-length integer from a byte slice. +/// Returns the type key and the number of bytes consumed. +fn decode_type_key(data: &[u8]) -> Result<(u16, usize), MessageError> { + let mut cursor = data; + let varint = VarInt::decode(&mut cursor).map_err(|_| MessageError::DecodeFailed)?; + let consumed = data.len() - cursor.remaining(); + let value = varint.into_inner(); + if value > u16::MAX as u64 { + return Err(MessageError::InvalidMessageType); + } + Ok((value as u16, consumed)) +} + /// Maximum size for a single CBOR message pub const MAX_MESSAGE_SIZE: usize = 1024; @@ -193,17 +232,17 @@ pub struct AuthCapabilities { } impl AuthCapabilities { - /// Encode this message to CBOR + /// Encode this message to bytes per OSP spec: + /// 1. Type key as RFC 9000 variable-length integer + /// 2. Message body as CBOR map pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key(NetworkMessageType::AuthCapabilities as u16, buf)?; + + // Write CBOR body (map only, no array wrapper) let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(NetworkMessageType::AuthCapabilities as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with 2 or 3 fields (field 2 is mandatory, field 1 is optional) let field_count = if self.psk_input_methods.is_empty() { 2 @@ -242,22 +281,19 @@ impl AuthCapabilities { Ok(()) } - /// Decode this message from CBOR + /// Decode this message from bytes per OSP spec: + /// 1. Type key as RFC 9000 variable-length integer + /// 2. Message body as CBOR map pub fn decode(data: &[u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != NetworkMessageType::AuthCapabilities as u16 { return Err(MessageError::InvalidMessageType); } + // Decode CBOR body (map only, no array wrapper) + let mut decoder = Decoder::new(&data[consumed..]); + // Body is a map with 2 or 3 fields (field 2 is mandatory, field 1 is optional) let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; if map_len != Some(2) && map_len != Some(3) { @@ -319,17 +355,17 @@ pub struct AuthSpake2Handshake<'a> { } impl<'a> AuthSpake2Handshake<'a> { - /// Encode this message to CBOR + /// Encode this message to bytes per OSP spec: + /// 1. Type key as RFC 9000 variable-length integer + /// 2. Message body as CBOR map pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key(NetworkMessageType::AuthSpake2Handshake as u16, buf)?; + + // Write CBOR body (map only, no array wrapper) let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(NetworkMessageType::AuthSpake2Handshake as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with 3 fields encoder.map(3).map_err(|_| MessageError::EncodeFailed)?; @@ -358,22 +394,19 @@ impl<'a> AuthSpake2Handshake<'a> { Ok(()) } - /// Decode this message from CBOR + /// Decode this message from bytes per OSP spec: + /// 1. Type key as RFC 9000 variable-length integer + /// 2. Message body as CBOR map pub fn decode(data: &'a [u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != NetworkMessageType::AuthSpake2Handshake as u16 { return Err(MessageError::InvalidMessageType); } + // Decode CBOR body (map only, no array wrapper) + let mut decoder = Decoder::new(&data[consumed..]); + // Body is a map let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; if map_len != Some(3) { @@ -445,17 +478,17 @@ pub struct AuthSpake2Confirmation<'a> { } impl<'a> AuthSpake2Confirmation<'a> { - /// Encode this message to CBOR + /// Encode this message to bytes per OSP spec: + /// 1. Type key as RFC 9000 variable-length integer + /// 2. Message body as CBOR map pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key(NetworkMessageType::AuthSpake2Confirmation as u16, buf)?; + + // Write CBOR body (map only, no array wrapper) let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(NetworkMessageType::AuthSpake2Confirmation as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with 1 field encoder.map(1).map_err(|_| MessageError::EncodeFailed)?; @@ -468,22 +501,19 @@ impl<'a> AuthSpake2Confirmation<'a> { Ok(()) } - /// Decode this message from CBOR + /// Decode this message from bytes per OSP spec: + /// 1. Type key as RFC 9000 variable-length integer + /// 2. Message body as CBOR map pub fn decode(data: &'a [u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != NetworkMessageType::AuthSpake2Confirmation as u16 { return Err(MessageError::InvalidMessageType); } + // Decode CBOR body (map only, no array wrapper) + let mut decoder = Decoder::new(&data[consumed..]); + // Body is a map with 1 field let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; if map_len != Some(1) { @@ -512,17 +542,17 @@ pub struct AuthStatus { } impl AuthStatus { - /// Encode this message to CBOR + /// Encode this message to bytes per OSP spec: + /// 1. Type key as RFC 9000 variable-length integer + /// 2. Message body as CBOR map pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key(NetworkMessageType::AuthStatus as u16, buf)?; + + // Write CBOR body (map only, no array wrapper) let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(NetworkMessageType::AuthStatus as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with 1 field encoder.map(1).map_err(|_| MessageError::EncodeFailed)?; @@ -535,22 +565,19 @@ impl AuthStatus { Ok(()) } - /// Decode this message from CBOR + /// Decode this message from bytes per OSP spec: + /// 1. Type key as RFC 9000 variable-length integer + /// 2. Message body as CBOR map pub fn decode(data: &[u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != NetworkMessageType::AuthStatus as u16 { return Err(MessageError::InvalidMessageType); } + // Decode CBOR body (map only, no array wrapper) + let mut decoder = Decoder::new(&data[consumed..]); + // Body is a map with 1 field let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; if map_len != Some(1) { @@ -596,19 +623,10 @@ impl<'a> NetworkMessage<'a> { } } - /// Decode a NetworkMessage from CBOR data by inspecting the type key + /// Decode a NetworkMessage from bytes by inspecting the type key pub fn decode(data: &'a [u8]) -> Result { - // Peek at the type key without consuming the decoder - let mut decoder = Decoder::new(data); - - // Read array header - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Read type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint to determine message type + let (type_key, _consumed) = decode_type_key(data)?; // Now decode the full message based on type match NetworkMessageType::from_u16(type_key)? { @@ -631,11 +649,11 @@ impl<'a> NetworkMessage<'a> { } } -/// Encode a NetworkMessage to CBOR bytes per W3C OpenScreen Protocol spec. +/// Encode a NetworkMessage to bytes per W3C OpenScreen Protocol spec. /// -/// Format: [message_type, message_body] -/// - message_type: CBOR unsigned integer (1005 for AuthHandshake, 1006 for AuthConfirmation) -/// - message_body: message-specific (bytes for handshake/confirmation) +/// Format: [type_key][cbor_body] +/// - type_key: RFC 9000 variable-length integer +/// - cbor_body: message-specific CBOR map pub fn encode_network_message<'a>( msg: &crate::NetworkMessage<'a>, ) -> Result, MessageError> { From 1cbd2f37263627f82b1ebd415a7980621cb16e34 Mon Sep 17 00:00:00 2001 From: Michiel De Backker Date: Sun, 25 Jan 2026 11:27:16 +0100 Subject: [PATCH 2/3] Fix hostname encoding to use URL-safe base64 Standard base64 contains +/= which are invalid in DNS labels. Use URL_SAFE_NO_PAD encoding per w3c/openscreenprotocol#365. --- openscreen-application/src/cert.rs | 26 ++++++++++-------- openscreen-network/src/messages.rs | 44 ++++++++++++++++++++---------- 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/openscreen-application/src/cert.rs b/openscreen-application/src/cert.rs index 1bec980..e68d164 100644 --- a/openscreen-application/src/cert.rs +++ b/openscreen-application/src/cert.rs @@ -53,10 +53,12 @@ impl SerialNumber { bytes } - /// Base64 encode serial number per RFC 4648 + /// URL-safe base64 encode serial number (no padding). + /// Spec says RFC 4648 base64, but standard base64 contains +/= which are + /// invalid in DNS labels. See: https://github.com/w3c/openscreenprotocol/issues/365 pub fn to_base64(&self) -> String { - use base64::{engine::general_purpose::STANDARD, Engine}; - STANDARD.encode(self.to_bytes()) + use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; + URL_SAFE_NO_PAD.encode(self.to_bytes()) } /// Parse from 160-bit bytes @@ -325,7 +327,7 @@ mod tests { assert_eq!(bytes.len(), 20); // 160 bits let base64 = serial.to_base64(); - assert_eq!(base64.len(), 28); // base64 encoding of 20 bytes + assert_eq!(base64.len(), 27); // URL-safe base64 (no padding) of 20 bytes } #[test] @@ -386,8 +388,9 @@ mod tests { let parts: Vec<&str> = cert.hostname.split('.').collect(); assert!(parts.len() >= 3); - // First part should be base64 serial (28 chars for 160-bit number) - assert_eq!(parts[0].len(), 28); + // First part should be URL-safe base64 serial (27 chars for 160-bit number, no padding) + // See: https://github.com/w3c/openscreenprotocol/issues/365 + assert_eq!(parts[0].len(), 27); // Second part should be sanitized name assert_eq!(parts[1], "receiver"); @@ -413,12 +416,13 @@ mod tests { let serial = SerialNumber::generate(); let base64 = serial.to_base64(); - // 20 bytes encoded in base64 = ceil(20 * 8 / 6) = 28 chars (with padding) - assert_eq!(base64.len(), 28); + // 20 bytes encoded in URL-safe base64 (no padding) = ceil(20 * 8 / 6) = 27 chars + // See: https://github.com/w3c/openscreenprotocol/issues/365 + assert_eq!(base64.len(), 27); - // Should be valid base64 - use base64::{engine::general_purpose::STANDARD, Engine}; - let decoded = STANDARD.decode(&base64).unwrap(); + // Should be valid URL-safe base64 (no padding) + use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; + let decoded = URL_SAFE_NO_PAD.decode(&base64).unwrap(); assert_eq!(decoded.len(), 20); } diff --git a/openscreen-network/src/messages.rs b/openscreen-network/src/messages.rs index c7ecad3..56fc386 100644 --- a/openscreen-network/src/messages.rs +++ b/openscreen-network/src/messages.rs @@ -66,7 +66,8 @@ fn encode_type_key( // Encode varint to a small stack buffer, then copy let mut temp = [0u8; 8]; - varint.encode(&mut temp.as_mut_slice()); + let mut slice = &mut temp[..]; + varint.encode(&mut slice); buf.extend_from_slice(&temp[..size]) .map_err(|_| MessageError::BufferFull) } @@ -290,9 +291,12 @@ impl AuthCapabilities { if type_key != NetworkMessageType::AuthCapabilities as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } - // Decode CBOR body (map only, no array wrapper) - let mut decoder = Decoder::new(&data[consumed..]); + /// Decode the CBOR body (after type key has been consumed) + pub fn decode_body(body: &[u8]) -> Result { + let mut decoder = Decoder::new(body); // Body is a map with 2 or 3 fields (field 2 is mandatory, field 1 is optional) let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; @@ -403,9 +407,12 @@ impl<'a> AuthSpake2Handshake<'a> { if type_key != NetworkMessageType::AuthSpake2Handshake as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } - // Decode CBOR body (map only, no array wrapper) - let mut decoder = Decoder::new(&data[consumed..]); + /// Decode the CBOR body (after type key has been consumed) + pub fn decode_body(body: &'a [u8]) -> Result { + let mut decoder = Decoder::new(body); // Body is a map let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; @@ -510,9 +517,12 @@ impl<'a> AuthSpake2Confirmation<'a> { if type_key != NetworkMessageType::AuthSpake2Confirmation as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } - // Decode CBOR body (map only, no array wrapper) - let mut decoder = Decoder::new(&data[consumed..]); + /// Decode the CBOR body (after type key has been consumed) + pub fn decode_body(body: &'a [u8]) -> Result { + let mut decoder = Decoder::new(body); // Body is a map with 1 field let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; @@ -574,9 +584,12 @@ impl AuthStatus { if type_key != NetworkMessageType::AuthStatus as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } - // Decode CBOR body (map only, no array wrapper) - let mut decoder = Decoder::new(&data[consumed..]); + /// Decode the CBOR body (after type key has been consumed) + pub fn decode_body(body: &[u8]) -> Result { + let mut decoder = Decoder::new(body); // Body is a map with 1 field let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; @@ -626,21 +639,22 @@ impl<'a> NetworkMessage<'a> { /// Decode a NetworkMessage from bytes by inspecting the type key pub fn decode(data: &'a [u8]) -> Result { // Read type key as RFC 9000 varint to determine message type - let (type_key, _consumed) = decode_type_key(data)?; + let (type_key, consumed) = decode_type_key(data)?; + let body = &data[consumed..]; - // Now decode the full message based on type + // Decode the CBOR body based on message type match NetworkMessageType::from_u16(type_key)? { NetworkMessageType::AuthCapabilities => Ok(NetworkMessage::AuthCapabilities( - AuthCapabilities::decode(data)?, + AuthCapabilities::decode_body(body)?, )), NetworkMessageType::AuthSpake2Handshake => Ok(NetworkMessage::AuthSpake2Handshake( - AuthSpake2Handshake::decode(data)?, + AuthSpake2Handshake::decode_body(body)?, )), NetworkMessageType::AuthSpake2Confirmation => Ok( - NetworkMessage::AuthSpake2Confirmation(AuthSpake2Confirmation::decode(data)?), + NetworkMessage::AuthSpake2Confirmation(AuthSpake2Confirmation::decode_body(body)?), ), NetworkMessageType::AuthStatus => { - Ok(NetworkMessage::AuthStatus(AuthStatus::decode(data)?)) + Ok(NetworkMessage::AuthStatus(AuthStatus::decode_body(body)?)) } NetworkMessageType::AuthSpake2Need => { unimplemented!("AuthSpake2Need message not yet supported") From ee7a55dc2db5969d9ce6aced2c63751850e73a58 Mon Sep 17 00:00:00 2001 From: Michiel De Backker Date: Mon, 26 Jan 2026 10:22:02 +0100 Subject: [PATCH 3/3] Fix: application message type key & lint fix. --- openscreen-application/Cargo.toml | 1 + openscreen-application/src/messages.rs | 623 ++++++++++++------------- openscreen-network/src/messages.rs | 6 +- 3 files changed, 312 insertions(+), 318 deletions(-) diff --git a/openscreen-application/Cargo.toml b/openscreen-application/Cargo.toml index 788dbdc..db8e47b 100644 --- a/openscreen-application/Cargo.toml +++ b/openscreen-application/Cargo.toml @@ -6,6 +6,7 @@ license.workspace = true repository.workspace = true [dependencies] +bytes = { version = "1", default-features = false } openscreen-common = { path = "../openscreen-common" } openscreen-network = { path = "../openscreen-network" } openscreen-crypto = { path = "../openscreen-crypto" } diff --git a/openscreen-application/src/messages.rs b/openscreen-application/src/messages.rs index dca82f3..be3f6fa 100644 --- a/openscreen-application/src/messages.rs +++ b/openscreen-application/src/messages.rs @@ -21,8 +21,10 @@ //! //! Reference: ref/w3c_ref/messages_appendix.cddl +use bytes::Buf; use heapless::Vec; use minicbor::{Decoder, Encoder}; +use openscreen_common::quinn_varint::{Codec, VarInt}; use openscreen_common::{MessageError, MAX_STRING_LENGTH, MAX_URLS}; /// A wrapper around heapless::Vec that implements minicbor's Write trait @@ -46,6 +48,38 @@ impl<'a, const N: usize> minicbor::encode::Write for VecWriter<'a, N> { } } +/// Encode a type key as RFC 9000 variable-length integer into a heapless::Vec +fn encode_type_key( + type_key: u16, + buf: &mut Vec, +) -> Result<(), MessageError> { + let varint = VarInt::from(type_key); + let size = varint.size(); + + // Ensure we have space + if buf.len() + size > N { + return Err(MessageError::BufferFull); + } + + // Encode varint to a small stack buffer, then copy + let mut temp = [0u8; 8]; + let mut slice = &mut temp[..]; + varint.encode(&mut slice); + buf.extend_from_slice(&temp[..size]) + .map_err(|_| MessageError::BufferFull) +} + +/// Decode a type key as RFC 9000 variable-length integer from a byte slice. +/// Returns the type key and the number of bytes consumed. +fn decode_type_key(data: &[u8]) -> Result<(u16, usize), MessageError> { + let mut cursor = data; + let varint = VarInt::decode(&mut cursor).map_err(|_| MessageError::DecodeFailed)?; + let consumed = data.len() - cursor.remaining(); + let value = varint.into_inner(); + let type_key = u16::try_from(value).map_err(|_| MessageError::InvalidMessageType)?; + Ok((type_key, consumed)) +} + /// Maximum size for a single CBOR message pub const MAX_MESSAGE_SIZE: usize = 1024; @@ -164,15 +198,13 @@ pub struct AgentInfoRequest { impl AgentInfoRequest { /// Encode this message to CBOR pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key(ApplicationMessageType::AgentInfoRequest as u16, buf)?; + + // Write CBOR body let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(ApplicationMessageType::AgentInfoRequest as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with request-id encoder.map(1).map_err(|_| MessageError::EncodeFailed)?; encoder.u8(0).map_err(|_| MessageError::EncodeFailed)?; @@ -185,19 +217,17 @@ impl AgentInfoRequest { /// Decode this message from CBOR pub fn decode(data: &[u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != ApplicationMessageType::AgentInfoRequest as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } + + /// Decode the CBOR body (after type key has been consumed) + pub fn decode_body(body: &[u8]) -> Result { + let mut decoder = Decoder::new(body); // Body is a map with one field let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; @@ -227,15 +257,13 @@ pub struct AgentInfoResponse<'a> { impl<'a> AgentInfoResponse<'a> { /// Encode this message to CBOR pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key(ApplicationMessageType::AgentInfoResponse as u16, buf)?; + + // Write CBOR body let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(ApplicationMessageType::AgentInfoResponse as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with 2 fields encoder.map(2).map_err(|_| MessageError::EncodeFailed)?; @@ -294,19 +322,17 @@ impl<'a> AgentInfoResponse<'a> { /// Decode this message from CBOR pub fn decode(data: &'a [u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != ApplicationMessageType::AgentInfoResponse as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } + + /// Decode the CBOR body (after type key has been consumed) + pub fn decode_body(body: &'a [u8]) -> Result { + let mut decoder = Decoder::new(body); // Body is a map with 2 fields let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; @@ -427,15 +453,13 @@ pub struct AgentStatusRequest<'a> { impl<'a> AgentStatusRequest<'a> { /// Encode this message to CBOR pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key(ApplicationMessageType::AgentStatusRequest as u16, buf)?; + + // Write CBOR body let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(ApplicationMessageType::AgentStatusRequest as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with request-id and optional status let field_count = if self.status.is_some() { 2 } else { 1 }; encoder @@ -464,19 +488,17 @@ impl<'a> AgentStatusRequest<'a> { /// Decode this message from CBOR pub fn decode(data: &'a [u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::DecodeFailed); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != ApplicationMessageType::AgentStatusRequest as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } + + /// Decode the CBOR body (after type key has been consumed) + pub fn decode_body(body: &'a [u8]) -> Result { + let mut decoder = Decoder::new(body); // Decode body map let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; @@ -532,15 +554,13 @@ pub struct AgentStatusResponse<'a> { impl<'a> AgentStatusResponse<'a> { /// Encode this message to CBOR pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key(ApplicationMessageType::AgentStatusResponse as u16, buf)?; + + // Write CBOR body let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(ApplicationMessageType::AgentStatusResponse as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with request-id and optional status let field_count = if self.status.is_some() { 2 } else { 1 }; encoder @@ -569,19 +589,17 @@ impl<'a> AgentStatusResponse<'a> { /// Decode this message from CBOR pub fn decode(data: &'a [u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::DecodeFailed); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != ApplicationMessageType::AgentStatusResponse as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } + + /// Decode the CBOR body (after type key has been consumed) + pub fn decode_body(body: &'a [u8]) -> Result { + let mut decoder = Decoder::new(body); // Decode body map let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; @@ -636,15 +654,13 @@ pub struct AgentInfoEvent<'a> { impl<'a> AgentInfoEvent<'a> { /// Encode this message to CBOR pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key(ApplicationMessageType::AgentInfoEvent as u16, buf)?; + + // Write CBOR body let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(ApplicationMessageType::AgentInfoEvent as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with one field (agent-info) encoder.map(1).map_err(|_| MessageError::EncodeFailed)?; encoder.u8(0).map_err(|_| MessageError::EncodeFailed)?; @@ -697,19 +713,17 @@ impl<'a> AgentInfoEvent<'a> { /// Decode this message from CBOR pub fn decode(data: &'a [u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::DecodeFailed); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != ApplicationMessageType::AgentInfoEvent as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } + + /// Decode the CBOR body (after type key has been consumed) + pub fn decode_body(body: &'a [u8]) -> Result { + let mut decoder = Decoder::new(body); // Body is a map with agent-info let body_map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; @@ -957,15 +971,13 @@ pub struct PresentationStartRequest<'a> { impl<'a> PresentationStartRequest<'a> { /// Encode this message to CBOR pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key(ApplicationMessageType::PresentationStartRequest as u16, buf)?; + + // Write CBOR body let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(ApplicationMessageType::PresentationStartRequest as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with 4 fields encoder.map(4).map_err(|_| MessageError::EncodeFailed)?; @@ -1007,19 +1019,17 @@ impl<'a> PresentationStartRequest<'a> { /// Decode this message from CBOR pub fn decode(data: &'a [u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != ApplicationMessageType::PresentationStartRequest as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } + + /// Decode from CBOR body (without type key) + pub fn decode_body(body: &'a [u8]) -> Result { + let mut decoder = Decoder::new(body); // Body is a map with 4 fields let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; @@ -1114,15 +1124,16 @@ pub struct PresentationStartResponse { impl PresentationStartResponse { /// Encode this message to CBOR pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key( + ApplicationMessageType::PresentationStartResponse as u16, + buf, + )?; + + // Write CBOR body let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(ApplicationMessageType::PresentationStartResponse as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with 3 or 4 fields let field_count = if self.http_response_code.is_some() { 4 @@ -1162,19 +1173,17 @@ impl PresentationStartResponse { /// Decode this message from CBOR pub fn decode(data: &[u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != ApplicationMessageType::PresentationStartResponse as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } + + /// Decode from CBOR body (without type key) + pub fn decode_body(body: &[u8]) -> Result { + let mut decoder = Decoder::new(body); // Body is a map with 3 or 4 fields let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; @@ -1236,15 +1245,16 @@ pub struct PresentationTerminationRequest<'a> { impl<'a> PresentationTerminationRequest<'a> { /// Encode this message to CBOR pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key( + ApplicationMessageType::PresentationTerminationRequest as u16, + buf, + )?; + + // Write CBOR body let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(ApplicationMessageType::PresentationTerminationRequest as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with 3 fields encoder.map(3).map_err(|_| MessageError::EncodeFailed)?; @@ -1271,19 +1281,17 @@ impl<'a> PresentationTerminationRequest<'a> { /// Decode this message from CBOR pub fn decode(data: &'a [u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != ApplicationMessageType::PresentationTerminationRequest as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } + + /// Decode from CBOR body (without type key) + pub fn decode_body(body: &'a [u8]) -> Result { + let mut decoder = Decoder::new(body); // Read the map let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; @@ -1336,15 +1344,16 @@ pub struct PresentationTerminationResponse { impl PresentationTerminationResponse { /// Encode this message to CBOR pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key( + ApplicationMessageType::PresentationTerminationResponse as u16, + buf, + )?; + + // Write CBOR body let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(ApplicationMessageType::PresentationTerminationResponse as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with 2 fields encoder.map(2).map_err(|_| MessageError::EncodeFailed)?; @@ -1365,19 +1374,17 @@ impl PresentationTerminationResponse { /// Decode this message from CBOR pub fn decode(data: &[u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != ApplicationMessageType::PresentationTerminationResponse as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } + + /// Decode from CBOR body (without type key) + pub fn decode_body(body: &[u8]) -> Result { + let mut decoder = Decoder::new(body); let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; if map_len != Some(2) { @@ -1426,15 +1433,16 @@ pub struct PresentationTerminationEvent<'a> { impl<'a> PresentationTerminationEvent<'a> { /// Encode this message to CBOR pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key( + ApplicationMessageType::PresentationTerminationEvent as u16, + buf, + )?; + + // Write CBOR body let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(ApplicationMessageType::PresentationTerminationEvent as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with 3 fields encoder.map(3).map_err(|_| MessageError::EncodeFailed)?; @@ -1461,19 +1469,17 @@ impl<'a> PresentationTerminationEvent<'a> { /// Decode this message from CBOR pub fn decode(data: &'a [u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != ApplicationMessageType::PresentationTerminationEvent as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } + + /// Decode from CBOR body (without type key) + pub fn decode_body(body: &'a [u8]) -> Result { + let mut decoder = Decoder::new(body); let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; if map_len != Some(3) { @@ -1528,15 +1534,16 @@ pub struct PresentationConnectionOpenRequest<'a> { impl<'a> PresentationConnectionOpenRequest<'a> { /// Encode this message to CBOR pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key( + ApplicationMessageType::PresentationConnectionOpenRequest as u16, + buf, + )?; + + // Write CBOR body let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(ApplicationMessageType::PresentationConnectionOpenRequest as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with 3 fields encoder.map(3).map_err(|_| MessageError::EncodeFailed)?; @@ -1563,19 +1570,17 @@ impl<'a> PresentationConnectionOpenRequest<'a> { /// Decode this message from CBOR pub fn decode(data: &'a [u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != ApplicationMessageType::PresentationConnectionOpenRequest as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } + + /// Decode from CBOR body (without type key) + pub fn decode_body(body: &'a [u8]) -> Result { + let mut decoder = Decoder::new(body); let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; if map_len != Some(3) { @@ -1630,15 +1635,16 @@ pub struct PresentationConnectionOpenResponse { impl PresentationConnectionOpenResponse { /// Encode this message to CBOR pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key( + ApplicationMessageType::PresentationConnectionOpenResponse as u16, + buf, + )?; + + // Write CBOR body let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(ApplicationMessageType::PresentationConnectionOpenResponse as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with 4 fields encoder.map(4).map_err(|_| MessageError::EncodeFailed)?; @@ -1671,19 +1677,17 @@ impl PresentationConnectionOpenResponse { /// Decode this message from CBOR pub fn decode(data: &[u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != ApplicationMessageType::PresentationConnectionOpenResponse as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } + + /// Decode from CBOR body (without type key) + pub fn decode_body(body: &[u8]) -> Result { + let mut decoder = Decoder::new(body); let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; if map_len != Some(4) { @@ -1744,15 +1748,16 @@ pub struct PresentationUrlAvailabilityRequest<'a> { impl<'a> PresentationUrlAvailabilityRequest<'a> { /// Encode this message to CBOR pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key( + ApplicationMessageType::PresentationUrlAvailabilityRequest as u16, + buf, + )?; + + // Write CBOR body let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(ApplicationMessageType::PresentationUrlAvailabilityRequest as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with 4 fields encoder.map(4).map_err(|_| MessageError::EncodeFailed)?; @@ -1788,19 +1793,17 @@ impl<'a> PresentationUrlAvailabilityRequest<'a> { /// Decode this message from CBOR pub fn decode(data: &'a [u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != ApplicationMessageType::PresentationUrlAvailabilityRequest as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } + + /// Decode from CBOR body (without type key) + pub fn decode_body(body: &'a [u8]) -> Result { + let mut decoder = Decoder::new(body); let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; if map_len != Some(4) { @@ -1865,15 +1868,16 @@ pub struct PresentationUrlAvailabilityResponse { impl PresentationUrlAvailabilityResponse { /// Encode this message to CBOR pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key( + ApplicationMessageType::PresentationUrlAvailabilityResponse as u16, + buf, + )?; + + // Write CBOR body let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(ApplicationMessageType::PresentationUrlAvailabilityResponse as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with 2 fields encoder.map(2).map_err(|_| MessageError::EncodeFailed)?; @@ -1899,19 +1903,17 @@ impl PresentationUrlAvailabilityResponse { /// Decode this message from CBOR pub fn decode(data: &[u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != ApplicationMessageType::PresentationUrlAvailabilityResponse as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } + + /// Decode from CBOR body (without type key) + pub fn decode_body(body: &[u8]) -> Result { + let mut decoder = Decoder::new(body); let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; if map_len != Some(2) { @@ -1969,15 +1971,16 @@ pub struct PresentationUrlAvailabilityEvent { impl PresentationUrlAvailabilityEvent { /// Encode this message to CBOR pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key( + ApplicationMessageType::PresentationUrlAvailabilityEvent as u16, + buf, + )?; + + // Write CBOR body let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(ApplicationMessageType::PresentationUrlAvailabilityEvent as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with 2 fields encoder.map(2).map_err(|_| MessageError::EncodeFailed)?; @@ -2003,19 +2006,17 @@ impl PresentationUrlAvailabilityEvent { /// Decode this message from CBOR pub fn decode(data: &[u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != ApplicationMessageType::PresentationUrlAvailabilityEvent as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } + + /// Decode from CBOR body (without type key) + pub fn decode_body(body: &[u8]) -> Result { + let mut decoder = Decoder::new(body); let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; if map_len != Some(2) { @@ -2078,15 +2079,16 @@ pub struct PresentationConnectionCloseEvent<'a> { impl<'a> PresentationConnectionCloseEvent<'a> { /// Encode this message to CBOR pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key( + ApplicationMessageType::PresentationConnectionCloseEvent as u16, + buf, + )?; + + // Write CBOR body let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(ApplicationMessageType::PresentationConnectionCloseEvent as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with 3 or 4 fields (error_message is optional) let field_count = if self.error_message.is_some() { 4 } else { 3 }; encoder @@ -2124,19 +2126,17 @@ impl<'a> PresentationConnectionCloseEvent<'a> { /// Decode this message from CBOR pub fn decode(data: &'a [u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != ApplicationMessageType::PresentationConnectionCloseEvent as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } + + /// Decode from CBOR body (without type key) + pub fn decode_body(body: &'a [u8]) -> Result { + let mut decoder = Decoder::new(body); let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; let field_count = map_len.ok_or(MessageError::InvalidField)?; @@ -2194,15 +2194,16 @@ pub struct PresentationConnectionMessage<'a> { impl<'a> PresentationConnectionMessage<'a> { /// Encode this message to CBOR pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key( + ApplicationMessageType::PresentationConnectionMessage as u16, + buf, + )?; + + // Write CBOR body let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(ApplicationMessageType::PresentationConnectionMessage as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with 2 fields encoder.map(2).map_err(|_| MessageError::EncodeFailed)?; @@ -2223,19 +2224,17 @@ impl<'a> PresentationConnectionMessage<'a> { /// Decode this message from CBOR pub fn decode(data: &'a [u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != ApplicationMessageType::PresentationConnectionMessage as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } + + /// Decode from CBOR body (without type key) + pub fn decode_body(body: &'a [u8]) -> Result { + let mut decoder = Decoder::new(body); // Read the map let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; @@ -2282,15 +2281,13 @@ pub struct PresentationChangeEvent<'a> { impl<'a> PresentationChangeEvent<'a> { /// Encode this message to CBOR pub fn encode(&self, buf: &mut Vec) -> Result<(), MessageError> { + // Write type key as RFC 9000 varint + encode_type_key(ApplicationMessageType::PresentationChangeEvent as u16, buf)?; + + // Write CBOR body let writer = VecWriter::new(buf); let mut encoder = Encoder::new(writer); - // Top-level array: [type_key, body] - encoder.array(2).map_err(|_| MessageError::EncodeFailed)?; - encoder - .u16(ApplicationMessageType::PresentationChangeEvent as u16) - .map_err(|_| MessageError::EncodeFailed)?; - // Body is a map with 2 fields encoder.map(2).map_err(|_| MessageError::EncodeFailed)?; @@ -2311,19 +2308,17 @@ impl<'a> PresentationChangeEvent<'a> { /// Decode this message from CBOR pub fn decode(data: &'a [u8]) -> Result { - let mut decoder = Decoder::new(data); - - // Top-level array: [type_key, body] - let array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - if array_len != Some(2) { - return Err(MessageError::InvalidField); - } - - // Check type key - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Read type key as RFC 9000 varint + let (type_key, consumed) = decode_type_key(data)?; if type_key != ApplicationMessageType::PresentationChangeEvent as u16 { return Err(MessageError::InvalidMessageType); } + Self::decode_body(&data[consumed..]) + } + + /// Decode from CBOR body (without type key) + pub fn decode_body(body: &'a [u8]) -> Result { + let mut decoder = Decoder::new(body); // Read the map let map_len = decoder.map().map_err(|_| MessageError::DecodeFailed)?; @@ -2430,94 +2425,94 @@ impl<'a> ApplicationMessage<'a> { /// Decode a message from CBOR pub fn decode(buf: &'a [u8]) -> Result { // First, peek at the message type to determine which variant to decode - let mut decoder = Decoder::new(buf); - - // All messages are encoded as [type_key, payload] - let _array_len = decoder.array().map_err(|_| MessageError::DecodeFailed)?; - let type_key = decoder.u16().map_err(|_| MessageError::DecodeFailed)?; + // Type key is encoded as RFC 9000 variable-length integer + let (type_key, consumed) = decode_type_key(buf)?; let msg_type = ApplicationMessageType::from_u16(type_key)?; + let body = &buf[consumed..]; - // Now decode the full message based on type + // Decode the body based on type (type key already consumed) match msg_type { ApplicationMessageType::AgentInfoRequest => Ok(ApplicationMessage::AgentInfoRequest( - AgentInfoRequest::decode(buf)?, + AgentInfoRequest::decode_body(body)?, )), ApplicationMessageType::AgentInfoResponse => Ok(ApplicationMessage::AgentInfoResponse( - AgentInfoResponse::decode(buf)?, + AgentInfoResponse::decode_body(body)?, )), ApplicationMessageType::AgentStatusRequest => Ok( - ApplicationMessage::AgentStatusRequest(AgentStatusRequest::decode(buf)?), + ApplicationMessage::AgentStatusRequest(AgentStatusRequest::decode_body(body)?), ), ApplicationMessageType::AgentStatusResponse => Ok( - ApplicationMessage::AgentStatusResponse(AgentStatusResponse::decode(buf)?), + ApplicationMessage::AgentStatusResponse(AgentStatusResponse::decode_body(body)?), ), ApplicationMessageType::AgentInfoEvent => Ok(ApplicationMessage::AgentInfoEvent( - AgentInfoEvent::decode(buf)?, + AgentInfoEvent::decode_body(body)?, )), ApplicationMessageType::PresentationUrlAvailabilityRequest => { Ok(ApplicationMessage::PresentationUrlAvailabilityRequest( - PresentationUrlAvailabilityRequest::decode(buf)?, + PresentationUrlAvailabilityRequest::decode_body(body)?, )) } ApplicationMessageType::PresentationUrlAvailabilityResponse => { Ok(ApplicationMessage::PresentationUrlAvailabilityResponse( - PresentationUrlAvailabilityResponse::decode(buf)?, + PresentationUrlAvailabilityResponse::decode_body(body)?, )) } ApplicationMessageType::PresentationUrlAvailabilityEvent => { Ok(ApplicationMessage::PresentationUrlAvailabilityEvent( - PresentationUrlAvailabilityEvent::decode(buf)?, + PresentationUrlAvailabilityEvent::decode_body(body)?, )) } ApplicationMessageType::PresentationStartRequest => { Ok(ApplicationMessage::PresentationStartRequest( - PresentationStartRequest::decode(buf)?, + PresentationStartRequest::decode_body(body)?, )) } ApplicationMessageType::PresentationStartResponse => { Ok(ApplicationMessage::PresentationStartResponse( - PresentationStartResponse::decode(buf)?, + PresentationStartResponse::decode_body(body)?, )) } ApplicationMessageType::PresentationTerminationRequest => { Ok(ApplicationMessage::PresentationTerminationRequest( - PresentationTerminationRequest::decode(buf)?, + PresentationTerminationRequest::decode_body(body)?, )) } ApplicationMessageType::PresentationTerminationResponse => { Ok(ApplicationMessage::PresentationTerminationResponse( - PresentationTerminationResponse::decode(buf)?, + PresentationTerminationResponse::decode_body(body)?, )) } ApplicationMessageType::PresentationTerminationEvent => { Ok(ApplicationMessage::PresentationTerminationEvent( - PresentationTerminationEvent::decode(buf)?, + PresentationTerminationEvent::decode_body(body)?, )) } ApplicationMessageType::PresentationConnectionOpenRequest => { Ok(ApplicationMessage::PresentationConnectionOpenRequest( - PresentationConnectionOpenRequest::decode(buf)?, + PresentationConnectionOpenRequest::decode_body(body)?, )) } ApplicationMessageType::PresentationConnectionOpenResponse => { Ok(ApplicationMessage::PresentationConnectionOpenResponse( - PresentationConnectionOpenResponse::decode(buf)?, + PresentationConnectionOpenResponse::decode_body(body)?, )) } ApplicationMessageType::PresentationConnectionCloseEvent => { Ok(ApplicationMessage::PresentationConnectionCloseEvent( - PresentationConnectionCloseEvent::decode(buf)?, + PresentationConnectionCloseEvent::decode_body(body)?, )) } ApplicationMessageType::PresentationConnectionMessage => { Ok(ApplicationMessage::PresentationConnectionMessage( - PresentationConnectionMessage::decode(buf)?, + PresentationConnectionMessage::decode_body(body)?, + )) + } + ApplicationMessageType::PresentationChangeEvent => { + Ok(ApplicationMessage::PresentationChangeEvent( + PresentationChangeEvent::decode_body(body)?, )) } - ApplicationMessageType::PresentationChangeEvent => Ok( - ApplicationMessage::PresentationChangeEvent(PresentationChangeEvent::decode(buf)?), - ), } } } diff --git a/openscreen-network/src/messages.rs b/openscreen-network/src/messages.rs index 56fc386..d3f8809 100644 --- a/openscreen-network/src/messages.rs +++ b/openscreen-network/src/messages.rs @@ -79,10 +79,8 @@ fn decode_type_key(data: &[u8]) -> Result<(u16, usize), MessageError> { let varint = VarInt::decode(&mut cursor).map_err(|_| MessageError::DecodeFailed)?; let consumed = data.len() - cursor.remaining(); let value = varint.into_inner(); - if value > u16::MAX as u64 { - return Err(MessageError::InvalidMessageType); - } - Ok((value as u16, consumed)) + let type_key = u16::try_from(value).map_err(|_| MessageError::InvalidMessageType)?; + Ok((type_key, consumed)) } /// Maximum size for a single CBOR message