summaryrefslogtreecommitdiff
path: root/examples/redis-unstable/src/call_reply.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/redis-unstable/src/call_reply.c')
-rw-r--r--examples/redis-unstable/src/call_reply.c540
1 files changed, 0 insertions, 540 deletions
diff --git a/examples/redis-unstable/src/call_reply.c b/examples/redis-unstable/src/call_reply.c
deleted file mode 100644
index 2a4f710..0000000
--- a/examples/redis-unstable/src/call_reply.c
+++ /dev/null
@@ -1,540 +0,0 @@
-/*
- * Copyright (c) 2009-Present, Redis Ltd.
- * All rights reserved.
- *
- * Licensed under your choice of (a) the Redis Source Available License 2.0
- * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the
- * GNU Affero General Public License v3 (AGPLv3).
- */
-
-#include "server.h"
-#include "call_reply.h"
-
-#define REPLY_FLAG_ROOT (1<<0)
-#define REPLY_FLAG_PARSED (1<<1)
-#define REPLY_FLAG_RESP3 (1<<2)
-
-/* --------------------------------------------------------
- * An opaque struct used to parse a RESP protocol reply and
- * represent it. Used when parsing replies such as in RM_Call
- * or Lua scripts.
- * -------------------------------------------------------- */
-struct CallReply {
- void *private_data;
- sds original_proto; /* Available only for root reply. */
- const char *proto;
- size_t proto_len;
- int type; /* REPLY_... */
- int flags; /* REPLY_FLAG... */
- size_t len; /* Length of a string, or the number elements in an array. */
- union {
- const char *str; /* String pointer for string and error replies. This
- * does not need to be freed, always points inside
- * a reply->proto buffer of the reply object or, in
- * case of array elements, of parent reply objects. */
- struct {
- const char *str;
- const char *format;
- } verbatim_str; /* Reply value for verbatim string */
- long long ll; /* Reply value for integer reply. */
- double d; /* Reply value for double reply. */
- struct CallReply *array; /* Array of sub-reply elements. used for set, array, map, and attribute */
- } val;
- list *deferred_error_list; /* list of errors in sds form or NULL */
- struct CallReply *attribute; /* attribute reply, NULL if not exists */
-};
-
-static void callReplySetSharedData(CallReply *rep, int type, const char *proto, size_t proto_len, int extra_flags) {
- rep->type = type;
- rep->proto = proto;
- rep->proto_len = proto_len;
- rep->flags |= extra_flags;
-}
-
-static void callReplyNull(void *ctx, const char *proto, size_t proto_len) {
- CallReply *rep = ctx;
- callReplySetSharedData(rep, REDISMODULE_REPLY_NULL, proto, proto_len, REPLY_FLAG_RESP3);
-}
-
-static void callReplyNullBulkString(void *ctx, const char *proto, size_t proto_len) {
- CallReply *rep = ctx;
- callReplySetSharedData(rep, REDISMODULE_REPLY_NULL, proto, proto_len, 0);
-}
-
-static void callReplyNullArray(void *ctx, const char *proto, size_t proto_len) {
- CallReply *rep = ctx;
- callReplySetSharedData(rep, REDISMODULE_REPLY_NULL, proto, proto_len, 0);
-}
-
-static void callReplyBulkString(void *ctx, const char *str, size_t len, const char *proto, size_t proto_len) {
- CallReply *rep = ctx;
- callReplySetSharedData(rep, REDISMODULE_REPLY_STRING, proto, proto_len, 0);
- rep->len = len;
- rep->val.str = str;
-}
-
-static void callReplyError(void *ctx, const char *str, size_t len, const char *proto, size_t proto_len) {
- CallReply *rep = ctx;
- callReplySetSharedData(rep, REDISMODULE_REPLY_ERROR, proto, proto_len, 0);
- rep->len = len;
- rep->val.str = str;
-}
-
-static void callReplySimpleStr(void *ctx, const char *str, size_t len, const char *proto, size_t proto_len) {
- CallReply *rep = ctx;
- callReplySetSharedData(rep, REDISMODULE_REPLY_STRING, proto, proto_len, 0);
- rep->len = len;
- rep->val.str = str;
-}
-
-static void callReplyLong(void *ctx, long long val, const char *proto, size_t proto_len) {
- CallReply *rep = ctx;
- callReplySetSharedData(rep, REDISMODULE_REPLY_INTEGER, proto, proto_len, 0);
- rep->val.ll = val;
-}
-
-static void callReplyDouble(void *ctx, double val, const char *proto, size_t proto_len) {
- CallReply *rep = ctx;
- callReplySetSharedData(rep, REDISMODULE_REPLY_DOUBLE, proto, proto_len, REPLY_FLAG_RESP3);
- rep->val.d = val;
-}
-
-static void callReplyVerbatimString(void *ctx, const char *format, const char *str, size_t len, const char *proto, size_t proto_len) {
- CallReply *rep = ctx;
- callReplySetSharedData(rep, REDISMODULE_REPLY_VERBATIM_STRING, proto, proto_len, REPLY_FLAG_RESP3);
- rep->len = len;
- rep->val.verbatim_str.str = str;
- rep->val.verbatim_str.format = format;
-}
-
-static void callReplyBigNumber(void *ctx, const char *str, size_t len, const char *proto, size_t proto_len) {
- CallReply *rep = ctx;
- callReplySetSharedData(rep, REDISMODULE_REPLY_BIG_NUMBER, proto, proto_len, REPLY_FLAG_RESP3);
- rep->len = len;
- rep->val.str = str;
-}
-
-static void callReplyBool(void *ctx, int val, const char *proto, size_t proto_len) {
- CallReply *rep = ctx;
- callReplySetSharedData(rep, REDISMODULE_REPLY_BOOL, proto, proto_len, REPLY_FLAG_RESP3);
- rep->val.ll = val;
-}
-
-static void callReplyParseCollection(ReplyParser *parser, CallReply *rep, size_t len, const char *proto, size_t elements_per_entry) {
- rep->len = len;
- rep->val.array = zcalloc(elements_per_entry * len * sizeof(CallReply));
- for (size_t i = 0; i < len * elements_per_entry; i += elements_per_entry) {
- for (size_t j = 0 ; j < elements_per_entry ; ++j) {
- rep->val.array[i + j].private_data = rep->private_data;
- parseReply(parser, rep->val.array + i + j);
- rep->val.array[i + j].flags |= REPLY_FLAG_PARSED;
- if (rep->val.array[i + j].flags & REPLY_FLAG_RESP3) {
- /* If one of the sub-replies is RESP3, then the current reply is also RESP3. */
- rep->flags |= REPLY_FLAG_RESP3;
- }
- }
- }
- rep->proto = proto;
- rep->proto_len = parser->curr_location - proto;
-}
-
-static void callReplyAttribute(ReplyParser *parser, void *ctx, size_t len, const char *proto) {
- CallReply *rep = ctx;
- rep->attribute = zcalloc(sizeof(CallReply));
-
- /* Continue parsing the attribute reply */
- rep->attribute->len = len;
- rep->attribute->type = REDISMODULE_REPLY_ATTRIBUTE;
- callReplyParseCollection(parser, rep->attribute, len, proto, 2);
- rep->attribute->flags |= REPLY_FLAG_PARSED | REPLY_FLAG_RESP3;
- rep->attribute->private_data = rep->private_data;
-
- /* Continue parsing the reply */
- parseReply(parser, rep);
-
- /* In this case we need to fix the proto address and len, it should start from the attribute */
- rep->proto = proto;
- rep->proto_len = parser->curr_location - proto;
- rep->flags |= REPLY_FLAG_RESP3;
-}
-
-static void callReplyArray(ReplyParser *parser, void *ctx, size_t len, const char *proto) {
- CallReply *rep = ctx;
- rep->type = REDISMODULE_REPLY_ARRAY;
- callReplyParseCollection(parser, rep, len, proto, 1);
-}
-
-static void callReplySet(ReplyParser *parser, void *ctx, size_t len, const char *proto) {
- CallReply *rep = ctx;
- rep->type = REDISMODULE_REPLY_SET;
- callReplyParseCollection(parser, rep, len, proto, 1);
- rep->flags |= REPLY_FLAG_RESP3;
-}
-
-static void callReplyMap(ReplyParser *parser, void *ctx, size_t len, const char *proto) {
- CallReply *rep = ctx;
- rep->type = REDISMODULE_REPLY_MAP;
- callReplyParseCollection(parser, rep, len, proto, 2);
- rep->flags |= REPLY_FLAG_RESP3;
-}
-
-static void callReplyParseError(void *ctx) {
- CallReply *rep = ctx;
- rep->type = REDISMODULE_REPLY_UNKNOWN;
-}
-
-/* Recursively free the current call reply and its sub-replies. */
-static void freeCallReplyInternal(CallReply *rep) {
- if (rep->type == REDISMODULE_REPLY_ARRAY || rep->type == REDISMODULE_REPLY_SET) {
- for (size_t i = 0 ; i < rep->len ; ++i) {
- freeCallReplyInternal(rep->val.array + i);
- }
- zfree(rep->val.array);
- }
-
- if (rep->type == REDISMODULE_REPLY_MAP || rep->type == REDISMODULE_REPLY_ATTRIBUTE) {
- for (size_t i = 0 ; i < rep->len ; ++i) {
- freeCallReplyInternal(rep->val.array + i * 2);
- freeCallReplyInternal(rep->val.array + i * 2 + 1);
- }
- zfree(rep->val.array);
- }
-
- if (rep->attribute) {
- freeCallReplyInternal(rep->attribute);
- zfree(rep->attribute);
- }
-}
-
-/* Free the given call reply and its children (in case of nested reply) recursively.
- * If private data was set when the CallReply was created it will not be freed, as it's
- * the caller's responsibility to free it before calling freeCallReply(). */
-void freeCallReply(CallReply *rep) {
- if (!(rep->flags & REPLY_FLAG_ROOT)) {
- return;
- }
- if (rep->flags & REPLY_FLAG_PARSED) {
- if (rep->type == REDISMODULE_REPLY_PROMISE) {
- zfree(rep);
- return;
- }
- freeCallReplyInternal(rep);
- }
- sdsfree(rep->original_proto);
- if (rep->deferred_error_list)
- listRelease(rep->deferred_error_list);
- zfree(rep);
-}
-
-CallReply *callReplyCreatePromise(void *private_data) {
- CallReply *res = zmalloc(sizeof(*res));
- res->type = REDISMODULE_REPLY_PROMISE;
- /* Mark the reply as parsed so there will be not attempt to parse
- * it when calling reply API such as freeCallReply.
- * Also mark the reply as root so freeCallReply will not ignore it. */
- res->flags |= REPLY_FLAG_PARSED | REPLY_FLAG_ROOT;
- res->private_data = private_data;
- return res;
-}
-
-static const ReplyParserCallbacks DefaultParserCallbacks = {
- .null_callback = callReplyNull,
- .bulk_string_callback = callReplyBulkString,
- .null_bulk_string_callback = callReplyNullBulkString,
- .null_array_callback = callReplyNullArray,
- .error_callback = callReplyError,
- .simple_str_callback = callReplySimpleStr,
- .long_callback = callReplyLong,
- .array_callback = callReplyArray,
- .set_callback = callReplySet,
- .map_callback = callReplyMap,
- .double_callback = callReplyDouble,
- .bool_callback = callReplyBool,
- .big_number_callback = callReplyBigNumber,
- .verbatim_string_callback = callReplyVerbatimString,
- .attribute_callback = callReplyAttribute,
- .error = callReplyParseError,
-};
-
-/* Parse the buffer located in rep->original_proto and update the CallReply
- * structure to represent its contents. */
-static void callReplyParse(CallReply *rep) {
- if (rep->flags & REPLY_FLAG_PARSED) {
- return;
- }
-
- ReplyParser parser = {.curr_location = rep->proto, .callbacks = DefaultParserCallbacks};
-
- parseReply(&parser, rep);
- rep->flags |= REPLY_FLAG_PARSED;
-}
-
-/* Return the call reply type (REDISMODULE_REPLY_...). */
-int callReplyType(CallReply *rep) {
- if (!rep) return REDISMODULE_REPLY_UNKNOWN;
- callReplyParse(rep);
- return rep->type;
-}
-
-/* Return reply string as buffer and len. Applicable to:
- * - REDISMODULE_REPLY_STRING
- * - REDISMODULE_REPLY_ERROR
- *
- * The return value is borrowed from CallReply, so it must not be freed
- * explicitly or used after CallReply itself is freed.
- *
- * The returned value is not NULL terminated and its length is returned by
- * reference through len, which must not be NULL.
- */
-const char *callReplyGetString(CallReply *rep, size_t *len) {
- callReplyParse(rep);
- if (rep->type != REDISMODULE_REPLY_STRING &&
- rep->type != REDISMODULE_REPLY_ERROR) return NULL;
- if (len) *len = rep->len;
- return rep->val.str;
-}
-
-/* Return a long long reply value. Applicable to:
- * - REDISMODULE_REPLY_INTEGER
- */
-long long callReplyGetLongLong(CallReply *rep) {
- callReplyParse(rep);
- if (rep->type != REDISMODULE_REPLY_INTEGER) return LLONG_MIN;
- return rep->val.ll;
-}
-
-/* Return a double reply value. Applicable to:
- * - REDISMODULE_REPLY_DOUBLE
- */
-double callReplyGetDouble(CallReply *rep) {
- callReplyParse(rep);
- if (rep->type != REDISMODULE_REPLY_DOUBLE) return LLONG_MIN;
- return rep->val.d;
-}
-
-/* Return a reply Boolean value. Applicable to:
- * - REDISMODULE_REPLY_BOOL
- */
-int callReplyGetBool(CallReply *rep) {
- callReplyParse(rep);
- if (rep->type != REDISMODULE_REPLY_BOOL) return INT_MIN;
- return rep->val.ll;
-}
-
-/* Return reply length. Applicable to:
- * - REDISMODULE_REPLY_STRING
- * - REDISMODULE_REPLY_ERROR
- * - REDISMODULE_REPLY_ARRAY
- * - REDISMODULE_REPLY_SET
- * - REDISMODULE_REPLY_MAP
- * - REDISMODULE_REPLY_ATTRIBUTE
- */
-size_t callReplyGetLen(CallReply *rep) {
- callReplyParse(rep);
- switch(rep->type) {
- case REDISMODULE_REPLY_STRING:
- case REDISMODULE_REPLY_ERROR:
- case REDISMODULE_REPLY_ARRAY:
- case REDISMODULE_REPLY_SET:
- case REDISMODULE_REPLY_MAP:
- case REDISMODULE_REPLY_ATTRIBUTE:
- return rep->len;
- default:
- return 0;
- }
-}
-
-static CallReply *callReplyGetCollectionElement(CallReply *rep, size_t idx, int elements_per_entry) {
- if (idx >= rep->len * elements_per_entry) return NULL; // real len is rep->len * elements_per_entry
- return rep->val.array+idx;
-}
-
-/* Return a reply array element at a given index. Applicable to:
- * - REDISMODULE_REPLY_ARRAY
- *
- * The return value is borrowed from CallReply, so it must not be freed
- * explicitly or used after CallReply itself is freed.
- */
-CallReply *callReplyGetArrayElement(CallReply *rep, size_t idx) {
- callReplyParse(rep);
- if (rep->type != REDISMODULE_REPLY_ARRAY) return NULL;
- return callReplyGetCollectionElement(rep, idx, 1);
-}
-
-/* Return a reply set element at a given index. Applicable to:
- * - REDISMODULE_REPLY_SET
- *
- * The return value is borrowed from CallReply, so it must not be freed
- * explicitly or used after CallReply itself is freed.
- */
-CallReply *callReplyGetSetElement(CallReply *rep, size_t idx) {
- callReplyParse(rep);
- if (rep->type != REDISMODULE_REPLY_SET) return NULL;
- return callReplyGetCollectionElement(rep, idx, 1);
-}
-
-static int callReplyGetMapElementInternal(CallReply *rep, size_t idx, CallReply **key, CallReply **val, int type) {
- callReplyParse(rep);
- if (rep->type != type) return C_ERR;
- if (idx >= rep->len) return C_ERR;
- if (key) *key = callReplyGetCollectionElement(rep, idx * 2, 2);
- if (val) *val = callReplyGetCollectionElement(rep, idx * 2 + 1, 2);
- return C_OK;
-}
-
-/* Retrieve a map reply key and value at a given index. Applicable to:
- * - REDISMODULE_REPLY_MAP
- *
- * The key and value are returned by reference through key and val,
- * which may also be NULL if not needed.
- *
- * Returns C_OK on success or C_ERR if reply type mismatches, or if idx is out
- * of range.
- *
- * The returned values are borrowed from CallReply, so they must not be freed
- * explicitly or used after CallReply itself is freed.
- */
-int callReplyGetMapElement(CallReply *rep, size_t idx, CallReply **key, CallReply **val) {
- return callReplyGetMapElementInternal(rep, idx, key, val, REDISMODULE_REPLY_MAP);
-}
-
-/* Return reply attribute, or NULL if it does not exist. Applicable to all replies.
- *
- * The returned values are borrowed from CallReply, so they must not be freed
- * explicitly or used after CallReply itself is freed.
- */
-CallReply *callReplyGetAttribute(CallReply *rep) {
- return rep->attribute;
-}
-
-/* Retrieve attribute reply key and value at a given index. Applicable to:
- * - REDISMODULE_REPLY_ATTRIBUTE
- *
- * The key and value are returned by reference through key and val,
- * which may also be NULL if not needed.
- *
- * Returns C_OK on success or C_ERR if reply type mismatches, or if idx is out
- * of range.
- *
- * The returned values are borrowed from CallReply, so they must not be freed
- * explicitly or used after CallReply itself is freed.
- */
-int callReplyGetAttributeElement(CallReply *rep, size_t idx, CallReply **key, CallReply **val) {
- return callReplyGetMapElementInternal(rep, idx, key, val, REDISMODULE_REPLY_MAP);
-}
-
-/* Return a big number reply value. Applicable to:
- * - REDISMODULE_REPLY_BIG_NUMBER
- *
- * The returned values are borrowed from CallReply, so they must not be freed
- * explicitly or used after CallReply itself is freed.
- *
- * The return value is guaranteed to be a big number, as described in the RESP3
- * protocol specifications.
- *
- * The returned value is not NULL terminated and its length is returned by
- * reference through len, which must not be NULL.
- */
-const char *callReplyGetBigNumber(CallReply *rep, size_t *len) {
- callReplyParse(rep);
- if (rep->type != REDISMODULE_REPLY_BIG_NUMBER) return NULL;
- *len = rep->len;
- return rep->val.str;
-}
-
-/* Return a verbatim string reply value. Applicable to:
- * - REDISMODULE_REPLY_VERBATIM_STRING
- *
- * If format is non-NULL, the verbatim reply format is also returned by value.
- *
- * The optional output argument can be given to get a verbatim reply
- * format, or can be set NULL if not needed.
- *
- * The return value is borrowed from CallReply, so it must not be freed
- * explicitly or used after CallReply itself is freed.
- *
- * The returned value is not NULL terminated and its length is returned by
- * reference through len, which must not be NULL.
- */
-const char *callReplyGetVerbatim(CallReply *rep, size_t *len, const char **format){
- callReplyParse(rep);
- if (rep->type != REDISMODULE_REPLY_VERBATIM_STRING) return NULL;
- *len = rep->len;
- if (format) *format = rep->val.verbatim_str.format;
- return rep->val.verbatim_str.str;
-}
-
-/* Return the current reply blob.
- *
- * The return value is borrowed from CallReply, so it must not be freed
- * explicitly or used after CallReply itself is freed.
- */
-const char *callReplyGetProto(CallReply *rep, size_t *proto_len) {
- *proto_len = rep->proto_len;
- return rep->proto;
-}
-
-/* Return CallReply private data, as set by the caller on callReplyCreate().
- */
-void *callReplyGetPrivateData(CallReply *rep) {
- return rep->private_data;
-}
-
-/* Return true if the reply or one of it sub-replies is RESP3 formatted. */
-int callReplyIsResp3(CallReply *rep) {
- return rep->flags & REPLY_FLAG_RESP3;
-}
-
-/* Returns a list of errors in sds form, or NULL. */
-list *callReplyDeferredErrorList(CallReply *rep) {
- return rep->deferred_error_list;
-}
-
-/* Create a new CallReply struct from the reply blob.
- *
- * The function will own the reply blob, so it must not be used or freed by
- * the caller after passing it to this function.
- *
- * The reply blob will be freed when the returned CallReply struct is later
- * freed using freeCallReply().
- *
- * The deferred_error_list is an optional list of errors that are present
- * in the reply blob, if given, this function will take ownership on it.
- *
- * The private_data is optional and can later be accessed using
- * callReplyGetPrivateData().
- *
- * NOTE: The parser used for parsing the reply and producing CallReply is
- * designed to handle valid replies created by Redis itself. IT IS NOT
- * DESIGNED TO HANDLE USER INPUT and using it to parse invalid replies is
- * unsafe.
- */
-CallReply *callReplyCreate(sds reply, list *deferred_error_list, void *private_data) {
- CallReply *res = zmalloc(sizeof(*res));
- res->flags = REPLY_FLAG_ROOT;
- res->original_proto = reply;
- res->proto = reply;
- res->proto_len = sdslen(reply);
- res->private_data = private_data;
- res->attribute = NULL;
- res->deferred_error_list = deferred_error_list;
- return res;
-}
-
-/* Create a new CallReply struct from the reply blob representing an error message.
- * Automatically creating deferred_error_list and set a copy of the reply in it.
- * Refer to callReplyCreate for detailed explanation.
- * Reply string can come in one of two forms:
- * 1. A protocol reply starting with "-CODE" and ending with "\r\n"
- * 2. A plain string, in which case this function adds the protocol header and footer. */
-CallReply *callReplyCreateError(sds reply, void *private_data) {
- sds err_buff = reply;
- if (err_buff[0] != '-') {
- err_buff = sdscatfmt(sdsempty(), "-ERR %S\r\n", reply);
- sdsfree(reply);
- }
- list *deferred_error_list = listCreate();
- listSetFreeMethod(deferred_error_list, sdsfreegeneric);
- listAddNodeTail(deferred_error_list, sdsnew(err_buff));
- return callReplyCreate(err_buff, deferred_error_list, private_data);
-}