watermelon_proto/proto/decoder/
stream.rs1use bytes::{BufMut, BytesMut};
2
3use crate::{
4 proto::{ServerOp, error::DecoderError},
5 util::CrlfFinder,
6};
7
8use super::DecoderStatus;
9
10const INITIAL_READ_BUF_CAPACITY: usize = 64 * 1024;
11
12#[derive(Debug)]
13pub struct StreamDecoder {
14 read_buf: BytesMut,
15 status: DecoderStatus,
16 crlf: CrlfFinder,
17}
18
19impl StreamDecoder {
20 #[must_use]
21 pub fn new() -> Self {
22 Self {
23 read_buf: BytesMut::with_capacity(INITIAL_READ_BUF_CAPACITY),
24 status: DecoderStatus::ControlLine { last_bytes_read: 0 },
25 crlf: CrlfFinder::new(),
26 }
27 }
28
29 #[must_use]
30 pub fn read_buf(&mut self) -> &mut (impl BufMut + use<>) {
31 &mut self.read_buf
32 }
33
34 pub fn decode(&mut self) -> Result<Option<ServerOp>, DecoderError> {
42 super::decode(&self.crlf, &mut self.status, &mut self.read_buf)
43 }
44}
45
46impl Default for StreamDecoder {
47 fn default() -> Self {
48 Self::new()
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use bytes::{BufMut as _, Bytes};
55 use claims::{assert_matches, assert_ok_eq};
56
57 use bytestring::ByteString;
58
59 use crate::{
60 StatusCode, Subject,
61 error::ServerError,
62 headers::{HeaderMap, HeaderName, HeaderValue},
63 message::{MessageBase, ServerMessage},
64 proto::{error::DecoderError, server::ServerOp},
65 util::ParseUintError,
66 };
67
68 use super::StreamDecoder;
69
70 #[test]
71 fn decode_ping() {
72 let mut decoder = StreamDecoder::new();
73 decoder.read_buf().put_slice(b"PING\r\n");
74 assert_ok_eq!(decoder.decode(), Some(ServerOp::Ping));
75 assert_ok_eq!(decoder.decode(), None);
76 }
77
78 #[test]
79 fn decode_pong() {
80 let mut decoder = StreamDecoder::new();
81 decoder.read_buf().put_slice(b"PONG\r\n");
82 assert_ok_eq!(decoder.decode(), Some(ServerOp::Pong));
83 assert_ok_eq!(decoder.decode(), None);
84 }
85
86 #[test]
87 fn decode_ok() {
88 let mut decoder = StreamDecoder::new();
89 decoder.read_buf().put_slice(b"+OK\r\n");
90 assert_ok_eq!(decoder.decode(), Some(ServerOp::Success));
91 assert_ok_eq!(decoder.decode(), None);
92 }
93
94 #[test]
95 fn decode_error() {
96 let mut decoder = StreamDecoder::new();
97 decoder
98 .read_buf()
99 .put_slice(b"-ERR 'Authorization Violation'\r\n");
100 assert_ok_eq!(
101 decoder.decode(),
102 Some(ServerOp::Error {
103 error: ServerError::AuthorizationViolation
104 })
105 );
106 assert_ok_eq!(decoder.decode(), None);
107 }
108
109 #[test]
110 fn decode_error_bare_quote() {
111 let mut decoder = StreamDecoder::new();
112 decoder.read_buf().put_slice(b"-ERR '\r\n");
115 assert_matches!(decoder.decode(), Err(DecoderError::InvalidErrorMessage));
116 }
117
118 #[test]
119 fn decode_error_empty_message() {
120 let mut decoder = StreamDecoder::new();
121 decoder.read_buf().put_slice(b"-ERR ''\r\n");
122 assert_ok_eq!(
123 decoder.decode(),
124 Some(ServerOp::Error {
125 error: ServerError::Other {
126 raw_message: ByteString::new()
127 }
128 })
129 );
130 }
131
132 #[test]
133 fn decode_msg() {
134 let mut decoder = StreamDecoder::new();
135 decoder
136 .read_buf()
137 .put_slice(b"MSG hello.world 1 12\r\nHello World!\r\n");
138 assert_ok_eq!(
139 decoder.decode(),
140 Some(ServerOp::Message {
141 message: ServerMessage {
142 status_code: None,
143 status_description: None,
144 subscription_id: 1.into(),
145 base: MessageBase {
146 subject: Subject::from_static("hello.world"),
147 reply_subject: None,
148 headers: HeaderMap::new(),
149 payload: Bytes::from_static(b"Hello World!")
150 }
151 }
152 })
153 );
154 assert_ok_eq!(decoder.decode(), None);
155 }
156
157 #[test]
158 fn decode_hmsg_status_description() {
159 const HEADERS: &str = "NATS/1.0 409 Batch Completed\r\nNats-Pending-Messages: 3\r\nNats-Pending-Bytes: 0\r\n\r\n";
160
161 let mut decoder = StreamDecoder::new();
162 decoder.read_buf().put_slice(
163 format!(
164 "HMSG _INBOX.abcd 9 {} {}\r\n{HEADERS}\r\n",
165 HEADERS.len(),
166 HEADERS.len()
167 )
168 .as_bytes(),
169 );
170 assert_ok_eq!(
171 decoder.decode(),
172 Some(ServerOp::Message {
173 message: ServerMessage {
174 status_code: Some(StatusCode::CONFLICT),
175 status_description: Some(ByteString::from_static("Batch Completed")),
176 subscription_id: 9.into(),
177 base: MessageBase {
178 subject: Subject::from_static("_INBOX.abcd"),
179 reply_subject: None,
180 headers: HeaderMap::from_iter([
181 (
182 HeaderName::from_static("Nats-Pending-Messages"),
183 HeaderValue::from_static("3")
184 ),
185 (
186 HeaderName::from_static("Nats-Pending-Bytes"),
187 HeaderValue::from_static("0")
188 ),
189 ]),
190 payload: Bytes::new(),
191 }
192 }
193 })
194 );
195 assert_ok_eq!(decoder.decode(), None);
196 }
197
198 #[test]
199 fn decode_hmsg_status_without_description() {
200 const HEADERS: &str = "NATS/1.0 100\r\n\r\n";
201
202 let mut decoder = StreamDecoder::new();
203 decoder.read_buf().put_slice(
204 format!(
205 "HMSG _INBOX.abcd 9 {} {}\r\n{HEADERS}\r\n",
206 HEADERS.len(),
207 HEADERS.len()
208 )
209 .as_bytes(),
210 );
211 assert_ok_eq!(
212 decoder.decode(),
213 Some(ServerOp::Message {
214 message: ServerMessage {
215 status_code: Some(StatusCode::IDLE_HEARTBEAT),
216 status_description: None,
217 subscription_id: 9.into(),
218 base: MessageBase {
219 subject: Subject::from_static("_INBOX.abcd"),
220 reply_subject: None,
221 headers: HeaderMap::new(),
222 payload: Bytes::new(),
223 }
224 }
225 })
226 );
227 assert_ok_eq!(decoder.decode(), None);
228 }
229
230 #[test]
231 fn decode_hmsg_status_invalid_description_separator() {
232 const HEADERS: &str = "NATS/1.0 409XBatch Completed\r\n\r\n";
233
234 let mut decoder = StreamDecoder::new();
235 decoder.read_buf().put_slice(
236 format!(
237 "HMSG _INBOX.abcd 9 {} {}\r\n{HEADERS}\r\n",
238 HEADERS.len(),
239 HEADERS.len()
240 )
241 .as_bytes(),
242 );
243 assert_matches!(decoder.decode(), Err(DecoderError::InvalidHead));
244 }
245
246 #[test]
247 fn decode_hmsg_non_utf8_header_value() {
248 const HEADERS: &[u8] = b"NATS/1.0\r\nX-Binary: \x00\x80\xffabc\r\n\r\n";
249
250 let mut decoder = StreamDecoder::new();
251 decoder.read_buf().put_slice(
252 format!("HMSG _INBOX.abcd 9 {} {}\r\n", HEADERS.len(), HEADERS.len()).as_bytes(),
253 );
254 decoder.read_buf().put_slice(HEADERS);
255 decoder.read_buf().put_slice(b"\r\n");
256 assert_ok_eq!(
257 decoder.decode(),
258 Some(ServerOp::Message {
259 message: ServerMessage {
260 status_code: None,
261 status_description: None,
262 subscription_id: 9.into(),
263 base: MessageBase {
264 subject: Subject::from_static("_INBOX.abcd"),
265 reply_subject: None,
266 headers: HeaderMap::from_iter([(
267 HeaderName::from_static("X-Binary"),
268 HeaderValue::from_bytes(b"\x00\x80\xffabc").unwrap(),
269 )]),
270 payload: Bytes::new(),
271 }
272 }
273 })
274 );
275 assert_ok_eq!(decoder.decode(), None);
276 }
277
278 #[test]
279 fn decode_hmsg_empty_header_value() {
280 const HEADERS: &str = "NATS/1.0\r\nA:\r\nB: \r\n\r\n";
281
282 let mut decoder = StreamDecoder::new();
283 decoder.read_buf().put_slice(
284 format!(
285 "HMSG _INBOX.abcd 9 {} {}\r\n{HEADERS}\r\n",
286 HEADERS.len(),
287 HEADERS.len()
288 )
289 .as_bytes(),
290 );
291 assert_ok_eq!(
292 decoder.decode(),
293 Some(ServerOp::Message {
294 message: ServerMessage {
295 status_code: None,
296 status_description: None,
297 subscription_id: 9.into(),
298 base: MessageBase {
299 subject: Subject::from_static("_INBOX.abcd"),
300 reply_subject: None,
301 headers: HeaderMap::from_iter([
302 (
303 HeaderName::from_static("A"),
304 HeaderValue::from_bytes(b"").unwrap(),
305 ),
306 (
307 HeaderName::from_static("B"),
308 HeaderValue::from_bytes(b"").unwrap(),
309 ),
310 ]),
311 payload: Bytes::new(),
312 }
313 }
314 })
315 );
316 assert_ok_eq!(decoder.decode(), None);
317 }
318
319 #[test]
320 fn msg_huge_payload_len() {
321 let mut decoder = StreamDecoder::new();
322 decoder
323 .read_buf()
324 .put_slice(b"MSG hello.world 1 18446744073709551615\r\nHello");
325 assert_matches!(
329 decoder.decode(),
330 Err(DecoderError::InvalidPayloadLength(ParseUintError::Overflow))
331 );
332 }
333
334 #[test]
335 fn msg_payload_len_over_limit() {
336 let mut decoder = StreamDecoder::new();
337 decoder
338 .read_buf()
339 .put_slice(b"MSG hello.world 1 134217729\r\n");
340 assert_matches!(
341 decoder.decode(),
342 Err(DecoderError::InvalidPayloadLength(ParseUintError::Overflow))
343 );
344 }
345
346 #[test]
347 fn hmsg_total_len_over_limit() {
348 let mut decoder = StreamDecoder::new();
349 decoder
350 .read_buf()
351 .put_slice(b"HMSG hello.world 1 100 134217729\r\n");
352 assert_matches!(
353 decoder.decode(),
354 Err(DecoderError::InvalidPayloadLength(ParseUintError::Overflow))
355 );
356 }
357
358 #[test]
359 fn head_too_long() {
360 let mut decoder = StreamDecoder::new();
361 decoder.read_buf().put_bytes(0, 200_000);
362 assert_matches!(
363 decoder.decode(),
364 Err(DecoderError::HeadTooLong { len: 200_000 })
365 );
366 }
367}