From 3bb818df405e667087fe3336cd91159790f63981 Mon Sep 17 00:00:00 2001 From: antirez Date: Tue, 24 May 2011 19:43:11 +0200 Subject: [PATCH 1/1] Make sure error and status replies emitted by Lua scripts can never have more than a newline, otherwise it is a protocol violation and clients will desync. --- src/networking.c | 7 +++++++ src/scripting.c | 12 ++++++++---- src/sds.c | 23 +++++++++++++++++++++++ src/sds.h | 1 + 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/networking.c b/src/networking.c index 976b472a..e88e27d1 100644 --- a/src/networking.c +++ b/src/networking.c @@ -246,10 +246,17 @@ void addReplyError(redisClient *c, char *err) { } void addReplyErrorFormat(redisClient *c, const char *fmt, ...) { + size_t l, j; va_list ap; va_start(ap,fmt); sds s = sdscatvprintf(sdsempty(),fmt,ap); va_end(ap); + /* Make sure there are no newlines in the string, otherwise invalid protocol + * is emitted. */ + l = sdslen(s); + for (j = 0; j < l; j++) { + if (s[j] == '\r' || s[j] == '\n') s[j] = ' '; + } _addReplyError(c,s,sdslen(s)); sdsfree(s); } diff --git a/src/scripting.c b/src/scripting.c index be6247a9..469d7870 100644 --- a/src/scripting.c +++ b/src/scripting.c @@ -332,8 +332,10 @@ void luaReplyToRedisReply(redisClient *c, lua_State *lua) { lua_gettable(lua,-2); t = lua_type(lua,-1); if (t == LUA_TSTRING) { - addReplySds(c,sdscatprintf(sdsempty(), - "-%s\r\n",(char*)lua_tostring(lua,-1))); + sds err = sdsnew(lua_tostring(lua,-1)); + sdsmapchars(err,"\r\n"," ",2); + addReplySds(c,sdscatprintf(sdsempty(),"-%s\r\n",err)); + sdsfree(err); lua_pop(lua,2); return; } @@ -343,8 +345,10 @@ void luaReplyToRedisReply(redisClient *c, lua_State *lua) { lua_gettable(lua,-2); t = lua_type(lua,-1); if (t == LUA_TSTRING) { - addReplySds(c,sdscatprintf(sdsempty(), - "+%s\r\n",(char*)lua_tostring(lua,-1))); + sds ok = sdsnew(lua_tostring(lua,-1)); + sdsmapchars(ok,"\r\n"," ",2); + addReplySds(c,sdscatprintf(sdsempty(),"+%s\r\n",ok)); + sdsfree(ok); lua_pop(lua,1); } else { void *replylen = addDeferredMultiBulkLength(c); diff --git a/src/sds.c b/src/sds.c index 63507000..2ec7c3cb 100644 --- a/src/sds.c +++ b/src/sds.c @@ -553,6 +553,29 @@ void sdssplitargs_free(sds *argv, int argc) { zfree(argv); } +/* Modify the string substituting all the occurrences of the set of + * characters specifed in the 'from' string to the corresponding character + * in the 'to' array. + * + * For instance: sdsmapchars(mystring, "ho", "01", 2) + * will have the effect of turning the string "hello" into "0ell1". + * + * The function returns the sds string pointer, that is always the same + * as the input pointer since no resize is needed. */ +sds sdsmapchars(sds s, char *from, char *to, size_t setlen) { + size_t j, i, l = sdslen(s); + + for (j = 0; j < l; j++) { + for (i = 0; i < setlen; i++) { + if (s[j] == from[i]) { + s[j] = to[i]; + break; + } + } + } + return s; +} + #ifdef SDS_TEST_MAIN #include #include "testhelp.h" diff --git a/src/sds.h b/src/sds.h index ea43f868..af5c4910 100644 --- a/src/sds.h +++ b/src/sds.h @@ -85,5 +85,6 @@ sds sdsfromlonglong(long long value); sds sdscatrepr(sds s, char *p, size_t len); sds *sdssplitargs(char *line, int *argc); void sdssplitargs_free(sds *argv, int argc); +sds sdsmapchars(sds s, char *from, char *to, size_t setlen); #endif -- 2.45.2