|
|
|
@ -1866,6 +1866,124 @@ static liAction* core_throttle_connection(liServer *srv, liWorker *wrk, liPlugin
|
|
|
|
|
return li_action_new_function(core_handle_throttle_connection, NULL, core_throttle_connection_free, param);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct core_map_data core_map_data;
|
|
|
|
|
struct core_map_data {
|
|
|
|
|
liPattern *pattern;
|
|
|
|
|
GHashTable *hash;
|
|
|
|
|
liAction *default_action;
|
|
|
|
|
};
|
|
|
|
|
static void core_map_free(liServer *srv, gpointer param) {
|
|
|
|
|
core_map_data *md = param;
|
|
|
|
|
|
|
|
|
|
UNUSED(srv);
|
|
|
|
|
|
|
|
|
|
if (md->default_action)
|
|
|
|
|
li_action_release(srv, md->default_action);
|
|
|
|
|
|
|
|
|
|
li_pattern_free(md->pattern);
|
|
|
|
|
g_hash_table_destroy(md->hash);
|
|
|
|
|
g_slice_free(core_map_data, md);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static liHandlerResult core_handle_map(liVRequest *vr, gpointer param, gpointer *context) {
|
|
|
|
|
liValue *v;
|
|
|
|
|
core_map_data *md = param;
|
|
|
|
|
|
|
|
|
|
UNUSED(context);
|
|
|
|
|
|
|
|
|
|
g_string_truncate(vr->wrk->tmp_str, 0);
|
|
|
|
|
li_pattern_eval(vr, vr->wrk->tmp_str, md->pattern, NULL, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
v = g_hash_table_lookup(md->hash, vr->wrk->tmp_str);
|
|
|
|
|
if (v)
|
|
|
|
|
li_action_enter(vr, v->data.val_action.action);
|
|
|
|
|
else if (md->default_action)
|
|
|
|
|
li_action_enter(vr, md->default_action);
|
|
|
|
|
|
|
|
|
|
return LI_HANDLER_GO_ON;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static liAction* core_map(liServer *srv, liWorker *wrk, liPlugin* p, liValue *val, gpointer userdata) {
|
|
|
|
|
core_map_data *md;
|
|
|
|
|
guint i;
|
|
|
|
|
liValue *list, *l, *r, *v;
|
|
|
|
|
liPattern *pattern;
|
|
|
|
|
|
|
|
|
|
UNUSED(wrk); UNUSED(p); UNUSED(userdata);
|
|
|
|
|
|
|
|
|
|
if (!val || val->type != LI_VALUE_LIST || val->data.list->len != 2) {
|
|
|
|
|
ERROR(srv, "%s", "'map' action expects a string => (list of key => action pairs) as parameter");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
l = g_array_index(val->data.list, liValue*, 0);
|
|
|
|
|
r = g_array_index(val->data.list, liValue*, 1);
|
|
|
|
|
if (l->type != LI_VALUE_STRING || r->type != LI_VALUE_LIST) {
|
|
|
|
|
ERROR(srv, "%s", "'map' action expects a string => (list of key => action pairs) as parameter");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pattern = li_pattern_new(srv, l->data.string->str);
|
|
|
|
|
if (!pattern) {
|
|
|
|
|
ERROR(srv, "'map' action: failed to compile pattern '%s'", l->data.string->str);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
md = g_slice_new(core_map_data);
|
|
|
|
|
md->pattern = pattern;
|
|
|
|
|
md->default_action = NULL;
|
|
|
|
|
md->hash = g_hash_table_new_full(
|
|
|
|
|
(GHashFunc) g_string_hash, (GEqualFunc) g_string_equal,
|
|
|
|
|
(GDestroyNotify) li_string_destroy_notify, (GDestroyNotify) li_value_free);
|
|
|
|
|
|
|
|
|
|
list = r;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < list->data.list->len; i++) {
|
|
|
|
|
v = g_array_index(list->data.list, liValue*, i);
|
|
|
|
|
|
|
|
|
|
if (v->type != LI_VALUE_LIST || v->data.list->len != 2) {
|
|
|
|
|
ERROR(srv, "%s", "'map' action expects a string => (list of key => action pairs) as parameter");
|
|
|
|
|
core_map_free(srv, md);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
l = g_array_index(v->data.list, liValue*, 0);
|
|
|
|
|
r = g_array_index(v->data.list, liValue*, 1);
|
|
|
|
|
|
|
|
|
|
if (r->type != LI_VALUE_ACTION) {
|
|
|
|
|
ERROR(srv, "%s", "'map' action expects a string => (list of key => action pairs) as parameter");
|
|
|
|
|
core_map_free(srv, md);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (l->type == LI_VALUE_NONE) {
|
|
|
|
|
/* default action */
|
|
|
|
|
md->default_action = li_value_extract_action(r);
|
|
|
|
|
} else if (l->type == LI_VALUE_STRING) {
|
|
|
|
|
/* string => action */
|
|
|
|
|
g_hash_table_insert(md->hash, li_value_extract_string(l), li_value_copy(r));
|
|
|
|
|
} else if (l->type == LI_VALUE_LIST) {
|
|
|
|
|
/* (string, string, ...) => action */
|
|
|
|
|
guint j;
|
|
|
|
|
liValue *v2;
|
|
|
|
|
|
|
|
|
|
for (j = 0; j < l->data.list->len; j++) {
|
|
|
|
|
v2 = g_array_index(l->data.list, liValue*, j);
|
|
|
|
|
|
|
|
|
|
if (v2->type != LI_VALUE_STRING) {
|
|
|
|
|
ERROR(srv, "%s", "'map' action expects a string => (list of key => action pairs) as parameter");
|
|
|
|
|
core_map_free(srv, md);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_hash_table_insert(md->hash, li_value_extract_string(v2), li_value_copy(r));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return li_action_new_function(core_handle_map, NULL, core_map_free, md);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void core_warmup(liServer *srv, liPlugin *p, gint32 id, GString *data) {
|
|
|
|
|
UNUSED(p);
|
|
|
|
|
UNUSED(id);
|
|
|
|
@ -1953,6 +2071,8 @@ static const liPluginAction actions[] = {
|
|
|
|
|
{ "io.throttle_pool", core_throttle_pool, NULL },
|
|
|
|
|
{ "io.throttle_ip", core_throttle_ip, NULL },
|
|
|
|
|
|
|
|
|
|
{ "map", core_map, NULL },
|
|
|
|
|
|
|
|
|
|
{ NULL, NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|