summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Grunder <michael.grunder@gmail.com>2020-05-19 12:56:02 -0700
committerGitHub <noreply@github.com>2020-05-19 12:56:02 -0700
commit5c9f49e2123c5df7148939a70b80cd72e4e59646 (patch)
tree7b91fb91c8f32870028ad564f0503e68921e2e8e
parent243099ccd24b3a02aa3685abcfac77306a3b7d67 (diff)
Resp3 verbatim string support (#805)
Pull RESP3 verbatim string handling from Redis Fixes #802
-rw-r--r--hiredis.c34
-rw-r--r--hiredis.h4
-rw-r--r--read.c14
-rw-r--r--read.h2
-rw-r--r--test.c11
5 files changed, 52 insertions, 13 deletions
diff --git a/hiredis.c b/hiredis.c
index 8e438f2..deb65a9 100644
--- a/hiredis.c
+++ b/hiredis.c
@@ -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;
}
@@ -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;
diff --git a/hiredis.h b/hiredis.h
index 6733199..9282671 100644
--- a/hiredis.h
+++ b/hiredis.h
@@ -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;
diff --git a/read.c b/read.c
index f6dfef0..835eb65 100644
--- a/read.c
+++ b/read.c
@@ -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;
}
}
@@ -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;
@@ -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:
diff --git a/read.h b/read.h
index 6eff14c..788c401 100644
--- a/read.h
+++ b/read.h
@@ -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. */
diff --git a/test.c b/test.c
index d8b9555..8e45e78 100644
--- a/test.c
+++ b/test.c
@@ -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) {