template <class ReplyT> bool Redox::submitToServer(Command<ReplyT> *c) { Redox *rdx = c->rdx_; c->pending_++; // Construct a char** from the vector vector<const char *> argv; transform(c->cmd_.begin(), c->cmd_.end(), back_inserter(argv), [](const string &s) { return s.c_str(); }); // Construct a size_t* of string lengths from the vector vector<size_t> argvlen; transform(c->cmd_.begin(), c->cmd_.end(), back_inserter(argvlen), [](const string &s) { return s.size(); }); if (redisAsyncCommandArgv(rdx->ctx_, commandCallback<ReplyT>, (void *)c->id_, argv.size(), &argv[0], &argvlen[0]) != REDIS_OK) { rdx->logger_.error() << "Could not send \"" << c->cmd() << "\": " << rdx->ctx_->errstr; c->reply_status_ = Command<ReplyT>::SEND_ERROR; c->invoke(); return false; } return true; }
int connection::redis_raw_cmd(redisCallbackFn* fn, void* priv_data, int argc, const char** argv, const size_t* argvlen) { if (NULL == context) { return error_code::REDIS_HAPP_CREATE; } return redisAsyncCommandArgv(context, fn, priv_data, argc, argv, argvlen); }
static int dispatch_thread_send_data(dispatch_data_thread *ddt) { int count_per_time = 1000; data_unit *du; while ((du = dmtqueue_pop(ddt->datas)) != NULL) { redisAsyncContext *actx; int j; size_t *argvlen = malloc(du->argc*sizeof(size_t)); reply_unit *ru = malloc(sizeof(reply_unit)); ru->du = du; ru->total_count = darray_n(ddt->abgs); ru->received_count = 0; ru->replys = malloc(ru->total_count*sizeof(redisReply *)); for (j = 0; j < du->argc; j ++) { argvlen[j] = sdslen(du->argv[j]); } for (j = 0; j < darray_n(ddt->abgs); j ++) { struct callback_data *cbd; int *keyindex, numkeys; abtest_server *abs; cbd = malloc(sizeof(struct callback_data)); cbd->ddt = ddt; cbd->ru = ru; cbd->idx = j; abtest_group *abg = darray_get(ddt->abgs, j); keyindex = get_keys_from_data_producer(du->dp, du->argv, du->argc, &numkeys); if (numkeys == 0) { unsigned int idx; idx = (unsigned int)rand()%darray_n(&abg->abtest_servers); abs = darray_get(&abg->abtest_servers,idx); } else { sds key = du->argv[keyindex[0]]; abs = abg->get_backend_server(abg,key,sdslen(key)); } free(keyindex); conn_context *cc = darray_get(abs->conn_contexts, du->hashvalue%darray_n(abs->conn_contexts)); actx = cc->actx; redisAsyncCommandArgv(actx, reply_callback, cbd, du->argc, du->argv, argvlen); } free(argvlen); ddt->count_wait_for_reply ++; if (count_per_time-- <= 0) break; } return VRT_OK; }
bool AsyncRedisMgr::redis_send(void *privdata,const int &argc,const char **argv,const size_t *argvlen) { if (argv == NULL || argvlen == NULL) { LOG4CPLUS_ERROR(logger,"we send the argv or arfvlen is null."); return false; } if(redisAsyncCommandArgv(m_redis_context,redis_recv,privdata,argc,argv,argvlen) != REDIS_OK) { LOG4CPLUS_ERROR(logger,"when we send command failed"); return false; } return true; }
static PHP_METHOD(swoole_redis, __call) { zval *params; char *command; zend_size_t command_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &command, &command_len, ¶ms) == FAILURE) { return; } if (Z_TYPE_P(params) != IS_ARRAY) { swoole_php_fatal_error(E_WARNING, "invalid params."); RETURN_FALSE; } swRedisClient *redis = swoole_get_object(getThis()); if (!redis) { swoole_php_fatal_error(E_WARNING, "the object is not an instance of swoole_redis."); RETURN_FALSE; } switch (redis->state) { case SWOOLE_REDIS_STATE_CONNECT: swoole_php_error(E_WARNING, "redis client is not connected."); RETURN_FALSE; break; case SWOOLE_REDIS_STATE_WAIT_RESULT: if (swoole_redis_is_message_command(command, command_len)) { swoole_php_error(E_WARNING, "redis client is waiting for response."); RETURN_FALSE; } break; case SWOOLE_REDIS_STATE_SUBSCRIBE: if (!swoole_redis_is_message_command(command, command_len)) { swoole_php_error(E_WARNING, "redis client is waiting for subscribed messages."); RETURN_FALSE; } break; case SWOOLE_REDIS_STATE_CLOSED: swoole_php_error(E_WARNING, "redis client connection is closed."); RETURN_FALSE; break; default: break; } int argc = zend_hash_num_elements(Z_ARRVAL_P(params)); size_t stack_argvlen[SW_REDIS_COMMAND_BUFFER_SIZE]; char *stack_argv[SW_REDIS_COMMAND_BUFFER_SIZE]; size_t *argvlen; char **argv; zend_bool free_mm = 0; if (argc > SW_REDIS_COMMAND_BUFFER_SIZE) { argvlen = emalloc(sizeof(size_t) * argc); argv = emalloc(sizeof(char*) * argc); free_mm = 1; } else { argvlen = stack_argvlen; argv = stack_argv; } #define FREE_MEM() do { \ for (i = 1; i < argc; i++) \ { \ efree((void* )argv[i]); \ } \ \ if (redis->state == SWOOLE_REDIS_STATE_SUBSCRIBE) \ { \ efree(argv[argc]); \ } \ \ if (free_mm) \ { \ efree(argvlen); \ efree(argv); \ } \ } while (0) assert(command_len < SW_REDIS_COMMAND_KEY_SIZE - 1); char command_name[SW_REDIS_COMMAND_KEY_SIZE]; memcpy(command_name, command, command_len); command_name[command_len] = '\0'; argv[0] = command_name; argvlen[0] = command_len; zval *value; int i = 1; /** * subscribe command */ if (redis->state == SWOOLE_REDIS_STATE_SUBSCRIBE || (redis->subscribe && swoole_redis_is_message_command(command, command_len))) { redis->state = SWOOLE_REDIS_STATE_SUBSCRIBE; SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(params), value) convert_to_string(value); argvlen[i] = (size_t) Z_STRLEN_P(value); argv[i] = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)); if (i == argc) { break; } i++; SW_HASHTABLE_FOREACH_END(); if (redisAsyncCommandArgv(redis->context, swoole_redis_onResult, NULL, argc + 1, (const char **) argv, (const size_t *) argvlen) < 0) { swoole_php_error(E_WARNING, "redisAsyncCommandArgv() failed."); FREE_MEM(); RETURN_FALSE; } } /** * storage command */ else { redis->state = SWOOLE_REDIS_STATE_WAIT_RESULT; redis->reqnum++; #if PHP_MAJOR_VERSION < 7 zval *callback; zval **cb_tmp; if (zend_hash_index_find(Z_ARRVAL_P(params), zend_hash_num_elements(Z_ARRVAL_P(params)) - 1, (void **) &cb_tmp) == FAILURE) { swoole_php_error(E_WARNING, "index out of array bounds."); FREE_MEM(); RETURN_FALSE; } callback = *cb_tmp; #else zval *callback = zend_hash_index_find(Z_ARRVAL_P(params), zend_hash_num_elements(Z_ARRVAL_P(params)) - 1); if (callback == NULL) { swoole_php_error(E_WARNING, "index out of array bounds."); FREE_MEM(); RETURN_FALSE; } #endif sw_zval_add_ref(&callback); callback = sw_zval_dup(callback); SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(params), value) if (i == argc) { break; } convert_to_string(value); argvlen[i] = (size_t) Z_STRLEN_P(value); argv[i] = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)); i++; SW_HASHTABLE_FOREACH_END(); if (redisAsyncCommandArgv(redis->context, swoole_redis_onResult, callback, argc, (const char **) argv, (const size_t *) argvlen) < 0) { swoole_php_error(E_WARNING, "redisAsyncCommandArgv() failed."); FREE_MEM(); RETURN_FALSE; } } FREE_MEM(); RETURN_TRUE; }
int AsyncConnection::send_command(const RedisCmd& cmd, redisCallbackFn* fn, void* privatedata) { return redisAsyncCommandArgv(async_context_, fn, privatedata, cmd.argc, (const char**)cmd.argv, cmd.argvlen); }
static int lua_client_command(lua_State *L) { lua_redis_client_t *lua_redis_client = (lua_redis_client_t *) luaL_checkudata(L, 1, LUA_REDIS_CLIENT_MT); static const char *argv[LUA_REDIS_MAX_ARGS]; static size_t argvlen[LUA_REDIS_MAX_ARGS]; int nargs, ltop, i; luv_ref_t *ref = NULL; int commandStatus; redisCallbackFn *redisCallback = NULL; if (lua_redis_client->redis_async_context == NULL) { return luaL_error(L, "RedisAsyncContext is null"); } /* consume callback, if any */ if (lua_isfunction(L, -1)) { ref = ref_alloc(); ref->L = L; ref->r = luaL_ref(L, LUA_REGISTRYINDEX); redisCallback = on_redis_response; } /* get arguments */ ltop = lua_gettop(L); nargs = 0; for (i = 2; i <= ltop; ++i) { /* unpack tables of arguments */ if (lua_istable(L, i)) { int j; for (j = 1; j <= lua_objlen(L, i); ++j) { lua_rawgeti(L, i, j); argv[nargs] = lua_tolstring(L, -1, &argvlen[nargs]); lua_pop(L, 1); if (argv[nargs] == NULL) { return luaL_argerror(L, i, "expected an array table of string or number values" ); } if (++nargs >= LUA_REDIS_MAX_ARGS) { return luaL_error(L, "too many arguments"); } } } else { argv[nargs] = lua_tolstring(L, i, &argvlen[nargs]); if (argv[nargs] == NULL) { return luaL_argerror(L, i, "expected a string or number value"); } if (++nargs >= LUA_REDIS_MAX_ARGS) { return luaL_error(L, "too many arguments"); } } } if (nargs <= 0) { return luaL_error(L, "missing command name"); } commandStatus = redisAsyncCommandArgv(lua_redis_client->redis_async_context, redisCallback, ref, nargs, argv, argvlen); if (commandStatus != REDIS_OK) { lua_rawgeti(L, LUA_REGISTRYINDEX, ref->r); luaL_unref(L, LUA_REGISTRYINDEX, ref->r); ref_free(ref); luv_push_async_error_raw(L, NULL, "Redis connection problem", "client_command", NULL); lua_pushnil(L); lua_call(L, 2, 0); } return 0; }
void rspamd_fuzzy_backend_count_redis (struct rspamd_fuzzy_backend *bk, rspamd_fuzzy_count_cb cb, void *ud, void *subr_ud) { struct rspamd_fuzzy_backend_redis *backend = subr_ud; struct rspamd_fuzzy_redis_session *session; struct upstream *up; struct timeval tv; rspamd_inet_addr_t *addr; g_assert (backend != NULL); session = g_slice_alloc0 (sizeof (*session)); session->backend = backend; REF_RETAIN (session->backend); session->callback.cb_count = cb; session->cbdata = ud; session->command = RSPAMD_FUZZY_REDIS_COMMAND_COUNT; session->nargs = 2; session->argv = g_malloc (sizeof (gchar *) * 2); session->argv[0] = g_strdup ("HLEN"); session->argv[1] = g_strdup (backend->redis_object); up = rspamd_upstream_get (backend->read_servers, RSPAMD_UPSTREAM_ROUND_ROBIN, NULL, 0); session->up = up; addr = rspamd_upstream_addr (up); g_assert (addr != NULL); session->ctx = rspamd_redis_pool_connect (backend->pool, backend->dbname, backend->password, rspamd_inet_address_to_string (addr), rspamd_inet_address_get_port (addr)); if (session->ctx == NULL) { rspamd_fuzzy_redis_session_dtor (session); if (cb) { cb (0, subr_ud); } } else { if (redisAsyncCommandArgv (session->ctx, rspamd_fuzzy_redis_count_callback, session, session->nargs, (const gchar **)session->argv, NULL) != REDIS_OK) { rspamd_fuzzy_redis_session_dtor (session); if (cb) { cb (0, subr_ud); } } else { /* Add timeout */ event_set (&session->timeout, -1, EV_TIMEOUT, rspamd_fuzzy_redis_timeout, session); event_base_set (rspamd_fuzzy_backend_event_base (bk), &session->timeout); double_to_tv (backend->timeout, &tv); event_add (&session->timeout, &tv); } } }
static PHP_METHOD(swoole_redis, __call) { zval *params; char *command; zend_size_t command_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &command, &command_len, ¶ms) == FAILURE) { return; } swRedisClient *redis = swoole_get_object(getThis()); switch (redis->state) { case SWOOLE_REDIS_STATE_CONNECT: swoole_php_error(E_WARNING, "redis client is not connected."); RETURN_FALSE; break; case SWOOLE_REDIS_STATE_WAIT: swoole_php_error(E_WARNING, "redis client is waiting for response."); RETURN_FALSE; break; case SWOOLE_REDIS_STATE_CLOSED: swoole_php_error(E_WARNING, "redis client connection is closed."); RETURN_FALSE; break; default: break; } #if PHP_MAJOR_VERSION < 7 zval *callback; zval **cb_tmp; if (zend_hash_index_find(Z_ARRVAL_P(params), zend_hash_num_elements(Z_ARRVAL_P(params)) - 1, (void **) &cb_tmp) == FAILURE) { swoole_php_error(E_WARNING, "index out of array."); RETURN_FALSE; } callback = *cb_tmp; redis->result_callback = callback; #else zval *callback = zend_hash_index_find(Z_ARRVAL_P(params), zend_hash_num_elements(Z_ARRVAL_P(params)) - 1); if (callback == NULL) { swoole_php_error(E_WARNING, "index out of array."); RETURN_FALSE; } redis->result_callback = &redis->_result_callback; memcpy(redis->result_callback, callback, sizeof(zval)); #endif sw_zval_add_ref(&redis->result_callback); redis->state = SWOOLE_REDIS_STATE_WAIT; int argc = zend_hash_num_elements(Z_ARRVAL_P(params)); size_t stack_argvlen[SW_REDIS_COMMAND_BUFFER_SIZE]; char *stack_argv[SW_REDIS_COMMAND_BUFFER_SIZE]; size_t *argvlen; char **argv; zend_bool free_mm = 0; if (argc > SW_REDIS_COMMAND_BUFFER_SIZE) { argvlen = emalloc(sizeof(size_t) * argc); argv = emalloc(sizeof(char*) * argc); free_mm = 1; } else { argvlen = stack_argvlen; argv = stack_argv; } assert(command_len < SW_REDIS_COMMAND_KEY_SIZE - 1); char command_name[SW_REDIS_COMMAND_KEY_SIZE]; memcpy(command_name, command, command_len); command_name[command_len] = '\0'; argv[0] = command_name; argvlen[0] = command_len; zval *value; int i = 1; SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(params), value) convert_to_string(value); argvlen[i] = (size_t) Z_STRLEN_P(value); argv[i] = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)); if (i == argc - 1) { break; } i++; SW_HASHTABLE_FOREACH_END(); if (redisAsyncCommandArgv(redis->context, swoole_redis_onResult, NULL, argc, (const char **) argv, (const size_t *) argvlen) < 0) { swoole_php_error(E_WARNING, "redisAsyncCommandArgv() failed."); RETURN_FALSE; } for (i = 1; i < argc; i++) { efree((void* )argv[i]); } if (free_mm) { efree(argvlen); efree(argv); } redis->state = SWOOLE_REDIS_STATE_WAIT; RETURN_TRUE; }
/*** * @function rspamd_redis.make_request({params}) * Make request to redis server, params is a table of key=value arguments in any order * @param {task} task worker task object * @param {ip} host server address * @param {function} callback callback to be called in form `function (task, err, data)` * @param {string} cmd command to be sent to redis * @param {table} args numeric array of strings used as redis arguments * @param {number} timeout timeout in seconds for request (1.0 by default) * @return {boolean} `true` if a request has been scheduled */ static int lua_redis_make_request (lua_State *L) { struct lua_redis_userdata *ud; struct rspamd_lua_ip *addr = NULL; struct rspamd_task *task = NULL; const gchar *cmd = NULL; gint top, cbref = -1; struct timeval tv; gboolean ret = FALSE; gdouble timeout = REDIS_DEFAULT_TIMEOUT; if (lua_istable (L, 1)) { /* Table version */ lua_pushstring (L, "task"); lua_gettable (L, -2); if (lua_type (L, -1) == LUA_TUSERDATA) { task = lua_check_task (L, -1); } lua_pop (L, 1); lua_pushstring (L, "callback"); lua_gettable (L, -2); if (lua_type (L, -1) == LUA_TFUNCTION) { /* This also pops function from the stack */ cbref = luaL_ref (L, LUA_REGISTRYINDEX); } else { msg_err ("bad callback argument for lua redis"); lua_pop (L, 1); } lua_pushstring (L, "cmd"); lua_gettable (L, -2); cmd = lua_tostring (L, -1); lua_pop (L, 1); lua_pushstring (L, "host"); lua_gettable (L, -2); if (lua_type (L, -1) == LUA_TUSERDATA) { addr = lua_check_ip (L, -1); } lua_pop (L, 1); lua_pushstring (L, "timeout"); lua_gettable (L, -2); timeout = lua_tonumber (L, -1); lua_pop (L, 1); if (task != NULL && addr != NULL && cbref != -1 && cmd != NULL) { ud = rspamd_mempool_alloc (task->task_pool, sizeof (struct lua_redis_userdata)); ud->task = task; ud->L = L; ud->cbref = cbref; lua_pushstring (L, "args"); lua_redis_parse_args (L, -1, cmd, ud); ret = TRUE; } else { if (cbref != -1) { luaL_unref (L, LUA_REGISTRYINDEX, cbref); } msg_err ("incorrect function invocation"); } } else if ((task = lua_check_task (L, 1)) != NULL) { addr = lua_check_ip (L, 2); top = lua_gettop (L); /* Now get callback */ if (lua_isfunction (L, 3) && addr != NULL && addr->addr && top >= 4) { /* Create userdata */ ud = rspamd_mempool_alloc (task->task_pool, sizeof (struct lua_redis_userdata)); ud->task = task; ud->L = L; /* Pop other arguments */ lua_pushvalue (L, 3); /* Get a reference */ ud->cbref = luaL_ref (L, LUA_REGISTRYINDEX); cmd = luaL_checkstring (L, 4); if (top > 4) { lua_redis_parse_args (L, 5, cmd, ud); } else { lua_redis_parse_args (L, 0, cmd, ud); } ret = TRUE; } else { msg_err ("incorrect function invocation"); } } if (ret) { ud->terminated = 0; ud->ctx = redisAsyncConnect (rspamd_inet_address_to_string (addr->addr), rspamd_inet_address_get_port (addr->addr)); redisAsyncSetConnectCallback (ud->ctx, lua_redis_connect_cb); if (ud->ctx == NULL || ud->ctx->err) { ud->terminated = 1; redisAsyncFree (ud->ctx); lua_redis_free_args (ud); luaL_unref (ud->L, LUA_REGISTRYINDEX, ud->cbref); lua_pushboolean (L, FALSE); return 1; } redisLibeventAttach (ud->ctx, ud->task->ev_base); ret = redisAsyncCommandArgv (ud->ctx, lua_redis_callback, ud, ud->nargs, (const gchar **)ud->args, NULL); if (ret == REDIS_OK) { rspamd_session_add_event (ud->task->s, lua_redis_fin, ud, g_quark_from_static_string ("lua redis")); double_to_tv (timeout, &tv); event_set (&ud->timeout, -1, EV_TIMEOUT, lua_redis_timeout, ud); event_base_set (ud->task->ev_base, &ud->timeout); event_add (&ud->timeout, &tv); } else { msg_info ("call to redis failed: %s", ud->ctx->errstr); ud->terminated = 1; lua_redis_free_args (ud); redisAsyncFree (ud->ctx); luaL_unref (ud->L, LUA_REGISTRYINDEX, ud->cbref); } } lua_pushboolean (L, ret); return 1; }
void cmd_send(struct cmd *cmd, formatting_fun f_format) { redisAsyncCommandArgv(cmd->ac, f_format, cmd, cmd->count, (const char **)cmd->argv, cmd->argv_len); }
cmd_response_t cmd_run(struct worker *w, struct http_client *client, const char *uri, size_t uri_len, const char *body, size_t body_len) { char *qmark = memchr(uri, '?', uri_len); char *slash; const char *p, *cmd_name = uri; int cmd_len; int param_count = 0, cur_param = 1; struct cmd *cmd; formatting_fun f_format; /* count arguments */ if(qmark) { uri_len = qmark - uri; } for(p = uri; p && p < uri + uri_len; param_count++) { p = memchr(p+1, '/', uri_len - (p+1-uri)); } if(body && body_len) { /* PUT request */ param_count++; } if(param_count == 0) { return CMD_PARAM_ERROR; } cmd = cmd_new(param_count); cmd->fd = client->fd; cmd->database = w->s->cfg->database; /* get output formatting function */ uri_len = cmd_select_format(client, cmd, uri, uri_len, &f_format); /* add HTTP info */ cmd_setup(cmd, client); /* check if we only have one command or more. */ slash = memchr(uri, '/', uri_len); if(slash) { /* detect DB number by checking if first arg is only numbers */ int has_db = 1; int db_num = 0; for(p = uri; p < slash; ++p) { if(*p < '0' || *p > '9') { has_db = 0; break; } db_num = db_num * 10 + (*p - '0'); } /* shift to next arg if a db was set up */ if(has_db) { char *next; cmd->database = db_num; cmd->count--; /* overcounted earlier */ cmd_name = slash + 1; if((next = memchr(cmd_name, '/', uri_len - (slash - uri)))) { cmd_len = next - cmd_name; } else { cmd_len = uri_len - (slash - uri + 1); } } else { cmd_len = slash - uri; } } else { cmd_len = uri_len; } /* there is always a first parameter, it's the command name */ cmd->argv[0] = malloc(cmd_len); memcpy(cmd->argv[0], cmd_name, cmd_len); cmd->argv_len[0] = cmd_len; /* check that the client is able to run this command */ if(!acl_allow_command(cmd, w->s->cfg, client)) { cmd_free(cmd); return CMD_ACL_FAIL; } if(cmd_is_subscribe(cmd)) { /* create a new connection to Redis */ cmd->ac = (redisAsyncContext*)pool_connect(w->pool, cmd->database, 0); /* register with the client, used upon disconnection */ client->pub_sub = cmd; cmd->pub_sub_client = client; } else if(cmd->database != w->s->cfg->database) { /* create a new connection to Redis for custom DBs */ cmd->ac = (redisAsyncContext*)pool_connect(w->pool, cmd->database, 0); } else { /* get a connection from the pool */ cmd->ac = (redisAsyncContext*)pool_get_context(w->pool); } /* no args (e.g. INFO command) */ if(!slash) { if(!cmd->ac) { cmd_free(cmd); return CMD_REDIS_UNAVAIL; } redisAsyncCommandArgv(cmd->ac, f_format, cmd, 1, (const char **)cmd->argv, cmd->argv_len); return CMD_SENT; } p = cmd_name + cmd_len + 1; while(p < uri + uri_len) { const char *arg = p; int arg_len; char *next = memchr(arg, '/', uri_len - (arg-uri)); if(!next || next > uri + uri_len) { /* last argument */ p = uri + uri_len; arg_len = p - arg; } else { /* found a slash */ arg_len = next - arg; p = next + 1; } /* record argument */ cmd->argv[cur_param] = decode_uri(arg, arg_len, &cmd->argv_len[cur_param], 1); cur_param++; } if(body && body_len) { /* PUT request */ cmd->argv[cur_param] = malloc(body_len); memcpy(cmd->argv[cur_param], body, body_len); cmd->argv_len[cur_param] = body_len; } /* send it off! */ if(cmd->ac) { cmd_send(cmd, f_format); return CMD_SENT; } /* failed to find a suitable connection to Redis. */ cmd_free(cmd); client->pub_sub = NULL; return CMD_REDIS_UNAVAIL; }
int cmd_run(struct server *s, struct evhttp_request *rq, const char *uri, size_t uri_len, const char *body, size_t body_len) { char *qmark = strchr(uri, '?'); char *slash; const char *p; int cmd_len; int param_count = 0, cur_param = 1, i; struct cmd *cmd; formatting_fun f_format; /* count arguments */ if(qmark) { uri_len = qmark - uri; } for(p = uri; p && p < uri + uri_len; param_count++) { p = strchr(p+1, '/'); } if(body && body_len) { /* PUT request */ param_count++; } cmd = cmd_new(rq, param_count); /* parse URI parameters */ evhttp_parse_query(uri, &cmd->uri_params); /* get output formatting function */ uri_len = cmd_select_format(cmd, uri, uri_len, &f_format); /* check if we only have one command or more. */ slash = memchr(uri, '/', uri_len); if(slash) { cmd_len = slash - uri; } else { cmd_len = uri_len; } /* there is always a first parameter, it's the command name */ cmd->argv[0] = uri; cmd->argv_len[0] = cmd_len; /* check that the client is able to run this command */ if(!acl_allow_command(cmd, s->cfg, rq)) { return -1; } /* check if we have to split the connection */ if(cmd_is_subscribe(cmd)) { struct pubsub_client *ps; ps = calloc(1, sizeof(struct pubsub_client)); ps->s = s = server_copy(s); ps->cmd = cmd; ps->rq = rq; evhttp_connection_set_closecb(rq->evcon, on_http_disconnect, ps); } /* no args (e.g. INFO command) */ if(!slash) { redisAsyncCommandArgv(s->ac, f_format, cmd, 1, cmd->argv, cmd->argv_len); return 0; } p = slash + 1; while(p < uri + uri_len) { const char *arg = p; int arg_len; char *next = strchr(arg, '/'); if(!next || next > uri + uri_len) { /* last argument */ p = uri + uri_len; arg_len = p - arg; } else { /* found a slash */ arg_len = next - arg; p = next + 1; } /* record argument */ cmd->argv[cur_param] = decode_uri(arg, arg_len, &cmd->argv_len[cur_param], 1); cur_param++; } if(body && body_len) { /* PUT request */ cmd->argv[cur_param] = body; cmd->argv_len[cur_param] = body_len; } /* push command to Redis. */ redisAsyncCommandArgv(s->ac, f_format, cmd, cmd->count, cmd->argv, cmd->argv_len); for(i = 1; i < cur_param; ++i) { free((char*)cmd->argv[i]); } return 0; }