supports inline command protocol for command:PING/ECHO/AUTH/SELECT

This commit is contained in:
fortrue 2017-09-08 11:13:54 +08:00
parent 1569b57bd7
commit 345ff2c20f
5 changed files with 146 additions and 13 deletions

View File

@ -527,7 +527,13 @@ bool Handler::preHandleRequest(Request* req, const String& key)
directResponse(req, Response::Pong); directResponse(req, Response::Pong);
} else { } else {
ResponsePtr res = ResponseAlloc::create(); ResponsePtr res = ResponseAlloc::create();
if (req->isInline()) {
SString<Const::MaxKeyLen> k;
RequestParser::decodeInlineArg(k, key);
res->setStr(k.data(), k.length());
} else {
res->setStr(key.data(), key.length()); res->setStr(key.data(), key.length());
}
handleResponse(nullptr, req, res); handleResponse(nullptr, req, res);
} }
return true; return true;
@ -1400,10 +1406,14 @@ bool Handler::permission(Request* req, const String& key, Response::GenericCode&
return true; return true;
} }
if (req->type() == Command::Auth) { if (req->type() == Command::Auth) {
SString<Const::MaxKeyLen> pw;
if (req->isInline()) {
RequestParser::decodeInlineArg(pw, key);
}
auto m = mProxy->authority(); auto m = mProxy->authority();
if (!m->hasAuth()) { if (!m->hasAuth()) {
code = Response::NoPasswordSet; code = Response::NoPasswordSet;
} else if (auto auth = m->get(key)) { } else if (auto auth = m->get(req->isInline() ? pw : key)) {
c->setAuth(auth); c->setAuth(auth);
code = Response::Ok; code = Response::Ok;
} else { } else {

View File

@ -57,6 +57,7 @@ Request::Request():
mType(Command::None), mType(Command::None),
mDone(false), mDone(false),
mDelivered(false), mDelivered(false),
mInline(false),
mFollowers(0), mFollowers(0),
mFollowersDone(0), mFollowersDone(0),
mRedirectCnt(0), mRedirectCnt(0),
@ -70,6 +71,7 @@ Request::Request(AcceptConnection* c):
mType(Command::None), mType(Command::None),
mDone(false), mDone(false),
mDelivered(false), mDelivered(false),
mInline(false),
mFollowers(0), mFollowers(0),
mFollowersDone(0), mFollowersDone(0),
mRedirectCnt(0), mRedirectCnt(0),
@ -82,6 +84,7 @@ Request::Request(GenericCode code):
mConn(nullptr), mConn(nullptr),
mDone(false), mDone(false),
mDelivered(false), mDelivered(false),
mInline(false),
mFollowers(0), mFollowers(0),
mFollowersDone(0), mFollowersDone(0),
mRedirectCnt(0), mRedirectCnt(0),
@ -164,6 +167,7 @@ void Request::set(const RequestParser& p, Request* leader)
mReq = p.request(); mReq = p.request();
} }
mKey = p.key(); mKey = p.key();
mInline = p.isInline();
} }
void Request::setAuth(const String& password) void Request::setAuth(const String& password)

View File

@ -129,6 +129,10 @@ public:
{ {
return mDelivered; return mDelivered;
} }
bool isInline() const
{
return mInline;
}
void setDelivered() void setDelivered()
{ {
mDelivered = true; mDelivered = true;
@ -163,6 +167,7 @@ private:
ResponsePtr mRes; ResponsePtr mRes;
bool mDone; bool mDone;
bool mDelivered; bool mDelivered;
bool mInline;
Segment mHead; //for multi key command mget/mset/del... Segment mHead; //for multi key command mget/mset/del...
Segment mReq; Segment mReq;
Segment mKey; Segment mKey;

View File

@ -25,6 +25,8 @@ void RequestParser::reset()
mStatus = Normal; mStatus = Normal;
mState = Idle; mState = Idle;
mInline = false; mInline = false;
mEscape = false;
mQuote = '\0';
mArgNum = 0; mArgNum = 0;
mArgCnt = 0; mArgCnt = 0;
mArgLen = 0; mArgLen = 0;
@ -92,9 +94,11 @@ RequestParser::Status RequestParser::parse(Buffer* buf, int& pos, bool split)
mState = InlineBegin; mState = InlineBegin;
mInline = true; mInline = true;
} }
/* NO break */
case InlineBegin: case InlineBegin:
if (ch == '\r') { if (ch == '\n') {
error = __LINE__; mState = Idle;
//error = __LINE__;
} else if (!isspace(ch)) { } else if (!isspace(ch)) {
mReq.begin().buf = buf; mReq.begin().buf = buf;
mReq.begin().pos = pos; mReq.begin().pos = pos;
@ -107,7 +111,13 @@ RequestParser::Status RequestParser::parse(Buffer* buf, int& pos, bool split)
if (isspace(ch)) { if (isspace(ch)) {
mCmd[mArgLen < Const::MaxCmdLen ? mArgLen : Const::MaxCmdLen - 1] = '\0'; mCmd[mArgLen < Const::MaxCmdLen ? mArgLen : Const::MaxCmdLen - 1] = '\0';
parseCmd(); parseCmd();
mState = ch == '\r' ? InlineLF : InlineArg; mArgCnt = 1;
if (ch == '\n') {
mArgNum = 1;
mState = Finished;
goto Done;
}
mState = InlineArgBegin;
} else { } else {
if (mArgLen < Const::MaxCmdLen) { if (mArgLen < Const::MaxCmdLen) {
mCmd[mArgLen] = tolower(ch); mCmd[mArgLen] = tolower(ch);
@ -115,15 +125,64 @@ RequestParser::Status RequestParser::parse(Buffer* buf, int& pos, bool split)
++mArgLen; ++mArgLen;
} }
break; break;
case InlineArg: case InlineArgBegin:
if (ch == '\r') {
mState = InlineLF;
}
break;
case InlineLF:
if (ch == '\n') { if (ch == '\n') {
mArgNum = mArgCnt;
mState = Finished; mState = Finished;
goto Done; goto Done;
} else if (isspace(ch)) {
break;
}
if (mArgCnt == 1) {
mKey.begin().buf = buf;
mKey.begin().pos = pos;
}
mState = InlineArg;
/* NO break */
case InlineArg:
if (mEscape) {
mEscape = false;
} else if (mQuote) {
if (ch == mQuote) {
mState = InlineArgEnd;
} else if (ch == '\\') {
mEscape = true;
} else if (ch == '\n') {
error = __LINE__;
}
} else {
if (isspace(ch)) {
if (mArgCnt == 1) {
mKey.end().buf = buf;
mKey.end().pos = pos;
}
++mArgCnt;
if (ch == '\n') {
mArgNum = mArgCnt;
mState = Finished;
goto Done;
} else {
mState = InlineArgBegin;
}
} else if (ch == '\'' || ch == '"') {
mQuote = ch;
}
}
break;
case InlineArgEnd:
if (isspace(ch)) {
if (mArgCnt == 1) {
mKey.end().buf = buf;
mKey.end().pos = pos;
}
++mArgCnt;
if (ch == '\n') {
mArgNum = mArgCnt;
mState = Finished;
goto Done;
} else {
mState = InlineArgBegin;
}
} else { } else {
error = __LINE__; error = __LINE__;
} }
@ -405,7 +464,13 @@ void RequestParser::parseCmd()
mType = c->type; mType = c->type;
mCommand = c; mCommand = c;
if (mInline) { if (mInline) {
if (mType != Command::Ping) { switch (mType) {
case Command::Ping:
case Command::Echo:
case Command::Auth:
case Command::Select:
break;
default:
mStatus = CmdError; mStatus = CmdError;
logNotice("unsupport command %s in inline command protocol", c->name); logNotice("unsupport command %s in inline command protocol", c->name);
return; return;

View File

@ -19,8 +19,9 @@ public:
Idle, // * or inline command Idle, // * or inline command
InlineBegin, InlineBegin,
InlineCmd, InlineCmd,
InlineLF, InlineArgBegin,
InlineArg, InlineArg,
InlineArgEnd,
ArgNum, // 2 ArgNum, // 2
ArgNumLF, // \r\n ArgNumLF, // \r\n
CmdTag, CmdTag,
@ -63,6 +64,8 @@ public:
~RequestParser(); ~RequestParser();
Status parse(Buffer* buf, int& pos, bool split); Status parse(Buffer* buf, int& pos, bool split);
void reset(); void reset();
template<int Size>
static bool decodeInlineArg(SString<Size>& dst, const String& src);
bool isIdle() const bool isIdle() const
{ {
return mState == Idle; return mState == Idle;
@ -116,6 +119,8 @@ private:
Status mStatus; Status mStatus;
State mState; State mState;
bool mInline; bool mInline;
bool mEscape;
char mQuote;
int mArgNum; int mArgNum;
int mArgCnt; int mArgCnt;
int mArgLen; int mArgLen;
@ -123,4 +128,48 @@ private:
int mByteCnt; 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 #endif