| 395 | } |
| 396 | |
| 397 | RedisCommandConsumeState RedisCommandParser::ConsumeImpl(butil::IOBuf& buf, |
| 398 | butil::Arena* arena, |
| 399 | ParseError* err) { |
| 400 | const auto pfc = static_cast<const char *>(buf.fetch1()); |
| 401 | if (pfc == NULL) { |
| 402 | *err = PARSE_ERROR_NOT_ENOUGH_DATA; |
| 403 | return CONSUME_STATE_ERROR; |
| 404 | } |
| 405 | // '*' stands for array "*<size>\r\n<sub-reply1><sub-reply2>..." |
| 406 | if (!_parsing_array && *pfc != '*') { |
| 407 | if (!std::isalpha(static_cast<unsigned char>(*pfc))) { |
| 408 | *err = PARSE_ERROR_TRY_OTHERS; |
| 409 | return CONSUME_STATE_ERROR; |
| 410 | } |
| 411 | const size_t buf_size = buf.size(); |
| 412 | const auto copy_str = static_cast<char *>(arena->allocate(buf_size + 1)); |
| 413 | // arena->allocate() may return NULL on allocation failure |
| 414 | if (copy_str == NULL) { |
| 415 | LOG(FATAL) << "Arena failed allocation"; |
| 416 | *err = PARSE_ERROR_ABSOLUTELY_WRONG; |
| 417 | return CONSUME_STATE_ERROR; |
| 418 | } |
| 419 | buf.copy_to(copy_str, buf_size); |
| 420 | if (*copy_str == ' ') { |
| 421 | *err = PARSE_ERROR_ABSOLUTELY_WRONG; |
| 422 | return CONSUME_STATE_ERROR; |
| 423 | } |
| 424 | copy_str[buf_size] = '\0'; |
| 425 | const size_t crlf_pos = butil::StringPiece(copy_str, buf_size).find("\r\n"); |
| 426 | if (crlf_pos == butil::StringPiece::npos) { // not enough data |
| 427 | *err = PARSE_ERROR_NOT_ENOUGH_DATA; |
| 428 | return CONSUME_STATE_ERROR; |
| 429 | } |
| 430 | size_t offset = 0; |
| 431 | while (offset < crlf_pos && copy_str[offset] != ' ') { |
| 432 | ++offset; |
| 433 | } |
| 434 | const auto first_arg = static_cast<char*>(arena->allocate(offset)); |
| 435 | memcpy(first_arg, copy_str, offset); |
| 436 | for (size_t i = 0; i < offset; ++i) { |
| 437 | first_arg[i] = tolower(first_arg[i]); |
| 438 | } |
| 439 | _args.push_back(butil::StringPiece(first_arg, offset)); |
| 440 | if (offset == crlf_pos) { |
| 441 | // only one argument, directly return |
| 442 | buf.pop_front(crlf_pos + 2); |
| 443 | return CONSUME_STATE_DONE; |
| 444 | } |
| 445 | size_t arg_start_pos = ++offset; |
| 446 | |
| 447 | for (; offset < crlf_pos; ++offset) { |
| 448 | if (copy_str[offset] != ' ') { |
| 449 | continue; |
| 450 | } |
| 451 | const auto arg_length = offset - arg_start_pos; |
| 452 | const auto arg = static_cast<char *>(arena->allocate(arg_length)); |
| 453 | memcpy(arg, copy_str + arg_start_pos, arg_length); |
| 454 | _args.push_back(butil::StringPiece(arg, arg_length)); |