Esempio n. 1
0
func (p *parser) parseString(buf *streambuf.Buffer) (common.NetString, bool, bool) {
	line, err := buf.UntilCRLF()
	if err != nil {
		return empty, true, false
	}

	if len(line) == 3 && line[1] == '-' && line[2] == '1' {
		return nilStr, true, true
	}

	length, err := parseInt(line[1:])
	if err != nil {
		logp.Err("Failed to read bulk message: %s", err)
		return empty, false, false
	}

	content, err := buf.CollectWithSuffix(int(length), []byte("\r\n"))
	if err != nil {
		if err != streambuf.ErrNoMoreBytes {
			return common.NetString{}, false, false
		}
		return common.NetString{}, true, false
	}

	return common.NetString(content), true, true
}
Esempio n. 2
0
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
}
Esempio n. 3
0
func (p *parser) parseSimpleString(buf *streambuf.Buffer) (common.NetString, bool, bool) {
	line, err := buf.UntilCRLF()
	if err != nil {
		return empty, true, false
	}

	return common.NetString(line[1:]), true, true
}
Esempio n. 4
0
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
}
Esempio n. 5
0
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
}
Esempio n. 6
0
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)
}
Esempio n. 7
0
func (p *parser) parseArray(depth int, buf *streambuf.Buffer) (common.NetString, bool, bool, bool) {
	line, err := buf.UntilCRLF()
	if err != nil {
		if isDebug {
			debugf("End of line not found, waiting for more data")
		}
		return empty, false, false, false
	}
	if isDebug {
		debugf("line %s: %d", line, buf.BufferConsumed())
	}

	if len(line) == 3 && line[1] == '-' && line[2] == '1' {
		return nilStr, false, true, true
	}

	if len(line) == 2 && line[1] == '0' {
		return emptyArr, false, true, true
	}

	count, err := parseInt(line[1:])
	if err != nil {
		logp.Err("Failed to read number of bulk messages: %s", err)
		return empty, false, false, false
	}
	if count < 0 {
		return nilStr, false, true, true
	} else if count == 0 {
		// should not happen, but handle just in case ParseInt did return 0
		return emptyArr, false, true, true
	}

	// invariant: count > 0

	// try to allocate content array right on stack
	var content [][]byte
	const arrayBufferSize = 32
	if int(count) <= arrayBufferSize {
		var arrayBuffer [arrayBufferSize][]byte
		content = arrayBuffer[:0]
	} else {
		content = make([][]byte, 0, count)
	}

	contentLen := 0
	// read sub elements

	iserror := false
	for i := 0; i < int(count); i++ {
		var value common.NetString
		var ok, complete bool

		value, iserror, ok, complete := p.dispatch(depth+1, buf)
		if !ok || !complete {
			if isDebug {
				debugf("Array incomplete")
			}
			return empty, iserror, ok, complete
		}

		content = append(content, []byte(value))
		contentLen += len(value)
	}

	// handle top-level request command
	if depth == 0 && isRedisCommand(content[0]) {
		p.message.isRequest = true
		p.message.method = content[0]
		if len(content) > 1 {
			p.message.path = content[1]
		}

		var value common.NetString
		if contentLen > 1 {
			tmp := make([]byte, contentLen+(len(content)-1)*1)
			join(tmp, content, []byte(" "))
			value = common.NetString(tmp)
		} else {
			value = common.NetString(content[0])
		}
		return value, iserror, true, true
	}

	// return redis array: [a, b, c]
	tmp := make([]byte, 2+contentLen+(len(content)-1)*2)
	tmp[0] = '['
	join(tmp[1:], content, []byte(", "))
	tmp[len(tmp)-1] = ']'
	value := common.NetString(tmp)
	return value, iserror, true, true
}