Use explicit buffer length field in the reply reader

This commit is contained in:
Pieter Noordhuis 2010-11-26 13:49:15 +01:00
parent adb0895e99
commit 5cf292cdd0

View File

@ -44,7 +44,8 @@ typedef struct redisReader {
void *reply; /* holds temporary reply */ void *reply; /* holds temporary reply */
sds buf; /* read buffer */ sds buf; /* read buffer */
unsigned int pos; /* buffer cursor */ size_t pos; /* buffer cursor */
size_t len; /* buffer length */
redisReadTask rstack[3]; /* stack of read tasks */ redisReadTask rstack[3]; /* stack of read tasks */
int ridx; /* index of stack */ int ridx; /* index of stack */
@ -163,20 +164,31 @@ static char *readBytes(redisReader *r, unsigned int bytes) {
return NULL; return NULL;
} }
static char *seekNewline(char *s) { /* Find pointer to \r\n. */
/* Find pointer to \r\n without strstr */ static char *seekNewline(char *s, size_t len) {
while (s != NULL) { int pos = 0;
s = strchr(s,'\r'); int _len = len-1;
if (s != NULL) {
if (s[1] == '\n') /* Position should be < len-1 because the character at "pos" should be
break; * followed by a \n. Note that strchr cannot be used because it doesn't
else * allow to search a limited length and the buffer that is being searched
s++; * might not have a trailing NULL character. */
while (pos < _len) {
while(pos < _len && s[pos] != '\r') pos++;
if (s[pos] != '\r') {
/* Not found. */
return NULL;
} else { } else {
break; if (s[pos+1] == '\n') {
/* Found. */
return s+pos;
} else {
/* Continue searching. */
pos++;
} }
} }
return s; }
return NULL;
} }
static char *readLine(redisReader *r, int *_len) { static char *readLine(redisReader *r, int *_len) {
@ -184,7 +196,7 @@ static char *readLine(redisReader *r, int *_len) {
int len; int len;
p = r->buf+r->pos; p = r->buf+r->pos;
s = seekNewline(p); s = seekNewline(p,(r->len-r->pos));
if (s != NULL) { if (s != NULL) {
len = s-(r->buf+r->pos); len = s-(r->buf+r->pos);
r->pos += len+2; /* skip \r\n */ r->pos += len+2; /* skip \r\n */
@ -253,7 +265,7 @@ static int processBulkItem(redisReader *r) {
int success = 0; int success = 0;
p = r->buf+r->pos; p = r->buf+r->pos;
s = seekNewline(p); s = seekNewline(p,r->len-r->pos);
if (s != NULL) { if (s != NULL) {
p = r->buf+r->pos; p = r->buf+r->pos;
bytelen = s-(r->buf+r->pos)+2; /* include \r\n */ bytelen = s-(r->buf+r->pos)+2; /* include \r\n */
@ -267,7 +279,7 @@ static int processBulkItem(redisReader *r) {
} else { } else {
/* Only continue when the buffer contains the entire bulk item. */ /* Only continue when the buffer contains the entire bulk item. */
bytelen += len+2; /* include \r\n */ bytelen += len+2; /* include \r\n */
if (r->pos+bytelen <= sdslen(r->buf)) { if (r->pos+bytelen <= r->len) {
obj = r->fn ? r->fn->createString(cur,s+2,len) : obj = r->fn ? r->fn->createString(cur,s+2,len) :
(void*)REDIS_REPLY_STRING; (void*)REDIS_REPLY_STRING;
success = 1; success = 1;
@ -463,8 +475,10 @@ void redisReplyReaderFeed(void *reader, char *buf, size_t len) {
redisReader *r = reader; redisReader *r = reader;
/* Copy the provided buffer. */ /* Copy the provided buffer. */
if (buf != NULL && len >= 1) if (buf != NULL && len >= 1) {
r->buf = sdscatlen(r->buf,buf,len); r->buf = sdscatlen(r->buf,buf,len);
r->len = sdslen(r->buf);
}
} }
int redisReplyReaderGetReply(void *reader, void **reply) { int redisReplyReaderGetReply(void *reader, void **reply) {
@ -472,7 +486,7 @@ int redisReplyReaderGetReply(void *reader, void **reply) {
if (reply != NULL) *reply = NULL; if (reply != NULL) *reply = NULL;
/* When the buffer is empty, there will never be a reply. */ /* When the buffer is empty, there will never be a reply. */
if (sdslen(r->buf) == 0) if (r->len == 0)
return REDIS_OK; return REDIS_OK;
/* Set first item to process when the stack is empty. */ /* Set first item to process when the stack is empty. */
@ -493,14 +507,15 @@ int redisReplyReaderGetReply(void *reader, void **reply) {
/* Discard the consumed part of the buffer. */ /* Discard the consumed part of the buffer. */
if (r->pos > 0) { if (r->pos > 0) {
if (r->pos == sdslen(r->buf)) { if (r->pos == r->len) {
/* sdsrange has a quirck on this edge case. */ /* sdsrange has a quirck on this edge case. */
sdsfree(r->buf); sdsfree(r->buf);
r->buf = sdsempty(); r->buf = sdsempty();
} else { } else {
r->buf = sdsrange(r->buf,r->pos,sdslen(r->buf)); r->buf = sdsrange(r->buf,r->pos,r->len);
} }
r->pos = 0; r->pos = 0;
r->len = sdslen(r->buf);
} }
/* Emit a reply when there is one. */ /* Emit a reply when there is one. */
@ -509,7 +524,7 @@ int redisReplyReaderGetReply(void *reader, void **reply) {
r->reply = NULL; r->reply = NULL;
/* Destroy the buffer when it is empty and is quite large. */ /* Destroy the buffer when it is empty and is quite large. */
if (sdslen(r->buf) == 0 && sdsavail(r->buf) > 16*1024) { if (r->len == 0 && sdsavail(r->buf) > 16*1024) {
sdsfree(r->buf); sdsfree(r->buf);
r->buf = sdsempty(); r->buf = sdsempty();
r->pos = 0; r->pos = 0;