func (p *parser) parseString(buf *streambuf.Buffer) (string, bool, bool) { line, err := buf.UntilCRLF() if err != nil { return "", true, false } if len(line) == 3 && line[1] == '-' && line[2] == '1' { return "nil", true, true } length, err := strconv.ParseInt(string(line[1:]), 10, 64) if err != nil { logp.Err("Failed to read bulk message: %s", err) return "", false, false } content, err := buf.CollectWithSuffix(int(length), []byte("\r\n")) if err != nil { if err != streambuf.ErrNoMoreBytes { return "", false, false } return "", true, false } return string(content), true, true }
func (p *parser) parseSimpleString(buf *streambuf.Buffer) (string, bool, bool) { line, err := buf.UntilCRLF() if err != nil { return "", true, false } return string(line[1:]), true, true }
func (p *parser) parseArray(depth int, buf *streambuf.Buffer) (string, bool, bool, bool) { line, err := buf.UntilCRLF() if err != nil { debug("End of line not found, waiting for more data") return "", false, false, false } debug("line %s: %d", line, buf.BufferConsumed()) if len(line) == 3 && line[1] == '-' && line[2] == '1' { return "nil", false, true, true } if len(line) == 2 && line[1] == '0' { return "[]", false, true, true } count, err := strconv.ParseInt(string(line[1:]), 10, 64) if err != nil { logp.Err("Failed to read number of bulk messages: %s", err) return "", false, false, false } if count < 0 { return "nil", false, true, true } content := make([]string, 0, count) // read sub elements iserror := false for i := 0; i < int(count); i++ { var value string var ok, complete bool value, iserror, ok, complete := p.dispatch(depth+1, buf) if !ok || !complete { debug("Array incomplete") return "", iserror, ok, complete } content = append(content, value) } if depth == 0 && isRedisCommand(content[0]) { // we've got a request p.message.IsRequest = true p.message.Method = content[0] p.message.Path = content[1] } var value string if depth == 0 && p.message.IsRequest { value = strings.Join(content, " ") } else { value = "[" + strings.Join(content, ", ") + "]" } return value, iserror, true, true }
func (p *parser) parseInt(buf *streambuf.Buffer) (string, bool, bool) { line, err := buf.UntilCRLF() if err != nil { return "", true, false } number := string(line[1:]) if _, err := strconv.ParseInt(number, 10, 64); err != nil { logp.Err("Failed to read integer reply: %s", err) } return number, true, true }
func doParseTextCommand(parser *parser, buf *streambuf.Buffer) parseResult { line, err := buf.UntilCRLF() if err != nil { if err == streambuf.ErrNoMoreBytes { return parser.needMore() } return parser.failing(err) } msg := parser.message command, args, err := splitCommandAndArgs(line) if err != nil { return parser.failing(err) } debug("parse command: '%s' '%s'", command, args) msg.IsRequest = 'a' <= command[0] && command[0] <= 'z' var cmd *textCommandType if msg.IsRequest { cmd = findTextCommandType(requestCommands, command) } else { cmd = findTextCommandType(responseCommands, command) if cmd == nil { b := command[0] if '0' <= b && b <= '9' { cmd = &counterResponse } } } if cmd == nil { debug("unknown command: %s", msg.command) if parser.config.parseUnkown { cmd = &unknownCommand } else { return parser.failing(ErrParserUnknownCommand) } } msg.command = &cmd.commandType msg.rawArgs = args msg.commandLine = memcacheString{line} msg.rawCommand = command // the command parser will work on already separated command line. // The parser will either yield a message directly, or switch to binary // data parsing mode, which is provided by explicit state return parser.contWithShallow(buf, cmd.parse) }