1use core::{mem, ops::Deref};
2
3use bytes::{Buf, Bytes, BytesMut};
4use bytestring::ByteString;
5
6use crate::{
7 MessageBase, ServerMessage, StatusCode, Subject, SubscriptionId,
8 error::ServerError,
9 headers::{
10 HeaderMap, HeaderName, HeaderValue,
11 error::{HeaderNameValidateError, HeaderValueValidateError},
12 },
13 status_code::StatusCodeError,
14 util::{self, CrlfFinder, ParseUintError},
15};
16
17pub use self::framed::{FrameDecoderError, decode_frame};
18pub use self::stream::StreamDecoder;
19
20use super::ServerOp;
21
22mod framed;
23mod stream;
24
25const MAX_HEAD_LEN: usize = 128 * 1024;
32
33const MAX_MSG_LEN: usize = 128 * 1024 * 1024;
40
41#[derive(Debug)]
42pub(super) enum DecoderStatus {
43 ControlLine {
44 last_bytes_read: usize,
45 },
46 Headers {
47 subscription_id: SubscriptionId,
48 subject: Subject,
49 reply_subject: Option<Subject>,
50 header_len: usize,
51 payload_len: usize,
52 },
53 Payload {
54 subscription_id: SubscriptionId,
55 subject: Subject,
56 reply_subject: Option<Subject>,
57 status_code: Option<StatusCode>,
58 status_description: Option<ByteString>,
59 headers: HeaderMap,
60 payload_len: usize,
61 },
62 Poisoned,
63}
64
65pub(super) trait BytesLike: Buf + Deref<Target = [u8]> {
66 fn len(&self) -> usize {
67 Buf::remaining(self)
68 }
69
70 fn split_to(&mut self, at: usize) -> Bytes {
71 self.copy_to_bytes(at)
72 }
73}
74
75impl BytesLike for Bytes {}
76impl BytesLike for BytesMut {}
77
78pub(super) fn decode(
79 crlf: &CrlfFinder,
80 status: &mut DecoderStatus,
81 read_buf: &mut impl BytesLike,
82) -> Result<Option<ServerOp>, DecoderError> {
83 loop {
84 match status {
85 DecoderStatus::ControlLine { last_bytes_read } => {
86 if read_buf.starts_with(b"+OK\r\n") {
87 debug_assert_eq!(
89 *last_bytes_read, 0,
90 "we shouldn't have handled any bytes before"
91 );
92 read_buf.advance("+OK\r\n".len());
93 return Ok(Some(ServerOp::Success));
94 }
95
96 if *last_bytes_read == read_buf.len() {
97 return Ok(None);
99 }
100
101 let Some(control_line_len) = crlf.find(read_buf) else {
102 return if read_buf.len() < MAX_HEAD_LEN {
103 *last_bytes_read = read_buf.len();
104 Ok(None)
105 } else {
106 Err(DecoderError::HeadTooLong {
107 len: read_buf.len(),
108 })
109 };
110 };
111
112 let mut control_line = read_buf.split_to(control_line_len + "\r\n".len());
113 control_line.truncate(control_line.len() - 2);
114
115 return if control_line.starts_with(b"MSG ") {
116 *status = decode_msg(control_line)?;
117 continue;
118 } else if control_line.starts_with(b"HMSG ") {
119 *status = decode_hmsg(control_line)?;
120 continue;
121 } else if control_line.starts_with(b"PING") {
122 Ok(Some(ServerOp::Ping))
123 } else if control_line.starts_with(b"PONG") {
124 Ok(Some(ServerOp::Pong))
125 } else if control_line.starts_with(b"+OK") {
126 Ok(Some(ServerOp::Success))
128 } else if control_line.starts_with(b"-ERR ") {
129 control_line.advance("-ERR ".len());
130 if control_line.len() < 2
134 || !control_line.starts_with(b"'")
135 || !control_line.ends_with(b"'")
136 {
137 return Err(DecoderError::InvalidErrorMessage);
138 }
139
140 control_line.advance(1);
141 control_line.truncate(control_line.len() - 1);
142 let raw_message = ByteString::try_from(control_line)
143 .map_err(|_| DecoderError::InvalidErrorMessage)?;
144 let error = ServerError::parse(raw_message);
145 Ok(Some(ServerOp::Error { error }))
146 } else if let Some(info) = control_line.strip_prefix(b"INFO ") {
147 let info = serde_json::from_slice(info).map_err(DecoderError::InvalidInfo)?;
148 Ok(Some(ServerOp::Info { info }))
149 } else {
150 Err(DecoderError::InvalidCommand)
151 };
152 }
153 DecoderStatus::Headers { header_len, .. } => {
154 if read_buf.len() < *header_len {
155 return Ok(None);
156 }
157
158 decode_headers(crlf, read_buf, status)?;
159 }
160 DecoderStatus::Payload { payload_len, .. } => {
161 if read_buf.len() < payload_len.saturating_add("\r\n".len()) {
166 return Ok(None);
167 }
168
169 let DecoderStatus::Payload {
170 subscription_id,
171 subject,
172 reply_subject,
173 status_code,
174 status_description,
175 headers,
176 payload_len,
177 } = mem::replace(status, DecoderStatus::ControlLine { last_bytes_read: 0 })
178 else {
179 unreachable!()
180 };
181
182 let payload = read_buf.split_to(payload_len);
183 read_buf.advance("\r\n".len());
184 let message = ServerMessage {
185 status_code,
186 status_description,
187 subscription_id,
188 base: MessageBase {
189 subject,
190 reply_subject,
191 headers,
192 payload,
193 },
194 };
195 return Ok(Some(ServerOp::Message { message }));
196 }
197 DecoderStatus::Poisoned => return Err(DecoderError::Poisoned),
198 }
199 }
200}
201
202fn decode_msg(mut control_line: Bytes) -> Result<DecoderStatus, DecoderError> {
203 control_line.advance("MSG ".len());
204
205 let mut chunks = util::split_spaces(control_line);
206 let (subject, subscription_id, reply_subject, payload_len) = match (
207 chunks.next(),
208 chunks.next(),
209 chunks.next(),
210 chunks.next(),
211 chunks.next(),
212 ) {
213 (Some(subject), Some(subscription_id), Some(reply_subject), Some(payload_len), None) => {
214 (subject, subscription_id, Some(reply_subject), payload_len)
215 }
216 (Some(subject), Some(subscription_id), Some(payload_len), None, None) => {
217 (subject, subscription_id, None, payload_len)
218 }
219 _ => return Err(DecoderError::InvalidMsgArgsCount),
220 };
221 let subject = Subject::from_dangerous_value(
222 subject
223 .try_into()
224 .map_err(|_| DecoderError::SubjectInvalidUtf8)?,
225 );
226 let subscription_id =
227 SubscriptionId::from_ascii_bytes(&subscription_id).map_err(DecoderError::SubscriptionId)?;
228 let reply_subject = reply_subject
229 .map(|reply_subject| {
230 ByteString::try_from(reply_subject).map_err(|_| DecoderError::ReplySubjectInvalidUtf8)
231 })
232 .transpose()?
233 .map(Subject::from_dangerous_value);
234 let payload_len =
235 util::parse_usize(&payload_len).map_err(DecoderError::InvalidPayloadLength)?;
236 if payload_len > MAX_MSG_LEN {
237 return Err(DecoderError::InvalidPayloadLength(ParseUintError::Overflow));
240 }
241 Ok(DecoderStatus::Payload {
242 subscription_id,
243 subject,
244 reply_subject,
245 status_code: None,
246 status_description: None,
247 headers: HeaderMap::new(),
248 payload_len,
249 })
250}
251
252fn decode_hmsg(mut control_line: Bytes) -> Result<DecoderStatus, DecoderError> {
253 control_line.advance("HMSG ".len());
254 let mut chunks = util::split_spaces(control_line);
255
256 let (subject, subscription_id, reply_subject, header_len, total_len) = match (
257 chunks.next(),
258 chunks.next(),
259 chunks.next(),
260 chunks.next(),
261 chunks.next(),
262 chunks.next(),
263 ) {
264 (
265 Some(subject),
266 Some(subscription_id),
267 Some(reply_to),
268 Some(header_len),
269 Some(total_len),
270 None,
271 ) => (
272 subject,
273 subscription_id,
274 Some(reply_to),
275 header_len,
276 total_len,
277 ),
278 (Some(subject), Some(subscription_id), Some(header_len), Some(total_len), None, None) => {
279 (subject, subscription_id, None, header_len, total_len)
280 }
281 _ => return Err(DecoderError::InvalidHmsgArgsCount),
282 };
283
284 let subject = Subject::from_dangerous_value(
285 subject
286 .try_into()
287 .map_err(|_| DecoderError::SubjectInvalidUtf8)?,
288 );
289 let subscription_id =
290 SubscriptionId::from_ascii_bytes(&subscription_id).map_err(DecoderError::SubscriptionId)?;
291 let reply_subject = reply_subject
292 .map(|reply_subject| {
293 ByteString::try_from(reply_subject).map_err(|_| DecoderError::ReplySubjectInvalidUtf8)
294 })
295 .transpose()?
296 .map(Subject::from_dangerous_value);
297 let header_len = util::parse_usize(&header_len).map_err(DecoderError::InvalidHeaderLength)?;
298 let total_len = util::parse_usize(&total_len).map_err(DecoderError::InvalidPayloadLength)?;
299 if total_len > MAX_MSG_LEN {
300 return Err(DecoderError::InvalidPayloadLength(ParseUintError::Overflow));
303 }
304
305 let payload_len = total_len
306 .checked_sub(header_len)
307 .ok_or(DecoderError::InvalidTotalLength)?;
308
309 Ok(DecoderStatus::Headers {
310 subscription_id,
311 subject,
312 reply_subject,
313 header_len,
314 payload_len,
315 })
316}
317
318fn decode_headers(
319 crlf: &CrlfFinder,
320 read_buf: &mut impl BytesLike,
321 status: &mut DecoderStatus,
322) -> Result<(), DecoderError> {
323 let DecoderStatus::Headers {
324 subscription_id,
325 subject,
326 reply_subject,
327 header_len,
328 payload_len,
329 } = mem::replace(status, DecoderStatus::Poisoned)
330 else {
331 unreachable!()
332 };
333
334 let header = read_buf.split_to(header_len);
335 let mut lines = util::lines_iter(crlf, header);
336 let head = lines.next().ok_or(DecoderError::MissingHead)?;
337 let status_line = head
338 .strip_prefix(b"NATS/1.0")
339 .ok_or(DecoderError::InvalidHead)?;
340 let status_code = if let Some(status_code) = status_line.get(1..4) {
341 Some(StatusCode::from_ascii_bytes(status_code).map_err(DecoderError::StatusCode)?)
342 } else {
343 None
344 };
345 let status_description = match status_line.get(4..) {
346 Some([separator, description @ ..]) => {
347 if !separator.is_ascii_whitespace() {
348 return Err(DecoderError::InvalidHead);
349 }
350
351 match description.trim_ascii() {
352 [] => None,
353 description => Some(
354 ByteString::try_from(head.slice_ref(description))
356 .map_err(|_| DecoderError::StatusDescriptionInvalidUtf8)?,
357 ),
358 }
359 }
360 _ => None,
361 };
362
363 let headers = lines
364 .filter(|line| !line.is_empty())
365 .map(|mut line| {
366 let i = memchr::memchr(b':', &line).ok_or(DecoderError::InvalidHeaderLine)?;
367
368 let name = line.split_to(i);
369 line.advance(":".len());
370 if line.first().is_some_and(u8::is_ascii_whitespace) {
371 line.advance(1);
373 }
374 let value = line;
375
376 let name = HeaderName::try_from(
377 ByteString::try_from(name).map_err(|_| DecoderError::HeaderNameInvalidUtf8)?,
378 )
379 .map_err(DecoderError::HeaderName)?;
380 let value = HeaderValue::from_bytes(&value).map_err(DecoderError::HeaderValue)?;
381 Ok((name, value))
382 })
383 .collect::<Result<_, _>>()?;
384
385 *status = DecoderStatus::Payload {
386 subscription_id,
387 subject,
388 reply_subject,
389 status_code,
390 status_description,
391 headers,
392 payload_len,
393 };
394 Ok(())
395}
396
397#[derive(Debug, thiserror::Error)]
398pub enum DecoderError {
399 #[error("The head exceeded the maximum head length (len {len} maximum {MAX_HEAD_LEN}")]
400 HeadTooLong { len: usize },
401 #[error("Invalid command")]
402 InvalidCommand,
403 #[error("MSG command has an unexpected number of arguments")]
404 InvalidMsgArgsCount,
405 #[error("HMSG command has an unexpected number of arguments")]
406 InvalidHmsgArgsCount,
407 #[error("The subject isn't valid utf-8")]
408 SubjectInvalidUtf8,
409 #[error("The reply subject isn't valid utf-8")]
410 ReplySubjectInvalidUtf8,
411 #[error("Couldn't parse the Subscription ID")]
412 SubscriptionId(#[source] ParseUintError),
413 #[error("Couldn't parse the length of the header")]
414 InvalidHeaderLength(#[source] ParseUintError),
415 #[error("Couldn't parse the length of the payload")]
416 InvalidPayloadLength(#[source] ParseUintError),
417 #[error("The total length is greater than the header length")]
418 InvalidTotalLength,
419 #[error("HMSG is missing head")]
420 MissingHead,
421 #[error("HMSG has an invalid head")]
422 InvalidHead,
423 #[error("HMSG header line is missing ': '")]
424 InvalidHeaderLine,
425 #[error("Couldn't parse the status code")]
426 StatusCode(#[source] StatusCodeError),
427 #[error("The status description isn't valid utf-8")]
428 StatusDescriptionInvalidUtf8,
429 #[error("The header name isn't valid utf-8")]
430 HeaderNameInvalidUtf8,
431 #[error("The header name couldn't be parsed")]
432 HeaderName(#[source] HeaderNameValidateError),
433 #[error("The header value couldn't be parsed")]
434 HeaderValue(#[source] HeaderValueValidateError),
435 #[error("INFO command JSON payload couldn't be deserialized")]
436 InvalidInfo(#[source] serde_json::Error),
437 #[error("-ERR command message couldn't be deserialized")]
438 InvalidErrorMessage,
439 #[error("The decoder was poisoned")]
440 Poisoned,
441}