File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / mod_trigger_b4_dl.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:35:00 2016 UTC (7 years, 9 months ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_41p8, HEAD
lighttpd 1.4.41

    1: #include "first.h"
    2: 
    3: #include "base.h"
    4: #include "log.h"
    5: #include "buffer.h"
    6: 
    7: #include "plugin.h"
    8: #include "response.h"
    9: #include "inet_ntop_cache.h"
   10: 
   11: #include <ctype.h>
   12: #include <stdlib.h>
   13: #include <fcntl.h>
   14: #include <string.h>
   15: 
   16: #if (defined(HAVE_GDBM_H) || defined(USE_MEMCACHED)) && defined(HAVE_PCRE_H)
   17: 
   18: #if defined(HAVE_GDBM_H)
   19: # include <gdbm.h>
   20: #endif
   21: 
   22: #if defined(HAVE_PCRE_H)
   23: # include <pcre.h>
   24: #endif
   25: 
   26: #if defined(USE_MEMCACHED)
   27: # include <libmemcached/memcached.h>
   28: #endif
   29: 
   30: /**
   31:  * this is a trigger_b4_dl for a lighttpd plugin
   32:  *
   33:  */
   34: 
   35: /* plugin config for all request/connections */
   36: 
   37: typedef struct {
   38: 	buffer *db_filename;
   39: 
   40: 	buffer *trigger_url;
   41: 	buffer *download_url;
   42: 	buffer *deny_url;
   43: 
   44: 	array  *mc_hosts;
   45: 	buffer *mc_namespace;
   46: #if defined(HAVE_PCRE_H)
   47: 	pcre *trigger_regex;
   48: 	pcre *download_regex;
   49: #endif
   50: #if defined(HAVE_GDBM_H)
   51: 	GDBM_FILE db;
   52: #endif
   53: 
   54: #if defined(USE_MEMCACHED)
   55: 	memcached_st *memc;
   56: #endif
   57: 
   58: 	unsigned short trigger_timeout;
   59: 	unsigned short debug;
   60: } plugin_config;
   61: 
   62: typedef struct {
   63: 	PLUGIN_DATA;
   64: 
   65: 	buffer *tmp_buf;
   66: 
   67: 	plugin_config **config_storage;
   68: 
   69: 	plugin_config conf;
   70: } plugin_data;
   71: 
   72: /* init the plugin data */
   73: INIT_FUNC(mod_trigger_b4_dl_init) {
   74: 	plugin_data *p;
   75: 
   76: 	p = calloc(1, sizeof(*p));
   77: 
   78: 	p->tmp_buf = buffer_init();
   79: 
   80: 	return p;
   81: }
   82: 
   83: /* detroy the plugin data */
   84: FREE_FUNC(mod_trigger_b4_dl_free) {
   85: 	plugin_data *p = p_d;
   86: 
   87: 	UNUSED(srv);
   88: 
   89: 	if (!p) return HANDLER_GO_ON;
   90: 
   91: 	if (p->config_storage) {
   92: 		size_t i;
   93: 		for (i = 0; i < srv->config_context->used; i++) {
   94: 			plugin_config *s = p->config_storage[i];
   95: 
   96: 			if (NULL == s) continue;
   97: 
   98: 			buffer_free(s->db_filename);
   99: 			buffer_free(s->download_url);
  100: 			buffer_free(s->trigger_url);
  101: 			buffer_free(s->deny_url);
  102: 
  103: 			buffer_free(s->mc_namespace);
  104: 			array_free(s->mc_hosts);
  105: 
  106: #if defined(HAVE_PCRE_H)
  107: 			if (s->trigger_regex) pcre_free(s->trigger_regex);
  108: 			if (s->download_regex) pcre_free(s->download_regex);
  109: #endif
  110: #if defined(HAVE_GDBM_H)
  111: 			if (s->db) gdbm_close(s->db);
  112: #endif
  113: #if defined(USE_MEMCACHED)
  114: 			if (s->memc) memcached_free(s->memc);
  115: #endif
  116: 
  117: 			free(s);
  118: 		}
  119: 		free(p->config_storage);
  120: 	}
  121: 
  122: 	buffer_free(p->tmp_buf);
  123: 
  124: 	free(p);
  125: 
  126: 	return HANDLER_GO_ON;
  127: }
  128: 
  129: /* handle plugin config and check values */
  130: 
  131: SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
  132: 	plugin_data *p = p_d;
  133: 	size_t i = 0;
  134: 
  135: 
  136: 	config_values_t cv[] = {
  137: 		{ "trigger-before-download.gdbm-filename",   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
  138: 		{ "trigger-before-download.trigger-url",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
  139: 		{ "trigger-before-download.download-url",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
  140: 		{ "trigger-before-download.deny-url",        NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
  141: 		{ "trigger-before-download.trigger-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 4 */
  142: 		{ "trigger-before-download.memcache-hosts",  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 5 */
  143: 		{ "trigger-before-download.memcache-namespace", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },    /* 6 */
  144: 		{ "trigger-before-download.debug",           NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 7 */
  145: 		{ NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
  146: 	};
  147: 
  148: 	if (!p) return HANDLER_ERROR;
  149: 
  150: 	p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
  151: 
  152: 	for (i = 0; i < srv->config_context->used; i++) {
  153: 		data_config const* config = (data_config const*)srv->config_context->data[i];
  154: 		plugin_config *s;
  155: #if defined(HAVE_PCRE_H)
  156: 		const char *errptr;
  157: 		int erroff;
  158: #endif
  159: 
  160: 		s = calloc(1, sizeof(plugin_config));
  161: 		s->db_filename    = buffer_init();
  162: 		s->download_url   = buffer_init();
  163: 		s->trigger_url    = buffer_init();
  164: 		s->deny_url       = buffer_init();
  165: 		s->mc_hosts       = array_init();
  166: 		s->mc_namespace   = buffer_init();
  167: 
  168: 		cv[0].destination = s->db_filename;
  169: 		cv[1].destination = s->trigger_url;
  170: 		cv[2].destination = s->download_url;
  171: 		cv[3].destination = s->deny_url;
  172: 		cv[4].destination = &(s->trigger_timeout);
  173: 		cv[5].destination = s->mc_hosts;
  174: 		cv[6].destination = s->mc_namespace;
  175: 		cv[7].destination = &(s->debug);
  176: 
  177: 		p->config_storage[i] = s;
  178: 
  179: 		if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
  180: 			return HANDLER_ERROR;
  181: 		}
  182: #if defined(HAVE_GDBM_H)
  183: 		if (!buffer_string_is_empty(s->db_filename)) {
  184: 			if (NULL == (s->db = gdbm_open(s->db_filename->ptr, 4096, GDBM_WRCREAT | GDBM_NOLOCK, S_IRUSR | S_IWUSR, 0))) {
  185: 				log_error_write(srv, __FILE__, __LINE__, "s",
  186: 						"gdbm-open failed");
  187: 				return HANDLER_ERROR;
  188: 			}
  189: 			fd_close_on_exec(gdbm_fdesc(s->db));
  190: 		}
  191: #endif
  192: #if defined(HAVE_PCRE_H)
  193: 		if (!buffer_string_is_empty(s->download_url)) {
  194: 			if (NULL == (s->download_regex = pcre_compile(s->download_url->ptr,
  195: 								      0, &errptr, &erroff, NULL))) {
  196: 
  197: 				log_error_write(srv, __FILE__, __LINE__, "sbss",
  198: 						"compiling regex for download-url failed:",
  199: 						s->download_url, "pos:", erroff);
  200: 				return HANDLER_ERROR;
  201: 			}
  202: 		}
  203: 
  204: 		if (!buffer_string_is_empty(s->trigger_url)) {
  205: 			if (NULL == (s->trigger_regex = pcre_compile(s->trigger_url->ptr,
  206: 								     0, &errptr, &erroff, NULL))) {
  207: 
  208: 				log_error_write(srv, __FILE__, __LINE__, "sbss",
  209: 						"compiling regex for trigger-url failed:",
  210: 						s->trigger_url, "pos:", erroff);
  211: 
  212: 				return HANDLER_ERROR;
  213: 			}
  214: 		}
  215: #endif
  216: 
  217: 		if (s->mc_hosts->used) {
  218: #if defined(USE_MEMCACHED)
  219: 			buffer *option_string = buffer_init();
  220: 			size_t k;
  221: 
  222: 			{
  223: 				data_string *ds = (data_string *)s->mc_hosts->data[0];
  224: 
  225: 				buffer_append_string_len(option_string, CONST_STR_LEN("--SERVER="));
  226: 				buffer_append_string_buffer(option_string, ds->value);
  227: 			}
  228: 
  229: 			for (k = 1; k < s->mc_hosts->used; k++) {
  230: 				data_string *ds = (data_string *)s->mc_hosts->data[k];
  231: 
  232: 				buffer_append_string_len(option_string, CONST_STR_LEN(" --SERVER="));
  233: 				buffer_append_string_buffer(option_string, ds->value);
  234: 			}
  235: 
  236: 			s->memc = memcached(CONST_BUF_LEN(option_string));
  237: 
  238: 			if (NULL == s->memc) {
  239: 				log_error_write(srv, __FILE__, __LINE__, "sb",
  240: 					"configuring memcached failed for option string:",
  241: 					option_string);
  242: 			}
  243: 			buffer_free(option_string);
  244: 
  245: 			if (NULL == s->memc) return HANDLER_ERROR;
  246: #else
  247: 			log_error_write(srv, __FILE__, __LINE__, "s",
  248: 					"memcache support is not compiled in but trigger-before-download.memcache-hosts is set, aborting");
  249: 			return HANDLER_ERROR;
  250: #endif
  251: 		}
  252: 
  253: 
  254: #if (!defined(HAVE_GDBM_H) && !defined(USE_MEMCACHED)) || !defined(HAVE_PCRE_H)
  255: 		log_error_write(srv, __FILE__, __LINE__, "s",
  256: 				"(either gdbm or libmemcached) and pcre are require, but were not found, aborting");
  257: 		return HANDLER_ERROR;
  258: #endif
  259: 	}
  260: 
  261: 	return HANDLER_GO_ON;
  262: }
  263: 
  264: #define PATCH(x) \
  265: 	p->conf.x = s->x;
  266: static int mod_trigger_b4_dl_patch_connection(server *srv, connection *con, plugin_data *p) {
  267: 	size_t i, j;
  268: 	plugin_config *s = p->config_storage[0];
  269: 
  270: #if defined(HAVE_GDBM)
  271: 	PATCH(db);
  272: #endif
  273: #if defined(HAVE_PCRE_H)
  274: 	PATCH(download_regex);
  275: 	PATCH(trigger_regex);
  276: #endif
  277: 	PATCH(trigger_timeout);
  278: 	PATCH(deny_url);
  279: 	PATCH(mc_namespace);
  280: 	PATCH(debug);
  281: #if defined(USE_MEMCACHED)
  282: 	PATCH(memc);
  283: #endif
  284: 
  285: 	/* skip the first, the global context */
  286: 	for (i = 1; i < srv->config_context->used; i++) {
  287: 		data_config *dc = (data_config *)srv->config_context->data[i];
  288: 		s = p->config_storage[i];
  289: 
  290: 		/* condition didn't match */
  291: 		if (!config_check_cond(srv, con, dc)) continue;
  292: 
  293: 		/* merge config */
  294: 		for (j = 0; j < dc->value->used; j++) {
  295: 			data_unset *du = dc->value->data[j];
  296: 
  297: 			if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.download-url"))) {
  298: #if defined(HAVE_PCRE_H)
  299: 				PATCH(download_regex);
  300: #endif
  301: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-url"))) {
  302: # if defined(HAVE_PCRE_H)
  303: 				PATCH(trigger_regex);
  304: # endif
  305: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.gdbm-filename"))) {
  306: #if defined(HAVE_GDBM_H)
  307: 				PATCH(db);
  308: #endif
  309: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-timeout"))) {
  310: 				PATCH(trigger_timeout);
  311: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.debug"))) {
  312: 				PATCH(debug);
  313: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.deny-url"))) {
  314: 				PATCH(deny_url);
  315: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-namespace"))) {
  316: 				PATCH(mc_namespace);
  317: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-hosts"))) {
  318: #if defined(USE_MEMCACHED)
  319: 				PATCH(memc);
  320: #endif
  321: 			}
  322: 		}
  323: 	}
  324: 
  325: 	return 0;
  326: }
  327: #undef PATCH
  328: 
  329: URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
  330: 	plugin_data *p = p_d;
  331: 	const char *remote_ip;
  332: 	data_string *ds;
  333: 
  334: #if defined(HAVE_PCRE_H)
  335: 	int n;
  336: # define N 10
  337: 	int ovec[N * 3];
  338: 
  339: 	if (con->mode != DIRECT) return HANDLER_GO_ON;
  340: 
  341: 	if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
  342: 
  343: 	mod_trigger_b4_dl_patch_connection(srv, con, p);
  344: 
  345: 	if (!p->conf.trigger_regex || !p->conf.download_regex) return HANDLER_GO_ON;
  346: 
  347: # if !defined(HAVE_GDBM_H) && !defined(USE_MEMCACHED)
  348: 	return HANDLER_GO_ON;
  349: # elif defined(HAVE_GDBM_H) && defined(USE_MEMCACHED)
  350: 	if (!p->conf.db && !p->conf.memc) return HANDLER_GO_ON;
  351: 	if (p->conf.db && p->conf.memc) {
  352: 		/* can't decide which one */
  353: 
  354: 		return HANDLER_GO_ON;
  355: 	}
  356: # elif defined(HAVE_GDBM_H)
  357: 	if (!p->conf.db) return HANDLER_GO_ON;
  358: # else
  359: 	if (!p->conf.memc) return HANDLER_GO_ON;
  360: # endif
  361: 
  362: 	if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "X-Forwarded-For"))) {
  363: 		/* X-Forwarded-For contains the ip behind the proxy */
  364: 
  365: 		remote_ip = ds->value->ptr;
  366: 
  367: 		/* memcache can't handle spaces */
  368: 	} else {
  369: 		remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
  370: 	}
  371: 
  372: 	if (p->conf.debug) {
  373: 		log_error_write(srv, __FILE__, __LINE__, "ss", "(debug) remote-ip:", remote_ip);
  374: 	}
  375: 
  376: 	/* check if URL is a trigger -> insert IP into DB */
  377: 	if ((n = pcre_exec(p->conf.trigger_regex, NULL, CONST_BUF_LEN(con->uri.path), 0, 0, ovec, 3 * N)) < 0) {
  378: 		if (n != PCRE_ERROR_NOMATCH) {
  379: 			log_error_write(srv, __FILE__, __LINE__, "sd",
  380: 					"execution error while matching:", n);
  381: 
  382: 			return HANDLER_ERROR;
  383: 		}
  384: 	} else {
  385: # if defined(HAVE_GDBM_H)
  386: 		if (p->conf.db) {
  387: 			/* the trigger matched */
  388: 			datum key, val;
  389: 
  390: 			key.dptr = (char *)remote_ip;
  391: 			key.dsize = strlen(remote_ip);
  392: 
  393: 			val.dptr = (char *)&(srv->cur_ts);
  394: 			val.dsize = sizeof(srv->cur_ts);
  395: 
  396: 			if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
  397: 				log_error_write(srv, __FILE__, __LINE__, "s",
  398: 						"insert failed");
  399: 			}
  400: 		}
  401: # endif
  402: # if defined(USE_MEMCACHED)
  403: 		if (p->conf.memc) {
  404: 			size_t i, len;
  405: 			buffer_copy_buffer(p->tmp_buf, p->conf.mc_namespace);
  406: 			buffer_append_string(p->tmp_buf, remote_ip);
  407: 
  408: 			len = buffer_string_length(p->tmp_buf);
  409: 			for (i = 0; i < len; i++) {
  410: 				if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
  411: 			}
  412: 
  413: 			if (p->conf.debug) {
  414: 				log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) triggered IP:", p->tmp_buf);
  415: 			}
  416: 
  417: 			if (MEMCACHED_SUCCESS != memcached_set(p->conf.memc,
  418: 					CONST_BUF_LEN(p->tmp_buf),
  419: 					(const char *)&(srv->cur_ts), sizeof(srv->cur_ts),
  420: 					p->conf.trigger_timeout, 0)) {
  421: 				log_error_write(srv, __FILE__, __LINE__, "s",
  422: 					"insert failed");
  423: 			}
  424: 		}
  425: # endif
  426: 	}
  427: 
  428: 	/* check if URL is a download -> check IP in DB, update timestamp */
  429: 	if ((n = pcre_exec(p->conf.download_regex, NULL, CONST_BUF_LEN(con->uri.path), 0, 0, ovec, 3 * N)) < 0) {
  430: 		if (n != PCRE_ERROR_NOMATCH) {
  431: 			log_error_write(srv, __FILE__, __LINE__, "sd",
  432: 					"execution error while matching: ", n);
  433: 			return HANDLER_ERROR;
  434: 		}
  435: 	} else {
  436: 		/* the download uri matched */
  437: # if defined(HAVE_GDBM_H)
  438: 		if (p->conf.db) {
  439: 			datum key, val;
  440: 			time_t last_hit;
  441: 
  442: 			key.dptr = (char *)remote_ip;
  443: 			key.dsize = strlen(remote_ip);
  444: 
  445: 			val = gdbm_fetch(p->conf.db, key);
  446: 
  447: 			if (val.dptr == NULL) {
  448: 				/* not found, redirect */
  449: 
  450: 				response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
  451: 				con->http_status = 307;
  452: 				con->file_finished = 1;
  453: 
  454: 				return HANDLER_FINISHED;
  455: 			}
  456: 
  457: 			memcpy(&last_hit, val.dptr, sizeof(time_t));
  458: 
  459: 			free(val.dptr);
  460: 
  461: 			if (srv->cur_ts - last_hit > p->conf.trigger_timeout) {
  462: 				/* found, but timeout, redirect */
  463: 
  464: 				response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
  465: 				con->http_status = 307;
  466: 				con->file_finished = 1;
  467: 
  468: 				if (p->conf.db) {
  469: 					if (0 != gdbm_delete(p->conf.db, key)) {
  470: 						log_error_write(srv, __FILE__, __LINE__, "s",
  471: 								"delete failed");
  472: 					}
  473: 				}
  474: 
  475: 				return HANDLER_FINISHED;
  476: 			}
  477: 
  478: 			val.dptr = (char *)&(srv->cur_ts);
  479: 			val.dsize = sizeof(srv->cur_ts);
  480: 
  481: 			if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
  482: 				log_error_write(srv, __FILE__, __LINE__, "s",
  483: 						"insert failed");
  484: 			}
  485: 		}
  486: # endif
  487: 
  488: # if defined(USE_MEMCACHED)
  489: 		if (p->conf.memc) {
  490: 			size_t i, len;
  491: 
  492: 			buffer_copy_buffer(p->tmp_buf, p->conf.mc_namespace);
  493: 			buffer_append_string(p->tmp_buf, remote_ip);
  494: 
  495: 			len = buffer_string_length(p->tmp_buf);
  496: 			for (i = 0; i < len; i++) {
  497: 				if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
  498: 			}
  499: 
  500: 			if (p->conf.debug) {
  501: 				log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) checking IP:", p->tmp_buf);
  502: 			}
  503: 
  504: 			/**
  505: 			 *
  506: 			 * memcached is do expiration for us, as long as we can fetch it every thing is ok
  507: 			 * and the timestamp is updated
  508: 			 *
  509: 			 */
  510: 			if (MEMCACHED_SUCCESS != memcached_exist(p->conf.memc, CONST_BUF_LEN(p->tmp_buf))) {
  511: 				response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
  512: 
  513: 				con->http_status = 307;
  514: 				con->file_finished = 1;
  515: 
  516: 				return HANDLER_FINISHED;
  517: 			}
  518: 
  519: 			/* set a new timeout */
  520: 			if (MEMCACHED_SUCCESS != memcached_set(p->conf.memc,
  521: 					CONST_BUF_LEN(p->tmp_buf),
  522: 					(const char *)&(srv->cur_ts), sizeof(srv->cur_ts),
  523: 					p->conf.trigger_timeout, 0)) {
  524: 				log_error_write(srv, __FILE__, __LINE__, "s",
  525: 					"insert failed");
  526: 			}
  527: 		}
  528: # endif
  529: 	}
  530: 
  531: #else
  532: 	UNUSED(srv);
  533: 	UNUSED(con);
  534: 	UNUSED(p_d);
  535: #endif
  536: 
  537: 	return HANDLER_GO_ON;
  538: }
  539: 
  540: #if defined(HAVE_GDBM_H)
  541: TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
  542: 	plugin_data *p = p_d;
  543: 	size_t i;
  544: 
  545: 	/* check DB each minute */
  546: 	if (srv->cur_ts % 60 != 0) return HANDLER_GO_ON;
  547: 
  548: 	/* cleanup */
  549: 	for (i = 0; i < srv->config_context->used; i++) {
  550: 		plugin_config *s = p->config_storage[i];
  551: 		datum key, val, okey;
  552: 
  553: 		if (!s->db) continue;
  554: 
  555: 		okey.dptr = NULL;
  556: 
  557: 		/* according to the manual this loop + delete does delete all entries on its way
  558: 		 *
  559: 		 * we don't care as the next round will remove them. We don't have to perfect here.
  560: 		 */
  561: 		for (key = gdbm_firstkey(s->db); key.dptr; key = gdbm_nextkey(s->db, okey)) {
  562: 			time_t last_hit;
  563: 			if (okey.dptr) {
  564: 				free(okey.dptr);
  565: 				okey.dptr = NULL;
  566: 			}
  567: 
  568: 			val = gdbm_fetch(s->db, key);
  569: 
  570: 			memcpy(&last_hit, val.dptr, sizeof(time_t));
  571: 
  572: 			free(val.dptr);
  573: 
  574: 			if (srv->cur_ts - last_hit > s->trigger_timeout) {
  575: 				gdbm_delete(s->db, key);
  576: 			}
  577: 
  578: 			okey = key;
  579: 		}
  580: 		if (okey.dptr) free(okey.dptr);
  581: 
  582: 		/* reorg once a day */
  583: 		if ((srv->cur_ts % (60 * 60 * 24) != 0)) gdbm_reorganize(s->db);
  584: 	}
  585: 	return HANDLER_GO_ON;
  586: }
  587: #endif
  588: 
  589: /* this function is called at dlopen() time and inits the callbacks */
  590: 
  591: int mod_trigger_b4_dl_plugin_init(plugin *p);
  592: int mod_trigger_b4_dl_plugin_init(plugin *p) {
  593: 	p->version     = LIGHTTPD_VERSION_ID;
  594: 	p->name        = buffer_init_string("trigger_b4_dl");
  595: 
  596: 	p->init        = mod_trigger_b4_dl_init;
  597: 	p->handle_uri_clean  = mod_trigger_b4_dl_uri_handler;
  598: 	p->set_defaults  = mod_trigger_b4_dl_set_defaults;
  599: #if defined(HAVE_GDBM_H)
  600: 	p->handle_trigger  = mod_trigger_b4_dl_handle_trigger;
  601: #endif
  602: 	p->cleanup     = mod_trigger_b4_dl_free;
  603: 
  604: 	p->data        = NULL;
  605: 
  606: 	return 0;
  607: }
  608: 
  609: #else
  610: 
  611: #pragma message("(either gdbm or libmemcached) and pcre are required, but were not found")
  612: 
  613: int mod_trigger_b4_dl_plugin_init(plugin *p);
  614: int mod_trigger_b4_dl_plugin_init(plugin *p) {
  615: 	UNUSED(p);
  616: 	return -1;
  617: }
  618: 
  619: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>