2
0
Fork 0
lighttpd2/src/plugin.c

436 lines
11 KiB
C

#include <lighttpd/base.h>
static gboolean plugin_load_default_option(liServer *srv, liServerOption *sopt);
static void plugin_free_default_options(liServer *srv, liPlugin *p);
static liPlugin* plugin_new(const gchar *name) {
liPlugin *p = g_slice_new0(liPlugin);
p->name = name;
return p;
}
static void plugin_free_options(liServer *srv, liPlugin *p) {
size_t i;
const liPluginOption *po;
liServerOption *so;
if (!p->options) return;
for (i = 0; (po = &p->options[i])->name; i++) {
if (NULL == (so = g_hash_table_lookup(srv->options, po->name))) break;
if (so->p != p) break;
g_hash_table_remove(srv->options, po->name);
}
}
static void plugin_free_actions(liServer *srv, liPlugin *p) {
size_t i;
const liPluginAction *pa;
liServerAction *sa;
if (!p->actions) return;
for (i = 0; (pa = &p->actions[i])->name; i++) {
if (NULL == (sa = g_hash_table_lookup(srv->actions, pa->name))) break;
if (sa->p != p) break;
g_hash_table_remove(srv->actions, pa->name);
}
}
static void plugin_free_setups(liServer *srv, liPlugin *p) {
size_t i;
const liliPluginSetupCB *ps;
liServerSetup *ss;
if (!p->setups) return;
for (i = 0; (ps = &p->setups[i])->name; i++) {
if (NULL == (ss = g_hash_table_lookup(srv->setups, ps->name))) break;
if (ss->p != p) break;
g_hash_table_remove(srv->setups, ps->name);
}
}
void plugin_free(liServer *srv, liPlugin *p) {
if (!p) return;
if (g_atomic_int_get(&srv->state) == LI_SERVER_RUNNING) {
ERROR(srv, "Cannot free plugin '%s' while server is running", p->name);
return;
}
g_hash_table_remove(srv->plugins, p->name);
plugin_free_default_options(srv, p);
plugin_free_options(srv, p);
plugin_free_actions(srv, p);
plugin_free_setups(srv, p);
if (p->free)
p->free(srv, p);
g_slice_free(liPlugin, p);
}
void server_plugins_free(liServer *srv) {
gpointer key, val;
GHashTableIter i;
if (g_atomic_int_get(&srv->state) == LI_SERVER_RUNNING) {
ERROR(srv, "%s", "Cannot free plugins while server is running");
return;
}
g_hash_table_iter_init(&i, srv->plugins);
while (g_hash_table_iter_next(&i, &key, &val)) {
liPlugin *p = (liPlugin*) val;
plugin_free_options(srv, p);
plugin_free_actions(srv, p);
plugin_free_setups(srv, p);
g_slice_free(liPlugin, p);
}
g_hash_table_destroy(srv->plugins);
g_hash_table_destroy(srv->options);
g_hash_table_destroy(srv->actions);
g_hash_table_destroy(srv->setups);
}
liPlugin *plugin_register(liServer *srv, const gchar *name, liPluginInitCB init) {
liPlugin *p;
if (!init) {
ERROR(srv, "Module '%s' needs an init function", name);
return NULL;
}
if (g_atomic_int_get(&srv->state) != LI_SERVER_STARTING) {
ERROR(srv, "Cannot register plugin '%s' after server was started", name);
return NULL;
}
if (g_hash_table_lookup(srv->plugins, name)) {
ERROR(srv, "Module '%s' already registered", name);
return NULL;
}
p = plugin_new(name);
p->id = g_hash_table_size(srv->plugins);
g_hash_table_insert(srv->plugins, (gchar*) p->name, p);
init(srv, p);
p->opt_base_index = g_hash_table_size(srv->options);
if (p->options) {
size_t i;
liServerOption *so;
const liPluginOption *po;
for (i = 0; (po = &p->options[i])->name; i++) {
if (NULL != (so = (liServerOption*)g_hash_table_lookup(srv->options, po->name))) {
ERROR(srv, "Option '%s' already registered by plugin '%s', unloading '%s'",
po->name,
so->p ? so->p->name : "<none>",
p->name);
plugin_free(srv, p);
return NULL;
}
so = g_slice_new0(liServerOption);
so->type = po->type;
so->parse_option = po->parse_option;
so->free_option = po->free_option;
so->index = g_hash_table_size(srv->options);
so->module_index = i;
so->p = p;
so->default_value = po->default_value;
g_hash_table_insert(srv->options, (gchar*) po->name, so);
plugin_load_default_option(srv, so);
}
}
if (p->actions) {
size_t i;
liServerAction *sa;
const liPluginAction *pa;
for (i = 0; (pa = &p->actions[i])->name; i++) {
if (NULL != (sa = (liServerAction*)g_hash_table_lookup(srv->actions, pa->name))) {
ERROR(srv, "Action '%s' already registered by plugin '%s', unloading '%s'",
pa->name,
sa->p ? sa->p->name : "<none>",
p->name);
plugin_free(srv, p);
return NULL;
}
sa = g_slice_new0(liServerAction);
sa->create_action = pa->create_action;
sa->p = p;
g_hash_table_insert(srv->actions, (gchar*) pa->name, sa);
}
}
if (p->setups) {
size_t i;
liServerSetup *ss;
const liliPluginSetupCB *ps;
for (i = 0; (ps = &p->setups[i])->name; i++) {
if (NULL != (ss = (liServerSetup*)g_hash_table_lookup(srv->setups, ps->name))) {
ERROR(srv, "Setup '%s' already registered by plugin '%s', unloading '%s'",
ps->name,
ss->p ? ss->p->name : "<none>",
p->name);
plugin_free(srv, p);
return NULL;
}
ss = g_slice_new0(liServerSetup);
ss->setup = ps->setup;
ss->p = p;
g_hash_table_insert(srv->setups, (gchar*) ps->name, ss);
}
}
return p;
}
static liServerOption* find_option(liServer *srv, const char *name) {
return (liServerOption*) g_hash_table_lookup(srv->options, name);
}
gboolean parse_option(liServer *srv, const char *name, liValue *val, liOptionSet *mark) {
liServerOption *sopt;
if (!srv || !name || !mark) return FALSE;
sopt = find_option(srv, name);
if (!sopt) {
ERROR(srv, "Unknown option '%s'", name);
return FALSE;
}
if (sopt->type != val->type && sopt->type != LI_VALUE_NONE) {
ERROR(srv, "Unexpected value type '%s', expected '%s' for option %s",
value_type_string(val->type), value_type_string(sopt->type), name);
return FALSE;
}
if (!sopt->parse_option) {
mark->value = value_extract(val);
} else {
if (!sopt->parse_option(srv, sopt->p, sopt->module_index, val, &mark->value)) {
/* errors should be logged by parse function */
return FALSE;
}
}
mark->ndx = sopt->index;
mark->sopt = sopt;
return TRUE;
}
void release_option(liServer *srv, liOptionSet *mark) { /** Does not free the option_set memory */
liServerOption *sopt;
if (!srv || !mark || !mark->sopt) return;
sopt = mark->sopt;
mark->sopt = NULL;
if (!sopt->free_option) {
switch (sopt->type) {
case LI_VALUE_NONE:
case LI_VALUE_BOOLEAN:
case LI_VALUE_NUMBER:
/* Nothing to free */
break;
case LI_VALUE_STRING:
if (mark->value.string)
g_string_free(mark->value.string, TRUE);
break;
case LI_VALUE_LIST:
if (mark->value.list)
value_list_free(mark->value.list);
break;
case LI_VALUE_HASH:
if (mark->value.hash)
g_hash_table_destroy(mark->value.hash);
break;
case LI_VALUE_ACTION:
if (mark->value.action)
action_release(srv, mark->value.action);
break;
case LI_VALUE_CONDITION:
if (mark->value.cond)
condition_release(srv, mark->value.cond);
break;
}
} else {
sopt->free_option(srv, sopt->p, sopt->module_index, mark->value);
}
{
liOptionValue empty = {0};
mark->value = empty;
}
}
liAction* option_action(liServer *srv, const gchar *name, liValue *val) {
liOptionSet setting;
if (!parse_option(srv, name, val, &setting)) {
return NULL;
}
return action_new_setting(setting);
}
liAction* create_action(liServer *srv, const gchar *name, liValue *val) {
liAction *a;
liServerAction *sa;
if (NULL == (sa = (liServerAction*) g_hash_table_lookup(srv->actions, name))) {
ERROR(srv, "Action '%s' doesn't exist", name);
return NULL;
}
if (NULL == (a = sa->create_action(srv, sa->p, val))) {
ERROR(srv, "Action '%s' creation failed", name);
return NULL;
}
return a;
}
gboolean call_setup(liServer *srv, const char *name, liValue *val) {
liServerSetup *ss;
if (NULL == (ss = (liServerSetup*) g_hash_table_lookup(srv->setups, name))) {
ERROR(srv, "Setup function '%s' doesn't exist", name);
return FALSE;
}
if (!ss->setup(srv, ss->p, val)) {
ERROR(srv, "Setup '%s' failed", name);
return FALSE;
}
return TRUE;
}
void plugins_prepare_callbacks(liServer *srv) {
GHashTableIter iter;
liPlugin *p;
gpointer v;
g_hash_table_iter_init(&iter, srv->plugins);
while (g_hash_table_iter_next(&iter, NULL, &v)) {
p = (liPlugin*) v;
if (p->handle_close)
g_array_append_val(srv->plugins_handle_close, p);
if (p->handle_vrclose)
g_array_append_val(srv->plugins_handle_vrclose, p);
}
}
void plugins_handle_close(liConnection *con) {
GArray *a = con->srv->plugins_handle_close;
guint i, len = a->len;
for (i = 0; i < len; i++) {
liPlugin *p = g_array_index(a, liPlugin*, i);
p->handle_close(con, p);
}
}
void plugins_handle_vrclose(liVRequest *vr) {
GArray *a = vr->wrk->srv->plugins_handle_vrclose;
guint i, len = a->len;
for (i = 0; i < len; i++) {
liPlugin *p = g_array_index(a, liPlugin*, i);
p->handle_vrclose(vr, p);
}
}
gboolean plugin_set_default_option(liServer *srv, const gchar* name, liValue *val) {
liServerOption *sopt;
liOptionSet setting;
liOptionValue v;
sopt = find_option(srv, name);
if (!sopt) {
ERROR(srv, "unknown option \"%s\"", name);
return FALSE;
}
/* assign new value */
if (!parse_option(srv, name, val, &setting)) {
return FALSE;
}
v = g_array_index(srv->option_def_values, liOptionValue, sopt->index);
g_array_index(srv->option_def_values, liOptionValue, sopt->index) = setting.value;
/* free old value */
setting.sopt = sopt;
setting.ndx = sopt->index;
setting.value = v;
release_option(srv, &setting);
return TRUE;
}
static gboolean plugin_load_default_option(liServer *srv, liServerOption *sopt) {
liOptionValue oval = {0};
if (!sopt)
return FALSE;
if (!sopt->parse_option) {
switch (sopt->type) {
case LI_VALUE_NONE:
break;
case LI_VALUE_BOOLEAN:
oval.boolean = GPOINTER_TO_INT(sopt->default_value);
case LI_VALUE_NUMBER:
oval.number = GPOINTER_TO_INT(sopt->default_value);
break;
case LI_VALUE_STRING:
oval.string = g_string_new((const char*) sopt->default_value);
break;
default:
oval.ptr = NULL;
}
} else {
if (!sopt->parse_option(srv, sopt->p, sopt->module_index, NULL, &oval)) {
/* errors should be logged by parse function */
return FALSE;
}
}
if (srv->option_def_values->len <= sopt->index)
g_array_set_size(srv->option_def_values, sopt->index + 1);
g_array_index(srv->option_def_values, liOptionValue, sopt->index) = oval;
return TRUE;
}
static void plugin_free_default_options(liServer *srv, liPlugin *p) {
static const liOptionValue oempty = {0};
GHashTableIter iter;
gpointer k, v;
g_hash_table_iter_init(&iter, srv->options);
while (g_hash_table_iter_next(&iter, &k, &v)) {
liServerOption *sopt = v;
liOptionSet mark;
mark.sopt = sopt;
mark.ndx = sopt->index;
if (sopt->p != p)
continue;
mark.value = g_array_index(srv->option_def_values, liOptionValue, sopt->index);
release_option(srv, &mark);
g_array_index(srv->option_def_values, liOptionValue, sopt->index) = oempty;
}
}