@@ -377,136 +377,138 @@ size_t RedisCommandParser::ParsedArgsSize() {
377377ParseError RedisCommandParser::Consume (butil::IOBuf& buf,
378378 std::vector<butil::StringPiece>* args,
379379 butil::Arena* arena) {
380- const auto pfc = static_cast <const char *>(buf.fetch1 ());
381- if (pfc == NULL ) {
382- return PARSE_ERROR_NOT_ENOUGH_DATA;
383- }
384- // '*' stands for array "*<size>\r\n<sub-reply1><sub-reply2>..."
385- if (!_parsing_array && *pfc != ' *' ) {
386- if (!std::isalpha (static_cast <unsigned char >(*pfc))) {
387- return PARSE_ERROR_TRY_OTHERS;
380+ do {
381+ const auto pfc = static_cast <const char *>(buf.fetch1 ());
382+ if (pfc == NULL ) {
383+ return PARSE_ERROR_NOT_ENOUGH_DATA;
388384 }
389- const size_t buf_size = buf.size ();
390- const auto copy_str = static_cast <char *>(arena->allocate (buf_size + 1 ));
391- buf.copy_to (copy_str, buf_size);
392- if (*copy_str == ' ' ) {
385+ // '*' stands for array "*<size>\r\n<sub-reply1><sub-reply2>..."
386+ if (!_parsing_array && *pfc != ' *' ) {
387+ if (!std::isalpha (static_cast <unsigned char >(*pfc))) {
388+ return PARSE_ERROR_TRY_OTHERS;
389+ }
390+ const size_t buf_size = buf.size ();
391+ const auto copy_str = static_cast <char *>(arena->allocate (buf_size + 1 ));
392+ buf.copy_to (copy_str, buf_size);
393+ if (*copy_str == ' ' ) {
394+ return PARSE_ERROR_ABSOLUTELY_WRONG;
395+ }
396+ copy_str[buf_size] = ' \0 ' ;
397+ const size_t crlf_pos = butil::StringPiece (copy_str, buf_size).find (" \r\n " );
398+ if (crlf_pos == butil::StringPiece::npos) { // not enough data
399+ return PARSE_ERROR_NOT_ENOUGH_DATA;
400+ }
401+ args->clear ();
402+ size_t offset = 0 ;
403+ while (offset < crlf_pos && copy_str[offset] != ' ' ) {
404+ ++offset;
405+ }
406+ const auto first_arg = static_cast <char *>(arena->allocate (offset));
407+ memcpy (first_arg, copy_str, offset);
408+ for (size_t i = 0 ; i < offset; ++i) {
409+ first_arg[i] = tolower (first_arg[i]);
410+ }
411+ args->push_back (butil::StringPiece (first_arg, offset));
412+ if (offset == crlf_pos) {
413+ // only one argument, directly return
414+ buf.pop_front (crlf_pos + 2 );
415+ return PARSE_OK;
416+ }
417+ size_t arg_start_pos = ++offset;
418+
419+ for (; offset < crlf_pos; ++offset) {
420+ if (copy_str[offset] != ' ' ) {
421+ continue ;
422+ }
423+ const auto arg_length = offset - arg_start_pos;
424+ const auto arg = static_cast <char *>(arena->allocate (arg_length));
425+ memcpy (arg, copy_str + arg_start_pos, arg_length);
426+ args->push_back (butil::StringPiece (arg, arg_length));
427+ arg_start_pos = ++offset;
428+ }
429+
430+ if (arg_start_pos < crlf_pos) {
431+ // process the last argument
432+ const auto arg_length = crlf_pos - arg_start_pos;
433+ const auto arg = static_cast <char *>(arena->allocate (arg_length));
434+ memcpy (arg, copy_str + arg_start_pos, arg_length);
435+ args->push_back (butil::StringPiece (arg, arg_length));
436+ }
437+
438+ buf.pop_front (crlf_pos + 2 );
439+ return PARSE_OK;
440+ }
441+ // '$' stands for bulk string "$<length>\r\n<string>\r\n"
442+ if (_parsing_array && *pfc != ' $' ) {
393443 return PARSE_ERROR_ABSOLUTELY_WRONG;
394444 }
395- copy_str[buf_size] = ' \0 ' ;
396- const size_t crlf_pos = butil::StringPiece (copy_str, buf_size).find (" \r\n " );
445+ char intbuf[32 ]; // enough for fc + 64-bit decimal + \r\n
446+ const size_t ncopied = buf.copy_to (intbuf, sizeof (intbuf) - 1 );
447+ intbuf[ncopied] = ' \0 ' ;
448+ const size_t crlf_pos = butil::StringPiece (intbuf, ncopied).find (" \r\n " );
397449 if (crlf_pos == butil::StringPiece::npos) { // not enough data
398450 return PARSE_ERROR_NOT_ENOUGH_DATA;
399451 }
400- args->clear ();
401- size_t offset = 0 ;
402- while (offset < crlf_pos && copy_str[offset] != ' ' ) {
403- ++offset;
404- }
405- const auto first_arg = static_cast <char *>(arena->allocate (offset));
406- memcpy (first_arg, copy_str, offset);
407- for (size_t i = 0 ; i < offset; ++i) {
408- first_arg[i] = tolower (first_arg[i]);
452+ char * endptr = NULL ;
453+ int64_t value = strtoll (intbuf + 1 /* skip fc*/ , &endptr, 10 );
454+ if (endptr != intbuf + crlf_pos) {
455+ LOG (ERROR) << ' `' << intbuf + 1 << " ' is not a valid 64-bit decimal" ;
456+ return PARSE_ERROR_ABSOLUTELY_WRONG;
409457 }
410- args->push_back (butil::StringPiece (first_arg, offset));
411- if (offset == crlf_pos) {
412- // only one argument, directly return
413- buf.pop_front (crlf_pos + 2 );
414- return PARSE_OK;
458+ if (value < 0 ) {
459+ LOG (ERROR) << " Invalid len=" << value << " in redis command" ;
460+ return PARSE_ERROR_ABSOLUTELY_WRONG;
415461 }
416- size_t arg_start_pos = ++offset;
417-
418- for (; offset < crlf_pos; ++offset) {
419- if (copy_str[offset] != ' ' ) {
420- continue ;
462+ if (!_parsing_array) {
463+ if (value > (int64_t )(FLAGS_redis_max_allocation_size / sizeof (butil::StringPiece))) {
464+ LOG (ERROR) << " command array size exceeds limit! max="
465+ << (FLAGS_redis_max_allocation_size / sizeof (butil::StringPiece))
466+ << " , actually=" << value;
467+ return PARSE_ERROR_ABSOLUTELY_WRONG;
421468 }
422- const auto arg_length = offset - arg_start_pos;
423- const auto arg = static_cast <char *>(arena->allocate (arg_length));
424- memcpy (arg, copy_str + arg_start_pos, arg_length);
425- args->push_back (butil::StringPiece (arg, arg_length));
426- arg_start_pos = ++offset;
469+ buf.pop_front (crlf_pos + 2 /* CRLF*/ );
470+ _parsing_array = true ;
471+ _length = value;
472+ _index = 0 ;
473+ _args.resize (value);
474+ continue ;
427475 }
428-
429- if (arg_start_pos < crlf_pos) {
430- // process the last argument
431- const auto arg_length = crlf_pos - arg_start_pos;
432- const auto arg = static_cast <char *>(arena->allocate (arg_length));
433- memcpy (arg, copy_str + arg_start_pos, arg_length);
434- args->push_back (butil::StringPiece (arg, arg_length));
476+ CHECK (_index < _length) << " a complete command has been parsed. "
477+ " impl of RedisCommandParser::Parse is buggy" ;
478+ const int64_t len = value; // `value' is length of the string
479+ if (len < 0 ) {
480+ LOG (ERROR) << " string in command is nil!" ;
481+ return PARSE_ERROR_ABSOLUTELY_WRONG;
435482 }
436-
437- buf.pop_front (crlf_pos + 2 );
438- return PARSE_OK;
439- }
440- // '$' stands for bulk string "$<length>\r\n<string>\r\n"
441- if (_parsing_array && *pfc != ' $' ) {
442- return PARSE_ERROR_ABSOLUTELY_WRONG;
443- }
444- char intbuf[32 ]; // enough for fc + 64-bit decimal + \r\n
445- const size_t ncopied = buf.copy_to (intbuf, sizeof (intbuf) - 1 );
446- intbuf[ncopied] = ' \0 ' ;
447- const size_t crlf_pos = butil::StringPiece (intbuf, ncopied).find (" \r\n " );
448- if (crlf_pos == butil::StringPiece::npos) { // not enough data
449- return PARSE_ERROR_NOT_ENOUGH_DATA;
450- }
451- char * endptr = NULL ;
452- int64_t value = strtoll (intbuf + 1 /* skip fc*/ , &endptr, 10 );
453- if (endptr != intbuf + crlf_pos) {
454- LOG (ERROR) << ' `' << intbuf + 1 << " ' is not a valid 64-bit decimal" ;
455- return PARSE_ERROR_ABSOLUTELY_WRONG;
456- }
457- if (value < 0 ) {
458- LOG (ERROR) << " Invalid len=" << value << " in redis command" ;
459- return PARSE_ERROR_ABSOLUTELY_WRONG;
460- }
461- if (!_parsing_array) {
462- if (value > (int64_t )(FLAGS_redis_max_allocation_size / sizeof (butil::StringPiece))) {
463- LOG (ERROR) << " command array size exceeds limit! max="
464- << (FLAGS_redis_max_allocation_size / sizeof (butil::StringPiece))
465- << " , actually=" << value;
483+ if (len > FLAGS_redis_max_allocation_size) {
484+ LOG (ERROR) << " command string exceeds max allocation size! max="
485+ << FLAGS_redis_max_allocation_size << " , actually=" << len;
466486 return PARSE_ERROR_ABSOLUTELY_WRONG;
467487 }
488+ if (buf.size () < crlf_pos + 2 + (size_t )len + 2 /* CRLF*/ ) {
489+ return PARSE_ERROR_NOT_ENOUGH_DATA;
490+ }
468491 buf.pop_front (crlf_pos + 2 /* CRLF*/ );
469- _parsing_array = true ;
470- _length = value;
471- _index = 0 ;
472- _args.resize (value);
473- return Consume (buf, args, arena);
474- }
475- CHECK (_index < _length) << " a complete command has been parsed. "
476- " impl of RedisCommandParser::Parse is buggy" ;
477- const int64_t len = value; // `value' is length of the string
478- if (len < 0 ) {
479- LOG (ERROR) << " string in command is nil!" ;
480- return PARSE_ERROR_ABSOLUTELY_WRONG;
481- }
482- if (len > FLAGS_redis_max_allocation_size) {
483- LOG (ERROR) << " command string exceeds max allocation size! max="
484- << FLAGS_redis_max_allocation_size << " , actually=" << len;
485- return PARSE_ERROR_ABSOLUTELY_WRONG;
486- }
487- if (buf.size () < crlf_pos + 2 + (size_t )len + 2 /* CRLF*/ ) {
488- return PARSE_ERROR_NOT_ENOUGH_DATA;
489- }
490- buf.pop_front (crlf_pos + 2 /* CRLF*/ );
491- char * d = (char *)arena->allocate ((len/8 + 1 ) * 8 );
492- buf.cutn (d, len);
493- d[len] = ' \0 ' ;
494- _args[_index].set (d, len);
495- if (_index == 0 ) {
496- // convert it to lowercase when it is command name
497- for (int i = 0 ; i < len; ++i) {
498- d[i] = ::tolower (d[i]);
492+ char * d = (char *)arena->allocate ((len/8 + 1 ) * 8 );
493+ buf.cutn (d, len);
494+ d[len] = ' \0 ' ;
495+ _args[_index].set (d, len);
496+ if (_index == 0 ) {
497+ // convert it to lowercase when it is command name
498+ for (int i = 0 ; i < len; ++i) {
499+ d[i] = ::tolower (d[i]);
500+ }
499501 }
500- }
501- char crlf[ 2 ] ;
502- buf. cutn (crlf, sizeof ( crlf));
503- if (crlf[ 0 ] != ' \r ' || crlf[ 1 ] != ' \n ' ) {
504- LOG (ERROR) << " string in command is not ended with CRLF " ;
505- return PARSE_ERROR_ABSOLUTELY_WRONG;
506- }
507- if (++_index < _length) {
508- return Consume (buf, args, arena);
509- }
502+ char crlf[ 2 ];
503+ buf. cutn ( crlf, sizeof (crlf)) ;
504+ if (crlf[ 0 ] != ' \r ' || crlf[ 1 ] != ' \n ' ) {
505+ LOG (ERROR) << " string in command is not ended with CRLF " ;
506+ return PARSE_ERROR_ABSOLUTELY_WRONG ;
507+ }
508+ if (++_index == _length) {
509+ break ;
510+ }
511+ } while ( true );
510512 args->swap (_args);
511513 Reset ();
512514 return PARSE_OK;
0 commit comments