diff --git a/src/mod_cml.c b/src/mod_cml.c index aa448eb3..2d620d66 100644 --- a/src/mod_cml.c +++ b/src/mod_cml.c @@ -14,194 +14,189 @@ #include #include -/* init the plugin data */ INIT_FUNC(mod_cml_init) { - plugin_data *p; - - p = calloc(1, sizeof(*p)); + return calloc(1, sizeof(plugin_data)); +} - p->basedir = buffer_init(); - p->baseurl = buffer_init(); - p->trigger_handler = buffer_init(); +static void mod_cml_free_config(plugin_data * const p) { + if (NULL == p->cvlist) return; + #if defined(USE_MEMCACHED) + /* (init i to 0 if global context; to 1 to skip empty global context) */ + for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) { + config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0]; + for (; -1 != cpv->k_id; ++cpv) { + switch (cpv->k_id) { + case 1: /* cml.memcache-hosts */ + if (cpv->vtype == T_CONFIG_LOCAL && NULL != cpv->v.v) + memcached_free(cpv->v.v); /* mod_cml_free_memcached() */ + break; + default: + break; + } + } + } + #endif +} - return p; +static int mod_cml_init_memcached(server *srv, config_plugin_value_t * const cpv) { + const array * const mc_hosts = cpv->v.a; + if (0 == mc_hosts->used) { + cpv->v.v = NULL; + return 1; + } + + #if defined(USE_MEMCACHED) + + buffer * const opts = srv->tmp_buf; + buffer_clear(opts); + for (uint32_t k = 0; k < mc_hosts->used; ++k) { + const data_string * const ds = (const data_string *)mc_hosts->data[k]; + buffer_append_string_len(opts, CONST_STR_LEN(" --SERVER=")); + buffer_append_string_buffer(opts, &ds->value); + } + + cpv->v.v = memcached(opts->ptr+1, buffer_string_length(opts)-1); + + if (cpv->v.v) { + cpv->vtype = T_CONFIG_LOCAL; + return 1; + } + else { + log_error(srv->errh, __FILE__, __LINE__, + "configuring memcached failed for option string: %s", opts->ptr); + return 0; + } + + #else + + log_error(srv->errh, __FILE__, __LINE__, + "memcache support is not compiled in but cml.memcache-hosts is set, " + "aborting"); + return 0; + + #endif } -/* detroy the plugin data */ FREE_FUNC(mod_cml_free) { - plugin_data *p = p_d; - - UNUSED(srv); - - if (!p) return HANDLER_GO_ON; - - if (p->config_storage) { - size_t i; - for (i = 0; i < srv->config_context->used; i++) { - plugin_config *s = p->config_storage[i]; - - if (NULL == s) continue; - - buffer_free(s->ext); - - buffer_free(s->mc_namespace); - buffer_free(s->power_magnet); - array_free(s->mc_hosts); + plugin_data * const p = p_d; + if (!p) return HANDLER_GO_ON; + UNUSED(srv); -#if defined(USE_MEMCACHED) - if (s->memc) memcached_free(s->memc); -#endif + free(p->trigger_handler.ptr); + free(p->basedir.ptr); + free(p->baseurl.ptr); - free(s); - } - free(p->config_storage); - } - - buffer_free(p->trigger_handler); - buffer_free(p->basedir); - buffer_free(p->baseurl); + mod_cml_free_config(p); - free(p); + free(p->cvlist); + free(p); - return HANDLER_GO_ON; + return HANDLER_GO_ON; } -/* handle plugin config and check values */ - -SETDEFAULTS_FUNC(mod_cml_set_defaults) { - plugin_data *p = p_d; - size_t i = 0; - - config_values_t cv[] = { - { "cml.extension", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ - { "cml.memcache-hosts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ - { "cml.memcache-namespace", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ - { "cml.power-magnet", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */ - { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } - }; - - if (!p) return HANDLER_ERROR; - - p->config_storage = calloc(srv->config_context->used, sizeof(plugin_config *)); - - for (i = 0; i < srv->config_context->used; i++) { - data_config const* config = (data_config const*)srv->config_context->data[i]; - plugin_config *s; - - s = calloc(1, sizeof(plugin_config)); - s->ext = buffer_init(); - s->mc_hosts = array_init(); - s->mc_namespace = buffer_init(); - s->power_magnet = buffer_init(); -#if defined(USE_MEMCACHED) - s->memc = NULL; -#endif - - cv[0].destination = s->ext; - cv[1].destination = s->mc_hosts; - cv[2].destination = s->mc_namespace; - cv[3].destination = s->power_magnet; - - p->config_storage[i] = s; - - if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) { - return HANDLER_ERROR; - } - - if (!array_is_vlist(s->mc_hosts)) { - log_error_write(srv, __FILE__, __LINE__, "s", - "unexpected value for cml.memcache-hosts; expected list of \"host\""); - return HANDLER_ERROR; - } - - if (s->mc_hosts->used) { -#if defined(USE_MEMCACHED) - buffer *option_string = buffer_init(); - size_t k; - - { - data_string *ds = (data_string *)s->mc_hosts->data[0]; - - buffer_append_string_len(option_string, CONST_STR_LEN("--SERVER=")); - buffer_append_string_buffer(option_string, &ds->value); - } - - for (k = 1; k < s->mc_hosts->used; k++) { - data_string *ds = (data_string *)s->mc_hosts->data[k]; - - buffer_append_string_len(option_string, CONST_STR_LEN(" --SERVER=")); - buffer_append_string_buffer(option_string, &ds->value); - } - - s->memc = memcached(CONST_BUF_LEN(option_string)); - - if (NULL == s->memc) { - log_error_write(srv, __FILE__, __LINE__, "sb", - "configuring memcached failed for option string:", - option_string); - } - buffer_free(option_string); - - if (NULL == s->memc) return HANDLER_ERROR; -#else - log_error_write(srv, __FILE__, __LINE__, "s", - "memcache support is not compiled in but cml.memcache-hosts is set, aborting"); - return HANDLER_ERROR; -#endif - } - } +static void mod_cml_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) { + switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */ + case 0: /* cml.extension */ + pconf->ext = cpv->v.b; + break; + case 1: /* cml.memcache-hosts *//* setdefaults inits memcached_st *memc */ + #if defined(USE_MEMCACHED) + if (cpv->vtype != T_CONFIG_LOCAL) break; + pconf->memc = cpv->v.v; + #endif + break; + case 2: /* cml.memcache-namespace */ + /*pconf->mc_namespace = cpv->v.b;*//*(unused)*/ + break; + case 3: /* cml.power-magnet */ + pconf->power_magnet = cpv->v.b; + break; + default:/* should not happen */ + return; + } +} - return HANDLER_GO_ON; +static void mod_cml_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) { + do { + mod_cml_merge_config_cpv(pconf, cpv); + } while ((++cpv)->k_id != -1); } -#define PATCH(x) \ - p->conf.x = s->x; -static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p) { - size_t i, j; - plugin_config *s = p->config_storage[0]; - - PATCH(ext); -#if defined(USE_MEMCACHED) - PATCH(memc); -#endif - PATCH(mc_namespace); - PATCH(power_magnet); - - /* skip the first, the global context */ - for (i = 1; i < srv->config_context->used; i++) { - if (!config_check_cond(con, i)) continue; /* condition not matched */ - - data_config *dc = (data_config *)srv->config_context->data[i]; - s = p->config_storage[i]; - - /* merge config */ - for (j = 0; j < dc->value->used; j++) { - data_unset *du = dc->value->data[j]; - - if (buffer_is_equal_string(&du->key, CONST_STR_LEN("cml.extension"))) { - PATCH(ext); - } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("cml.memcache-hosts"))) { -#if defined(USE_MEMCACHED) - PATCH(memc); -#endif - } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("cml.memcache-namespace"))) { - PATCH(mc_namespace); - } else if (buffer_is_equal_string(&du->key, CONST_STR_LEN("cml.power-magnet"))) { - PATCH(power_magnet); - } - } - } +static void mod_cml_patch_config(connection * const con, plugin_data * const p) { + memcpy(&p->conf, &p->defaults, sizeof(plugin_config)); + for (int i = 1, used = p->nconfig; i < used; ++i) { + if (config_check_cond(con, (uint32_t)p->cvlist[i].k_id)) + mod_cml_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]); + } +} - return 0; +SETDEFAULTS_FUNC(mod_cml_set_defaults) { + static const config_plugin_keys_t cpk[] = { + { CONST_STR_LEN("cml.extension"), + T_CONFIG_STRING, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("cml.memcache-hosts"), + T_CONFIG_ARRAY, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("cml.memcache-namespace"), /*(unused)*/ + T_CONFIG_STRING, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("cml.power-magnet"), + T_CONFIG_STRING, + T_CONFIG_SCOPE_CONNECTION } + ,{ NULL, 0, + T_CONFIG_UNSET, + T_CONFIG_SCOPE_UNSET } + }; + + plugin_data * const p = p_d; + if (!config_plugin_values_init(srv, p, cpk, "mod_cml")) + return HANDLER_ERROR; + + /* process and validate config directives + * (init i to 0 if global context; to 1 to skip empty global context) */ + for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) { + config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0]; + for (; -1 != cpv->k_id; ++cpv) { + switch (cpv->k_id) { + case 0: /* cml.extension */ + break; + case 1: /* cml.memcache-hosts */ /* config converted to memc handles */ + if (!array_is_vlist(cpv->v.a)) { + log_error(srv->errh, __FILE__, __LINE__, + "unexpected value for %s; " + "expected list of \"host\"", cpk[cpv->k_id].k); + return HANDLER_ERROR; + } + if (!mod_cml_init_memcached(srv, cpv)) { + return HANDLER_ERROR; + } + break; + case 2: /* cml.memcache-namespace *//*(unused)*/ + case 3: /* cml.power-magnet */ + break; + default:/* should not happen */ + break; + } + } + } + + /* initialize p->defaults from global config context */ + if (p->nconfig > 0 && p->cvlist->v.u2[1]) { + const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0]; + if (-1 != cpv->k_id) + mod_cml_merge_config(&p->defaults, cpv); + } + + return HANDLER_GO_ON; } -#undef PATCH -static int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) { +static int cache_call_lua(server *srv, connection *con, plugin_data *p, const buffer *cml_file) { buffer *b; char *c; /* cleanup basedir */ - b = p->baseurl; + b = &p->baseurl; buffer_copy_buffer(b, con->uri.path); for (c = b->ptr + buffer_string_length(b); c > b->ptr && *c != '/'; c--); @@ -209,7 +204,7 @@ static int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer * buffer_string_set_length(b, c - b->ptr + 1); } - b = p->basedir; + b = &p->basedir; buffer_copy_buffer(b, con->physical.path); for (c = b->ptr + buffer_string_length(b); c > b->ptr && *c != '/'; c--); @@ -228,14 +223,14 @@ static int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer * URIHANDLER_FUNC(mod_cml_power_magnet) { plugin_data *p = p_d; - mod_cml_patch_connection(srv, con, p); - - buffer_clear(p->basedir); - buffer_clear(p->baseurl); - buffer_clear(p->trigger_handler); + mod_cml_patch_config(con, p); if (buffer_string_is_empty(p->conf.power_magnet)) return HANDLER_GO_ON; + buffer_clear(&p->basedir); + buffer_clear(&p->baseurl); + buffer_clear(&p->trigger_handler); + /* * power-magnet: * cml.power-magnet = server.docroot + "/rewrite.cml" @@ -282,11 +277,7 @@ URIHANDLER_FUNC(mod_cml_is_handled) { if (buffer_string_is_empty(con->physical.path)) return HANDLER_ERROR; - mod_cml_patch_connection(srv, con, p); - - buffer_clear(p->basedir); - buffer_clear(p->baseurl); - buffer_clear(p->trigger_handler); + mod_cml_patch_config(con, p); if (buffer_string_is_empty(p->conf.ext)) return HANDLER_GO_ON; @@ -294,6 +285,10 @@ URIHANDLER_FUNC(mod_cml_is_handled) { return HANDLER_GO_ON; } + buffer_clear(&p->basedir); + buffer_clear(&p->baseurl); + buffer_clear(&p->trigger_handler); + switch(cache_call_lua(srv, con, p, con->physical.path)) { case -1: /* error */ @@ -321,6 +316,7 @@ URIHANDLER_FUNC(mod_cml_is_handled) { } } + int mod_cml_plugin_init(plugin *p); int mod_cml_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; diff --git a/src/mod_cml.h b/src/mod_cml.h index d1d0c52a..a2a4f0be 100644 --- a/src/mod_cml.h +++ b/src/mod_cml.h @@ -14,29 +14,24 @@ #define plugin_data mod_cache_plugin_data typedef struct { - buffer *ext; - - array *mc_hosts; - buffer *mc_namespace; -#if defined(USE_MEMCACHED) - memcached_st *memc; -#endif - buffer *power_magnet; + const buffer *ext; + const buffer *power_magnet; + /*const buffer *mc_namespace;*//*(unused)*/ + #if defined(USE_MEMCACHED) + memcached_st *memc; + #endif } plugin_config; typedef struct { - PLUGIN_DATA; - - buffer *basedir; - buffer *baseurl; - - buffer *trigger_handler; - - plugin_config **config_storage; + PLUGIN_DATA; + plugin_config defaults; + plugin_config conf; - plugin_config conf; + buffer basedir; + buffer baseurl; + buffer trigger_handler; } plugin_data; -int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn); +int cache_parse_lua(server *srv, connection *con, plugin_data *p, const buffer *fn); #endif diff --git a/src/mod_cml_lua.c b/src/mod_cml_lua.c index ba786f33..41ea2842 100644 --- a/src/mod_cml_lua.c +++ b/src/mod_cml_lua.c @@ -101,7 +101,7 @@ static int cache_export_get_params(lua_State *L, int tbl, buffer *qrystr) { return 0; } -int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { +int cache_parse_lua(server *srv, connection *con, plugin_data *p, const buffer *fn) { lua_State *L; int ret = -1; buffer *b; @@ -145,8 +145,8 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { c_to_lua_push(L, header_tbl, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo)); } - c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(p->basedir)); - c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(p->baseurl)); + c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(&p->basedir)); + c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(&p->baseurl)); } lua_setglobal(L, "request"); @@ -187,7 +187,7 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { lua_pop(L, 1); /* fetch the data from lua */ - lua_to_c_get_string(L, "trigger_handler", p->trigger_handler); + lua_to_c_get_string(L, "trigger_handler", &p->trigger_handler); if (0 == lua_to_c_get_string(L, "output_contenttype", b)) { http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(b)); @@ -230,7 +230,7 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { /* the file is relative, make it absolute */ if (s[0] != '/') { - buffer_copy_buffer(b, p->basedir); + buffer_copy_buffer(b, &p->basedir); buffer_append_string(b, lua_tostring(L, -1)); } else { buffer_copy_string(b, lua_tostring(L, -1)); @@ -243,7 +243,7 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { switch(errno) { case ENOENT: /* a file is missing, call the handler to generate it */ - if (!buffer_string_is_empty(p->trigger_handler)) { + if (!buffer_string_is_empty(&p->trigger_handler)) { ret = 1; /* cache-miss */ log_error_write(srv, __FILE__, __LINE__, "s", @@ -305,13 +305,13 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { } } - if (ret == 1 && !buffer_string_is_empty(p->trigger_handler)) { + if (ret == 1 && !buffer_string_is_empty(&p->trigger_handler)) { /* cache-miss */ - buffer_copy_buffer(con->uri.path, p->baseurl); - buffer_append_string_buffer(con->uri.path, p->trigger_handler); + buffer_copy_buffer(con->uri.path, &p->baseurl); + buffer_append_string_buffer(con->uri.path, &p->trigger_handler); - buffer_copy_buffer(con->physical.path, p->basedir); - buffer_append_string_buffer(con->physical.path, p->trigger_handler); + buffer_copy_buffer(con->physical.path, &p->basedir); + buffer_append_string_buffer(con->physical.path, &p->trigger_handler); chunkqueue_reset(con->write_queue); }