From cde93fa7cb837ab246a208dd6e30ec5f2f78898e Mon Sep 17 00:00:00 2001 From: Thiago Ribeiro Date: Thu, 26 Jul 2012 11:31:27 -0300 Subject: [PATCH 1/2] Created a function to concatenate the arrays values as a string separated by the wildcard ":". A new file example file "arrays.vcl" was generated to explain the correct usage. The great motivation to develop this new resource is reduce the number of connections that varnish runs on redis and makes everything with just one query. --- examples/arrays.vcl | 95 +++++++++++++++++++++++++++++++++++++++++++++ src/vmod_redis.c | 28 ++++++++++++- 2 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 examples/arrays.vcl diff --git a/examples/arrays.vcl b/examples/arrays.vcl new file mode 100644 index 0000000..17a9065 --- /dev/null +++ b/examples/arrays.vcl @@ -0,0 +1,95 @@ +# +# A trivial example to demonstrate how to use this vmod +# + +import redis; + +backend be1 { + .host = "192.168.0.1"; + .port = "80"; +} + +backend be2 { + .host = "192.168.0.1"; + .port = "80"; +} + +#sub vcl_init { + # + # By default, the redis module will attempt to connect to a Redis server + # at 127.0.0.1:6379 with a connect timeout of 200 milliseconds. + # + # The function redis.init_redis(host, port, timeout_ms) may be used to + # connect to an alternate Redis server or use a different connect timeout. + # + # redis.init_redis("localhost", 6379, 200); /* default values */ +#} + +sub vcl_recv { + # + # redis.call is a function that sends the command to redis and return the + # return value as a string. + # + # As an example I have a hash on redis that permits me control a domain's redirect: + # + # redis-cli> add vrnsh mydomain.com + # redis-cli> hmset vrnsh:mydomain.com 'type' 'r' 'to' 'anotherdomain.com' 'code' '301' + # + # And I have another domain appointment to a backend server: + # + # redis-cli> sadd vrnsh mydomaintwo.com + # redis-cli> hmset vrnsh:mydomaintwo.com 'type' 'd' 'backend' 'be2' + # + # So, now I can read the request and check on redis if it's exists. + # If the response is true, the string returned would be something + # like this: + # + # REDIRECT + # + # r:anotherdomain.com:301 + # + # DOMAIN + # + # d:be2 + # + # The keys set on the array will be disconsidered and the values + # will be concatenated using ":" as wildcard to make the correct separation. + # + set req.http.redis_key = redis.call("HGETALL vrnsh:" + req.http.host); + + if( req.http.redis_key ) { + # Read type param + et req.http.htype = regsub(req.http.redis_key, "^(r|d):(.*)", "\1"); + + # Read the domain backend from redis + if( req.http.htype == "d" ) { + # This regex is the number of parameters that you have returned. + # If you have more or less parameters, please adapt this. + # Don't forget to respect the correct parameters' sequences. + set req.http.hbackend = regsub(req.http.redis_key, "(.*):(.*)", "\2"); + + if( req.http.hbackend == "be1" ) { + set req.backend = be11; + } else if( req.http.hbackend == "be2" ) { + set req.backend = be2; + } + } + + # Read and set a redirect from redis + if( req.http.htype == "r" ) { + set req.http.Location = regsub(req.http.redis_key,"(.*):(.*):(.*)", "\2"); + set req.http.herror = regsub(req.http.redis_key,"(.*):(.*):(.*)", "\3"); + + if( req.http.herror == "302" ) { + error 302 req.http.Location; + } else if( req.http.herror == "301" ) { + error 301 req.http.Location; + } else { + error 705 req.http.Location; + } + } + # If not found, raise the correct error + } else { + error 404 + } +} diff --git a/src/vmod_redis.c b/src/vmod_redis.c index 171c80d..e6f4e78 100644 --- a/src/vmod_redis.c +++ b/src/vmod_redis.c @@ -151,6 +151,32 @@ vmod_send(struct sess *sp, struct vmod_priv *priv, const char *command) } } +const char * +arr_to_str(redisReply *reply) +{ + int i = 0; + int len = 0; + const char *ret = NULL; + char *digits; + + digits = malloc(reply->elements*sizeof(int)); + + for(i;ielements;i++) { + if( i%2 != 0 ) { + strcat(digits,reply->element[i]->str); + strcat(digits,":"); + } + } + + len = strlen(digits); + digits[len-1] = '\0'; + + ret = strdup(digits); + free(digits); + + return ret; +} + const char * vmod_call(struct sess *sp, struct vmod_priv *priv, const char *command) { @@ -183,7 +209,7 @@ vmod_call(struct sess *sp, struct vmod_priv *priv, const char *command) ret = strdup(reply->str); break; case REDIS_REPLY_ARRAY: - ret = strdup("array"); + ret = arr_to_str(reply); break; default: ret = strdup("unexpected"); From ae8c9dd4b782f8e256cf393797f72f34b9c68d4b Mon Sep 17 00:00:00 2001 From: Thiago Ribeiro Date: Thu, 26 Jul 2012 11:42:52 -0300 Subject: [PATCH 2/2] Just corrected a mistake at line 62 to write the 'set' correctly --- examples/arrays.vcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/arrays.vcl b/examples/arrays.vcl index 17a9065..9e2f35c 100644 --- a/examples/arrays.vcl +++ b/examples/arrays.vcl @@ -59,7 +59,7 @@ sub vcl_recv { if( req.http.redis_key ) { # Read type param - et req.http.htype = regsub(req.http.redis_key, "^(r|d):(.*)", "\1"); + set req.http.htype = regsub(req.http.redis_key, "^(r|d):(.*)", "\1"); # Read the domain backend from redis if( req.http.htype == "d" ) {