mirror of
https://github.com/joyieldInc/predixy.git
synced 2025-12-24 22:46:41 +08:00
176 lines
3.5 KiB
C++
176 lines
3.5 KiB
C++
/*
|
|
* predixy - A high performance and full features proxy for redis.
|
|
* Copyright (C) 2017 Joyield, Inc. <joyield.com@gmail.com>
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#ifndef _PREDIXY_REQUEST_PARSER_H_
|
|
#define _PREDIXY_REQUEST_PARSER_H_
|
|
|
|
#include <map>
|
|
#include "Predixy.h"
|
|
|
|
class RequestParser
|
|
{
|
|
public:
|
|
static const int MaxAllowInvalidByteCount = 1024;
|
|
enum State
|
|
{
|
|
Idle, // * or inline command
|
|
InlineBegin,
|
|
InlineCmd,
|
|
InlineArgBegin,
|
|
InlineArg,
|
|
InlineArgEnd,
|
|
ArgNum, // 2
|
|
ArgNumLF, // \r\n
|
|
CmdTag,
|
|
CmdLen,
|
|
CmdLenLF,
|
|
CmdBody,
|
|
CmdBodyTooLong,
|
|
CmdBodyLF,
|
|
KeyTag,
|
|
KeyLen,
|
|
KeyLenLF,
|
|
KeyBody,
|
|
KeyBodyLF,
|
|
ArgTag,
|
|
ArgLen,
|
|
ArgLenLF,
|
|
ArgBody,
|
|
ArgBodyLF,
|
|
SArgTag,
|
|
SArgLen,
|
|
SArgLenLF,
|
|
SArgBody,
|
|
SArgBodyLF,
|
|
Finished,
|
|
|
|
Error
|
|
};
|
|
enum Status
|
|
{
|
|
Normal,
|
|
Partial,
|
|
Complete,
|
|
CmdError,
|
|
ArgError,
|
|
ParseError
|
|
};
|
|
static void init();
|
|
public:
|
|
RequestParser();
|
|
~RequestParser();
|
|
Status parse(Buffer* buf, int& pos, bool split);
|
|
void reset();
|
|
template<int Size>
|
|
static bool decodeInlineArg(SString<Size>& dst, const String& src);
|
|
bool isIdle() const
|
|
{
|
|
return mState == Idle;
|
|
}
|
|
Command::Type type() const
|
|
{
|
|
return mType;
|
|
}
|
|
const Command* command() const
|
|
{
|
|
return mCommand;
|
|
}
|
|
bool isInline() const
|
|
{
|
|
return mInline;
|
|
}
|
|
Segment& request()
|
|
{
|
|
return mReq;
|
|
}
|
|
const Segment& request() const
|
|
{
|
|
return mReq;
|
|
}
|
|
int argNum() const
|
|
{
|
|
return mArgNum;
|
|
}
|
|
const char* cmd() const
|
|
{
|
|
return mCmd;
|
|
}
|
|
Segment& key()
|
|
{
|
|
return mKey;
|
|
}
|
|
const Segment& key() const
|
|
{
|
|
return mKey;
|
|
}
|
|
private:
|
|
void parseCmd();
|
|
bool isKey(bool split) const;
|
|
bool isSplit(bool split) const;
|
|
private:
|
|
Command::Type mType;
|
|
const Command* mCommand;
|
|
Segment mReq;
|
|
Segment mKey;
|
|
char mCmd[Const::MaxCmdLen];
|
|
Status mStatus;
|
|
State mState;
|
|
bool mInline;
|
|
bool mEscape;
|
|
char mQuote;
|
|
int mArgNum;
|
|
int mArgCnt;
|
|
int mArgLen;
|
|
int mArgBodyCnt;
|
|
int mByteCnt;
|
|
};
|
|
|
|
template<int Size>
|
|
bool RequestParser::decodeInlineArg(SString<Size>& dst, const String& src)
|
|
{
|
|
bool ret = true;
|
|
bool escape = false;
|
|
char quote = '\0';
|
|
const char* p = src.data();
|
|
for (int i = 0; i < src.length(); ++i, ++p) {
|
|
char c = *p;
|
|
if (escape) {
|
|
if (quote == '"') {
|
|
switch (c) {
|
|
case 'n': c = '\n'; break;
|
|
case 'r': c = '\r'; break;
|
|
case 't': c = '\t'; break;
|
|
case 'b': c = '\b'; break;
|
|
case 'a': c = '\a'; break;
|
|
default: break;
|
|
}
|
|
} else {
|
|
if (!dst.append('\\')) {
|
|
ret = false;
|
|
}
|
|
}
|
|
escape = false;
|
|
} else if (quote) {
|
|
if (c == '\\') {
|
|
escape = true;
|
|
continue;
|
|
} else if (c == quote) {
|
|
quote = '\0';
|
|
continue;
|
|
}
|
|
} else if (c == '"' || c == '\'') {
|
|
quote = c;
|
|
continue;
|
|
}
|
|
if (!dst.append(c)) {
|
|
ret = false;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#endif
|