rocketmq_protocol/protocol/body/
message_codec.rs1use std::collections::HashMap;
10use std::net::Ipv4Addr;
11use std::net::Ipv6Addr;
12use std::net::SocketAddr;
13use std::net::SocketAddrV4;
14use std::net::SocketAddrV6;
15
16use bytes::Buf;
17use bytes::Bytes;
18use cheetah_string::CheetahString;
19use rocketmq_error::Error;
20use rocketmq_error::Result;
21
22use rocketmq_model::common::sys_flag::message_sys_flag::MessageSysFlag;
23
24pub const MESSAGE_MAGIC_CODE: i32 = -626_843_481;
25pub const MESSAGE_MAGIC_CODE_V2: i32 = -626_843_477;
26pub const NAME_VALUE_SEPARATOR: u8 = 1;
27pub const PROPERTY_SEPARATOR: u8 = 2;
28
29#[derive(Clone, Debug, Eq, PartialEq)]
30pub struct DecodedMessageFrame {
31 pub store_size: i32,
32 pub magic_code: i32,
33 pub body_crc: u32,
34 pub queue_id: i32,
35 pub flag: i32,
36 pub queue_offset: i64,
37 pub commit_log_offset: i64,
38 pub sys_flag: i32,
39 pub born_timestamp: i64,
40 pub born_host: SocketAddr,
41 pub store_timestamp: i64,
42 pub store_host: SocketAddr,
43 pub reconsume_times: i32,
44 pub prepared_transaction_offset: i64,
45 pub body: Bytes,
46 pub topic: CheetahString,
47 pub properties_string: CheetahString,
48 pub properties: HashMap<CheetahString, CheetahString>,
49}
50
51pub fn decode_message_frame(input: &mut Bytes) -> Result<DecodedMessageFrame> {
52 let initial_len = input.remaining();
53 let store_size = read_i32(input)?;
54 if store_size <= 0 || store_size as usize > initial_len {
55 return Err(invalid("invalid total message size"));
56 }
57 let magic_code = read_i32(input)?;
58 if magic_code != MESSAGE_MAGIC_CODE && magic_code != MESSAGE_MAGIC_CODE_V2 {
59 return Err(invalid("unknown message magic code"));
60 }
61 let body_crc = read_u32(input)?;
62 let queue_id = read_i32(input)?;
63 let flag = read_i32(input)?;
64 let queue_offset = read_i64(input)?;
65 let commit_log_offset = read_i64(input)?;
66 let sys_flag = read_i32(input)?;
67 let born_timestamp = read_i64(input)?;
68 let born_host = read_host(input, sys_flag & MessageSysFlag::BORNHOST_V6_FLAG != 0)?;
69 let store_timestamp = read_i64(input)?;
70 let store_host = read_host(input, sys_flag & MessageSysFlag::STOREHOSTADDRESS_V6_FLAG != 0)?;
71 let reconsume_times = read_i32(input)?;
72 let prepared_transaction_offset = read_i64(input)?;
73 let body = read_sized_i32(input)?;
74 let topic_len = if magic_code == MESSAGE_MAGIC_CODE_V2 {
75 let value = read_i16(input)?;
76 usize::try_from(value).map_err(|_| invalid("negative topic length"))?
77 } else {
78 usize::from(read_u8(input)?)
79 };
80 let topic_bytes = take(input, topic_len)?;
81 let topic = std::str::from_utf8(&topic_bytes)
82 .map(CheetahString::from_slice)
83 .map_err(invalid_source)?;
84 let property_len = usize::try_from(read_i16(input)?).map_err(|_| invalid("negative properties length"))?;
85 let property_bytes = take(input, property_len)?;
86 let properties_string = CheetahString::from(String::from_utf8_lossy(&property_bytes).as_ref());
87 let properties = decode_properties(&property_bytes);
88
89 Ok(DecodedMessageFrame {
90 store_size,
91 magic_code,
92 body_crc,
93 queue_id,
94 flag,
95 queue_offset,
96 commit_log_offset,
97 sys_flag,
98 born_timestamp,
99 born_host,
100 store_timestamp,
101 store_host,
102 reconsume_times,
103 prepared_transaction_offset,
104 body,
105 topic,
106 properties_string,
107 properties,
108 })
109}
110
111pub fn decode_properties(bytes: &[u8]) -> HashMap<CheetahString, CheetahString> {
112 bytes
113 .split(|byte| *byte == PROPERTY_SEPARATOR)
114 .filter_map(|entry| {
115 let separator = entry.iter().position(|byte| *byte == NAME_VALUE_SEPARATOR)?;
116 if separator == 0 || separator + 1 >= entry.len() {
117 return None;
118 }
119 let key = String::from_utf8_lossy(&entry[..separator]);
120 let value = String::from_utf8_lossy(&entry[separator + 1..]);
121 Some((CheetahString::from(key.as_ref()), CheetahString::from(value.as_ref())))
122 })
123 .collect()
124}
125
126fn invalid(reason: &'static str) -> Error {
127 crate::error::invalid_body("decode_message_frame", reason)
128}
129
130fn invalid_source(source: impl std::error::Error + Send + Sync + 'static) -> Error {
131 crate::error::invalid_body_source("decode_message_frame", source)
132}
133
134fn ensure(input: &Bytes, len: usize) -> Result<()> {
135 if input.remaining() < len {
136 Err(invalid("truncated message frame"))
137 } else {
138 Ok(())
139 }
140}
141
142fn read_u8(input: &mut Bytes) -> Result<u8> {
143 ensure(input, 1)?;
144 Ok(input.get_u8())
145}
146fn read_i16(input: &mut Bytes) -> Result<i16> {
147 ensure(input, 2)?;
148 Ok(input.get_i16())
149}
150fn read_i32(input: &mut Bytes) -> Result<i32> {
151 ensure(input, 4)?;
152 Ok(input.get_i32())
153}
154fn read_u32(input: &mut Bytes) -> Result<u32> {
155 ensure(input, 4)?;
156 Ok(input.get_u32())
157}
158fn read_i64(input: &mut Bytes) -> Result<i64> {
159 ensure(input, 8)?;
160 Ok(input.get_i64())
161}
162fn take(input: &mut Bytes, len: usize) -> Result<Bytes> {
163 ensure(input, len)?;
164 Ok(input.split_to(len))
165}
166fn read_sized_i32(input: &mut Bytes) -> Result<Bytes> {
167 let len = usize::try_from(read_i32(input)?).map_err(|_| invalid("negative body length"))?;
168 take(input, len)
169}
170
171fn read_host(input: &mut Bytes, ipv6: bool) -> Result<SocketAddr> {
172 if ipv6 {
173 let bytes = take(input, 16)?;
174 let mut address = [0_u8; 16];
175 address.copy_from_slice(&bytes);
176 let port = read_i32(input)? as u16;
177 Ok(SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::from(address), port, 0, 0)))
178 } else {
179 let bytes = take(input, 4)?;
180 let mut address = [0_u8; 4];
181 address.copy_from_slice(&bytes);
182 let port = read_i32(input)? as u16;
183 Ok(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from(address), port)))
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use bytes::BufMut;
190 use bytes::BytesMut;
191
192 use super::*;
193
194 fn golden_frame() -> Bytes {
195 let mut frame = BytesMut::new();
196 frame.put_i32(0);
197 frame.put_i32(MESSAGE_MAGIC_CODE);
198 frame.put_u32(7);
199 frame.put_i32(3);
200 frame.put_i32(9);
201 frame.put_i64(11);
202 frame.put_i64(13);
203 frame.put_i32(0);
204 frame.put_i64(17);
205 frame.put_slice(&[127, 0, 0, 1]);
206 frame.put_i32(10911);
207 frame.put_i64(19);
208 frame.put_slice(&[127, 0, 0, 2]);
209 frame.put_i32(10912);
210 frame.put_i32(2);
211 frame.put_i64(23);
212 frame.put_i32(4);
213 frame.put_slice(b"body");
214 frame.put_u8(5);
215 frame.put_slice(b"topic");
216 frame.put_i16(8);
217 frame.put_slice(b"k\x01value\x02");
218 let len = frame.len() as i32;
219 frame[..4].copy_from_slice(&len.to_be_bytes());
220 frame.freeze()
221 }
222
223 #[test]
224 fn decodes_frozen_v1_frame() {
225 let decoded = decode_message_frame(&mut golden_frame()).unwrap();
226 assert_eq!(decoded.topic, "topic");
227 assert_eq!(decoded.body, Bytes::from_static(b"body"));
228 assert_eq!(decoded.properties.get("k").map(CheetahString::as_str), Some("value"));
229 assert_eq!(decoded.born_host.to_string(), "127.0.0.1:10911");
230 }
231
232 #[test]
233 fn rejects_truncated_and_unknown_frames() {
234 let mut truncated = golden_frame().slice(..20);
235 assert!(decode_message_frame(&mut truncated).is_err());
236 let mut unknown = golden_frame();
237 let mut bytes = BytesMut::from(unknown.as_ref());
238 bytes[4..8].copy_from_slice(&0_i32.to_be_bytes());
239 unknown = bytes.freeze();
240 assert!(decode_message_frame(&mut unknown).is_err());
241 }
242}