Browse Source

[mod_vhost] Implement vhost.map_regex action

personal/stbuehler/wip
Thomas Porzelt 13 years ago
parent
commit
45d91e48e4
  1. 165
      src/modules/mod_vhost.c

165
src/modules/mod_vhost.c

@ -19,7 +19,7 @@
* - lookup action by using the hostname as the key of the hashtable
* - if not found, use default action
* - fast and flexible but no matching on hostnames possible
* (todo) vhost.map_regex ["host1regex": action1, "host2regex": action2, "default": action0];
* vhost.map_regex ["host1regex": action1, "host2regex": action2, "default": action0];
* - lookup action by traversing the list and applying a regex match of the hostname on each entry
* - if no match, use default action
* - slowest method but the most flexible one
@ -87,6 +87,22 @@ struct vhost_map_data {
};
typedef struct vhost_map_data vhost_map_data;
struct vhost_map_regex_entry {
GRegex *regex;
liValue *action;
ev_tstamp tstamp;
guint hits;
guint hits_30s;
};
typedef struct vhost_map_regex_entry vhost_map_regex_entry;
struct vhost_map_regex_data {
liPlugin *plugin;
GArray *list; /* array of vhost_map_regex_entry */
liValue *default_action;
};
typedef struct vhost_map_regex_data vhost_map_regex_data;
struct vhost_pattern_part {
enum {
VHOST_PATTERN_STRING,
@ -318,6 +334,152 @@ static liAction* vhost_map_create(liServer *srv, liPlugin* p, liValue *val) {
return li_action_new_function(vhost_map, NULL, vhost_map_free, md);
}
static liHandlerResult vhost_map_regex(liVRequest *vr, gpointer param, gpointer *context) {
liValue *v;
vhost_map_regex_entry *entry;
guint i;
ev_tstamp now;
vhost_map_regex_data *mrd = param;
gboolean debug = _OPTION(vr, mrd->plugin, 0).boolean;
UNUSED(context);
/* loop through all rules to find a match */
for (i = 0; i < mrd->list->len; i++) {
entry = &g_array_index(mrd->list, vhost_map_regex_entry, i);
if (!g_regex_match(entry->regex, vr->request.uri.host->str, 0, NULL))
continue;
v = entry->action;
/* match found, update stats */
now = CUR_TS(vr->wrk);
entry->hits++;
if ((now - entry->tstamp) > 30.0) {
vhost_map_regex_entry *entry_prev, entry_tmp;
entry->tstamp = now;
entry->hits_30s = entry->hits;
entry->hits = 0;
if (i) {
entry_prev = &g_array_index(mrd->list, vhost_map_regex_entry, i-1);
if ((now - entry_prev->tstamp) > 30.0) {
entry_prev->tstamp = now;
entry_prev->hits_30s = entry_prev->hits;
entry_prev->hits = 0;
}
/* reorder list and put entries with more hits at the beginning */
if (entry->hits_30s > entry_prev->hits_30s) {
/* swap entry and entry_prev */
entry_tmp = *entry_prev;
g_array_index(mrd->list, vhost_map_regex_entry, i-1) = *entry;
g_array_index(mrd->list, vhost_map_regex_entry, i) = entry_tmp;
entry = &g_array_index(mrd->list, vhost_map_regex_entry, i-1);
}
}
}
break;
}
if (v) {
if (debug)
VR_DEBUG(vr, "vhost_map_regex: host %s matches pattern \"%s\"", vr->request.uri.host->str, g_regex_get_pattern(entry->regex));
li_action_enter(vr, v->data.val_action.action);
} else if (mrd->default_action) {
if (debug)
VR_DEBUG(vr, "vhost_map_regex: host %s didn't match, executing default action", vr->request.uri.host->str);
li_action_enter(vr, mrd->default_action->data.val_action.action);
} else {
if (debug)
VR_DEBUG(vr, "vhost_map_regex: neither did %s match nor default action specified, doing nothing", vr->request.uri.host->str);
}
return LI_HANDLER_GO_ON;
}
static void vhost_map_regex_free(liServer *srv, gpointer param) {
guint i;
vhost_map_regex_entry *entry;
vhost_map_regex_data *mrd = param;
UNUSED(srv);
for (i = 0; i < mrd->list->len; i++) {
entry = &g_array_index(mrd->list, vhost_map_regex_entry, i);
g_regex_unref(entry->regex);
li_value_free(entry->action);
}
g_array_free(mrd->list, TRUE);
if (mrd->default_action)
li_value_free(mrd->default_action);
g_slice_free(vhost_map_regex_data, mrd);
}
static liAction* vhost_map_regex_create(liServer *srv, liPlugin* p, liValue *val) {
GHashTable *hash;
GHashTableIter iter;
gpointer k, v;
vhost_map_regex_data *mrd;
vhost_map_regex_entry entry;
GError *err = NULL;
if (!val || val->type != LI_VALUE_HASH) {
ERROR(srv, "%s", "vhost.map_regex expects a hashtable as parameter");
return NULL;
}
mrd = g_slice_new0(vhost_map_regex_data);
mrd->plugin = p;
mrd->list = g_array_new(FALSE, FALSE, sizeof(vhost_map_regex_entry));
hash = val->data.hash;
/* check if every value in the hashtable is an action */
g_hash_table_iter_init(&iter, hash);
while (g_hash_table_iter_next(&iter, &k, &v)) {
val = v;
if (val->type != LI_VALUE_ACTION) {
ERROR(srv, "vhost.map_regex expects a hashtable with action values as parameter, %s value given", li_value_type_string(val->type));
vhost_map_regex_free(srv, mrd);
return NULL;
}
if (g_str_equal(((GString*)k)->str, "default")) {
mrd->default_action = li_value_copy(val);
continue;
}
entry.hits = 0;
entry.hits_30s = 0;
entry.tstamp = 0.0;
entry.regex = g_regex_new(((GString*)k)->str, G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, &err);
if (!entry.regex || err) {
vhost_map_regex_free(srv, mrd);
ERROR(srv, "vhost.map_regex: error compiling regex \"%s\": %s", ((GString*)k)->str, err->message);
g_error_free(err);
return NULL;
}
entry.action = li_value_copy(val);
g_array_append_val(mrd->list, entry);
}
return li_action_new_function(vhost_map_regex, NULL, vhost_map_regex_free, mrd);
}
static liHandlerResult vhost_pattern(liVRequest *vr, gpointer param, gpointer *context) {
GArray *parts = g_array_sized_new(FALSE, TRUE, sizeof(vhost_pattern_hostpart), 6);
vhost_pattern_data *pattern = param;
@ -521,6 +683,7 @@ static const liPluginOption options[] = {
static const liPluginAction actions[] = {
{ "vhost.simple", vhost_simple_create },
{ "vhost.map", vhost_map_create },
{ "vhost.map_regex", vhost_map_regex_create },
{ "vhost.pattern", vhost_pattern_create },
{ NULL, NULL }

Loading…
Cancel
Save