2005-07-06 11:58:19 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include "buffer.h"
|
|
|
|
#include "server.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "plugin.h"
|
|
|
|
#include "response.h"
|
|
|
|
|
|
|
|
#include "stream.h"
|
|
|
|
|
|
|
|
#include "mod_cml.h"
|
|
|
|
|
|
|
|
/* init the plugin data */
|
2005-07-06 16:36:46 +00:00
|
|
|
INIT_FUNC(mod_cml_init) {
|
2005-07-06 11:58:19 +00:00
|
|
|
plugin_data *p;
|
|
|
|
|
|
|
|
p = calloc(1, sizeof(*p));
|
|
|
|
|
2005-07-07 09:19:42 +00:00
|
|
|
p->basedir = buffer_init();
|
2005-07-11 11:01:59 +00:00
|
|
|
p->baseurl = buffer_init();
|
2005-07-07 09:19:42 +00:00
|
|
|
p->session_id = buffer_init();
|
|
|
|
p->trigger_handler = buffer_init();
|
|
|
|
|
2005-07-06 11:58:19 +00:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* detroy the plugin data */
|
2005-07-06 16:36:46 +00:00
|
|
|
FREE_FUNC(mod_cml_free) {
|
2005-07-06 11:58:19 +00:00
|
|
|
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];
|
|
|
|
|
|
|
|
buffer_free(s->ext);
|
|
|
|
|
2005-07-09 20:17:07 +00:00
|
|
|
buffer_free(s->mc_namespace);
|
|
|
|
array_free(s->mc_hosts);
|
|
|
|
|
|
|
|
#if defined(HAVE_MEMCACHE_H)
|
|
|
|
if (s->mc) mc_free(s->mc);
|
|
|
|
#endif
|
|
|
|
|
2005-07-06 11:58:19 +00:00
|
|
|
free(s);
|
|
|
|
}
|
|
|
|
free(p->config_storage);
|
|
|
|
}
|
|
|
|
|
2005-07-07 09:19:42 +00:00
|
|
|
buffer_free(p->trigger_handler);
|
|
|
|
buffer_free(p->session_id);
|
2005-07-06 11:58:19 +00:00
|
|
|
buffer_free(p->basedir);
|
2005-07-11 11:01:59 +00:00
|
|
|
buffer_free(p->baseurl);
|
2005-07-06 11:58:19 +00:00
|
|
|
|
|
|
|
free(p);
|
|
|
|
|
|
|
|
return HANDLER_GO_ON;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* handle plugin config and check values */
|
|
|
|
|
2005-07-06 16:36:46 +00:00
|
|
|
SETDEFAULTS_FUNC(mod_cml_set_defaults) {
|
2005-07-06 11:58:19 +00:00
|
|
|
plugin_data *p = p_d;
|
|
|
|
size_t i = 0;
|
|
|
|
|
|
|
|
config_values_t cv[] = {
|
2005-07-09 20:17:07 +00:00
|
|
|
{ "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 */
|
2005-07-06 11:58:19 +00:00
|
|
|
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!p) return HANDLER_ERROR;
|
|
|
|
|
|
|
|
p->config_storage = malloc(srv->config_context->used * sizeof(specific_config *));
|
|
|
|
|
|
|
|
for (i = 0; i < srv->config_context->used; i++) {
|
|
|
|
plugin_config *s;
|
|
|
|
|
|
|
|
s = malloc(sizeof(plugin_config));
|
|
|
|
s->ext = buffer_init();
|
2005-07-09 20:17:07 +00:00
|
|
|
s->mc_hosts = array_init();
|
|
|
|
s->mc_namespace = buffer_init();
|
2005-07-15 17:46:13 +00:00
|
|
|
#if defined(HAVE_MEMCACHE_H)
|
|
|
|
s->mc = NULL;
|
|
|
|
#endif
|
2005-07-06 11:58:19 +00:00
|
|
|
|
|
|
|
cv[0].destination = s->ext;
|
2005-07-09 20:17:07 +00:00
|
|
|
cv[1].destination = s->mc_hosts;
|
|
|
|
cv[2].destination = s->mc_namespace;
|
2005-07-06 11:58:19 +00:00
|
|
|
|
|
|
|
p->config_storage[i] = s;
|
|
|
|
|
|
|
|
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
|
|
|
|
return HANDLER_ERROR;
|
|
|
|
}
|
2005-07-09 20:17:07 +00:00
|
|
|
|
|
|
|
if (s->mc_hosts->used) {
|
|
|
|
#if defined(HAVE_MEMCACHE_H)
|
|
|
|
size_t k;
|
|
|
|
s->mc = mc_new();
|
|
|
|
|
|
|
|
for (k = 0; k < s->mc_hosts->used; k++) {
|
|
|
|
data_string *ds = (data_string *)s->mc_hosts->data[k];
|
|
|
|
|
|
|
|
if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sb",
|
|
|
|
"connection to host failed:",
|
|
|
|
ds->value);
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
2005-07-06 11:58:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return HANDLER_GO_ON;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define PATCH(x) \
|
|
|
|
p->conf.x = s->x;
|
2005-08-08 10:27:07 +00:00
|
|
|
static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p) {
|
2005-07-06 11:58:19 +00:00
|
|
|
size_t i, j;
|
2005-08-08 10:27:07 +00:00
|
|
|
plugin_config *s = p->config_storage[0];
|
|
|
|
|
|
|
|
PATCH(ext);
|
|
|
|
#if defined(HAVE_MEMCACHE_H)
|
|
|
|
PATCH(mc);
|
|
|
|
#endif
|
|
|
|
PATCH(mc_namespace);
|
2005-07-06 11:58:19 +00:00
|
|
|
|
|
|
|
/* skip the first, the global context */
|
|
|
|
for (i = 1; i < srv->config_context->used; i++) {
|
|
|
|
data_config *dc = (data_config *)srv->config_context->data[i];
|
2005-08-08 10:27:07 +00:00
|
|
|
s = p->config_storage[i];
|
2005-07-06 11:58:19 +00:00
|
|
|
|
|
|
|
/* condition didn't match */
|
|
|
|
if (!config_check_cond(srv, con, dc)) continue;
|
|
|
|
|
|
|
|
/* merge config */
|
|
|
|
for (j = 0; j < dc->value->used; j++) {
|
|
|
|
data_unset *du = dc->value->data[j];
|
|
|
|
|
2005-07-07 09:19:42 +00:00
|
|
|
if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.extension"))) {
|
2005-07-06 11:58:19 +00:00
|
|
|
PATCH(ext);
|
2005-07-11 11:01:59 +00:00
|
|
|
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-hosts"))) {
|
|
|
|
#if defined(HAVE_MEMCACHE_H)
|
|
|
|
PATCH(mc);
|
|
|
|
#endif
|
|
|
|
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-namespace"))) {
|
|
|
|
PATCH(mc_namespace);
|
2005-07-06 11:58:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#undef PATCH
|
|
|
|
|
|
|
|
|
|
|
|
int cache_get_cookie_session_id(server *srv, connection *con, plugin_data *p) {
|
|
|
|
data_unset *d;
|
2005-11-18 12:00:48 +00:00
|
|
|
|
|
|
|
UNUSED(srv);
|
2005-07-06 11:58:19 +00:00
|
|
|
|
|
|
|
if (NULL != (d = array_get_element(con->request.headers, "Cookie"))) {
|
|
|
|
data_string *ds = (data_string *)d;
|
|
|
|
size_t key = 0, value = 0;
|
|
|
|
size_t is_key = 1, is_sid = 0;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
/* found COOKIE */
|
|
|
|
if (!DATA_IS_STRING(d)) return -1;
|
|
|
|
if (ds->value->used == 0) return -1;
|
|
|
|
|
|
|
|
if (ds->value->ptr[0] == '\0' ||
|
|
|
|
ds->value->ptr[0] == '=' ||
|
|
|
|
ds->value->ptr[0] == ';') return -1;
|
|
|
|
|
|
|
|
buffer_reset(p->session_id);
|
|
|
|
for (i = 0; i < ds->value->used; i++) {
|
|
|
|
switch(ds->value->ptr[i]) {
|
|
|
|
case '=':
|
|
|
|
if (is_key) {
|
|
|
|
if (0 == strncmp(ds->value->ptr + key, "PHPSESSID", i - key)) {
|
|
|
|
/* found PHP-session-id-key */
|
|
|
|
is_sid = 1;
|
|
|
|
}
|
|
|
|
value = i + 1;
|
|
|
|
|
|
|
|
is_key = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case ';':
|
|
|
|
if (is_sid) {
|
|
|
|
buffer_copy_string_len(p->session_id, ds->value->ptr + value, i - value);
|
|
|
|
}
|
|
|
|
|
|
|
|
is_sid = 0;
|
|
|
|
key = i + 1;
|
|
|
|
value = 0;
|
|
|
|
is_key = 1;
|
|
|
|
break;
|
|
|
|
case ' ':
|
|
|
|
if (is_key == 1 && key == i) key = i + 1;
|
|
|
|
if (is_key == 0 && value == i) value = i + 1;
|
|
|
|
break;
|
|
|
|
case '\0':
|
|
|
|
if (is_sid) {
|
|
|
|
buffer_copy_string_len(p->session_id, ds->value->ptr + value, i - value);
|
|
|
|
}
|
|
|
|
/* fin */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return !buffer_is_empty(p->session_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
int cache_get_url_session_id(server *srv, connection *con, plugin_data *p) {
|
|
|
|
size_t key = 0, value = 0;
|
|
|
|
size_t is_key = 1, is_sid = 0;
|
|
|
|
size_t i;
|
|
|
|
|
2005-11-18 12:00:48 +00:00
|
|
|
UNUSED(srv);
|
2005-07-06 11:58:19 +00:00
|
|
|
buffer_reset(p->session_id);
|
|
|
|
for (i = 0; i < con->uri.query->used; i++) {
|
|
|
|
switch(con->uri.query->ptr[i]) {
|
|
|
|
case '=':
|
|
|
|
if (is_key) {
|
|
|
|
if (0 == strncmp(con->uri.query->ptr + key, "PHPSESSID", i - key)) {
|
|
|
|
/* found PHP-session-id-key */
|
|
|
|
is_sid = 1;
|
|
|
|
}
|
|
|
|
value = i + 1;
|
|
|
|
|
|
|
|
is_key = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case '&':
|
|
|
|
if (is_sid) {
|
|
|
|
buffer_copy_string_len(p->session_id, con->uri.query->ptr + value, i - value);
|
|
|
|
}
|
|
|
|
|
|
|
|
is_sid = 0;
|
|
|
|
key = i + 1;
|
|
|
|
value = 0;
|
|
|
|
is_key = 1;
|
|
|
|
break;
|
|
|
|
case ' ':
|
|
|
|
if (is_key == 1 && key == i) key = i + 1;
|
|
|
|
if (is_key == 0 && value == i) value = i + 1;
|
|
|
|
break;
|
|
|
|
case '\0':
|
|
|
|
if (is_sid) {
|
|
|
|
buffer_copy_string_len(p->session_id, con->uri.query->ptr + value, i - value);
|
|
|
|
}
|
|
|
|
/* fin */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2005-11-10 12:15:10 +00:00
|
|
|
|
2005-07-06 11:58:19 +00:00
|
|
|
return !buffer_is_empty(p->session_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
int cache_get_session_id(server *srv, connection *con, plugin_data *p) {
|
|
|
|
|
|
|
|
return cache_get_cookie_session_id(srv, con, p) ||
|
|
|
|
cache_get_url_session_id(srv, con, p);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-07-06 16:36:46 +00:00
|
|
|
URIHANDLER_FUNC(mod_cml_is_handled) {
|
2005-07-06 11:58:19 +00:00
|
|
|
int ct_len, s_len;
|
|
|
|
buffer *b;
|
|
|
|
char *c;
|
|
|
|
buffer *fn = con->physical.path;
|
|
|
|
plugin_data *p = p_d;
|
2005-07-15 17:46:13 +00:00
|
|
|
int ret;
|
2005-07-06 11:58:19 +00:00
|
|
|
|
|
|
|
if (fn->used == 0) return HANDLER_ERROR;
|
|
|
|
|
2005-08-08 10:27:07 +00:00
|
|
|
mod_cml_patch_connection(srv, con, p);
|
2005-07-06 11:58:19 +00:00
|
|
|
|
2005-07-07 09:19:42 +00:00
|
|
|
buffer_reset(p->basedir);
|
2005-07-11 11:01:59 +00:00
|
|
|
buffer_reset(p->baseurl);
|
2005-07-07 09:19:42 +00:00
|
|
|
buffer_reset(p->session_id);
|
|
|
|
buffer_reset(p->trigger_handler);
|
|
|
|
|
2005-07-06 11:58:19 +00:00
|
|
|
if (buffer_is_empty(p->conf.ext)) return HANDLER_GO_ON;
|
|
|
|
|
|
|
|
ct_len = p->conf.ext->used - 1;
|
|
|
|
s_len = fn->used - 1;
|
|
|
|
|
|
|
|
if (s_len < ct_len) return HANDLER_GO_ON;
|
|
|
|
|
|
|
|
if (0 != strncmp(fn->ptr + s_len - ct_len, p->conf.ext->ptr, ct_len)) {
|
|
|
|
/* not my job */
|
|
|
|
return HANDLER_GO_ON;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* cleanup basedir */
|
2005-07-11 11:01:59 +00:00
|
|
|
b = p->baseurl;
|
|
|
|
buffer_copy_string_buffer(b, con->uri.path);
|
|
|
|
for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
|
|
|
|
|
|
|
|
if (*c == '/') {
|
|
|
|
b->used = c - b->ptr + 2;
|
|
|
|
*(c+1) = '\0';
|
|
|
|
}
|
|
|
|
|
2005-07-06 11:58:19 +00:00
|
|
|
b = p->basedir;
|
|
|
|
buffer_copy_string_buffer(b, fn);
|
|
|
|
for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
|
|
|
|
|
|
|
|
if (*c == '/') {
|
|
|
|
b->used = c - b->ptr + 2;
|
|
|
|
*(c+1) = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
/* prepare variables
|
|
|
|
* - session-id
|
|
|
|
* - cookie-based
|
|
|
|
* - get-param-based
|
|
|
|
*/
|
|
|
|
|
|
|
|
cache_get_session_id(srv, con, p);
|
|
|
|
|
2005-07-15 17:46:13 +00:00
|
|
|
ret = cache_parse_lua(srv, con, p, fn);
|
|
|
|
|
|
|
|
switch(ret) {
|
2005-07-06 11:58:19 +00:00
|
|
|
case -1:
|
2005-07-11 11:01:59 +00:00
|
|
|
/* error */
|
|
|
|
if (con->conf.log_request_handling) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s", "cache-error");
|
|
|
|
}
|
2005-07-06 11:58:19 +00:00
|
|
|
con->http_status = 500;
|
|
|
|
return HANDLER_COMEBACK;
|
|
|
|
case 0:
|
2005-07-11 11:01:59 +00:00
|
|
|
if (con->conf.log_request_handling) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s", "cache-hit");
|
|
|
|
}
|
|
|
|
/* cache-hit */
|
2005-07-06 11:58:19 +00:00
|
|
|
buffer_reset(con->physical.path);
|
|
|
|
return HANDLER_FINISHED;
|
|
|
|
case 1:
|
2005-07-11 11:01:59 +00:00
|
|
|
if (con->conf.log_request_handling) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s", "cache-miss");
|
|
|
|
}
|
|
|
|
/* cache miss */
|
2005-07-06 11:58:19 +00:00
|
|
|
return HANDLER_COMEBACK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-07-06 16:36:46 +00:00
|
|
|
int mod_cml_plugin_init(plugin *p) {
|
2005-07-06 11:58:19 +00:00
|
|
|
p->version = LIGHTTPD_VERSION_ID;
|
|
|
|
p->name = buffer_init_string("cache");
|
|
|
|
|
2005-07-06 16:36:46 +00:00
|
|
|
p->init = mod_cml_init;
|
|
|
|
p->cleanup = mod_cml_free;
|
|
|
|
p->set_defaults = mod_cml_set_defaults;
|
2005-07-06 11:58:19 +00:00
|
|
|
|
2005-07-06 16:36:46 +00:00
|
|
|
p->handle_subrequest_start = mod_cml_is_handled;
|
2005-07-06 11:58:19 +00:00
|
|
|
|
|
|
|
p->data = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|