1#![allow(clippy::cast_possible_truncation)]
16#![allow(clippy::too_many_arguments)]
17#![allow(clippy::match_same_arms)]
18#![allow(clippy::needless_continue)]
19#![allow(clippy::manual_let_else)]
23#![allow(clippy::redundant_else)]
24
25use super::commands::{
26 memcache_arithmetic, memcache_cas, memcache_delete, memcache_retrieval, memcache_storage,
27 memcache_touch,
28};
29use crate::msg::{KeyPos, Msg, MsgParseResult, MsgType};
30
31pub const MEMCACHE_MAX_KEY_LENGTH: usize = 250;
33
34#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
37pub struct HashTag {
38 pub open: u8,
40 pub close: u8,
42}
43
44#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
49#[repr(u32)]
50pub enum ReqState {
51 #[default]
53 Start = 0,
54 ReqType = 1,
56 SpacesBeforeKey = 2,
58 Key = 3,
60 SpacesBeforeKeys = 4,
62 SpacesBeforeFlags = 5,
64 Flags = 6,
66 SpacesBeforeExpiry = 7,
68 Expiry = 8,
70 SpacesBeforeVlen = 9,
72 Vlen = 10,
74 SpacesBeforeCas = 11,
76 Cas = 12,
78 RuntoVal = 13,
80 Val = 14,
82 SpacesBeforeNum = 15,
84 Num = 16,
86 RuntoCrlf = 17,
88 Crlf = 18,
90 Noreply = 19,
92 AfterNoreply = 20,
94 AlmostDone = 21,
96}
97
98impl ReqState {
99 fn from_u32(v: u32) -> Self {
100 match v {
101 1 => Self::ReqType,
102 2 => Self::SpacesBeforeKey,
103 3 => Self::Key,
104 4 => Self::SpacesBeforeKeys,
105 5 => Self::SpacesBeforeFlags,
106 6 => Self::Flags,
107 7 => Self::SpacesBeforeExpiry,
108 8 => Self::Expiry,
109 9 => Self::SpacesBeforeVlen,
110 10 => Self::Vlen,
111 11 => Self::SpacesBeforeCas,
112 12 => Self::Cas,
113 13 => Self::RuntoVal,
114 14 => Self::Val,
115 15 => Self::SpacesBeforeNum,
116 16 => Self::Num,
117 17 => Self::RuntoCrlf,
118 18 => Self::Crlf,
119 19 => Self::Noreply,
120 20 => Self::AfterNoreply,
121 21 => Self::AlmostDone,
122 _ => Self::Start,
123 }
124 }
125}
126
127#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
129#[repr(u32)]
130pub enum RspState {
131 #[default]
133 Start = 0,
134 RspNum = 1,
136 RspStr = 2,
138 SpacesBeforeKey = 3,
140 Key = 4,
142 SpacesBeforeFlags = 5,
144 Flags = 6,
146 SpacesBeforeVlen = 7,
148 Vlen = 8,
150 RuntoVal = 9,
152 Val = 10,
154 ValLf = 11,
156 End = 12,
158 RuntoCrlf = 13,
160 Crlf = 14,
162 AlmostDone = 15,
164}
165
166impl RspState {
167 fn from_u32(v: u32) -> Self {
168 match v {
169 1 => Self::RspNum,
170 2 => Self::RspStr,
171 3 => Self::SpacesBeforeKey,
172 4 => Self::Key,
173 5 => Self::SpacesBeforeFlags,
174 6 => Self::Flags,
175 7 => Self::SpacesBeforeVlen,
176 8 => Self::Vlen,
177 9 => Self::RuntoVal,
178 10 => Self::Val,
179 11 => Self::ValLf,
180 12 => Self::End,
181 13 => Self::RuntoCrlf,
182 14 => Self::Crlf,
183 15 => Self::AlmostDone,
184 _ => Self::Start,
185 }
186 }
187}
188
189const CR: u8 = b'\r';
190const LF: u8 = b'\n';
191
192fn classify_command(token: &[u8]) -> MsgType {
193 match token {
194 b"get" => MsgType::ReqMcGet,
195 b"gets" => MsgType::ReqMcGets,
196 b"set" => MsgType::ReqMcSet,
197 b"add" => MsgType::ReqMcAdd,
198 b"cas" => MsgType::ReqMcCas,
199 b"incr" => MsgType::ReqMcIncr,
200 b"decr" => MsgType::ReqMcDecr,
201 b"quit" => MsgType::ReqMcQuit,
202 b"touch" => MsgType::ReqMcTouch,
203 b"append" => MsgType::ReqMcAppend,
204 b"delete" => MsgType::ReqMcDelete,
205 b"prepend" => MsgType::ReqMcPrepend,
206 b"replace" => MsgType::ReqMcReplace,
207 _ => MsgType::Unknown,
208 }
209}
210
211fn classify_response(token: &[u8]) -> MsgType {
212 match token {
213 b"END" => MsgType::RspMcEnd,
214 b"VALUE" => MsgType::RspMcValue,
215 b"ERROR" => MsgType::RspMcError,
216 b"STORED" => MsgType::RspMcStored,
217 b"EXISTS" => MsgType::RspMcExists,
218 b"DELETED" => MsgType::RspMcDeleted,
219 b"TOUCHED" => MsgType::RspMcTouched,
220 b"NOT_FOUND" => MsgType::RspMcNotFound,
221 b"NOT_STORED" => MsgType::RspMcNotStored,
222 b"CLIENT_ERROR" => MsgType::RspMcClientError,
223 b"SERVER_ERROR" => MsgType::RspMcServerError,
224 _ => MsgType::Unknown,
225 }
226}
227
228fn make_keypos(input: &[u8], start: usize, end: usize, hash_tag: Option<HashTag>) -> KeyPos {
229 let bytes = input[start..end].to_vec();
230 if let Some(tag) = hash_tag {
231 if let Some(open_idx) = bytes.iter().position(|&b| b == tag.open) {
232 if let Some(close_offset) = bytes[open_idx + 1..].iter().position(|&b| b == tag.close) {
233 let tag_start = open_idx + 1;
234 let tag_end = open_idx + 1 + close_offset;
235 return KeyPos::new(bytes, tag_start..tag_end);
236 }
237 }
238 }
239 KeyPos::without_tag(bytes)
240}
241
242#[allow(clippy::too_many_lines)]
272pub fn memcache_parse_req(r: &mut Msg, input: &[u8]) -> MsgParseResult {
273 memcache_parse_req_tagged(r, input, None)
274}
275
276#[allow(clippy::too_many_lines)]
291pub fn memcache_parse_req_tagged(
292 r: &mut Msg,
293 input: &[u8],
294 hash_tag: Option<HashTag>,
295) -> MsgParseResult {
296 if !r.is_request() {
297 r.set_parse_result(MsgParseResult::Error);
298 return MsgParseResult::Error;
299 }
300 let mut state = ReqState::from_u32(r.parser_state());
301 let mut p = r.parser_pos();
302 let mut token: Option<usize> = r.parser_token();
303 let mut vlen = r.vlen();
304 let mut ty = r.ty();
305 let mut is_read = r.flags().is_read;
306 let mut quit = r.flags().quit;
307 let mut expect_reply = r.flags().expect_datastore_reply;
308 let mut ntokens = r.ntokens();
309
310 'machine: while p < input.len() {
311 let ch = input[p];
312 match state {
313 ReqState::Start => {
314 if ch == b' ' {
315 p += 1;
316 continue;
317 }
318 if !ch.is_ascii_lowercase() {
319 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
320 }
321 token = Some(p);
322 state = ReqState::ReqType;
323 }
325 ReqState::ReqType => {
326 if ch == b' ' || ch == CR {
327 let start = match token {
328 Some(s) => s,
329 None => {
330 return finish_error(
331 r, state, p, token, vlen, ty, is_read, quit, ntokens,
332 );
333 }
334 };
335 let cmd = &input[start..p];
336 token = None;
337 ty = classify_command(cmd);
338 ntokens = ntokens.saturating_add(1);
339 is_read = matches!(
340 ty,
341 MsgType::ReqMcGet | MsgType::ReqMcGets | MsgType::ReqMcQuit
342 );
343 if matches!(ty, MsgType::ReqMcQuit) {
344 quit = true;
345 state = ReqState::Crlf;
347 continue;
349 }
350 match ty {
351 MsgType::ReqMcGet
352 | MsgType::ReqMcGets
353 | MsgType::ReqMcDelete
354 | MsgType::ReqMcCas
355 | MsgType::ReqMcSet
356 | MsgType::ReqMcAdd
357 | MsgType::ReqMcReplace
358 | MsgType::ReqMcAppend
359 | MsgType::ReqMcPrepend
360 | MsgType::ReqMcIncr
361 | MsgType::ReqMcDecr
362 | MsgType::ReqMcTouch => {
363 if ch == CR {
364 return finish_error(
365 r, state, p, token, vlen, ty, is_read, quit, ntokens,
366 );
367 }
368 state = ReqState::SpacesBeforeKey;
369 p += 1;
370 continue;
371 }
372 MsgType::Unknown => {
373 return finish_error(
374 r, state, p, token, vlen, ty, is_read, quit, ntokens,
375 );
376 }
377 _ => {
378 return finish_error(
379 r, state, p, token, vlen, ty, is_read, quit, ntokens,
380 );
381 }
382 }
383 } else if !ch.is_ascii_lowercase() {
384 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
385 } else {
386 p += 1;
387 }
388 }
389 ReqState::SpacesBeforeKey => {
390 if ch == b' ' {
391 p += 1;
392 } else {
393 token = None;
394 state = ReqState::Key;
395 }
397 }
398 ReqState::Key => {
399 if token.is_none() {
400 token = Some(p);
401 }
402 if ch == b' ' || ch == CR {
403 let start = token.expect("token recorded");
404 let keylen = p - start;
405 if keylen == 0 || keylen > MEMCACHE_MAX_KEY_LENGTH {
406 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
407 }
408 let kp = make_keypos(input, start, p, hash_tag);
409 r.push_key(kp);
410 ntokens = ntokens.saturating_add(1);
411 token = None;
412 let storage = memcache_storage(ty);
413 let arithmetic = memcache_arithmetic(ty);
414 let touch = memcache_touch(ty);
415 let delete = memcache_delete(ty);
416 let retrieval = memcache_retrieval(ty);
417 if storage {
418 state = ReqState::SpacesBeforeFlags;
419 } else if arithmetic || touch {
420 state = ReqState::SpacesBeforeNum;
421 } else if delete {
422 state = ReqState::RuntoCrlf;
423 } else if retrieval {
424 state = ReqState::SpacesBeforeKeys;
425 } else {
426 state = ReqState::RuntoCrlf;
427 }
428 if ch == CR {
429 if storage || arithmetic {
430 return finish_error(
431 r, state, p, token, vlen, ty, is_read, quit, ntokens,
432 );
433 }
434 } else {
436 p += 1;
437 }
438 } else {
439 p += 1;
440 }
441 }
442 ReqState::SpacesBeforeKeys => {
443 match ch {
444 b' ' => {
445 p += 1;
446 }
447 CR => {
448 state = ReqState::AlmostDone;
449 p += 1;
450 }
451 _ => {
452 token = None;
453 state = ReqState::Key;
454 }
456 }
457 }
458 ReqState::SpacesBeforeFlags => {
459 if ch == b' ' {
460 p += 1;
461 } else if ch.is_ascii_digit() {
462 token = Some(p);
463 state = ReqState::Flags;
464 p += 1;
465 } else {
466 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
467 }
468 }
469 ReqState::Flags => {
470 if ch.is_ascii_digit() {
471 p += 1;
472 } else if ch == b' ' {
473 token = None;
474 state = ReqState::SpacesBeforeExpiry;
475 p += 1;
476 } else {
477 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
478 }
479 }
480 ReqState::SpacesBeforeExpiry => {
481 if ch == b' ' {
482 p += 1;
483 } else if ch.is_ascii_digit() {
484 token = Some(p);
485 state = ReqState::Expiry;
486 p += 1;
487 } else {
488 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
489 }
490 }
491 ReqState::Expiry => {
492 if ch.is_ascii_digit() {
493 p += 1;
494 } else if ch == b' ' {
495 token = None;
496 state = ReqState::SpacesBeforeVlen;
497 p += 1;
498 } else {
499 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
500 }
501 }
502 ReqState::SpacesBeforeVlen => {
503 if ch == b' ' {
504 p += 1;
505 } else if ch.is_ascii_digit() {
506 vlen = u32::from(ch - b'0');
507 state = ReqState::Vlen;
508 p += 1;
509 } else {
510 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
511 }
512 }
513 ReqState::Vlen => {
514 if ch.is_ascii_digit() {
515 vlen = vlen.saturating_mul(10).saturating_add(u32::from(ch - b'0'));
516 p += 1;
517 } else if memcache_cas(ty) {
518 if ch != b' ' {
519 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
520 }
521 token = None;
522 state = ReqState::SpacesBeforeCas;
523 } else if ch == b' ' || ch == CR {
525 token = None;
526 state = ReqState::RuntoCrlf;
527 } else {
529 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
530 }
531 }
532 ReqState::SpacesBeforeCas => {
533 if ch == b' ' {
534 p += 1;
535 } else if ch.is_ascii_digit() {
536 token = Some(p);
537 state = ReqState::Cas;
538 p += 1;
539 } else {
540 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
541 }
542 }
543 ReqState::Cas => {
544 if ch.is_ascii_digit() {
545 p += 1;
546 } else if ch == b' ' || ch == CR {
547 token = None;
548 state = ReqState::RuntoCrlf;
549 } else {
551 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
552 }
553 }
554 ReqState::RuntoVal => match ch {
555 LF => {
556 state = ReqState::Val;
557 p += 1;
558 }
559 _ => {
560 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
561 }
562 },
563 ReqState::Val => {
564 let m = p.saturating_add(vlen as usize);
565 if m >= input.len() {
566 let consumed = input.len() - p;
567 vlen = vlen.saturating_sub(consumed as u32);
568 p = input.len();
569 break 'machine;
570 }
571 if input[m] != CR {
572 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
573 }
574 p = m + 1;
575 state = ReqState::AlmostDone;
576 }
577 ReqState::SpacesBeforeNum => {
578 if ch == b' ' {
579 p += 1;
580 } else if ch.is_ascii_digit() || ch == b'-' {
581 token = Some(p);
582 state = ReqState::Num;
583 p += 1;
584 } else {
585 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
586 }
587 }
588 ReqState::Num => {
589 if ch.is_ascii_digit() {
590 p += 1;
591 } else if ch == b' ' || ch == CR {
592 token = None;
593 state = ReqState::RuntoCrlf;
594 } else {
596 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
597 }
598 }
599 ReqState::RuntoCrlf => match ch {
600 b' ' => {
601 p += 1;
602 }
603 b'n' if (memcache_storage(ty)
604 || memcache_arithmetic(ty)
605 || memcache_delete(ty)
606 || memcache_touch(ty)) =>
607 {
608 token = Some(p);
609 state = ReqState::Noreply;
610 p += 1;
611 }
612 CR => {
613 if memcache_storage(ty) {
614 state = ReqState::RuntoVal;
615 } else {
616 state = ReqState::AlmostDone;
617 }
618 p += 1;
619 }
620 _ => {
621 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
622 }
623 },
624 ReqState::Noreply => match ch {
625 b' ' | CR => {
626 let start = match token {
627 Some(s) => s,
628 None => {
629 return finish_error(
630 r, state, p, token, vlen, ty, is_read, quit, ntokens,
631 );
632 }
633 };
634 if p - start == 7 && &input[start..p] == b"noreply" {
635 token = None;
636 expect_reply = false;
637 state = ReqState::AfterNoreply;
638 } else {
640 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
641 }
642 }
643 _ => {
644 p += 1;
645 }
646 },
647 ReqState::AfterNoreply => match ch {
648 b' ' => {
649 p += 1;
650 }
651 CR => {
652 if memcache_storage(ty) {
653 state = ReqState::RuntoVal;
654 } else {
655 state = ReqState::AlmostDone;
656 }
657 p += 1;
658 }
659 _ => {
660 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
661 }
662 },
663 ReqState::Crlf => match ch {
664 b' ' => {
665 p += 1;
666 }
667 CR => {
668 state = ReqState::AlmostDone;
669 p += 1;
670 }
671 _ => {
672 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
673 }
674 },
675 ReqState::AlmostDone => match ch {
676 LF => {
677 return finish_done(r, p + 1, ty, is_read, quit, expect_reply, ntokens, vlen);
678 }
679 _ => {
680 return finish_error(r, state, p, token, vlen, ty, is_read, quit, ntokens);
681 }
682 },
683 }
684 }
685
686 r.set_parser_state(state as u32);
688 r.set_parser_pos(p);
689 r.set_parser_token(token);
690 r.set_vlen(vlen);
691 r.set_ntokens(ntokens);
692 if ty != MsgType::Unknown {
693 r.set_type(ty);
694 }
695 r.flags_mut().is_read = is_read;
696 r.flags_mut().quit = quit;
697 r.flags_mut().expect_datastore_reply = expect_reply;
698 r.set_parse_result(MsgParseResult::Again);
699 MsgParseResult::Again
700}
701
702#[allow(clippy::too_many_arguments)]
703fn finish_done(
704 r: &mut Msg,
705 next_pos: usize,
706 ty: MsgType,
707 is_read: bool,
708 quit: bool,
709 expect_reply: bool,
710 ntokens: u32,
711 vlen: u32,
712) -> MsgParseResult {
713 r.set_type(ty);
714 r.flags_mut().is_read = is_read;
715 r.flags_mut().quit = quit;
716 r.flags_mut().expect_datastore_reply = expect_reply;
717 r.set_ntokens(ntokens);
718 r.set_vlen(vlen);
719 r.set_parser_state(ReqState::Start as u32);
720 r.set_parser_pos(next_pos);
721 r.set_parser_token(None);
722 r.set_parse_result(MsgParseResult::Ok);
723 MsgParseResult::Ok
724}
725
726#[allow(clippy::too_many_arguments)]
727fn finish_error(
728 r: &mut Msg,
729 state: ReqState,
730 pos: usize,
731 token: Option<usize>,
732 vlen: u32,
733 ty: MsgType,
734 is_read: bool,
735 quit: bool,
736 ntokens: u32,
737) -> MsgParseResult {
738 r.set_parser_state(state as u32);
739 r.set_parser_pos(pos);
740 r.set_parser_token(token);
741 r.set_vlen(vlen);
742 r.set_ntokens(ntokens);
743 if ty != MsgType::Unknown {
744 r.set_type(ty);
745 }
746 r.flags_mut().is_read = is_read;
747 r.flags_mut().quit = quit;
748 r.set_parse_result(MsgParseResult::Error);
749 MsgParseResult::Error
750}
751
752#[allow(clippy::too_many_lines)]
773pub fn memcache_parse_rsp(r: &mut Msg, input: &[u8]) -> MsgParseResult {
774 if r.is_request() {
775 r.set_parse_result(MsgParseResult::Error);
776 return MsgParseResult::Error;
777 }
778 let mut state = RspState::from_u32(r.parser_state());
779 let mut p = r.parser_pos();
780 let mut token: Option<usize> = r.parser_token();
781 let mut vlen = r.vlen();
782 let mut ty = r.ty();
783 let mut end_marker = r.end_marker();
784
785 while p < input.len() {
786 let ch = input[p];
787 match state {
788 RspState::Start => {
789 if ch.is_ascii_digit() {
790 state = RspState::RspNum;
791 } else {
792 state = RspState::RspStr;
793 }
794 }
796 RspState::RspNum => {
797 if token.is_none() {
798 token = Some(p);
799 }
800 if ch.is_ascii_digit() {
801 p += 1;
802 } else if ch == b' ' || ch == CR {
803 token = None;
804 ty = MsgType::RspMcNum;
805 state = RspState::Crlf;
806 } else {
808 return finish_error_rsp(r, state, p, token, vlen, ty, end_marker);
809 }
810 }
811 RspState::RspStr => {
812 if token.is_none() {
813 token = Some(p);
814 }
815 if ch == b' ' || ch == CR {
816 let start = token.expect("token recorded");
817 let key_bytes = &input[start..p];
818 ty = classify_response(key_bytes);
819 if ty == MsgType::RspMcEnd {
820 end_marker = Some(start);
821 }
822 match ty {
823 MsgType::Unknown => {
824 return finish_error_rsp(r, state, p, token, vlen, ty, end_marker);
825 }
826 MsgType::RspMcStored
827 | MsgType::RspMcNotStored
828 | MsgType::RspMcExists
829 | MsgType::RspMcNotFound
830 | MsgType::RspMcDeleted
831 | MsgType::RspMcTouched
832 | MsgType::RspMcEnd
833 | MsgType::RspMcError => {
834 state = RspState::Crlf;
835 }
836 MsgType::RspMcValue => {
837 state = RspState::SpacesBeforeKey;
838 }
839 MsgType::RspMcClientError | MsgType::RspMcServerError => {
840 state = RspState::RuntoCrlf;
841 }
842 _ => {
843 return finish_error_rsp(r, state, p, token, vlen, ty, end_marker);
844 }
845 }
846 } else {
848 p += 1;
849 }
850 }
851 RspState::SpacesBeforeKey => {
852 if ch == b' ' {
853 p += 1;
854 } else {
855 state = RspState::Key;
856 }
858 }
859 RspState::Key => {
860 if ch == b' ' {
861 state = RspState::SpacesBeforeFlags;
862 }
863 p += 1;
864 }
865 RspState::SpacesBeforeFlags => {
866 if ch == b' ' {
867 p += 1;
868 } else if ch.is_ascii_digit() {
869 state = RspState::Flags;
870 } else {
872 return finish_error_rsp(r, state, p, token, vlen, ty, end_marker);
873 }
874 }
875 RspState::Flags => {
876 if ch.is_ascii_digit() {
877 p += 1;
878 } else if ch == b' ' {
879 state = RspState::SpacesBeforeVlen;
880 p += 1;
881 } else {
882 return finish_error_rsp(r, state, p, token, vlen, ty, end_marker);
883 }
884 }
885 RspState::SpacesBeforeVlen => {
886 if ch == b' ' {
887 p += 1;
888 } else if ch.is_ascii_digit() {
889 state = RspState::Vlen;
890 vlen = 0;
891 } else {
893 return finish_error_rsp(r, state, p, token, vlen, ty, end_marker);
894 }
895 }
896 RspState::Vlen => {
897 if ch.is_ascii_digit() {
898 vlen = vlen.saturating_mul(10).saturating_add(u32::from(ch - b'0'));
899 p += 1;
900 } else if ch == b' ' || ch == CR {
901 state = RspState::RuntoCrlf;
902 } else {
904 return finish_error_rsp(r, state, p, token, vlen, ty, end_marker);
905 }
906 }
907 RspState::RuntoVal => match ch {
908 LF => {
909 state = RspState::Val;
910 token = None;
911 p += 1;
912 }
913 _ => {
914 return finish_error_rsp(r, state, p, token, vlen, ty, end_marker);
915 }
916 },
917 RspState::Val => {
918 let m = p.saturating_add(vlen as usize);
919 if m >= input.len() {
920 let consumed = input.len() - p;
921 vlen = vlen.saturating_sub(consumed as u32);
922 p = input.len();
923 break;
924 }
925 if input[m] != CR {
926 return finish_error_rsp(r, state, p, token, vlen, ty, end_marker);
927 }
928 p = m + 1;
929 state = RspState::ValLf;
930 }
931 RspState::ValLf => match ch {
932 LF => {
933 state = RspState::RspStr;
934 p += 1;
935 }
936 _ => {
937 return finish_error_rsp(r, state, p, token, vlen, ty, end_marker);
938 }
939 },
940 RspState::End => {
941 if token.is_none() {
942 if ch != b'E' {
943 return finish_error_rsp(r, state, p, token, vlen, ty, end_marker);
944 }
945 token = Some(p);
946 p += 1;
947 } else if ch == CR {
948 let start = token.expect("token recorded");
949 if p - start == 3 && &input[start..p] == b"END" {
950 end_marker = Some(start);
951 state = RspState::AlmostDone;
952 token = None;
953 p += 1;
954 } else {
955 return finish_error_rsp(r, state, p, token, vlen, ty, end_marker);
956 }
957 } else {
958 p += 1;
959 }
960 }
961 RspState::RuntoCrlf => match ch {
962 CR => {
963 if ty == MsgType::RspMcValue {
964 state = RspState::RuntoVal;
965 } else {
966 state = RspState::AlmostDone;
967 }
968 p += 1;
969 }
970 _ => {
971 p += 1;
972 }
973 },
974 RspState::Crlf => match ch {
975 b' ' => {
976 p += 1;
977 }
978 CR => {
979 state = RspState::AlmostDone;
980 p += 1;
981 }
982 _ => {
983 return finish_error_rsp(r, state, p, token, vlen, ty, end_marker);
984 }
985 },
986 RspState::AlmostDone => match ch {
987 LF => {
988 r.set_type(ty);
989 r.set_vlen(vlen);
990 r.set_end_marker(end_marker);
991 r.set_parser_state(RspState::Start as u32);
992 r.set_parser_pos(p + 1);
993 r.set_parser_token(None);
994 r.set_parse_result(MsgParseResult::Ok);
995 return MsgParseResult::Ok;
996 }
997 _ => {
998 return finish_error_rsp(r, state, p, token, vlen, ty, end_marker);
999 }
1000 },
1001 }
1002 }
1003
1004 r.set_parser_state(state as u32);
1005 r.set_parser_pos(p);
1006 r.set_parser_token(token);
1007 r.set_vlen(vlen);
1008 r.set_end_marker(end_marker);
1009 if ty != MsgType::Unknown {
1010 r.set_type(ty);
1011 }
1012 r.set_parse_result(MsgParseResult::Again);
1013 MsgParseResult::Again
1014}
1015
1016fn finish_error_rsp(
1017 r: &mut Msg,
1018 state: RspState,
1019 pos: usize,
1020 token: Option<usize>,
1021 vlen: u32,
1022 ty: MsgType,
1023 end_marker: Option<usize>,
1024) -> MsgParseResult {
1025 r.set_parser_state(state as u32);
1026 r.set_parser_pos(pos);
1027 r.set_parser_token(token);
1028 r.set_vlen(vlen);
1029 r.set_end_marker(end_marker);
1030 if ty != MsgType::Unknown {
1031 r.set_type(ty);
1032 }
1033 r.set_parse_result(MsgParseResult::Error);
1034 MsgParseResult::Error
1035}
1036
1037#[cfg(test)]
1038mod tests {
1039 use super::*;
1040
1041 fn parse_req(input: &[u8]) -> Msg {
1042 let mut m = Msg::new(0, MsgType::Unknown, true);
1043 let _ = memcache_parse_req(&mut m, input);
1044 m
1045 }
1046
1047 fn parse_rsp(input: &[u8]) -> Msg {
1048 let mut m = Msg::new(0, MsgType::Unknown, false);
1049 let _ = memcache_parse_rsp(&mut m, input);
1050 m
1051 }
1052
1053 #[test]
1054 fn parse_get() {
1055 let m = parse_req(b"get key1\r\n");
1056 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1057 assert_eq!(m.ty(), MsgType::ReqMcGet);
1058 assert_eq!(m.keys()[0].key(), b"key1");
1059 assert!(m.flags().is_read);
1060 }
1061
1062 #[test]
1063 fn parse_set() {
1064 let m = parse_req(b"set key1 0 0 3\r\nval\r\n");
1065 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1066 assert_eq!(m.ty(), MsgType::ReqMcSet);
1067 assert_eq!(m.keys()[0].key(), b"key1");
1068 assert_eq!(m.vlen(), 3);
1069 }
1070
1071 #[test]
1072 fn parse_set_noreply() {
1073 let m = parse_req(b"set key1 0 0 3 noreply\r\nval\r\n");
1074 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1075 assert!(!m.flags().expect_datastore_reply);
1076 }
1077
1078 #[test]
1079 fn parse_delete() {
1080 let m = parse_req(b"delete key1\r\n");
1081 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1082 assert_eq!(m.ty(), MsgType::ReqMcDelete);
1083 }
1084
1085 #[test]
1086 fn parse_incr() {
1087 let m = parse_req(b"incr counter 1\r\n");
1088 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1089 assert_eq!(m.ty(), MsgType::ReqMcIncr);
1090 }
1091
1092 #[test]
1093 fn parse_quit() {
1094 let m = parse_req(b"quit\r\n");
1095 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1096 assert_eq!(m.ty(), MsgType::ReqMcQuit);
1097 assert!(m.flags().quit);
1098 }
1099
1100 #[test]
1101 fn parse_get_multikey() {
1102 let m = parse_req(b"get a b c\r\n");
1103 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1104 let keys: Vec<&[u8]> = m.keys().iter().map(crate::msg::KeyPos::key).collect();
1105 assert_eq!(keys, vec![&b"a"[..], b"b", b"c"]);
1106 }
1107
1108 #[test]
1109 fn parse_cas() {
1110 let m = parse_req(b"cas key1 0 0 3 7\r\nval\r\n");
1111 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1112 assert_eq!(m.ty(), MsgType::ReqMcCas);
1113 }
1114
1115 #[test]
1116 fn parse_too_long_key_errors() {
1117 let mut input = b"get ".to_vec();
1118 input.extend(std::iter::repeat_n(b'k', MEMCACHE_MAX_KEY_LENGTH + 1));
1119 input.extend_from_slice(b"\r\n");
1120 let m = parse_req(&input);
1121 assert_eq!(m.parse_result(), MsgParseResult::Error);
1122 }
1123
1124 #[test]
1125 fn parse_empty_key_errors() {
1126 let m = parse_req(b"get \r\n");
1127 assert_eq!(m.parse_result(), MsgParseResult::Error);
1128 }
1129
1130 #[test]
1131 fn parse_truncated_returns_again() {
1132 let m = parse_req(b"get key");
1133 assert_eq!(m.parse_result(), MsgParseResult::Again);
1134 }
1135
1136 #[test]
1137 fn parse_stored_response() {
1138 let m = parse_rsp(b"STORED\r\n");
1139 assert_eq!(m.ty(), MsgType::RspMcStored);
1140 }
1141
1142 #[test]
1143 fn parse_value_response() {
1144 let m = parse_rsp(b"VALUE key 0 3\r\nval\r\nEND\r\n");
1145 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1146 assert_eq!(m.ty(), MsgType::RspMcEnd);
1147 }
1148
1149 #[test]
1150 fn parse_numeric_response() {
1151 let m = parse_rsp(b"42\r\n");
1152 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1153 assert_eq!(m.ty(), MsgType::RspMcNum);
1154 }
1155
1156 #[test]
1157 fn parse_server_error_response() {
1158 let m = parse_rsp(b"SERVER_ERROR oops\r\n");
1159 assert_eq!(m.parse_result(), MsgParseResult::Ok);
1160 assert_eq!(m.ty(), MsgType::RspMcServerError);
1161 }
1162
1163 #[test]
1164 fn parse_response_unknown_keyword_errors() {
1165 let m = parse_rsp(b"BOGUS\r\n");
1166 assert_eq!(m.parse_result(), MsgParseResult::Error);
1167 }
1168}