1#![allow(clippy::cast_possible_truncation)]
19#![allow(clippy::cast_possible_wrap)]
20#![allow(clippy::too_many_arguments)]
21#![allow(clippy::match_same_arms)]
22#![allow(clippy::needless_continue)]
23#![allow(clippy::manual_let_else)]
24
25use super::commands::{classify, error_lookup, lookup, CommandClass, RoutingOverride};
26use crate::io::mbuf::MBUF_MAX_SIZE;
27use crate::msg::{ArgPos, KeyPos, Msg, MsgParseResult, MsgRouting, MsgType};
28
29const CR: u8 = b'\r';
30const LF: u8 = b'\n';
31
32#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
35pub struct HashTag {
36 pub open: u8,
38 pub close: u8,
40}
41
42#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
43#[repr(u32)]
44enum ReqState {
45 #[default]
46 Start = 0,
47 Narg = 1,
48 NargLf = 2,
49 ReqTypeLen = 3,
50 ReqTypeLenLf = 4,
51 ReqType = 5,
52 ReqTypeLf = 6,
53 KeyLen = 7,
54 KeyLenLf = 8,
55 Key = 9,
56 KeyLf = 10,
57 Arg1Len = 11,
58 Arg1LenLf = 12,
59 Arg1 = 13,
60 Arg1Lf = 14,
61 Arg2Len = 15,
62 Arg2LenLf = 16,
63 Arg2 = 17,
64 Arg2Lf = 18,
65 Arg3Len = 19,
66 Arg3LenLf = 20,
67 Arg3 = 21,
68 Arg3Lf = 22,
69 ArgnLen = 23,
70 ArgnLenLf = 24,
71 Argn = 25,
72 ArgnLf = 26,
73 InlinePing = 27,
74}
75
76impl ReqState {
77 fn from_u32(v: u32) -> Self {
78 match v {
79 1 => Self::Narg,
80 2 => Self::NargLf,
81 3 => Self::ReqTypeLen,
82 4 => Self::ReqTypeLenLf,
83 5 => Self::ReqType,
84 6 => Self::ReqTypeLf,
85 7 => Self::KeyLen,
86 8 => Self::KeyLenLf,
87 9 => Self::Key,
88 10 => Self::KeyLf,
89 11 => Self::Arg1Len,
90 12 => Self::Arg1LenLf,
91 13 => Self::Arg1,
92 14 => Self::Arg1Lf,
93 15 => Self::Arg2Len,
94 16 => Self::Arg2LenLf,
95 17 => Self::Arg2,
96 18 => Self::Arg2Lf,
97 19 => Self::Arg3Len,
98 20 => Self::Arg3LenLf,
99 21 => Self::Arg3,
100 22 => Self::Arg3Lf,
101 23 => Self::ArgnLen,
102 24 => Self::ArgnLenLf,
103 25 => Self::Argn,
104 26 => Self::ArgnLf,
105 27 => Self::InlinePing,
106 _ => Self::Start,
107 }
108 }
109}
110
111#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
112#[repr(u32)]
113enum RspState {
114 #[default]
115 Start = 0,
116 Status = 1,
117 Error = 2,
118 Integer = 3,
119 IntegerStart = 4,
120 Simple = 5,
121 Bulk = 6,
122 BulkLf = 7,
123 BulkArg = 8,
124 BulkArgLf = 9,
125 Multibulk = 10,
126 MultibulkNargLf = 11,
127 MultibulkArgnLen = 12,
128 MultibulkArgnLenLf = 13,
129 MultibulkArgn = 14,
130 MultibulkArgnLf = 15,
131 RuntoCrlf = 16,
132 AlmostDone = 17,
133}
134
135impl RspState {
136 fn from_u32(v: u32) -> Self {
137 match v {
138 1 => Self::Status,
139 2 => Self::Error,
140 3 => Self::Integer,
141 4 => Self::IntegerStart,
142 5 => Self::Simple,
143 6 => Self::Bulk,
144 7 => Self::BulkLf,
145 8 => Self::BulkArg,
146 9 => Self::BulkArgLf,
147 10 => Self::Multibulk,
148 11 => Self::MultibulkNargLf,
149 12 => Self::MultibulkArgnLen,
150 13 => Self::MultibulkArgnLenLf,
151 14 => Self::MultibulkArgn,
152 15 => Self::MultibulkArgnLf,
153 16 => Self::RuntoCrlf,
154 17 => Self::AlmostDone,
155 _ => Self::Start,
156 }
157 }
158}
159
160pub fn redis_parse_req(r: &mut Msg, input: &[u8]) -> MsgParseResult {
181 redis_parse_req_with_args(r, input, None, true)
182}
183
184#[allow(clippy::too_many_lines)]
201pub fn redis_parse_req_with_args(
202 r: &mut Msg,
203 input: &[u8],
204 hash_tag: Option<HashTag>,
205 record_args: bool,
206) -> MsgParseResult {
207 if !r.is_request() {
208 r.set_parse_result(MsgParseResult::Error);
209 return MsgParseResult::Error;
210 }
211 let mut state = ReqState::from_u32(r.parser_state());
212 let mut p = r.parser_pos();
213 let mut token: Option<usize> = r.parser_token();
214 let mut rlen = r.rlen();
215 let mut rntokens = r.rntokens();
216 let mut ntokens = r.ntokens();
217 let mut nkeys = r.nkeys();
218 let mut ty = r.ty();
219 let mut is_read = r.flags().is_read;
220 let mut quit = r.flags().quit;
221 let mut routing = r.routing();
222
223 while p < input.len() {
224 let ch = input[p];
225 match state {
226 ReqState::Start | ReqState::Narg => {
227 if token.is_none() {
228 if ch == b'p' || ch == b'P' {
229 state = ReqState::InlinePing;
230 p += 1;
231 continue;
232 }
233 if ch != b'*' {
234 return finish_req_error(
235 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
236 routing,
237 );
238 }
239 token = Some(p);
240 rntokens = 0;
241 state = ReqState::Narg;
242 p += 1;
243 } else if ch.is_ascii_digit() {
244 rntokens = rntokens
245 .saturating_mul(10)
246 .saturating_add(u32::from(ch - b'0'));
247 p += 1;
248 } else if ch == CR {
249 if rntokens == 0 {
250 return finish_req_error(
251 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
252 routing,
253 );
254 }
255 ntokens = rntokens;
256 token = None;
257 state = ReqState::NargLf;
258 p += 1;
259 } else {
260 return finish_req_error(
261 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
262 routing,
263 );
264 }
265 }
266 ReqState::InlinePing => {
267 if input.len() - p >= 5
269 && input[p].eq_ignore_ascii_case(&b'i')
270 && input[p + 1].eq_ignore_ascii_case(&b'n')
271 && input[p + 2].eq_ignore_ascii_case(&b'g')
272 && input[p + 3] == CR
273 && input[p + 4] == LF
274 {
275 ty = MsgType::ReqRedisPing;
276 is_read = true;
277 routing = MsgRouting::LocalNodeOnly;
278 p += 5;
279 return finish_req_ok(r, p, ty, is_read, quit, routing, ntokens, nkeys);
280 }
281 return finish_req_error(
282 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit, routing,
283 );
284 }
285 ReqState::NargLf => {
286 if ch == LF {
287 state = ReqState::ReqTypeLen;
288 p += 1;
289 } else {
290 return finish_req_error(
291 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
292 routing,
293 );
294 }
295 }
296 ReqState::ReqTypeLen => {
297 if token.is_none() {
298 if ch != b'$' {
299 return finish_req_error(
300 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
301 routing,
302 );
303 }
304 token = Some(p);
305 rlen = 0;
306 p += 1;
307 } else if ch.is_ascii_digit() {
308 rlen = rlen.saturating_mul(10).saturating_add(u32::from(ch - b'0'));
309 p += 1;
310 } else if ch == CR {
311 if rlen == 0 || rntokens == 0 {
312 return finish_req_error(
313 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
314 routing,
315 );
316 }
317 rntokens -= 1;
318 token = None;
319 state = ReqState::ReqTypeLenLf;
320 p += 1;
321 } else {
322 return finish_req_error(
323 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
324 routing,
325 );
326 }
327 }
328 ReqState::ReqTypeLenLf => {
329 if ch == LF {
330 state = ReqState::ReqType;
331 p += 1;
332 } else {
333 return finish_req_error(
334 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
335 routing,
336 );
337 }
338 }
339 ReqState::ReqType => {
340 if token.is_none() {
341 token = Some(p);
342 }
343 let start = token.expect("token recorded");
344 let needed = start + rlen as usize;
345 if needed >= input.len() {
346 p = input.len();
348 break;
349 }
350 if input[needed] != CR {
351 return finish_req_error(
352 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
353 routing,
354 );
355 }
356 let cmd_bytes = &input[start..needed];
357 p = needed + 1;
358 rlen = 0;
359 token = None;
360 let prev_ty = ty;
361 if prev_ty != MsgType::ReqRedisScript {
362 ty = MsgType::Unknown;
363 }
364 if let Some((found, traits)) = lookup(cmd_bytes) {
365 ty = found;
366 is_read = traits.is_read;
367 quit = traits.quit;
368 routing = match traits.routing {
369 RoutingOverride::None => routing,
370 RoutingOverride::LocalNodeOnly => MsgRouting::LocalNodeOnly,
371 RoutingOverride::TokenOwnerLocalRackOnly => {
372 MsgRouting::TokenOwnerLocalRackOnly
373 }
374 RoutingOverride::AllNodesAllRacksAllDcs => {
375 MsgRouting::AllNodesAllRacksAllDcs
376 }
377 };
378 if ty == MsgType::ReqRedisExists && prev_ty == MsgType::ReqRedisScript {
379 ty = MsgType::ReqRedisScriptExists;
380 routing = MsgRouting::AllNodesAllRacksAllDcs;
381 is_read = true;
382 }
383 if ty == MsgType::ReqRedisPing {
384 return finish_req_ok(
387 r,
388 p + 1,
389 ty,
390 true,
391 quit,
392 MsgRouting::LocalNodeOnly,
393 ntokens,
394 nkeys,
395 );
396 }
397 } else {
398 return finish_req_error(
399 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
400 routing,
401 );
402 }
403 state = ReqState::ReqTypeLf;
404 continue;
405 }
406 ReqState::ReqTypeLf => {
407 if ty == MsgType::ReqRedisScript {
408 state = ReqState::ReqTypeLen;
409 p += 1;
410 continue;
411 }
412 if ty == MsgType::HackSettingConnConsistency {
413 state = ReqState::Arg1Len;
414 p += 1;
415 continue;
416 }
417 if ch != LF {
418 return finish_req_error(
419 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
420 routing,
421 );
422 }
423 p += 1;
424 let class = classify(ty);
425 if matches!(class, CommandClass::Argz) && rntokens == 0 {
426 return finish_req_ok(r, p, ty, is_read, quit, routing, ntokens, nkeys);
427 }
428 if class == CommandClass::ArgUpto1 && rntokens == 0 {
429 return finish_req_ok(r, p, ty, is_read, quit, routing, ntokens, nkeys);
430 }
431 if class == CommandClass::ArgUpto1 && rntokens == 1 {
432 state = ReqState::Arg1Len;
433 continue;
434 }
435 if matches!(
436 ty,
437 MsgType::ReqRedisScriptLoad | MsgType::ReqRedisScriptExists
438 ) {
439 state = ReqState::Arg1Len;
440 continue;
441 }
442 if class == CommandClass::ArgEval {
443 state = ReqState::Arg1Len;
444 continue;
445 }
446 state = ReqState::KeyLen;
447 }
448 ReqState::KeyLen => {
449 if token.is_none() {
450 if ch != b'$' {
451 return finish_req_error(
452 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
453 routing,
454 );
455 }
456 token = Some(p);
457 rlen = 0;
458 p += 1;
459 } else if ch.is_ascii_digit() {
460 rlen = rlen.saturating_mul(10).saturating_add(u32::from(ch - b'0'));
461 p += 1;
462 } else if ch == CR {
463 if rlen == 0 || rlen as usize >= MBUF_MAX_SIZE || rntokens == 0 {
464 return finish_req_error(
465 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
466 routing,
467 );
468 }
469 rntokens -= 1;
470 token = None;
471 state = ReqState::KeyLenLf;
472 p += 1;
473 } else {
474 return finish_req_error(
475 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
476 routing,
477 );
478 }
479 }
480 ReqState::KeyLenLf => {
481 if ch == LF {
482 state = ReqState::Key;
483 p += 1;
484 } else {
485 return finish_req_error(
486 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
487 routing,
488 );
489 }
490 }
491 ReqState::Key => {
492 if token.is_none() {
493 token = Some(p);
494 }
495 let start = token.expect("token recorded");
496 let needed = start + rlen as usize;
497 if needed >= input.len() {
498 p = input.len();
499 break;
500 }
501 if input[needed] != CR {
502 return finish_req_error(
503 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
504 routing,
505 );
506 }
507 let kbytes = input[start..needed].to_vec();
508 p = needed + 1;
509 rlen = 0;
510 let kp = if let Some(tag) = hash_tag {
511 if let Some(open_idx) = kbytes.iter().position(|&b| b == tag.open) {
512 if let Some(close_off) =
513 kbytes[open_idx + 1..].iter().position(|&b| b == tag.close)
514 {
515 let s = open_idx + 1;
516 let e = open_idx + 1 + close_off;
517 KeyPos::new(kbytes, s..e)
518 } else {
519 KeyPos::without_tag(kbytes)
520 }
521 } else {
522 KeyPos::without_tag(kbytes)
523 }
524 } else {
525 KeyPos::without_tag(kbytes)
526 };
527 r.push_key(kp);
528 token = None;
529 state = ReqState::KeyLf;
530 }
531 ReqState::KeyLf => {
532 if ch != LF {
533 return finish_req_error(
534 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
535 routing,
536 );
537 }
538 p += 1;
539 let class = classify(ty);
540 match class {
541 CommandClass::Arg0 => {
542 if rntokens != 0 {
543 return finish_req_error(
544 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read,
545 quit, routing,
546 );
547 }
548 return finish_req_ok(r, p, ty, is_read, quit, routing, ntokens, nkeys);
549 }
550 CommandClass::Arg1 => {
551 if rntokens != 1 {
552 return finish_req_error(
553 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read,
554 quit, routing,
555 );
556 }
557 state = ReqState::Arg1Len;
558 }
559 CommandClass::Arg2 => {
560 if rntokens != 2 {
561 return finish_req_error(
562 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read,
563 quit, routing,
564 );
565 }
566 state = ReqState::Arg1Len;
567 }
568 CommandClass::Arg3 => {
569 if rntokens != 3 {
570 return finish_req_error(
571 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read,
572 quit, routing,
573 );
574 }
575 state = ReqState::Arg1Len;
576 }
577 CommandClass::ArgN => {
578 if rntokens == 0 {
579 return finish_req_ok(r, p, ty, is_read, quit, routing, ntokens, nkeys);
580 }
581 state = ReqState::Arg1Len;
582 }
583 CommandClass::ArgX => {
584 if rntokens == 0 {
585 return finish_req_ok(r, p, ty, is_read, quit, routing, ntokens, nkeys);
586 }
587 state = ReqState::KeyLen;
588 }
589 CommandClass::ArgKvX => {
590 if ntokens.is_multiple_of(2) {
591 return finish_req_error(
592 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read,
593 quit, routing,
594 );
595 }
596 state = ReqState::Arg1Len;
597 }
598 CommandClass::ArgEval => {
599 nkeys = nkeys.saturating_sub(1);
600 if nkeys > 0 {
601 state = ReqState::KeyLen;
602 } else if rntokens > 0 {
603 state = ReqState::ArgnLen;
604 } else {
605 return finish_req_ok(r, p, ty, is_read, quit, routing, ntokens, nkeys);
606 }
607 }
608 _ => {
609 return finish_req_error(
610 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
611 routing,
612 );
613 }
614 }
615 }
616 ReqState::Arg1Len => {
617 match read_bulk_len(input, &mut p, &mut token, &mut rlen, &mut rntokens) {
618 BulkLenStep::More => {}
619 BulkLenStep::Done => state = ReqState::Arg1LenLf,
620 BulkLenStep::Error => {
621 return finish_req_error(
622 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
623 routing,
624 );
625 }
626 BulkLenStep::Eof => break,
627 }
628 }
629 ReqState::Arg1LenLf => {
630 if ch == LF {
631 state = ReqState::Arg1;
632 p += 1;
633 } else {
634 return finish_req_error(
635 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
636 routing,
637 );
638 }
639 }
640 ReqState::Arg1 => match read_bulk_arg(input, p, rlen, record_args, r) {
641 ArgStep::More => {
642 p = input.len();
643 let consumed = (p - r.parser_pos()) as u32;
644 let _ = consumed;
645 break;
646 }
647 ArgStep::Done(new_p) => {
648 p = new_p;
649 rlen = 0;
650 state = ReqState::Arg1Lf;
651 }
652 ArgStep::Error => {
653 return finish_req_error(
654 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
655 routing,
656 );
657 }
658 },
659 ReqState::Arg1Lf => {
660 if ch != LF {
661 return finish_req_error(
662 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
663 routing,
664 );
665 }
666 p += 1;
667 let class = classify(ty);
668 match class {
669 CommandClass::ArgUpto1 | CommandClass::Arg1 => {
670 if rntokens != 0 {
671 return finish_req_error(
672 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read,
673 quit, routing,
674 );
675 }
676 return finish_req_ok(r, p, ty, is_read, quit, routing, ntokens, nkeys);
677 }
678 CommandClass::Arg2 => {
679 if rntokens != 1 {
680 return finish_req_error(
681 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read,
682 quit, routing,
683 );
684 }
685 state = ReqState::Arg2Len;
686 }
687 CommandClass::Arg3 => {
688 if rntokens != 2 {
689 return finish_req_error(
690 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read,
691 quit, routing,
692 );
693 }
694 state = ReqState::Arg2Len;
695 }
696 CommandClass::ArgN => {
697 if rntokens == 0 {
698 return finish_req_ok(r, p, ty, is_read, quit, routing, ntokens, nkeys);
699 }
700 state = ReqState::ArgnLen;
701 }
702 CommandClass::ArgEval => {
703 if rntokens < 1 {
712 return finish_req_error(
713 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read,
714 quit, routing,
715 );
716 }
717 state = ReqState::Arg2Len;
718 }
719 CommandClass::ArgKvX => {
720 if rntokens == 0 {
721 return finish_req_ok(r, p, ty, is_read, quit, routing, ntokens, nkeys);
722 }
723 state = ReqState::KeyLen;
724 }
725 _ => {
726 return finish_req_error(
727 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
728 routing,
729 );
730 }
731 }
732 }
733 ReqState::Arg2Len => {
734 match read_bulk_len(input, &mut p, &mut token, &mut rlen, &mut rntokens) {
735 BulkLenStep::More => {}
736 BulkLenStep::Done => state = ReqState::Arg2LenLf,
737 BulkLenStep::Error => {
738 return finish_req_error(
739 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
740 routing,
741 );
742 }
743 BulkLenStep::Eof => break,
744 }
745 }
746 ReqState::Arg2LenLf => {
747 if ch == LF {
748 state = ReqState::Arg2;
749 p += 1;
750 } else {
751 return finish_req_error(
752 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
753 routing,
754 );
755 }
756 }
757 ReqState::Arg2 => {
758 let class = classify(ty);
759 let token_start = if class == CommandClass::ArgEval && token.is_none() {
760 Some(p)
761 } else {
762 token
763 };
764 token = token_start;
765 match read_bulk_arg(input, p, rlen, record_args, r) {
766 ArgStep::More => {
767 p = input.len();
768 break;
769 }
770 ArgStep::Done(new_p) => {
771 p = new_p;
772 if class == CommandClass::ArgEval {
773 let start = token.unwrap_or(0);
779 if start >= p.saturating_sub(1) {
780 return finish_req_error(
781 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty,
782 is_read, quit, routing,
783 );
784 }
785 let mut nkey: u32 = 0;
786 for &b in &input[start..p - 1] {
787 if b.is_ascii_digit() {
788 nkey =
789 nkey.saturating_mul(10).saturating_add(u32::from(b - b'0'));
790 } else {
791 return finish_req_error(
792 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty,
793 is_read, quit, routing,
794 );
795 }
796 }
797 if rntokens < nkey {
802 return finish_req_error(
803 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty,
804 is_read, quit, routing,
805 );
806 }
807 nkeys = nkey;
808 token = None;
809 }
810 rlen = 0;
811 state = ReqState::Arg2Lf;
812 }
813 ArgStep::Error => {
814 return finish_req_error(
815 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
816 routing,
817 );
818 }
819 }
820 }
821 ReqState::Arg2Lf => {
822 if ch != LF {
823 return finish_req_error(
824 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
825 routing,
826 );
827 }
828 p += 1;
829 let class = classify(ty);
830 match class {
831 CommandClass::Arg2 => {
832 if rntokens != 0 {
833 return finish_req_error(
834 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read,
835 quit, routing,
836 );
837 }
838 return finish_req_ok(r, p, ty, is_read, quit, routing, ntokens, nkeys);
839 }
840 CommandClass::Arg3 => {
841 if rntokens != 1 {
842 return finish_req_error(
843 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read,
844 quit, routing,
845 );
846 }
847 state = ReqState::Arg3Len;
848 }
849 CommandClass::ArgN => {
850 if rntokens == 0 {
851 return finish_req_ok(r, p, ty, is_read, quit, routing, ntokens, nkeys);
852 }
853 state = ReqState::ArgnLen;
854 }
855 CommandClass::ArgEval => {
856 if rntokens == 0 {
863 return finish_req_ok(r, p, ty, is_read, quit, routing, ntokens, nkeys);
864 }
865 if nkeys == 0 {
877 state = ReqState::ArgnLen;
878 } else {
879 state = ReqState::KeyLen;
880 }
881 }
882 _ => {
883 return finish_req_error(
884 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
885 routing,
886 );
887 }
888 }
889 }
890 ReqState::Arg3Len => {
891 match read_bulk_len(input, &mut p, &mut token, &mut rlen, &mut rntokens) {
892 BulkLenStep::More => {}
893 BulkLenStep::Done => state = ReqState::Arg3LenLf,
894 BulkLenStep::Error => {
895 return finish_req_error(
896 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
897 routing,
898 );
899 }
900 BulkLenStep::Eof => break,
901 }
902 }
903 ReqState::Arg3LenLf => {
904 if ch == LF {
905 state = ReqState::Arg3;
906 p += 1;
907 } else {
908 return finish_req_error(
909 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
910 routing,
911 );
912 }
913 }
914 ReqState::Arg3 => match read_bulk_arg(input, p, rlen, record_args, r) {
915 ArgStep::More => {
916 p = input.len();
917 break;
918 }
919 ArgStep::Done(new_p) => {
920 p = new_p;
921 rlen = 0;
922 state = ReqState::Arg3Lf;
923 }
924 ArgStep::Error => {
925 return finish_req_error(
926 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
927 routing,
928 );
929 }
930 },
931 ReqState::Arg3Lf => {
932 if ch != LF {
933 return finish_req_error(
934 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
935 routing,
936 );
937 }
938 p += 1;
939 let class = classify(ty);
940 match class {
941 CommandClass::Arg3 => {
942 if rntokens != 0 {
943 return finish_req_error(
944 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read,
945 quit, routing,
946 );
947 }
948 return finish_req_ok(r, p, ty, is_read, quit, routing, ntokens, nkeys);
949 }
950 CommandClass::ArgN => {
951 if rntokens == 0 {
952 return finish_req_ok(r, p, ty, is_read, quit, routing, ntokens, nkeys);
953 }
954 state = ReqState::ArgnLen;
955 }
956 _ => {
957 return finish_req_error(
958 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
959 routing,
960 );
961 }
962 }
963 }
964 ReqState::ArgnLen => {
965 match read_bulk_len(input, &mut p, &mut token, &mut rlen, &mut rntokens) {
966 BulkLenStep::More => {}
967 BulkLenStep::Done => state = ReqState::ArgnLenLf,
968 BulkLenStep::Error => {
969 return finish_req_error(
970 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
971 routing,
972 );
973 }
974 BulkLenStep::Eof => break,
975 }
976 }
977 ReqState::ArgnLenLf => {
978 if ch == LF {
979 state = ReqState::Argn;
980 p += 1;
981 } else {
982 return finish_req_error(
983 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
984 routing,
985 );
986 }
987 }
988 ReqState::Argn => match read_bulk_arg(input, p, rlen, record_args, r) {
989 ArgStep::More => {
990 p = input.len();
991 break;
992 }
993 ArgStep::Done(new_p) => {
994 p = new_p;
995 rlen = 0;
996 state = ReqState::ArgnLf;
997 }
998 ArgStep::Error => {
999 return finish_req_error(
1000 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
1001 routing,
1002 );
1003 }
1004 },
1005 ReqState::ArgnLf => {
1006 if ch != LF {
1007 return finish_req_error(
1008 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
1009 routing,
1010 );
1011 }
1012 p += 1;
1013 let class = classify(ty);
1014 match class {
1015 CommandClass::ArgN | CommandClass::ArgEval => {
1016 if rntokens == 0 {
1017 return finish_req_ok(r, p, ty, is_read, quit, routing, ntokens, nkeys);
1018 }
1019 state = ReqState::ArgnLen;
1020 }
1021 _ => {
1022 return finish_req_error(
1023 r, state, p, token, rlen, rntokens, ntokens, nkeys, ty, is_read, quit,
1024 routing,
1025 );
1026 }
1027 }
1028 }
1029 }
1030 }
1031
1032 r.set_parser_state(state as u32);
1034 r.set_parser_pos(p);
1035 r.set_parser_token(token);
1036 r.set_rlen(rlen);
1037 r.set_rntokens(rntokens);
1038 r.set_ntokens(ntokens);
1039 r.set_nkeys(nkeys);
1040 if ty != MsgType::Unknown {
1041 r.set_type(ty);
1042 }
1043 r.flags_mut().is_read = is_read;
1044 r.flags_mut().quit = quit;
1045 r.flags_mut().rewrite_with_ts_possible = false;
1046 r.set_routing(routing);
1047 r.set_parse_result(MsgParseResult::Again);
1048 MsgParseResult::Again
1049}
1050
1051#[derive(Debug)]
1052enum BulkLenStep {
1053 More,
1054 Done,
1055 Error,
1056 Eof,
1057}
1058
1059fn read_bulk_len(
1060 input: &[u8],
1061 p: &mut usize,
1062 token: &mut Option<usize>,
1063 rlen: &mut u32,
1064 rntokens: &mut u32,
1065) -> BulkLenStep {
1066 if *p >= input.len() {
1067 return BulkLenStep::Eof;
1068 }
1069 let ch = input[*p];
1070 if token.is_none() {
1071 if ch != b'$' {
1072 return BulkLenStep::Error;
1073 }
1074 *token = Some(*p);
1075 *rlen = 0;
1076 *p += 1;
1077 return BulkLenStep::More;
1078 }
1079 if ch.is_ascii_digit() {
1080 *rlen = rlen.saturating_mul(10).saturating_add(u32::from(ch - b'0'));
1081 *p += 1;
1082 BulkLenStep::More
1083 } else if ch == CR {
1084 let start = token.expect("token recorded");
1085 if *p - start <= 1 || *rntokens == 0 {
1086 return BulkLenStep::Error;
1087 }
1088 *rntokens -= 1;
1089 *token = None;
1090 *p += 1;
1091 BulkLenStep::Done
1092 } else {
1093 BulkLenStep::Error
1094 }
1095}
1096
1097#[derive(Debug)]
1098enum ArgStep {
1099 More,
1101 Done(usize),
1103 Error,
1105}
1106
1107fn read_bulk_arg(input: &[u8], p: usize, rlen: u32, record: bool, r: &mut Msg) -> ArgStep {
1108 let needed = match p.checked_add(rlen as usize) {
1109 Some(n) => n,
1110 None => return ArgStep::Error,
1111 };
1112 if needed >= input.len() {
1113 return ArgStep::More;
1114 }
1115 if input[needed] != CR {
1116 return ArgStep::Error;
1117 }
1118 if record && rlen > 0 {
1119 r.push_arg(ArgPos::new(input[p..needed].to_vec()));
1120 }
1121 ArgStep::Done(needed + 1)
1122}
1123
1124#[allow(clippy::too_many_arguments)]
1125fn finish_req_ok(
1126 r: &mut Msg,
1127 pos: usize,
1128 ty: MsgType,
1129 is_read: bool,
1130 quit: bool,
1131 routing: MsgRouting,
1132 ntokens: u32,
1133 nkeys: u32,
1134) -> MsgParseResult {
1135 if ty == MsgType::Unknown {
1136 r.set_parse_result(MsgParseResult::Error);
1137 return MsgParseResult::Error;
1138 }
1139 r.set_type(ty);
1140 r.flags_mut().is_read = is_read;
1141 r.flags_mut().quit = quit;
1142 r.set_routing(routing);
1143 r.set_ntokens(ntokens);
1144 r.set_nkeys(nkeys);
1145 r.set_parser_state(0);
1146 r.set_parser_pos(pos);
1147 r.set_parser_token(None);
1148 r.set_parse_result(MsgParseResult::Ok);
1149 MsgParseResult::Ok
1150}
1151
1152#[allow(clippy::too_many_arguments)]
1153fn finish_req_error(
1154 r: &mut Msg,
1155 state: ReqState,
1156 pos: usize,
1157 token: Option<usize>,
1158 rlen: u32,
1159 rntokens: u32,
1160 ntokens: u32,
1161 nkeys: u32,
1162 ty: MsgType,
1163 is_read: bool,
1164 quit: bool,
1165 routing: MsgRouting,
1166) -> MsgParseResult {
1167 r.set_parser_state(state as u32);
1168 r.set_parser_pos(pos);
1169 r.set_parser_token(token);
1170 r.set_rlen(rlen);
1171 r.set_rntokens(rntokens);
1172 r.set_ntokens(ntokens);
1173 r.set_nkeys(nkeys);
1174 if ty != MsgType::Unknown {
1175 r.set_type(ty);
1176 }
1177 r.flags_mut().is_read = is_read;
1178 r.flags_mut().quit = quit;
1179 r.set_routing(routing);
1180 r.set_parse_result(MsgParseResult::Error);
1181 MsgParseResult::Error
1182}
1183
1184#[allow(clippy::too_many_lines)]
1204pub fn redis_parse_rsp(r: &mut Msg, input: &[u8]) -> MsgParseResult {
1205 if r.is_request() {
1206 r.set_parse_result(MsgParseResult::Error);
1207 return MsgParseResult::Error;
1208 }
1209 let mut state = RspState::from_u32(r.parser_state());
1210 let mut p = r.parser_pos();
1211 let mut token: Option<usize> = r.parser_token();
1212 let mut rlen = r.rlen();
1213 let mut rntokens = r.rntokens();
1214 let mut ty = r.ty();
1215 let mut integer = r.integer();
1216 let mut int_negative = false;
1217 let mut ntoken_start: Option<usize> = r.ntoken_start();
1218 let mut ntoken_end: Option<usize> = r.ntoken_end();
1219
1220 while p < input.len() {
1221 let ch = input[p];
1222 match state {
1223 RspState::Start => {
1224 ty = MsgType::Unknown;
1225 match ch {
1226 b'+' => {
1227 ty = MsgType::RspRedisStatus;
1228 state = RspState::RuntoCrlf;
1229 p += 1;
1230 }
1231 b'-' => {
1232 ty = MsgType::RspRedisError;
1233 state = RspState::Error;
1234 }
1235 b':' => {
1236 ty = MsgType::RspRedisInteger;
1237 state = RspState::IntegerStart;
1238 integer = 0;
1239 int_negative = false;
1240 p += 1;
1241 }
1242 b'$' => {
1243 ty = MsgType::RspRedisBulk;
1244 state = RspState::Bulk;
1245 }
1246 b'*' => {
1247 ty = MsgType::RspRedisMultibulk;
1248 state = RspState::Multibulk;
1249 }
1250 _ => {
1251 return finish_rsp_error(
1252 r,
1253 state,
1254 p,
1255 token,
1256 rlen,
1257 rntokens,
1258 ty,
1259 integer,
1260 ntoken_start,
1261 ntoken_end,
1262 );
1263 }
1264 }
1265 }
1266 RspState::Status => {
1273 state = RspState::RuntoCrlf;
1274 }
1275 RspState::Error => {
1276 if token.is_none() {
1277 if ch != b'-' {
1278 return finish_rsp_error(
1279 r,
1280 state,
1281 p,
1282 token,
1283 rlen,
1284 rntokens,
1285 ty,
1286 integer,
1287 ntoken_start,
1288 ntoken_end,
1289 );
1290 }
1291 token = Some(p);
1292 p += 1;
1293 } else if ch == b' ' || ch == CR {
1294 let start = token.expect("token recorded");
1295 if let Some(t) = error_lookup(&input[start..p]) {
1296 ty = t;
1297 }
1298 state = RspState::RuntoCrlf;
1299 token = None;
1300 } else {
1302 p += 1;
1303 }
1304 }
1305 RspState::Integer => {
1306 state = RspState::IntegerStart;
1308 integer = 0;
1309 int_negative = false;
1310 }
1311 RspState::IntegerStart => {
1312 if ch == CR {
1313 if int_negative {
1314 integer = -integer;
1315 }
1316 state = RspState::AlmostDone;
1317 p += 1;
1318 } else if ch == b'-' {
1319 int_negative = true;
1320 p += 1;
1321 } else if ch.is_ascii_digit() {
1322 integer = integer
1323 .saturating_mul(10)
1324 .saturating_add(i64::from(ch - b'0'));
1325 p += 1;
1326 } else {
1327 return finish_rsp_error(
1328 r,
1329 state,
1330 p,
1331 token,
1332 rlen,
1333 rntokens,
1334 ty,
1335 integer,
1336 ntoken_start,
1337 ntoken_end,
1338 );
1339 }
1340 }
1341 RspState::Simple => {
1342 if ch == CR {
1343 state = RspState::MultibulkArgnLf;
1344 rntokens = rntokens.saturating_sub(1);
1345 }
1346 p += 1;
1347 }
1348 RspState::RuntoCrlf => {
1349 if ch == CR {
1350 state = RspState::AlmostDone;
1351 p += 1;
1352 } else {
1353 p += 1;
1354 }
1355 }
1356 RspState::AlmostDone => {
1357 if ch != LF {
1358 return finish_rsp_error(
1359 r,
1360 state,
1361 p,
1362 token,
1363 rlen,
1364 rntokens,
1365 ty,
1366 integer,
1367 ntoken_start,
1368 ntoken_end,
1369 );
1370 }
1371 p += 1;
1372 return finish_rsp_ok(r, p, ty, integer, ntoken_start, ntoken_end);
1373 }
1374 RspState::Bulk => {
1375 if token.is_none() {
1376 if ch != b'$' {
1377 return finish_rsp_error(
1378 r,
1379 state,
1380 p,
1381 token,
1382 rlen,
1383 rntokens,
1384 ty,
1385 integer,
1386 ntoken_start,
1387 ntoken_end,
1388 );
1389 }
1390 token = Some(p);
1391 rlen = 0;
1392 p += 1;
1393 } else if ch == b'-' {
1394 state = RspState::RuntoCrlf;
1395 p += 1;
1396 } else if ch.is_ascii_digit() {
1397 rlen = rlen.saturating_mul(10).saturating_add(u32::from(ch - b'0'));
1398 p += 1;
1399 } else if ch == CR {
1400 let start = token.expect("token recorded");
1401 if p - start <= 1 {
1402 return finish_rsp_error(
1403 r,
1404 state,
1405 p,
1406 token,
1407 rlen,
1408 rntokens,
1409 ty,
1410 integer,
1411 ntoken_start,
1412 ntoken_end,
1413 );
1414 }
1415 token = None;
1416 state = RspState::BulkLf;
1417 p += 1;
1418 } else {
1419 return finish_rsp_error(
1420 r,
1421 state,
1422 p,
1423 token,
1424 rlen,
1425 rntokens,
1426 ty,
1427 integer,
1428 ntoken_start,
1429 ntoken_end,
1430 );
1431 }
1432 }
1433 RspState::BulkLf => {
1434 if ch == LF {
1435 state = RspState::BulkArg;
1436 p += 1;
1437 } else {
1438 return finish_rsp_error(
1439 r,
1440 state,
1441 p,
1442 token,
1443 rlen,
1444 rntokens,
1445 ty,
1446 integer,
1447 ntoken_start,
1448 ntoken_end,
1449 );
1450 }
1451 }
1452 RspState::BulkArg => {
1453 let needed = match p.checked_add(rlen as usize) {
1454 Some(n) => n,
1455 None => {
1456 return finish_rsp_error(
1457 r,
1458 state,
1459 p,
1460 token,
1461 rlen,
1462 rntokens,
1463 ty,
1464 integer,
1465 ntoken_start,
1466 ntoken_end,
1467 );
1468 }
1469 };
1470 if needed >= input.len() {
1471 p = input.len();
1472 break;
1473 }
1474 if input[needed] != CR {
1475 return finish_rsp_error(
1476 r,
1477 state,
1478 p,
1479 token,
1480 rlen,
1481 rntokens,
1482 ty,
1483 integer,
1484 ntoken_start,
1485 ntoken_end,
1486 );
1487 }
1488 p = needed + 1;
1489 rlen = 0;
1490 state = RspState::BulkArgLf;
1491 }
1492 RspState::BulkArgLf => {
1493 if ch != CR && ch != LF {
1494 return finish_rsp_error(
1495 r,
1496 state,
1497 p,
1498 token,
1499 rlen,
1500 rntokens,
1501 ty,
1502 integer,
1503 ntoken_start,
1504 ntoken_end,
1505 );
1506 }
1507 if ch == CR {
1508 p += 1;
1509 continue;
1510 }
1511 p += 1;
1512 return finish_rsp_ok(r, p, ty, integer, ntoken_start, ntoken_end);
1513 }
1514 RspState::Multibulk => {
1515 if token.is_none() {
1516 if ch != b'*' {
1517 return finish_rsp_error(
1518 r,
1519 state,
1520 p,
1521 token,
1522 rlen,
1523 rntokens,
1524 ty,
1525 integer,
1526 ntoken_start,
1527 ntoken_end,
1528 );
1529 }
1530 token = Some(p);
1531 ntoken_start = Some(p);
1532 rntokens = 0;
1533 p += 1;
1534 } else if ch == b'-' {
1535 state = RspState::RuntoCrlf;
1536 p += 1;
1537 } else if ch.is_ascii_digit() {
1538 rntokens = rntokens
1539 .saturating_mul(10)
1540 .saturating_add(u32::from(ch - b'0'));
1541 p += 1;
1542 } else if ch == CR {
1543 let start = token.expect("token recorded");
1544 if p - start <= 1 {
1545 return finish_rsp_error(
1546 r,
1547 state,
1548 p,
1549 token,
1550 rlen,
1551 rntokens,
1552 ty,
1553 integer,
1554 ntoken_start,
1555 ntoken_end,
1556 );
1557 }
1558 ntoken_end = Some(p);
1559 token = None;
1560 state = RspState::MultibulkNargLf;
1561 p += 1;
1562 } else {
1563 return finish_rsp_error(
1564 r,
1565 state,
1566 p,
1567 token,
1568 rlen,
1569 rntokens,
1570 ty,
1571 integer,
1572 ntoken_start,
1573 ntoken_end,
1574 );
1575 }
1576 }
1577 RspState::MultibulkNargLf => {
1578 if ch != LF {
1579 return finish_rsp_error(
1580 r,
1581 state,
1582 p,
1583 token,
1584 rlen,
1585 rntokens,
1586 ty,
1587 integer,
1588 ntoken_start,
1589 ntoken_end,
1590 );
1591 }
1592 p += 1;
1593 if rntokens == 0 {
1594 return finish_rsp_ok(r, p, ty, integer, ntoken_start, ntoken_end);
1595 }
1596 state = RspState::MultibulkArgnLen;
1597 }
1598 RspState::MultibulkArgnLen => {
1599 if token.is_none() {
1600 if ch == b'*' {
1601 state = RspState::Multibulk;
1602 continue;
1604 }
1605 if ch == b':' || ch == b'+' || ch == b'-' {
1606 state = RspState::Simple;
1607 continue;
1609 }
1610 if ch != b'$' {
1611 return finish_rsp_error(
1612 r,
1613 state,
1614 p,
1615 token,
1616 rlen,
1617 rntokens,
1618 ty,
1619 integer,
1620 ntoken_start,
1621 ntoken_end,
1622 );
1623 }
1624 token = Some(p);
1625 rlen = 0;
1626 p += 1;
1627 } else if ch.is_ascii_digit() {
1628 rlen = rlen.saturating_mul(10).saturating_add(u32::from(ch - b'0'));
1629 p += 1;
1630 } else if ch == b'-' {
1631 p += 1;
1632 } else if ch == CR {
1633 let start = token.expect("token recorded");
1634 if p - start <= 1 || rntokens == 0 {
1635 return finish_rsp_error(
1636 r,
1637 state,
1638 p,
1639 token,
1640 rlen,
1641 rntokens,
1642 ty,
1643 integer,
1644 ntoken_start,
1645 ntoken_end,
1646 );
1647 }
1648 if rlen == 1 && p - start == 3 {
1649 rlen = 0;
1650 state = RspState::MultibulkArgnLf;
1651 } else {
1652 state = RspState::MultibulkArgnLenLf;
1653 }
1654 rntokens = rntokens.saturating_sub(1);
1655 token = None;
1656 p += 1;
1657 } else {
1658 return finish_rsp_error(
1659 r,
1660 state,
1661 p,
1662 token,
1663 rlen,
1664 rntokens,
1665 ty,
1666 integer,
1667 ntoken_start,
1668 ntoken_end,
1669 );
1670 }
1671 }
1672 RspState::MultibulkArgnLenLf => {
1673 if ch == LF {
1674 state = RspState::MultibulkArgn;
1675 p += 1;
1676 } else {
1677 return finish_rsp_error(
1678 r,
1679 state,
1680 p,
1681 token,
1682 rlen,
1683 rntokens,
1684 ty,
1685 integer,
1686 ntoken_start,
1687 ntoken_end,
1688 );
1689 }
1690 }
1691 RspState::MultibulkArgn => {
1692 let needed = match p.checked_add(rlen as usize) {
1693 Some(n) => n,
1694 None => {
1695 return finish_rsp_error(
1696 r,
1697 state,
1698 p,
1699 token,
1700 rlen,
1701 rntokens,
1702 ty,
1703 integer,
1704 ntoken_start,
1705 ntoken_end,
1706 );
1707 }
1708 };
1709 if needed >= input.len() {
1710 p = input.len();
1711 break;
1712 }
1713 if input[needed] != CR {
1714 return finish_rsp_error(
1715 r,
1716 state,
1717 p,
1718 token,
1719 rlen,
1720 rntokens,
1721 ty,
1722 integer,
1723 ntoken_start,
1724 ntoken_end,
1725 );
1726 }
1727 if rlen > 0 {
1728 r.push_arg(ArgPos::new(input[p..needed].to_vec()));
1729 }
1730 p = needed + 1;
1731 rlen = 0;
1732 state = RspState::MultibulkArgnLf;
1733 }
1734 RspState::MultibulkArgnLf => {
1735 if ch != LF {
1736 return finish_rsp_error(
1737 r,
1738 state,
1739 p,
1740 token,
1741 rlen,
1742 rntokens,
1743 ty,
1744 integer,
1745 ntoken_start,
1746 ntoken_end,
1747 );
1748 }
1749 p += 1;
1750 if rntokens == 0 {
1751 return finish_rsp_ok(r, p, ty, integer, ntoken_start, ntoken_end);
1752 }
1753 state = RspState::MultibulkArgnLen;
1754 }
1755 }
1756 }
1757
1758 r.set_parser_state(state as u32);
1759 r.set_parser_pos(p);
1760 r.set_parser_token(token);
1761 r.set_rlen(rlen);
1762 r.set_rntokens(rntokens);
1763 r.set_integer(integer);
1764 r.set_ntoken_span(ntoken_start, ntoken_end);
1765 if ty != MsgType::Unknown {
1766 r.set_type(ty);
1767 }
1768 r.flags_mut().is_error = super::commands::is_redis_error(ty);
1769 r.set_parse_result(MsgParseResult::Again);
1770 MsgParseResult::Again
1771}
1772
1773fn finish_rsp_ok(
1774 r: &mut Msg,
1775 pos: usize,
1776 ty: MsgType,
1777 integer: i64,
1778 ntoken_start: Option<usize>,
1779 ntoken_end: Option<usize>,
1780) -> MsgParseResult {
1781 if ty == MsgType::Unknown {
1782 r.set_parse_result(MsgParseResult::Error);
1783 return MsgParseResult::Error;
1784 }
1785 r.set_type(ty);
1786 r.set_integer(integer);
1787 r.set_ntoken_span(ntoken_start, ntoken_end);
1788 r.set_parser_state(0);
1789 r.set_parser_pos(pos);
1790 r.set_parser_token(None);
1791 r.flags_mut().is_error = super::commands::is_redis_error(ty);
1792 r.set_parse_result(MsgParseResult::Ok);
1793 MsgParseResult::Ok
1794}
1795
1796#[allow(clippy::too_many_arguments)]
1797fn finish_rsp_error(
1798 r: &mut Msg,
1799 state: RspState,
1800 pos: usize,
1801 token: Option<usize>,
1802 rlen: u32,
1803 rntokens: u32,
1804 ty: MsgType,
1805 integer: i64,
1806 ntoken_start: Option<usize>,
1807 ntoken_end: Option<usize>,
1808) -> MsgParseResult {
1809 r.set_parser_state(state as u32);
1810 r.set_parser_pos(pos);
1811 r.set_parser_token(token);
1812 r.set_rlen(rlen);
1813 r.set_rntokens(rntokens);
1814 r.set_integer(integer);
1815 r.set_ntoken_span(ntoken_start, ntoken_end);
1816 if ty != MsgType::Unknown {
1817 r.set_type(ty);
1818 }
1819 r.set_parse_result(MsgParseResult::Error);
1820 MsgParseResult::Error
1821}
1822
1823#[cfg(test)]
1824mod tests {
1825 use super::*;
1826
1827 fn parse_req(input: &[u8]) -> Msg {
1828 let mut m = Msg::new(0, MsgType::Unknown, true);
1829 let _ = redis_parse_req(&mut m, input);
1830 m
1831 }
1832
1833 fn parse_rsp(input: &[u8]) -> Msg {
1834 let mut m = Msg::new(0, MsgType::Unknown, false);
1835 let _ = redis_parse_rsp(&mut m, input);
1836 m
1837 }
1838
1839 #[test]
1840 fn parse_get() {
1841 let m = parse_req(b"*2\r\n$3\r\nGET\r\n$3\r\nfoo\r\n");
1842 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1843 assert_eq!(m.ty(), MsgType::ReqRedisGet);
1844 assert_eq!(m.keys()[0].key(), b"foo");
1845 }
1846
1847 #[test]
1848 fn parse_set() {
1849 let m = parse_req(b"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n");
1850 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1851 assert_eq!(m.ty(), MsgType::ReqRedisSet);
1852 assert_eq!(m.keys()[0].key(), b"foo");
1853 assert_eq!(m.args()[0].bytes(), b"bar");
1854 }
1855
1856 #[test]
1857 fn parse_del_multikey() {
1858 let m = parse_req(b"*4\r\n$3\r\nDEL\r\n$1\r\na\r\n$1\r\nb\r\n$1\r\nc\r\n");
1859 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1860 assert_eq!(m.ty(), MsgType::ReqRedisDel);
1861 let keys: Vec<&[u8]> = m.keys().iter().map(crate::msg::KeyPos::key).collect();
1862 assert_eq!(keys, vec![&b"a"[..], b"b", b"c"]);
1863 }
1864
1865 #[test]
1866 fn parse_mset() {
1867 let m = parse_req(b"*5\r\n$4\r\nMSET\r\n$1\r\na\r\n$1\r\n1\r\n$1\r\nb\r\n$1\r\n2\r\n");
1868 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1869 assert_eq!(m.ty(), MsgType::ReqRedisMset);
1870 let keys: Vec<&[u8]> = m.keys().iter().map(crate::msg::KeyPos::key).collect();
1871 assert_eq!(keys, vec![&b"a"[..], b"b"]);
1872 }
1873
1874 #[test]
1875 fn parse_ping_inline() {
1876 let m = parse_req(b"PING\r\n");
1877 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1878 assert_eq!(m.ty(), MsgType::ReqRedisPing);
1879 }
1880
1881 #[test]
1882 fn parse_ping_resp() {
1883 let m = parse_req(b"*1\r\n$4\r\nPING\r\n");
1884 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1885 assert_eq!(m.ty(), MsgType::ReqRedisPing);
1886 }
1887
1888 #[test]
1889 fn parse_unknown_command_errors() {
1890 let m = parse_req(b"*1\r\n$3\r\nFOO\r\n");
1891 assert_eq!(m.parse_result(), MsgParseResult::Error);
1892 }
1893
1894 #[test]
1895 fn parse_truncated_returns_again() {
1896 let m = parse_req(b"*2\r\n$3\r\nGET\r\n$3\r\nfo");
1897 assert_eq!(m.parse_result(), MsgParseResult::Again);
1898 }
1899
1900 #[test]
1901 fn parse_status_response() {
1902 let m = parse_rsp(b"+OK\r\n");
1903 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1904 assert_eq!(m.ty(), MsgType::RspRedisStatus);
1905 }
1906
1907 #[test]
1908 fn parse_error_response_classifies() {
1909 let m = parse_rsp(b"-WRONGTYPE Operation not allowed\r\n");
1910 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1911 assert_eq!(m.ty(), MsgType::RspRedisErrorWrongtype);
1912 assert!(m.flags().is_error);
1913 }
1914
1915 #[test]
1916 fn parse_integer_response() {
1917 let m = parse_rsp(b":42\r\n");
1918 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1919 assert_eq!(m.ty(), MsgType::RspRedisInteger);
1920 assert_eq!(m.integer(), 42);
1921 }
1922
1923 #[test]
1924 fn parse_bulk_response() {
1925 let m = parse_rsp(b"$5\r\nhello\r\n");
1926 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1927 assert_eq!(m.ty(), MsgType::RspRedisBulk);
1928 }
1929
1930 #[test]
1931 fn parse_null_bulk_response() {
1932 let m = parse_rsp(b"$-1\r\n");
1933 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1934 assert_eq!(m.ty(), MsgType::RspRedisBulk);
1935 }
1936
1937 #[test]
1938 fn parse_empty_multibulk_response() {
1939 let m = parse_rsp(b"*0\r\n");
1940 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1941 assert_eq!(m.ty(), MsgType::RspRedisMultibulk);
1942 }
1943}