1use std::borrow::Cow;
16use std::collections::HashMap;
17use std::io::Cursor;
18use std::net::IpAddr;
19use std::net::Ipv4Addr;
20use std::net::Ipv6Addr;
21use std::net::SocketAddr;
22use std::str;
23
24use byteorder::BigEndian;
25use byteorder::ByteOrder;
26use bytes::Buf;
27use bytes::BufMut;
28use bytes::Bytes;
29use bytes::BytesMut;
30use cheetah_string::CheetahBuilder;
31use cheetah_string::CheetahString;
32use memchr::memchr;
33
34use crate::common::compression::compressor_factory::CompressorFactory;
35use rocketmq_model::codec::string_to_bytes;
36use rocketmq_model::common::message::message_client_ext::MessageClientExt;
37use rocketmq_model::common::message::message_ext::MessageExt;
38use rocketmq_model::common::message::message_id::MessageId;
39use rocketmq_model::common::message::message_property::MessageProperties;
40use rocketmq_model::common::message::message_single::Message;
41use rocketmq_model::common::message::MessageConst;
42use rocketmq_model::common::message::MessageTrait;
43use rocketmq_model::common::message::MessageVersion;
44use rocketmq_model::common::sys_flag::message_sys_flag::MessageSysFlag;
45use rocketmq_model::utils::crc32_utils::crc32;
46use rocketmq_model::utils::message_utils::build_message_id;
47
48pub const CHARSET_UTF8: &str = "UTF-8";
49pub const MESSAGE_MAGIC_CODE_POSITION: usize = 4;
50pub const MESSAGE_FLAG_POSITION: usize = 16;
51pub const MESSAGE_PHYSIC_OFFSET_POSITION: usize = 28;
52pub const MESSAGE_STORE_TIMESTAMP_POSITION: usize = 56;
53pub const MESSAGE_MAGIC_CODE: i32 = -626843481;
54pub const MESSAGE_MAGIC_CODE_V2: i32 = -626843477;
55pub const BLANK_MAGIC_CODE: i32 = -875286124;
56pub const NAME_VALUE_SEPARATOR: char = '\u{0001}';
57pub const PROPERTY_SEPARATOR: char = '\u{0002}';
58pub const PHY_POS_POSITION: usize = 4 + 4 + 4 + 4 + 4 + 8;
59pub const QUEUE_OFFSET_POSITION: usize = 4 + 4 + 4 + 4 + 4;
60pub const SYSFLAG_POSITION: usize = 4 + 4 + 4 + 4 + 4 + 8 + 8;
61pub const BORN_TIMESTAMP_POSITION: usize = 4 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 8;
62
63const SMALL_PROPERTIES_PREALLOC_THRESHOLD: usize = 16;
64const SMALL_PROPERTY_PREALLOC_BYTES: usize = 34;
65
66macro_rules! decode_message_properties_into {
67 ($map:ident, $properties:expr) => {{
68 let properties = $properties;
69 let bytes = properties.as_bytes();
70 let mut index = 0;
71 let len = bytes.len();
72 while index < len {
73 let new_index = memchr(PROPERTY_SEPARATOR as u8, &bytes[index..]).map_or(len, |i| index + i);
74 if new_index - index >= 3 {
75 if let Some(kv_sep_index) = memchr(NAME_VALUE_SEPARATOR as u8, &bytes[index..new_index]) {
76 let kv_sep_index = index + kv_sep_index;
77 if kv_sep_index > index && kv_sep_index < new_index - 1 {
78 let k = &properties[index..kv_sep_index];
79 let v = &properties[kv_sep_index + 1..new_index];
80 $map.insert(CheetahString::from_slice(k), CheetahString::from_slice(v));
81 }
82 }
83 }
84 index = new_index + 1;
85 }
86 }};
87}
88
89fn get_i16_checked(buffer: &mut Bytes) -> Option<i16> {
90 if buffer.remaining() < 2 {
91 None
92 } else {
93 Some(buffer.get_i16())
94 }
95}
96
97fn get_i32_checked(buffer: &mut Bytes) -> Option<i32> {
98 if buffer.remaining() < 4 {
99 None
100 } else {
101 Some(buffer.get_i32())
102 }
103}
104
105fn split_to_checked(buffer: &mut Bytes, len: usize) -> Option<Bytes> {
106 if buffer.remaining() < len {
107 None
108 } else {
109 Some(buffer.split_to(len))
110 }
111}
112
113pub fn string_to_message_properties(properties: Option<&CheetahString>) -> HashMap<CheetahString, CheetahString> {
114 if let Some(properties) = properties {
115 str_to_message_properties(Some(properties.as_str()))
116 } else {
117 HashMap::new()
118 }
119}
120
121pub fn str_to_message_properties(properties: Option<&str>) -> HashMap<CheetahString, CheetahString> {
122 let mut map = HashMap::new();
123 if let Some(properties) = properties {
124 decode_message_properties_into!(map, properties);
125 }
126 map
127}
128
129#[inline]
132pub fn message_properties_to_string(properties: &HashMap<CheetahString, CheetahString>) -> CheetahString {
133 if properties.is_empty() {
134 return CheetahString::empty();
135 }
136
137 let property_count = properties.len();
138 let capacity = if property_count <= SMALL_PROPERTIES_PREALLOC_THRESHOLD {
139 property_count * SMALL_PROPERTY_PREALLOC_BYTES
140 } else {
141 let mut len = 0;
142 for (name, value) in properties.iter() {
143 len += name.len();
144 len += value.len();
145 len += 2; }
147 len
148 };
149
150 let mut builder = CheetahBuilder::with_capacity(capacity);
151 for (name, value) in properties.iter() {
152 builder.push_str(name.as_str());
153 builder.push(NAME_VALUE_SEPARATOR);
154
155 builder.push_str(value.as_str());
156 builder.push(PROPERTY_SEPARATOR);
157 }
158 builder.finish()
159}
160
161pub fn cheetah_from_utf8_lossy(bytes: &[u8]) -> CheetahString {
164 match String::from_utf8_lossy(bytes) {
165 Cow::Borrowed(value) => CheetahString::from_slice(value),
166 Cow::Owned(value) => CheetahString::from_string(value),
167 }
168}
169
170pub fn decode_client(
171 byte_buffer: &mut Bytes,
172 read_body: bool,
173 de_compress_body: bool,
174 is_set_properties_string: bool,
175 check_crc: bool,
176) -> Option<MessageClientExt> {
177 decode(
192 byte_buffer,
193 read_body,
194 de_compress_body,
195 false,
196 is_set_properties_string,
197 check_crc,
198 )
199 .map(|msg_ext| MessageClientExt {
200 message_ext_inner: msg_ext,
201 })
202}
203
204pub fn decode(
206 byte_buffer: &mut Bytes,
207 read_body: bool,
208 de_compress_body: bool,
209 _is_client: bool,
210 is_set_properties_string: bool,
211 check_crc: bool,
212) -> Option<MessageExt> {
213 let frame = crate::protocol::body::message_codec::decode_message_frame(byte_buffer).ok()?;
214
215 if read_body && !frame.body.is_empty() && check_crc && crc32(&frame.body) != frame.body_crc {
216 return None;
217 }
218
219 let mut msg_ext = MessageExt::default();
220 msg_ext.set_store_size(frame.store_size);
221 msg_ext.set_body_crc(frame.body_crc);
222 msg_ext.set_queue_id(frame.queue_id);
223 msg_ext.message.set_flag(frame.flag);
224 msg_ext.set_queue_offset(frame.queue_offset);
225 msg_ext.set_commit_log_offset(frame.commit_log_offset);
226 msg_ext.set_sys_flag(frame.sys_flag);
227 msg_ext.set_born_timestamp(frame.born_timestamp);
228 msg_ext.set_born_host(frame.born_host);
229 msg_ext.set_store_timestamp(frame.store_timestamp);
230 msg_ext.set_store_host(frame.store_host);
231 msg_ext.set_reconsume_times(frame.reconsume_times);
232 msg_ext.set_prepared_transaction_offset(frame.prepared_transaction_offset);
233 msg_ext.message.set_topic(frame.topic);
234
235 if read_body && !frame.body.is_empty() {
236 let mut body = frame.body;
237 if de_compress_body && (frame.sys_flag & MessageSysFlag::COMPRESSED_FLAG) == MessageSysFlag::COMPRESSED_FLAG {
238 let compression_type = MessageSysFlag::try_get_compression_type(frame.sys_flag).ok()?;
239 body = compression_type.try_decompression(&body).ok()?;
240 }
241 msg_ext.message.set_body(Some(body));
242 }
243
244 let mut properties = frame.properties;
245 if is_set_properties_string && !frame.properties_string.is_empty() {
246 properties.insert(
247 CheetahString::from_static_str("propertiesString"),
248 frame.properties_string,
249 );
250 }
251 *msg_ext.message.properties_mut() = MessageProperties::from_map(properties);
252 msg_ext.set_msg_id(CheetahString::from_string(build_message_id(
253 frame.store_host,
254 frame.commit_log_offset,
255 )));
256
257 Some(msg_ext)
258}
259
260pub fn count_inner_msg_num(bytes: Option<Bytes>) -> u32 {
261 match bytes {
262 None => 0,
263 Some(mut bytes) => {
264 let mut count = 0;
265 while bytes.has_remaining() {
266 let size = bytes.slice(0..4).get_i32();
267 if size as usize > bytes.len() {
268 break;
269 }
270 let _ = bytes.split_to(size as usize);
271 count += 1;
272 }
273 count
274 }
275 }
276}
277
278pub fn encode_messages(messages: &[Message]) -> Bytes {
279 let mut bytes = BytesMut::new();
280 for message in messages {
281 encode_message_into(message, &mut bytes);
282 }
283 bytes.freeze()
284}
285
286pub fn encode_message(message: &Message) -> Bytes {
287 let mut bytes = BytesMut::new();
288 encode_message_into(message, &mut bytes);
289 bytes.freeze()
290}
291
292pub fn encode_message_into(message: &Message, bytes: &mut BytesMut) {
297 let empty_body = Bytes::new();
298 let body = message.get_body().unwrap_or(&empty_body);
299 let body_len = body.len();
300 let properties = message_properties_to_string(message.properties().as_map());
301 let properties_bytes = properties.as_bytes();
302 let properties_length = properties_bytes.len();
303
304 let store_size = 4 + 4 + 4 + 4 + 4 + body_len + 2 + properties_length;
310
311 bytes.reserve(store_size);
312
313 bytes.put_i32(store_size as i32);
315
316 bytes.put_i32(0);
318
319 bytes.put_u32(0);
321
322 bytes.put_i32(message.flag());
324
325 bytes.put_i32(body_len as i32);
327 bytes.put_slice(body);
328
329 bytes.put_i16(properties_length as i16);
331 bytes.put_slice(properties_bytes);
332}
333
334pub fn decodes_batch(byte_buffer: &mut Bytes, read_body: bool, decompress_body: bool) -> Vec<MessageExt> {
335 let mut messages = Vec::new();
336 while byte_buffer.has_remaining() {
337 if let Some(msg_ext) = decode(byte_buffer, read_body, decompress_body, false, false, false) {
338 messages.push(msg_ext);
339 } else {
340 break;
341 }
342 }
343 messages
344}
345
346fn split_next_message_frame(byte_buffer: &mut Bytes) -> Option<Bytes> {
347 let remaining = byte_buffer.remaining();
348 if remaining < 4 {
349 return None;
350 }
351
352 let mut header = byte_buffer.clone();
353 let store_size = header.get_i32();
354 if store_size <= 0 || store_size as usize > remaining {
355 return None;
356 }
357
358 Some(byte_buffer.split_to(store_size as usize))
359}
360
361pub fn decodes_batch_with_metadata_filter<F>(
362 byte_buffer: &mut Bytes,
363 read_body: bool,
364 decompress_body: bool,
365 mut should_decode_body: F,
366) -> Vec<MessageExt>
367where
368 F: FnMut(&MessageExt) -> bool,
369{
370 let mut messages = Vec::new();
371 while byte_buffer.has_remaining() {
372 let Some(frame) = split_next_message_frame(byte_buffer) else {
373 break;
374 };
375 let mut metadata_frame = frame.clone();
376 let Some(metadata) = decode(&mut metadata_frame, false, false, false, false, false) else {
377 break;
378 };
379 if !should_decode_body(&metadata) {
380 continue;
381 }
382
383 let mut full_frame = frame;
384 if let Some(msg_ext) = decode(&mut full_frame, read_body, decompress_body, false, false, false) {
385 messages.push(msg_ext);
386 } else {
387 break;
388 }
389 }
390 messages
391}
392
393pub fn decodes_batch_client(byte_buffer: &mut Bytes, read_body: bool, decompress_body: bool) -> Vec<MessageClientExt> {
394 let mut messages = Vec::new();
395 while byte_buffer.has_remaining() {
396 if let Some(msg_ext) = decode_client(byte_buffer, read_body, decompress_body, false, false) {
397 messages.push(msg_ext);
398 } else {
399 break;
400 }
401 }
402 messages
403}
404
405pub fn decode_messages_from(mut message_ext: MessageExt, vec_: &mut Vec<MessageExt>) {
406 let Some(body) = message_ext.message.body_mut().raw_mut().as_mut() else {
407 return;
408 };
409 let messages = decode_messages(body);
410 for message in messages {
411 let mut message_ext_inner = MessageExt {
412 message,
413 ..MessageExt::default()
414 };
415 message_ext_inner.set_topic(message_ext.topic().to_owned());
416 message_ext_inner.queue_offset = message_ext.queue_offset;
417 message_ext_inner.queue_id = message_ext.queue_id;
418 message_ext_inner.set_flag(message_ext.get_flag());
419 message_ext_inner.store_host = message_ext.store_host;
423 message_ext_inner.born_host = message_ext.born_host;
424 message_ext_inner.store_timestamp = message_ext.store_timestamp;
425 message_ext_inner.born_timestamp = message_ext.born_timestamp;
426 message_ext_inner.sys_flag = message_ext.sys_flag;
427 message_ext_inner.commit_log_offset = message_ext.commit_log_offset;
428 message_ext_inner.set_wait_store_msg_ok(message_ext.is_wait_store_msg_ok());
429 vec_.push(message_ext_inner);
430 }
431}
432
433pub fn decode_messages(buffer: &mut Bytes) -> Vec<Message> {
434 let mut messages = Vec::new();
435 while buffer.has_remaining() {
436 let Some(message) = try_decode_message(buffer) else {
437 break;
438 };
439 messages.push(message);
440 }
441 messages
442}
443
444pub fn decode_message(buffer: &mut Bytes) -> Message {
445 try_decode_message(buffer).unwrap_or_default()
446}
447
448fn try_decode_message(buffer: &mut Bytes) -> Option<Message> {
449 let store_size = get_i32_checked(buffer)?;
451 if store_size <= 0 {
452 return None;
453 }
454
455 let _ = get_i32_checked(buffer)?;
457
458 let _ = get_i32_checked(buffer)?;
460
461 let flag = get_i32_checked(buffer)?;
463
464 let body_len = get_i32_checked(buffer)?;
466 if body_len < 0 {
467 return None;
468 }
469 let body = split_to_checked(buffer, body_len as usize)?;
470
471 let properties_length = get_i16_checked(buffer)?;
473 if properties_length < 0 {
474 return None;
475 }
476 let properties = split_to_checked(buffer, properties_length as usize)?;
477 let message_properties = str_to_message_properties(Some(str::from_utf8(&properties).ok()?));
480
481 let mut message = Message::default();
482 message.set_body(Some(body));
483 message.set_properties(message_properties);
484 message.set_flag(flag);
485 Some(message)
486}
487
488const MSG_ID_IPV4_LEN: usize = 32;
489const MSG_ID_IPV6_LEN: usize = 56;
490
491pub fn validate_message_id(msg_id: &str) -> Result<(), String> {
492 let msg_id = msg_id.trim();
493
494 if msg_id.is_empty() {
495 return Err("Message ID cannot be empty".to_string());
496 }
497
498 let len = msg_id.len();
499 if len != MSG_ID_IPV4_LEN && len != MSG_ID_IPV6_LEN {
500 return Err(format!(
501 "Invalid message ID length: {len}. Expected {MSG_ID_IPV4_LEN} characters (IPv4) or {MSG_ID_IPV6_LEN} \
502 characters (IPv6)"
503 ));
504 }
505
506 if !msg_id.bytes().all(|b| b.is_ascii_hexdigit()) {
507 return Err("Message ID must be a valid hexadecimal string".to_string());
508 }
509
510 Ok(())
511}
512
513pub fn decode_message_id(msg_id: &str) -> Result<MessageId, String> {
514 validate_message_id(msg_id)?;
515 let bytes = string_to_bytes(msg_id).ok_or_else(|| "Failed to decode message ID: invalid hex string".to_string())?;
516 let mut buffer = Bytes::from(bytes);
517 let address = if msg_id.len() == 32 {
518 let mut ip = [0u8; 4];
519 buffer.copy_to_slice(&mut ip);
520 let port = buffer.get_i32();
521 SocketAddr::new(IpAddr::V4(Ipv4Addr::from(ip)), port as u16)
522 } else {
523 let mut ip = [0u8; 16];
524 buffer.copy_to_slice(&mut ip);
525 let port = buffer.get_i32();
526 SocketAddr::new(IpAddr::V6(Ipv6Addr::from(ip)), port as u16)
527 };
528 Ok(MessageId {
529 address,
530 offset: buffer.get_i64(),
531 })
532}
533
534pub fn encode(message_ext: &MessageExt, need_compress: bool) -> rocketmq_error::Result<Bytes> {
535 let body = message_ext
536 .get_body()
537 .ok_or_else(|| crate::error::invalid_argument("message body is required"))?;
538 let topic = message_ext.topic().as_bytes();
539 let topic_len = topic.len();
540 let properties = message_properties_to_string(message_ext.get_properties());
541 let properties_bytes = properties.as_bytes();
542 let properties_length = properties_bytes.len();
543 let sys_flag = message_ext.sys_flag;
544 let born_host_length = if (sys_flag & MessageSysFlag::BORNHOST_V6_FLAG) == 0 {
545 8
546 } else {
547 20
548 };
549 let store_host_address_length = if (sys_flag & MessageSysFlag::STOREHOSTADDRESS_V6_FLAG) == 0 {
550 8
551 } else {
552 20
553 };
554 let new_body = if need_compress && (sys_flag & MessageSysFlag::COMPRESSED_FLAG) == MessageSysFlag::COMPRESSED_FLAG {
555 let compressor = CompressorFactory::get_compressor(MessageSysFlag::try_get_compression_type(sys_flag)?);
556 let compressed_body = compressor.compress(body, 5)?;
557 Some(compressed_body)
558 } else {
559 None
560 };
561 let body_len = new_body.as_ref().map_or(body.len(), |b| b.len());
562 let store_size = if message_ext.store_size > 0 {
563 message_ext.store_size as usize
564 } else {
565 4 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 8 + born_host_length + 8 + store_host_address_length + 4 + 8 + 4 + body_len + 1 + topic_len + 2 + properties_length };
583 let mut byte_buffer = BytesMut::with_capacity(store_size);
584
585 byte_buffer.put_i32(store_size as i32);
587
588 byte_buffer.put_i32(MESSAGE_MAGIC_CODE);
590
591 byte_buffer.put_u32(message_ext.body_crc);
593
594 byte_buffer.put_i32(message_ext.queue_id);
596
597 byte_buffer.put_i32(message_ext.message.flag());
599
600 byte_buffer.put_i64(message_ext.queue_offset);
602
603 byte_buffer.put_i64(message_ext.commit_log_offset);
605
606 byte_buffer.put_i32(message_ext.sys_flag);
608
609 byte_buffer.put_i64(message_ext.born_timestamp);
611
612 let born_host = message_ext.born_host;
615 match born_host {
616 SocketAddr::V4(value) => byte_buffer.extend(value.ip().octets()),
617 SocketAddr::V6(value) => byte_buffer.extend(value.ip().octets()),
618 };
619
620 byte_buffer.put_i32(born_host.port() as i32);
621
622 byte_buffer.put_i64(message_ext.store_timestamp);
624
625 let store_host = message_ext.store_host;
628 match store_host {
629 SocketAddr::V4(value) => byte_buffer.extend(value.ip().octets()),
630 SocketAddr::V6(value) => byte_buffer.extend(value.ip().octets()),
631 };
632
633 byte_buffer.put_i32(store_host.port() as i32);
634
635 byte_buffer.put_i32(message_ext.reconsume_times);
637
638 byte_buffer.put_i64(message_ext.prepared_transaction_offset);
640
641 byte_buffer.put_i32(body_len as i32);
643 if let Some(new_body) = new_body {
644 byte_buffer.put_slice(&new_body);
645 } else {
646 byte_buffer.put_slice(body);
647 }
648
649 byte_buffer.put_u8(topic_len as u8);
651 byte_buffer.put_slice(topic);
652
653 byte_buffer.put_i16(properties_length as i16);
655 byte_buffer.put_slice(properties_bytes);
656
657 Ok(byte_buffer.freeze())
658}
659
660pub fn encode_uniquely(message_ext: &MessageExt, need_compress: bool) -> rocketmq_error::Result<Bytes> {
661 let body = message_ext
662 .get_body()
663 .ok_or_else(|| crate::error::invalid_argument("message body is required"))?;
664 let topics = message_ext.topic().as_bytes();
665 let topic_len = topics.len();
666 let properties = message_properties_to_string(message_ext.get_properties());
667 let properties_bytes = properties.as_bytes();
668 let properties_length = properties_bytes.len();
669 let sys_flag = message_ext.sys_flag;
670 let born_host_length = if (sys_flag & MessageSysFlag::BORNHOST_V6_FLAG) == 0 {
671 8
672 } else {
673 20
674 };
675 let new_body = if need_compress && (sys_flag & MessageSysFlag::COMPRESSED_FLAG) == MessageSysFlag::COMPRESSED_FLAG {
676 let compressor = CompressorFactory::get_compressor(MessageSysFlag::try_get_compression_type(sys_flag)?);
677 let compressed_body = compressor.compress(body, 5)?;
678 Some(compressed_body)
679 } else {
680 None
681 };
682 let body_len = new_body.as_ref().map_or(body.len(), |b| b.len());
683 let store_size = if message_ext.store_size > 0 {
684 message_ext.store_size as usize
685 } else {
686 4 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 8 + born_host_length + 4 + 8 + 4 + body_len + 1 + topic_len + 2 + properties_length };
702 let capacity = if message_ext.store_size > 0 {
703 store_size.saturating_sub(8)
704 } else {
705 store_size
706 };
707 let mut byte_buffer = BytesMut::with_capacity(capacity);
708
709 byte_buffer.put_i32(store_size as i32);
711
712 byte_buffer.put_i32(MESSAGE_MAGIC_CODE);
714
715 byte_buffer.put_u32(message_ext.body_crc);
717
718 byte_buffer.put_i32(message_ext.queue_id);
720
721 byte_buffer.put_i32(message_ext.message.flag());
723
724 byte_buffer.put_i64(message_ext.queue_offset);
726
727 byte_buffer.put_i64(message_ext.commit_log_offset);
729
730 byte_buffer.put_i32(message_ext.sys_flag);
732
733 byte_buffer.put_i64(message_ext.born_timestamp);
735
736 let born_host = message_ext.born_host;
739 match born_host {
740 SocketAddr::V4(value) => byte_buffer.extend(value.ip().octets()),
741 SocketAddr::V6(value) => byte_buffer.extend(value.ip().octets()),
742 };
743 byte_buffer.put_i32(born_host.port() as i32);
744
745 byte_buffer.put_i32(message_ext.reconsume_times);
747
748 byte_buffer.put_i64(message_ext.prepared_transaction_offset);
750
751 byte_buffer.put_i32(body_len as i32);
753 if let Some(new_body) = new_body {
754 byte_buffer.put_slice(&new_body);
755 } else {
756 byte_buffer.put_slice(body);
757 }
758
759 byte_buffer.put_i16(topic_len as i16);
761 byte_buffer.put_slice(topics);
762
763 byte_buffer.put_i16(properties_length as i16);
765 byte_buffer.put_slice(properties_bytes);
766
767 Ok(byte_buffer.freeze())
768}
769
770pub fn create_crc32(mut input: &mut [u8], crc32: u32) {
771 input.put(MessageConst::PROPERTY_CRC32.as_bytes());
772 input.put_u8(NAME_VALUE_SEPARATOR as u8);
773 let mut crc32 = crc32;
774 for _ in 0..10 {
775 let mut b = b'0';
776 if crc32 > 0 {
777 b += (crc32 % 10) as u8;
778 crc32 /= 10;
779 }
780 input.put_u8(b);
781 }
782 input.put_u8(PROPERTY_SEPARATOR as u8);
783}
784
785pub fn decode_properties(bytes: &mut Bytes) -> Option<HashMap<CheetahString, CheetahString>> {
786 if bytes.len() < SYSFLAG_POSITION + 4 {
788 return None;
789 }
790
791 let sys_flag = BigEndian::read_i32(&bytes[SYSFLAG_POSITION..SYSFLAG_POSITION + 4]);
793 let magic_code = BigEndian::read_i32(&bytes[MESSAGE_MAGIC_CODE_POSITION..MESSAGE_MAGIC_CODE_POSITION + 4]);
794 let version = match MessageVersion::value_of_magic_code(magic_code) {
795 Ok(value) => value,
796 Err(_) => return None,
797 };
798
799 let bornhost_length = if (sys_flag & MessageSysFlag::BORNHOST_V6_FLAG) == 0 {
801 8
802 } else {
803 20
804 };
805 let storehost_address_length = if (sys_flag & MessageSysFlag::STOREHOSTADDRESS_V6_FLAG) == 0 {
806 8
807 } else {
808 20
809 };
810
811 let body_size_position = 4 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 8 + bornhost_length + 8 + storehost_address_length + 4 + 8; if bytes.len() < body_size_position + 4 {
828 return None;
829 }
830
831 let body_size = BigEndian::read_i32(&bytes[body_size_position..body_size_position + 4]) as usize;
833
834 let topic_length_position = body_size_position + 4 + body_size;
836 if bytes.len() < topic_length_position {
837 return None;
838 }
839
840 let slice = &bytes[topic_length_position..];
842 let _cursor = Cursor::new(slice);
843 let topic_length_size = version.get_topic_length_size();
844 bytes.advance(topic_length_position);
845 let topic_length = version.get_topic_length(bytes);
846
847 let properties_position = topic_length_position + topic_length_size + topic_length;
849 if bytes.len() < properties_position + 2 {
850 return None;
851 }
852
853 let properties_length = BigEndian::read_i16(&bytes[properties_position..properties_position + 2]);
855
856 let properties_start = properties_position + 2;
858 if properties_length > 0 {
859 let end = properties_start + (properties_length as usize);
860 if bytes.len() < end {
861 return None;
862 }
863 let properties_bytes = &bytes[properties_start..end];
864 if let Ok(properties_string) = String::from_utf8(properties_bytes.to_vec()) {
865 Some(string_to_message_properties(Some(&CheetahString::from_string(
866 properties_string,
867 ))))
868 } else {
869 None
870 }
871 } else {
872 None
873 }
874}
875
876#[cfg(test)]
877mod tests {
878 use bytes::BufMut;
879 use bytes::BytesMut;
880
881 use super::*;
882
883 fn message_ext_with_tag(queue_offset: i64, tag: &str, body_size: usize) -> MessageExt {
884 let message = Message::builder()
885 .topic("MetadataFilterTopic")
886 .tags(tag)
887 .body(vec![b'x'; body_size])
888 .build()
889 .expect("test message should build");
890
891 let mut message_ext = MessageExt::default();
892 message_ext.set_message_inner(message);
893 message_ext.set_queue_id(1);
894 message_ext.set_queue_offset(queue_offset);
895 message_ext.set_commit_log_offset(queue_offset * 1024);
896 message_ext
897 }
898
899 #[test]
900 fn encode_messages_matches_concatenated_single_message_wire_bytes() {
901 let messages = vec![
902 Message::builder()
903 .topic("BatchTopic")
904 .tags("TagA")
905 .body_slice(b"first")
906 .build_unchecked(),
907 Message::builder()
908 .topic("BatchTopic")
909 .keys(vec!["key-a".to_string(), "key-b".to_string()])
910 .body_slice(b"second-message")
911 .build_unchecked(),
912 ];
913 let mut expected = BytesMut::new();
914 for message in &messages {
915 expected.put_slice(&encode_message(message));
916 }
917
918 assert_eq!(encode_messages(&messages), expected.freeze());
919 }
920
921 #[test]
922 fn decodes_batch_with_metadata_filter_skips_bodies_for_rejected_frames() {
923 let rejected = message_ext_with_tag(0, "Skip", 1024);
924 let accepted = message_ext_with_tag(1, "Keep", 32);
925 let mut payload = BytesMut::new();
926 payload.put_slice(&encode(&rejected, false).expect("rejected message should encode"));
927 payload.put_slice(&encode(&accepted, false).expect("accepted message should encode"));
928 let mut payload = payload.freeze();
929 let mut inspected = Vec::new();
930
931 let messages = decodes_batch_with_metadata_filter(&mut payload, true, false, |metadata| {
932 inspected.push((metadata.queue_offset, metadata.get_body().is_some(), metadata.tags()));
933 metadata.tags().as_deref() == Some("Keep")
934 });
935
936 assert_eq!(messages.len(), 1);
937 assert_eq!(messages[0].queue_offset, 1);
938 assert_eq!(
939 messages[0].get_body().expect("accepted body should materialize").len(),
940 32
941 );
942 assert_eq!(payload.len(), 0);
943 assert_eq!(inspected.len(), 2);
944 assert_eq!(inspected[0], (0, false, Some(CheetahString::from_static_str("Skip"))));
945 assert_eq!(inspected[1], (1, false, Some(CheetahString::from_static_str("Keep"))));
946 }
947
948 #[test]
949 fn message_properties_to_string_preserves_separator_format() {
950 let mut properties = HashMap::new();
951 properties.insert(
952 CheetahString::from_static_str("key"),
953 CheetahString::from_static_str("value"),
954 );
955
956 let encoded = message_properties_to_string(&properties);
957
958 assert_eq!(encoded, "key\u{0001}value\u{0002}");
959 }
960
961 #[test]
962 fn message_properties_to_string_empty_properties_returns_empty_string() {
963 let properties = HashMap::new();
964
965 let encoded = message_properties_to_string(&properties);
966
967 assert!(encoded.is_empty());
968 }
969
970 #[test]
971 fn message_properties_to_string_round_trips_small_property_map() {
972 let properties = [
973 ("topic", "benchmark-topic"),
974 ("keys", "key-a"),
975 ("tags", "tag-a"),
976 ("trace", "trace-001"),
977 ]
978 .into_iter()
979 .map(|(key, value)| {
980 (
981 CheetahString::from_static_str(key),
982 CheetahString::from_static_str(value),
983 )
984 })
985 .collect::<HashMap<_, _>>();
986
987 let encoded = message_properties_to_string(&properties);
988 let decoded = string_to_message_properties(Some(&encoded));
989
990 assert_eq!(decoded, properties);
991 }
992
993 #[test]
994 fn string_and_str_property_decoders_share_behavior() {
995 let encoded =
996 CheetahString::from_static_str("valid\u{0001}value\u{0002}empty\u{0001}\u{0002}next\u{0001}two\u{0002}");
997
998 let from_cheetah = string_to_message_properties(Some(&encoded));
999 let from_str = str_to_message_properties(Some(encoded.as_str()));
1000
1001 assert_eq!(from_cheetah, from_str);
1002 assert_eq!(from_cheetah.len(), 2);
1003 }
1004
1005 #[test]
1006 fn str_to_message_properties_ignores_empty_and_malformed_segments() {
1007 let encoded = concat!(
1008 "valid\u{0001}value\u{0002}",
1009 "\u{0002}",
1010 "empty_value\u{0001}\u{0002}",
1011 "missing_separator\u{0002}",
1012 "second\u{0001}two\u{0002}"
1013 );
1014
1015 let decoded = str_to_message_properties(Some(encoded));
1016
1017 assert_eq!(decoded.len(), 2);
1018 assert_eq!(decoded.get("valid").map(CheetahString::as_str), Some("value"));
1019 assert_eq!(decoded.get("second").map(CheetahString::as_str), Some("two"));
1020 }
1021
1022 #[test]
1023 fn decode_messages_rejects_invalid_utf8_properties() {
1024 let mut bytes = BytesMut::new();
1025 let store_size = 4 + 4 + 4 + 4 + 4 + 2 + 1; bytes.put_i32(store_size);
1034 bytes.put_i32(0);
1035 bytes.put_i32(0);
1036 bytes.put_i32(0);
1037 bytes.put_i32(0);
1038 bytes.put_i16(1);
1039 bytes.put_u8(0xff);
1040
1041 let mut bytes = bytes.freeze();
1042
1043 assert!(decode_messages(&mut bytes).is_empty());
1044 }
1045
1046 #[test]
1047 fn cheetah_from_utf8_lossy_borrows_valid_utf8() {
1048 let encoded = b"key\x01value\x02";
1049
1050 let decoded = cheetah_from_utf8_lossy(encoded);
1051
1052 assert_eq!(decoded, "key\u{0001}value\u{0002}");
1053 }
1054
1055 #[test]
1056 fn cheetah_from_utf8_lossy_preserves_lossy_invalid_utf8_behavior() {
1057 let encoded = b"key\x01\xff\x02";
1058
1059 let decoded = cheetah_from_utf8_lossy(encoded);
1060
1061 assert_eq!(decoded.as_str(), String::from_utf8_lossy(encoded).as_ref());
1062 }
1063
1064 #[test]
1065 fn count_inner_msg_num_counts_correctly_for_multiple_messages() {
1066 let mut bytes = BytesMut::new();
1067 bytes.put_i32(8);
1068 bytes.put_slice(&[0, 0, 0, 0]);
1069 bytes.put_i32(8);
1070 bytes.put_slice(&[0, 0, 0, 0]);
1071 assert_eq!(count_inner_msg_num(Some(bytes.freeze())), 2);
1072 }
1073
1074 #[test]
1075 fn count_inner_msg_num_counts_correctly_for_single_message() {
1076 let mut bytes = BytesMut::new();
1077 bytes.put_i32(8);
1078 bytes.put_slice(&[0, 0, 0, 0]);
1079 assert_eq!(count_inner_msg_num(Some(bytes.freeze())), 1);
1080 }
1081
1082 #[test]
1083 fn count_inner_msg_num_counts_zero_for_no_messages() {
1084 let bytes = BytesMut::new();
1085 assert_eq!(count_inner_msg_num(Some(bytes.freeze())), 0);
1086 }
1087
1088 #[test]
1089 fn count_inner_msg_num_ignores_incomplete_messages() {
1090 let mut bytes = BytesMut::new();
1091 bytes.put_i32(4);
1092 assert_eq!(count_inner_msg_num(Some(bytes.freeze())), 1);
1093 }
1094
1095 #[test]
1096 fn decode_message_id_ipv4() {
1097 let msg_id = "7F0000010007D8260BF075769D36C348";
1098 let message_id = decode_message_id(msg_id).unwrap();
1099 assert_eq!(message_id.address, "127.0.0.1:55334".parse().unwrap());
1100 assert_eq!(message_id.offset, 860316681131967304);
1101 }
1102
1103 #[test]
1104 fn encode_with_compression() {
1105 let mut message_ext = MessageExt::default();
1106 message_ext.set_body(Bytes::from("Hello, World!"));
1107 let result = encode(&message_ext, true);
1108 assert!(result.is_ok());
1109 let bytes = result.unwrap();
1110 assert!(!bytes.is_empty());
1111 }
1112
1113 #[test]
1114 fn encode_with_unknown_compression_type_returns_error() {
1115 let mut message_ext = MessageExt::default();
1116 message_ext.set_body(Bytes::from_static(b"Hello, World!"));
1117 message_ext.set_sys_flag(MessageSysFlag::COMPRESSED_FLAG | (0x7 << 8));
1118
1119 let result = encode(&message_ext, true);
1120
1121 assert!(result.is_err());
1122 }
1123
1124 #[test]
1125 fn decode_compressed_body_uses_sys_flag_compression_type() {
1126 let body = Bytes::from_static(b"Hello from compressed RocketMQ body");
1127
1128 for compression_flag in [
1129 MessageSysFlag::COMPRESSION_LZ4_TYPE,
1130 MessageSysFlag::COMPRESSION_ZSTD_TYPE,
1131 MessageSysFlag::COMPRESSION_ZLIB_TYPE,
1132 ] {
1133 let mut message_ext = MessageExt::default();
1134 message_ext.set_body(body.clone());
1135 message_ext.set_sys_flag(MessageSysFlag::COMPRESSED_FLAG | compression_flag);
1136 let mut encoded = encode(&message_ext, true).expect("compressed message should encode");
1137
1138 let decoded =
1139 decode(&mut encoded, true, true, false, false, false).expect("compressed message should decode");
1140
1141 assert_eq!(decoded.get_body(), Some(&body));
1142 }
1143 }
1144
1145 #[test]
1146 fn encode_without_compression() {
1147 let mut message_ext = MessageExt::default();
1148 message_ext.set_body(Bytes::from("Hello, World!"));
1149 let result = encode(&message_ext, false);
1150 assert!(result.is_ok());
1151 let bytes = result.unwrap();
1152 assert!(!bytes.is_empty());
1153 }
1154
1155 #[test]
1156 fn encode_with_empty_body() {
1157 let mut message_ext = MessageExt::default();
1158 message_ext.set_body(Bytes::new());
1159 let result = encode(&message_ext, false);
1160 assert!(result.is_ok());
1161 let bytes = result.unwrap();
1162 assert!(!bytes.is_empty());
1163 }
1164
1165 #[test]
1166 fn encode_with_large_body() {
1167 let mut message_ext = MessageExt::default();
1168 let large_body = vec![0u8; 1024 * 1024];
1169 message_ext.set_body(Bytes::from(large_body));
1170 let result = encode(&message_ext, false);
1171 assert!(result.is_ok());
1172 let bytes = result.unwrap();
1173 assert!(!bytes.is_empty());
1174 }
1175
1176 #[test]
1177 fn encode_uniquely_with_compression() {
1178 let mut message_ext = MessageExt::default();
1179 message_ext.set_body(Bytes::from("Hello, World!"));
1180 let result = encode_uniquely(&message_ext, true);
1181 assert!(result.is_ok());
1182 let bytes = result.unwrap();
1183 assert!(!bytes.is_empty());
1184 }
1185
1186 #[test]
1187 fn encode_uniquely_without_compression() {
1188 let mut message_ext = MessageExt::default();
1189 message_ext.set_body(Bytes::from("Hello, World!"));
1190 let result = encode_uniquely(&message_ext, false);
1191 assert!(result.is_ok());
1192 let bytes = result.unwrap();
1193 assert!(!bytes.is_empty());
1194 }
1195
1196 #[test]
1197 fn encode_uniquely_with_empty_body() {
1198 let mut message_ext = MessageExt::default();
1199 message_ext.set_body(Bytes::new());
1200 let result = encode_uniquely(&message_ext, false);
1201 assert!(result.is_ok());
1202 let bytes = result.unwrap();
1203 assert!(!bytes.is_empty());
1204 }
1205
1206 #[test]
1207 fn encode_uniquely_with_large_body() {
1208 let mut message_ext = MessageExt::default();
1209 let large_body = vec![0u8; 1024 * 1024];
1210 message_ext.set_body(Bytes::from(large_body));
1211 let result = encode_uniquely(&message_ext, false);
1212 assert!(result.is_ok());
1213 let bytes = result.unwrap();
1214 assert!(!bytes.is_empty());
1215 }
1216
1217 #[test]
1218 fn decode_properties_returns_none_if_bytes_length_is_insufficient() {
1219 let mut bytes = Bytes::from(vec![0; SYSFLAG_POSITION + 3]);
1220 assert!(decode_properties(&mut bytes).is_none());
1221 }
1222
1223 #[test]
1224 fn decode_properties_returns_none_if_magic_code_is_invalid() {
1225 let mut bytes = BytesMut::from_iter(vec![0u8; SYSFLAG_POSITION + 4 + MESSAGE_MAGIC_CODE_POSITION + 4]);
1226 BigEndian::write_i32(&mut bytes[SYSFLAG_POSITION..SYSFLAG_POSITION + 4], 0);
1227 BigEndian::write_i32(
1228 &mut bytes[MESSAGE_MAGIC_CODE_POSITION..MESSAGE_MAGIC_CODE_POSITION + 4],
1229 -1,
1230 );
1231 assert!(decode_properties(&mut bytes.freeze()).is_none());
1232 }
1233
1234 #[test]
1235 fn decode_properties_returns_none_if_body_size_is_insufficient() {
1236 let mut bytes = BytesMut::from_iter(vec![0u8; SYSFLAG_POSITION + 4 + MESSAGE_MAGIC_CODE_POSITION + 4 + 4]);
1237 BigEndian::write_i32(&mut bytes[SYSFLAG_POSITION..SYSFLAG_POSITION + 4], 0);
1238 BigEndian::write_i32(
1239 &mut bytes[MESSAGE_MAGIC_CODE_POSITION..MESSAGE_MAGIC_CODE_POSITION + 4],
1240 MESSAGE_MAGIC_CODE,
1241 );
1242 assert!(decode_properties(&mut bytes.freeze()).is_none());
1243 }
1244
1245 #[test]
1246 fn decode_properties_returns_none_if_topic_length_is_insufficient() {
1247 let mut bytes = BytesMut::from_iter(vec![
1248 0u8;
1249 SYSFLAG_POSITION + 4 + MESSAGE_MAGIC_CODE_POSITION + 4 + 4 + 4
1250 ]);
1251 BigEndian::write_i32(&mut bytes[SYSFLAG_POSITION..SYSFLAG_POSITION + 4], 0);
1252 BigEndian::write_i32(
1253 &mut bytes[MESSAGE_MAGIC_CODE_POSITION..MESSAGE_MAGIC_CODE_POSITION + 4],
1254 MESSAGE_MAGIC_CODE,
1255 );
1256 BigEndian::write_i32(
1257 &mut bytes[SYSFLAG_POSITION + 4 + MESSAGE_MAGIC_CODE_POSITION + 4
1258 ..SYSFLAG_POSITION + 4 + MESSAGE_MAGIC_CODE_POSITION + 4 + 4],
1259 0,
1260 );
1261 assert!(decode_properties(&mut bytes.freeze()).is_none());
1262 }
1263
1264 #[test]
1265 fn decode_properties_returns_none_if_properties_length_is_insufficient() {
1266 let mut bytes = BytesMut::from_iter(vec![
1267 0u8;
1268 SYSFLAG_POSITION + 4 + MESSAGE_MAGIC_CODE_POSITION + 4 + 4 + 4 + 2
1269 ]);
1270 BigEndian::write_i32(&mut bytes[SYSFLAG_POSITION..SYSFLAG_POSITION + 4], 0);
1271 BigEndian::write_i32(
1272 &mut bytes[MESSAGE_MAGIC_CODE_POSITION..MESSAGE_MAGIC_CODE_POSITION + 4],
1273 MESSAGE_MAGIC_CODE,
1274 );
1275 BigEndian::write_i32(
1276 &mut bytes[SYSFLAG_POSITION + 4 + MESSAGE_MAGIC_CODE_POSITION + 4
1277 ..SYSFLAG_POSITION + 4 + MESSAGE_MAGIC_CODE_POSITION + 4 + 4],
1278 0,
1279 );
1280 BigEndian::write_i16(
1281 &mut bytes[SYSFLAG_POSITION + 4 + MESSAGE_MAGIC_CODE_POSITION + 4 + 4 + 4
1282 ..SYSFLAG_POSITION + 4 + MESSAGE_MAGIC_CODE_POSITION + 4 + 4 + 4 + 2],
1283 1,
1284 );
1285 assert!(decode_properties(&mut bytes.freeze()).is_none());
1286 }
1287
1288 #[test]
1289 fn validate_message_id_ipv4_32_chars() {
1290 let result = validate_message_id("AC11000100002A9F0000000000000001");
1291 assert!(result.is_ok());
1292 }
1293
1294 #[test]
1295 fn validate_message_id_ipv6_56_chars() {
1296 let result = validate_message_id("20010db800000000000000000000000100002A9F0000000000000001");
1297 assert!(result.is_ok());
1298 }
1299
1300 #[test]
1301 fn validate_message_id_ipv6_40_chars_rejected() {
1302 let result = validate_message_id("20010db800000000000000000000000100000001");
1303 assert!(result.is_err());
1304 if let Err(e) = result {
1305 assert!(e.contains("Invalid message ID length"));
1306 assert!(e.contains("56 characters (IPv6)"));
1307 }
1308 }
1309
1310 #[test]
1311 fn decode_message_id_ipv6() {
1312 let msg_id = "20010db800000000000000000000000100002A9F0000000000000001";
1313 let message_id = decode_message_id(msg_id).unwrap();
1314 assert_eq!(message_id.address, "[2001:db8::1]:10911".parse().unwrap());
1315 assert_eq!(message_id.offset, 1);
1316 }
1317
1318 #[test]
1319 fn decode_message_id_ipv6_full_address() {
1320 let msg_id = "20010db81234567800000000abcdef0100002A9F0000000000001234";
1321 let message_id = decode_message_id(msg_id).unwrap();
1322 assert_eq!(
1323 message_id.address,
1324 "[2001:db8:1234:5678::abcd:ef01]:10911".parse().unwrap()
1325 );
1326 assert_eq!(message_id.offset, 4660);
1327 }
1328}