int RedisFrameDecoder::ProcessInlineBuffer(ChannelHandlerContext& ctx, Buffer& buffer, RedisCommandFrame* frame) { TRACE_LOG("Enter inline processing."); int index = buffer.IndexOf(kCRLF, 2); if (-1 == index) { return 0; } while (true) { char ch; if (!buffer.ReadByte(ch)) { break; } if (ch == ' ') { continue; } buffer.AdvanceReadIndex(-1); int current = buffer.GetReadIndex(); if (current == index) { buffer.AdvanceReadIndex(2); //skip "\r\n" break; } int space_index = buffer.IndexOf(" ", 1, current, index - 2); if (-1 == space_index) { break; } Buffer* arg = frame->GetNextArgument(space_index - current); buffer.Read(arg, space_index - current); buffer.AdvanceReadIndex(1); //skip space char } int current = buffer.GetReadIndex(); if (current < index) { Buffer* arg = frame->GetNextArgument(index - current); buffer.Read(arg, index - current); buffer.AdvanceReadIndex(2); //skip "\r\n" } return 1; }
bool RedisCommandDecoder::Decode(Channel* channel, Buffer& buffer, RedisCommandFrame& msg) { while (buffer.Readable() && (buffer.GetRawReadBuffer()[0] == '\r' || buffer.GetRawReadBuffer()[0] == '\n')) { buffer.AdvanceReadIndex(1); } size_t mark_read_index = buffer.GetReadIndex(); char ch; if (buffer.ReadByte(ch)) { int ret = -1; if (ch == '*') { //reqtype = REDIS_REQ_MULTIBULK; msg.m_is_inline = false; ret = ProcessMultibulkBuffer(channel, buffer, msg); } else { //reqtype = REDIS_REQ_INLINE; msg.m_is_inline = true; buffer.AdvanceReadIndex(-1); ret = ProcessInlineBuffer(buffer, msg); } if (ret > 0) { size_t raw_data_size = buffer.GetReadIndex() - mark_read_index; msg.m_raw_msg.WrapReadableContent(buffer.GetRawReadBuffer() - raw_data_size, raw_data_size); return true; } else { msg.Clear(); if (0 == ret) { buffer.SetReadIndex(mark_read_index); } return false; } } buffer.SetReadIndex(mark_read_index); return false; }
int RedisCommandDecoder::ProcessInlineBuffer(Buffer& buffer, RedisCommandFrame& frame) { int index = buffer.IndexOf(kCRLF, 2); if (-1 == index) { return 0; } while (true) { char ch; if (!buffer.ReadByte(ch)) { break; } if (ch == ' ') { continue; } buffer.AdvanceReadIndex(-1); int current = buffer.GetReadIndex(); if (current == index) { buffer.AdvanceReadIndex(2); //skip "\r\n" break; } int space_index = buffer.IndexOf(" ", 1, current, index); if (-1 == space_index) { break; } frame.FillNextArgument(buffer, space_index - current); buffer.AdvanceReadIndex(1); //skip space char } int current = buffer.GetReadIndex(); if (current < index) { frame.FillNextArgument(buffer, index - current); buffer.AdvanceReadIndex(2); //skip "\r\n" } return 1; }
inline void FillNextArgument(Buffer& buf, size_t len) { const char* str = buf.GetRawReadBuffer(); buf.AdvanceReadIndex(len); if (m_cmd_seted) { m_args.push_back(std::string(str, len)); } else { m_cmd.append(str, len); m_cmd_seted = true; } }
int RedisCommandFrame::EncodeRawProtocol(Buffer& buf) { if (m_is_inline) { ArgumentArray::iterator it = m_args.begin(); while (it != m_args.end()) { Buffer* arg = *it; uint32 datalen = arg->ReadableBytes(); buf.Write(arg, datalen); arg->AdvanceReadIndex(0-datalen); it++; if (it != m_args.end()) { buf.Printf(" "); } } buf.Write("\r\n", 2); return 0; } else { buf.Printf("*%d\r\n", m_args.size()); ArgumentArray::iterator it = m_args.begin(); while (it != m_args.end()) { Buffer* arg = *it; uint32 datalen = arg->ReadableBytes(); buf.Printf("$%d\r\n", datalen); buf.Write(arg, datalen); buf.Write("\r\n", 2); arg->AdvanceReadIndex(0-datalen); it++; } return 0; } }
bool RedisCommandDecoder::Decode(ChannelHandlerContext& ctx, Channel* channel, Buffer& buffer, RedisCommandFrame& msg) { bool have_empty = false; while (buffer.Readable() && (buffer.GetRawReadBuffer()[0] == '\r' || buffer.GetRawReadBuffer()[0] == '\n')) { buffer.AdvanceReadIndex(1); have_empty = true; } if(!m_ignore_empty && have_empty) { msg.Clear(); return true; } return Decode(channel, buffer, msg); }
static inline int readBulkLen(Buffer& buffer, int& len) { char *eptr = NULL; const char* raw = buffer.GetRawReadBuffer(); int tmp = strtol(raw, &eptr, 10); if ((eptr - raw) > (buffer.ReadableBytes() - 2)) { return 0; } if (*eptr != '\r' || *(eptr + 1) != '\n') { return -1; } len = tmp; buffer.AdvanceReadIndex(eptr - raw + 2); return 1; }
int RedisCommandFrame::EncodeToBuffer(Buffer& buf) { char ch = m_is_inline ? 1 : 0; buf.WriteByte(ch); size_t size = m_args.size(); BufferHelper::WriteFixUInt32(buf, size); ArgumentArray::iterator it = m_args.begin(); while (it != m_args.end()) { Buffer* item = *it; size_t datalen = item->ReadableBytes(); BufferHelper::WriteFixUInt32(buf, datalen); buf.Write(item, datalen); item->AdvanceReadIndex(0 - datalen); it++; } return 0; }
FrameDecodeResult<RedisCommandFrame> RedisFrameDecoder::Decode( ChannelHandlerContext& ctx, Channel* channel, Buffer& buffer) { int reqtype = -1; size_t mark_read_index = buffer.GetReadIndex(); char ch; if (buffer.ReadByte(ch)) { RedisCommandFrame* frame = NULL; NEW(frame, RedisCommandFrame); int ret = -1; if (ch == '*') { reqtype = REDIS_REQ_MULTIBULK; frame->m_is_inline = false; ret = ProcessMultibulkBuffer(ctx, buffer, frame); } else { reqtype = REDIS_REQ_INLINE; frame->m_is_inline = true; buffer.AdvanceReadIndex(-1); ret = ProcessInlineBuffer(ctx, buffer, frame); } if (ret > 0) { return FrameDecodeResult<RedisCommandFrame> (frame, StandardDestructor<RedisCommandFrame> ); } else { DELETE(frame); if (0 == ret) { buffer.SetReadIndex(mark_read_index); } return FrameDecodeResult<RedisCommandFrame> (); } } return FrameDecodeResult<RedisCommandFrame> (); }
int FastRedisCommandDecoder::ProcessMultibulkBuffer(Buffer& buffer, std::string& err) { const char *newline = NULL; int pos = 0, ok; int64_t ll; //const char* querybuf = buffer.GetRawReadBuffer(); if (m_multibulklen == 0) { m_cmd.Clear(); m_argc = 0; /* Multi bulk length cannot be read without a \r\n */ newline = strchr(buffer.GetRawReadBuffer(), '\r'); if (newline == NULL) { if (buffer.ReadableBytes() > REDIS_INLINE_MAX_SIZE) { err = "Protocol error: too big mbulk count string"; return -1; } return 0; } /* Buffer should also contain \n */ if (newline - buffer.GetRawReadBuffer() > (buffer.ReadableBytes() - 2)) return 0; /* We know for sure there is a whole line since newline != NULL, * so go ahead and find out the multi bulk length. */ ok = string2ll(buffer.GetRawReadBuffer() + 1, newline - (buffer.GetRawReadBuffer() + 1), &ll); if (!ok || ll > 1024 * 1024) { err = "Protocol error: invalid multibulk length"; return -1; } pos = (newline - buffer.GetRawReadBuffer()) + 2; if (ll <= 0) { buffer.AdvanceReadIndex(pos); return 1; } m_multibulklen = ll; m_cmd.ReserveArgs(ll); } while (m_multibulklen) { /* Read bulk length if unknown */ if (m_bulklen == -1) { newline = strchr(buffer.GetRawReadBuffer() + pos, '\r'); if (newline == NULL) { if (buffer.ReadableBytes() > REDIS_INLINE_MAX_SIZE) { err = "Protocol error: too big bulk count string"; return -1; } break; } /* Buffer should also contain \n */ if (newline - buffer.GetRawReadBuffer() > (buffer.ReadableBytes() - 2)) break; if (buffer.GetRawReadBuffer()[pos] != '$') { err = "Protocol error: expected '$', got '%c'"; //err = "Protocol error: expected '$', got '%c'", c->querybuf[pos]; return -1; } ok = string2ll(buffer.GetRawReadBuffer() + pos + 1, newline - (buffer.GetRawReadBuffer() + pos + 1), &ll); if (!ok || ll < 0 || ll > 512 * 1024 * 1024) { err = "Protocol error: invalid bulk length"; return -1; } pos += newline - (buffer.GetRawReadBuffer() + pos) + 2; m_bulklen = ll; } /* Read bulk argument */ if (buffer.ReadableBytes() - pos < (unsigned) (m_bulklen + 2)) { /* Not enough data (+2 == trailing \r\n) */ break; } else { /* Optimization: if the buffer contains JUST our bulk element * instead of creating a new object by *copying* the sds we * just use the current sds string. */ std::string* arg = m_cmd.GetMutableArgument(m_argc++); arg->assign(buffer.GetRawReadBuffer() + pos, m_bulklen); pos += m_bulklen + 2; m_bulklen = -1; m_multibulklen--; } } /* Trim to pos */ if (pos) { buffer.AdvanceReadIndex(pos); } /* We're done when c->multibulk == 0 */ if (m_multibulklen == 0) { m_cmd.Adapt(); m_argc = 0; return 1; } return 0; }
int RedisCommandDecoder::ProcessMultibulkBuffer(Channel* channel, Buffer& buffer, RedisCommandFrame& frame) { if (buffer.ReadableBytes() < 3) //at least '0\r\n' { return 0; } int multibulklen = 0; int read_len_ret = readBulkLen(buffer, multibulklen); if (read_len_ret == 0) { return 0; } else if (read_len_ret < 0) { THROW_DECODE_EX("Protocol error: expected CRLF at bulk length end"); return -1; } if (multibulklen > 512 * 1024 * 1024) { THROW_DECODE_EX("Protocol error: invalid multibulk length"); return -1; } int parsed_args = 0; while (parsed_args < multibulklen) { if (buffer.ReadableBytes() < 4) //at least '$0\r\n' { return 0; } char expected = 0; buffer.ReadByte(expected); if (expected != '$') { if (NULL != channel) { char temp[100]; sprintf(temp, "Protocol error: expected '$', , got '%c'", buffer.GetRawReadBuffer()[0]); THROW_DECODE_EX(temp); } return -1; } int arglen = 0; read_len_ret = readBulkLen(buffer, arglen); if (read_len_ret == 0) { return 0; } else if (read_len_ret < 0) { THROW_DECODE_EX("Protocol error: expected CRLF at bulk length end"); return -1; } if (arglen > 512 * 1024 * 1024) { THROW_DECODE_EX("Protocol error: invalid bulk length"); return -1; } if (buffer.ReadableBytes() < (arglen + 2)) { return 0; } if (buffer.GetRawReadBuffer()[arglen] != '\r' || buffer.GetRawReadBuffer()[arglen + 1] != '\n') { THROW_DECODE_EX("Protocol error: expected CRLF at bulk end."); return -1; } frame.FillNextArgument(buffer, arglen); buffer.AdvanceReadIndex(2); parsed_args++; } return 1; }