Repository URL to install this package:
|
Version:
2.0.17 ▾
|
#include <uwsgi.h>
#ifdef UWSGI_ROUTING
extern struct uwsgi_server uwsgi;
/*
by Unbit
syntax:
route = /^foobar1(.*)/ hash:key=foo$1poo,algo=murmur2,var=MYHASH,items=node1;node2;node3
*/
struct uwsgi_router_hash_conf {
char *key;
size_t key_len;
char *var;
size_t var_len;
char *algo;
char *items;
size_t items_len;
};
static int uwsgi_routing_func_hash(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
struct uwsgi_router_hash_conf *urhc = (struct uwsgi_router_hash_conf *) ur->data2;
struct uwsgi_hash_algo *uha = uwsgi_hash_algo_get(urhc->algo);
if (!uha) {
uwsgi_log("[uwsgi-hash-router] unable to find hash algo \"%s\"\n", urhc->algo);
return UWSGI_ROUTE_BREAK;
}
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urhc->key, urhc->key_len);
if (!ub) return UWSGI_ROUTE_BREAK;
uint32_t h = uha->func(ub->buf, ub->pos);
uwsgi_buffer_destroy(ub);
// now count the number of items
uint32_t items = 1;
size_t i, ilen = urhc->items_len;
for(i=0;i<ilen;i++) {
if (urhc->items[i] == ';') items++;
}
// skip last semicolon
if (urhc->items[ilen-1] == ';') items--;
if (items < 1) return UWSGI_ROUTE_BREAK;
uint32_t hashed_result = h % items;
uint32_t found = 0;
char *value = urhc->items;
uint16_t vallen = 0;
for(i=0;i<ilen;i++) {
if (!value) {
value = urhc->items + i;
}
if (urhc->items[i] == ';') {
if (found == hashed_result) {
vallen = (urhc->items+i) - value;
break;
}
value = NULL;
found++;
}
}
if (vallen == 0) {
// first item
if (hashed_result == 0) {
value = urhc->items;
vallen = urhc->items_len;
}
// last item
else if (value != NULL) {
vallen = (urhc->items + urhc->items_len) - value;
}
}
if (!vallen) {
uwsgi_log("[uwsgi-hash-router] BUG !!! unable to hash items\n");
return UWSGI_ROUTE_BREAK;
}
if (!uwsgi_req_append(wsgi_req, urhc->var, urhc->var_len, value, vallen)) {
uwsgi_log("[uwsgi-hash-router] unable to append hash var to the request\n");
return UWSGI_ROUTE_BREAK;
}
return UWSGI_ROUTE_NEXT;
}
static int uwsgi_router_hash(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_hash;
ur->data = args;
ur->data_len = strlen(args);
struct uwsgi_router_hash_conf *urhc = uwsgi_calloc(sizeof(struct uwsgi_router_hash_conf));
if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=',
"key", &urhc->key,
"var", &urhc->var,
"algo", &urhc->algo,
"items", &urhc->items,
NULL)) {
uwsgi_log("invalid route syntax: %s\n", args);
exit(1);
}
if (!urhc->key || !urhc->var || !urhc->items) {
uwsgi_log("invalid route syntax: you need to specify a hash key, a var and a set of items\n");
exit(1);
}
urhc->key_len = strlen(urhc->key);
urhc->var_len = strlen(urhc->var);
urhc->items_len = strlen(urhc->items);
if (!urhc->algo) urhc->algo = "djb33x";
ur->data2 = urhc;
return 0;
}
static void router_hash_register() {
uwsgi_register_router("hash", uwsgi_router_hash);
}
struct uwsgi_plugin router_hash_plugin = {
.name = "router_hash",
.on_load = router_hash_register,
};
#else
struct uwsgi_plugin router_hash_plugin = {
.name = "router_hash",
};
#endif