Skip to content

Commit

Permalink
Resp3 verbatim string support (#805)
Browse files Browse the repository at this point in the history
Pull RESP3 verbatim string handling from Redis

Fixes #802
  • Loading branch information
michael-grunder authored May 19, 2020
1 parent 243099c commit 5c9f49e
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 13 deletions.
34 changes: 24 additions & 10 deletions hiredis.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ void freeReplyObject(void *reply) {
case REDIS_REPLY_STATUS:
case REDIS_REPLY_STRING:
case REDIS_REPLY_DOUBLE:
case REDIS_REPLY_VERB:
free(r->str);
break;
}
Expand All @@ -121,21 +122,34 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len
if (r == NULL)
return NULL;

buf = malloc(len+1);
if (buf == NULL) {
freeReplyObject(r);
return NULL;
}

assert(task->type == REDIS_REPLY_ERROR ||
task->type == REDIS_REPLY_STATUS ||
task->type == REDIS_REPLY_STRING);
task->type == REDIS_REPLY_STRING ||
task->type == REDIS_REPLY_VERB);

/* Copy string value */
memcpy(buf,str,len);
buf[len] = '\0';
if (task->type == REDIS_REPLY_VERB) {
buf = malloc(len-4+1); /* Skip 4 bytes of verbatim type header. */
if (buf == NULL) {
freeReplyObject(r);
return NULL;
}
memcpy(r->vtype,str,3);
r->vtype[3] = '\0';
memcpy(buf,str+4,len-4);
buf[len-4] = '\0';
r->len = len - 4;
} else {
buf = malloc(len+1);
if (buf == NULL) {
freeReplyObject(r);
return NULL;
}
memcpy(buf,str,len);
buf[len] = '\0';
r->len = len;
}
r->str = buf;
r->len = len;

if (task->parent) {
parent = task->parent->obj;
Expand Down
4 changes: 3 additions & 1 deletion hiredis.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ typedef struct redisReply {
double dval; /* The double when type is REDIS_REPLY_DOUBLE */
size_t len; /* Length of string */
char *str; /* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING
and REDIS_REPLY_DOUBLE (in additional to dval). */
REDIS_REPLY_VERB, and REDIS_REPLY_DOUBLE (in additional to dval). */
char vtype[4]; /* Used for REDIS_REPLY_VERB, contains the null
terminated 3 character content type, such as "txt". */
size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */
struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
} redisReply;
Expand Down
14 changes: 13 additions & 1 deletion read.c
Original file line number Diff line number Diff line change
Expand Up @@ -383,10 +383,18 @@ static int processBulkItem(redisReader *r) {
/* Only continue when the buffer contains the entire bulk item. */
bytelen += len+2; /* include \r\n */
if (r->pos+bytelen <= r->len) {
if ((cur->type == REDIS_REPLY_VERB && len < 4) ||
(cur->type == REDIS_REPLY_VERB && s[5] != ':'))
{
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
"Verbatim string 4 bytes of content type are "
"missing or incorrectly encoded.");
return REDIS_ERR;
}
if (r->fn && r->fn->createString)
obj = r->fn->createString(cur,s+2,len);
else
obj = (void*)REDIS_REPLY_STRING;
obj = (void*)(long)cur->type;
success = 1;
}
}
Expand Down Expand Up @@ -551,6 +559,9 @@ static int processItem(redisReader *r) {
case '#':
cur->type = REDIS_REPLY_BOOL;
break;
case '=':
cur->type = REDIS_REPLY_VERB;
break;
default:
__redisReaderSetErrorProtocolByte(r,*p);
return REDIS_ERR;
Expand All @@ -571,6 +582,7 @@ static int processItem(redisReader *r) {
case REDIS_REPLY_BOOL:
return processLineItem(r);
case REDIS_REPLY_STRING:
case REDIS_REPLY_VERB:
return processBulkItem(r);
case REDIS_REPLY_ARRAY:
case REDIS_REPLY_MAP:
Expand Down
2 changes: 1 addition & 1 deletion read.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@
#define REDIS_REPLY_ERROR 6
#define REDIS_REPLY_DOUBLE 7
#define REDIS_REPLY_BOOL 8
#define REDIS_REPLY_VERB 9
#define REDIS_REPLY_MAP 9
#define REDIS_REPLY_SET 10
#define REDIS_REPLY_ATTR 11
#define REDIS_REPLY_PUSH 12
#define REDIS_REPLY_BIGNUM 13
#define REDIS_REPLY_VERB 14

#define REDIS_READER_MAX_BUF (1024*16) /* Default max unused reader buffer. */

Expand Down
11 changes: 11 additions & 0 deletions test.c
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,17 @@ static void test_reply_reader(void) {
((redisReply*)reply)->elements == 0);
freeReplyObject(reply);
redisReaderFree(reader);

/* RESP3 verbatim strings (GitHub issue #802) */
test("Can parse RESP3 verbatim strings: ");
reader = redisReaderCreate();
redisReaderFeed(reader,(char*)"=10\r\ntxt:LOLWUT\r\n",17);
ret = redisReaderGetReply(reader,&reply);
test_cond(ret == REDIS_OK &&
((redisReply*)reply)->type == REDIS_REPLY_VERB &&
!memcmp(((redisReply*)reply)->str,"LOLWUT", 6));
freeReplyObject(reply);
redisReaderFree(reader);
}

static void test_free_null(void) {
Expand Down

0 comments on commit 5c9f49e

Please sign in to comment.