summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hiredis.c4
-rw-r--r--hiredis.h3
-rw-r--r--read.c20
-rw-r--r--test.c11
4 files changed, 36 insertions, 2 deletions
diff --git a/hiredis.c b/hiredis.c
index 5591cb9..2c1fb82 100644
--- a/hiredis.c
+++ b/hiredis.c
@@ -114,6 +114,7 @@ void freeReplyObject(void *reply) {
case REDIS_REPLY_STRING:
case REDIS_REPLY_DOUBLE:
case REDIS_REPLY_VERB:
+ case REDIS_REPLY_BIGNUM:
hi_free(r->str);
break;
}
@@ -131,7 +132,8 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len
assert(task->type == REDIS_REPLY_ERROR ||
task->type == REDIS_REPLY_STATUS ||
task->type == REDIS_REPLY_STRING ||
- task->type == REDIS_REPLY_VERB);
+ task->type == REDIS_REPLY_VERB ||
+ task->type == REDIS_REPLY_BIGNUM);
/* Copy string value */
if (task->type == REDIS_REPLY_VERB) {
diff --git a/hiredis.h b/hiredis.h
index a629930..e77a88a 100644
--- a/hiredis.h
+++ b/hiredis.h
@@ -112,7 +112,8 @@ 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
- REDIS_REPLY_VERB, and REDIS_REPLY_DOUBLE (in additional to dval). */
+ REDIS_REPLY_VERB, REDIS_REPLY_DOUBLE (in additional to dval),
+ and REDIS_REPLY_BIGNUM. */
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 */
diff --git a/read.c b/read.c
index 89b5b5a..5e0e0b4 100644
--- a/read.c
+++ b/read.c
@@ -337,6 +337,22 @@ static int processLineItem(redisReader *r) {
obj = r->fn->createBool(cur,bval);
else
obj = (void*)REDIS_REPLY_BOOL;
+ } else if (cur->type == REDIS_REPLY_BIGNUM) {
+ /* Ensure all characters are decimal digits (with possible leading
+ * minus sign). */
+ for (int i = 0; i < len; i++) {
+ /* XXX Consider: Allow leading '+'? Error on leading '0's? */
+ if (i == 0 && p[0] == '-') continue;
+ if (p[i] < '0' || p[i] > '9') {
+ __redisReaderSetError(r,REDIS_ERR_PROTOCOL,
+ "Bad bignum value");
+ return REDIS_ERR;
+ }
+ }
+ if (r->fn && r->fn->createString)
+ obj = r->fn->createString(cur,p,len);
+ else
+ obj = (void*)REDIS_REPLY_BIGNUM;
} else {
/* Type will be error or status. */
for (int i = 0; i < len; i++) {
@@ -587,6 +603,9 @@ static int processItem(redisReader *r) {
case '>':
cur->type = REDIS_REPLY_PUSH;
break;
+ case '(':
+ cur->type = REDIS_REPLY_BIGNUM;
+ break;
default:
__redisReaderSetErrorProtocolByte(r,*p);
return REDIS_ERR;
@@ -605,6 +624,7 @@ static int processItem(redisReader *r) {
case REDIS_REPLY_DOUBLE:
case REDIS_REPLY_NIL:
case REDIS_REPLY_BOOL:
+ case REDIS_REPLY_BIGNUM:
return processLineItem(r);
case REDIS_REPLY_STRING:
case REDIS_REPLY_VERB:
diff --git a/test.c b/test.c
index fa861b3..f830695 100644
--- a/test.c
+++ b/test.c
@@ -714,6 +714,17 @@ static void test_reply_reader(void) {
((redisReply*)reply)->element[4]->integer == 999);
freeReplyObject(reply);
redisReaderFree(reader);
+
+ test("Can parse RESP3 bignum: ");
+ reader = redisReaderCreate();
+ redisReaderFeed(reader,"(3492890328409238509324850943850943825024385\r\n",46);
+ ret = redisReaderGetReply(reader,&reply);
+ test_cond(ret == REDIS_OK &&
+ ((redisReply*)reply)->type == REDIS_REPLY_BIGNUM &&
+ ((redisReply*)reply)->len == 43 &&
+ !strcmp(((redisReply*)reply)->str,"3492890328409238509324850943850943825024385"));
+ freeReplyObject(reply);
+ redisReaderFree(reader);
}
static void test_free_null(void) {