Issue #2068, Refactor ACL command

This commit is contained in:
Pavlo Yatsukhnenko
2022-11-01 12:53:23 +02:00
parent f2cef8be06
commit 504810a5d1
5 changed files with 120 additions and 62 deletions
+21
View File
@@ -2168,6 +2168,27 @@ redis_xinfo_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_t
return FAILURE;
}
PHP_REDIS_API int
redis_acl_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx)
{
if (ctx == NULL) {
return redis_read_variant_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR) {
return redis_boolean_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR + 1) {
return redis_string_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR + 2) {
return redis_long_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR + 3) {
return redis_acl_getuser_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else if (ctx == PHPREDIS_CTX_PTR + 4) {
return redis_acl_log_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL);
} else {
ZEND_ASSERT(!"memory corruption?");
return FAILURE;
}
}
PHP_REDIS_API int
redis_read_acl_log_reply(RedisSock *redis_sock, zval *zret, long count) {
zval zsub;
+1
View File
@@ -161,6 +161,7 @@ PHP_REDIS_API int
redis_read_mpop_response(RedisSock *redis_sock, zval *zdst, int elements, void *ctx);
/* Specialized ACL reply handlers */
PHP_REDIS_API int redis_acl_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_read_acl_getuser_reply(RedisSock *redis_sock, zval *zret, long len);
PHP_REDIS_API int redis_acl_getuser_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
PHP_REDIS_API int redis_read_acl_log_reply(RedisSock *redis_sock, zval *zret, long count);
+1 -43
View File
@@ -1129,49 +1129,7 @@ PHP_METHOD(Redis, type)
/* {{{ proto mixed Redis::acl(string $op, ...) }}} */
PHP_METHOD(Redis, acl) {
RedisSock *redis_sock;
FailableResultCallback cb;
zval *zargs;
zend_string *op;
char *cmd;
int cmdlen, argc = ZEND_NUM_ARGS();
if (argc < 1 || (redis_sock = redis_sock_get(getThis(), 0)) == NULL) {
if (argc < 1) {
php_error_docref(NULL, E_WARNING, "ACL command requires at least one argument");
}
RETURN_FALSE;
}
zargs = emalloc(argc * sizeof(*zargs));
if (zend_get_parameters_array(ht, argc, zargs) == FAILURE) {
efree(zargs);
RETURN_FALSE;
}
/* Read the subcommand and set response callback */
op = zval_get_string(&zargs[0]);
if (zend_string_equals_literal_ci(op, "GETUSER")) {
cb = redis_acl_getuser_reply;
} else if (zend_string_equals_literal_ci(op, "LOG")) {
cb = redis_acl_log_reply;
} else {
cb = redis_read_variant_reply;
}
/* Make our command and free args */
cmd = redis_variadic_str_cmd("ACL", zargs, argc, &cmdlen);
zend_string_release(op);
efree(zargs);
REDIS_PROCESS_REQUEST(redis_sock, cmd, cmdlen);
if (IS_ATOMIC(redis_sock)) {
if (cb(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL, NULL) < 0) {
RETURN_FALSE;
}
}
REDIS_PROCESS_RESPONSE(cb);
REDIS_PROCESS_CMD(acl, redis_acl_response);
}
/* {{{ proto long Redis::append(string key, string val) */
+94 -17
View File
@@ -2100,6 +2100,100 @@ redis_pop_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
return SUCCESS;
}
int
redis_acl_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
smart_string cmdstr = {0};
zend_string *zstr;
zval *z_args;
int argc, i;
if ((argc = ZEND_NUM_ARGS()) < 1) {
php_error_docref(NULL, E_WARNING, "ACL command requires at least one argument");
return FAILURE;
}
z_args = ecalloc(argc, sizeof(*z_args));
if (zend_get_parameters_array(ht, argc, z_args) == FAILURE) {
goto failure;
}
zstr = zval_get_string(&z_args[0]);
if (zend_string_equals_literal_ci(zstr, "CAT") ||
zend_string_equals_literal_ci(zstr, "LIST") ||
zend_string_equals_literal_ci(zstr, "USERS")
) {
*ctx = NULL;
} else if (zend_string_equals_literal_ci(zstr, "LOAD") ||
zend_string_equals_literal_ci(zstr, "SAVE")
) {
*ctx = PHPREDIS_CTX_PTR;
} else if (zend_string_equals_literal_ci(zstr, "GENPASS") ||
zend_string_equals_literal_ci(zstr, "WHOAMI")
) {
*ctx = PHPREDIS_CTX_PTR + 1;
} else if (zend_string_equals_literal_ci(zstr, "SETUSER")) {
if (argc < 2) {
php_error_docref(NULL, E_WARNING, "ACL SETUSER requires at least one argument");
zend_string_release(zstr);
goto failure;
}
*ctx = PHPREDIS_CTX_PTR;
} else if (zend_string_equals_literal_ci(zstr, "DELUSER")) {
if (argc < 2) {
php_error_docref(NULL, E_WARNING, "ACL DELUSER requires at least one argument");
zend_string_release(zstr);
goto failure;
}
*ctx = PHPREDIS_CTX_PTR + 2;
} else if (zend_string_equals_literal_ci(zstr, "GETUSER")) {
if (argc < 2) {
php_error_docref(NULL, E_WARNING, "ACL GETUSER requires at least one argument");
zend_string_release(zstr);
goto failure;
}
*ctx = PHPREDIS_CTX_PTR + 3;
} else if (zend_string_equals_literal_ci(zstr, "DRYRUN")) {
if (argc < 3) {
php_error_docref(NULL, E_WARNING, "ACL DRYRUN requires at least two arguments");
zend_string_release(zstr);
goto failure;
}
*ctx = PHPREDIS_CTX_PTR;
} else if (zend_string_equals_literal_ci(zstr, "LOG")) {
if (argc > 1 && Z_TYPE(z_args[1]) == IS_STRING && ZVAL_STRICMP_STATIC(&z_args[1], "RESET")) {
*ctx = PHPREDIS_CTX_PTR;
} else {
*ctx = PHPREDIS_CTX_PTR + 4;
}
} else {
php_error_docref(NULL, E_WARNING, "Unknown ACL operation '%s'", ZSTR_VAL(zstr));
zend_string_release(zstr);
goto failure;
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "ACL");
redis_cmd_append_sstr_zstr(&cmdstr, zstr);
zend_string_release(zstr);
for (i = 1; i < argc; ++i) {
zstr = zval_get_string(&z_args[i]);
redis_cmd_append_sstr_zstr(&cmdstr, zstr);
zend_string_release(zstr);
}
efree(z_args);
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
failure:
efree(z_args);
return FAILURE;
}
/* Attempt to pull a long expiry from a zval. We're more restrictave than zval_get_long
* because that function will return integers from things like open file descriptors
* which should simply fail as a TTL */
@@ -3168,23 +3262,6 @@ int redis_pfcount_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
return SUCCESS;
}
char *redis_variadic_str_cmd(char *kw, zval *argv, int argc, int *cmd_len) {
smart_string cmdstr = {0};
zend_string *zstr;
int i;
redis_cmd_init_sstr(&cmdstr, argc, kw, strlen(kw));
for (i = 0; i < argc; i++) {
zstr = zval_get_string(&argv[i]);
redis_cmd_append_sstr_zstr(&cmdstr, zstr);
zend_string_release(zstr);
}
*cmd_len = cmdstr.len;
return cmdstr.c;
}
int redis_auth_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
+3 -2
View File
@@ -31,8 +31,6 @@ int redis_build_raw_cmd(zval *z_args, int argc, char **cmd, int *cmd_len);
/* Construct a script command */
smart_string *redis_build_script_cmd(smart_string *cmd, int argc, zval *z_args);
char *redis_variadic_str_cmd(char *kw, zval *argv, int argc, int *cmd_len);
/* Redis command generics. Many commands share common prototypes meaning that
* we can write one function to handle all of them. For example, there are
* many COMMAND key value commands, or COMMAND key commands. */
@@ -187,6 +185,9 @@ int redis_geosearchstore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock
* specific processing we do (e.g. verifying subarguments) that make them
* unique */
int redis_acl_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_set_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);