2016-03-19 15:14:35 +00:00
|
|
|
#include "first.h"
|
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
#include "base.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "buffer.h"
|
|
|
|
|
|
|
|
#include "plugin.h"
|
|
|
|
#include "response.h"
|
|
|
|
#include "inet_ntop_cache.h"
|
|
|
|
|
2009-10-11 14:31:42 +00:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2016-01-03 14:48:11 +00:00
|
|
|
#if (defined(HAVE_GDBM_H) || defined(USE_MEMCACHED)) && defined(HAVE_PCRE_H)
|
2015-08-29 09:28:01 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
#if defined(HAVE_GDBM_H)
|
2009-10-11 14:31:42 +00:00
|
|
|
# include <gdbm.h>
|
2005-07-07 22:48:42 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(HAVE_PCRE_H)
|
2009-10-11 14:31:42 +00:00
|
|
|
# include <pcre.h>
|
2005-07-07 22:48:42 +00:00
|
|
|
#endif
|
|
|
|
|
2016-01-03 14:48:11 +00:00
|
|
|
#if defined(USE_MEMCACHED)
|
|
|
|
# include <libmemcached/memcached.h>
|
2005-07-07 22:48:42 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
|
|
|
* this is a trigger_b4_dl for a lighttpd plugin
|
2006-10-04 13:26:23 +00:00
|
|
|
*
|
2005-07-07 22:48:42 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* plugin config for all request/connections */
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
buffer *db_filename;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
buffer *trigger_url;
|
|
|
|
buffer *download_url;
|
|
|
|
buffer *deny_url;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
array *mc_hosts;
|
2005-07-08 22:28:46 +00:00
|
|
|
buffer *mc_namespace;
|
2005-07-07 22:48:42 +00:00
|
|
|
#if defined(HAVE_PCRE_H)
|
|
|
|
pcre *trigger_regex;
|
|
|
|
pcre *download_regex;
|
|
|
|
#endif
|
|
|
|
#if defined(HAVE_GDBM_H)
|
|
|
|
GDBM_FILE db;
|
|
|
|
#endif
|
|
|
|
|
2016-01-03 14:48:11 +00:00
|
|
|
#if defined(USE_MEMCACHED)
|
|
|
|
memcached_st *memc;
|
2005-07-07 22:48:42 +00:00
|
|
|
#endif
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
unsigned short trigger_timeout;
|
2005-08-17 17:36:03 +00:00
|
|
|
unsigned short debug;
|
2005-07-07 22:48:42 +00:00
|
|
|
} plugin_config;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
PLUGIN_DATA;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-08 22:28:46 +00:00
|
|
|
buffer *tmp_buf;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
plugin_config **config_storage;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
|
|
|
plugin_config conf;
|
2005-07-07 22:48:42 +00:00
|
|
|
} plugin_data;
|
|
|
|
|
|
|
|
/* init the plugin data */
|
|
|
|
INIT_FUNC(mod_trigger_b4_dl_init) {
|
|
|
|
plugin_data *p;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
p = calloc(1, sizeof(*p));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-08 22:28:46 +00:00
|
|
|
p->tmp_buf = buffer_init();
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* detroy the plugin data */
|
|
|
|
FREE_FUNC(mod_trigger_b4_dl_free) {
|
|
|
|
plugin_data *p = p_d;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
UNUSED(srv);
|
|
|
|
|
|
|
|
if (!p) return HANDLER_GO_ON;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
if (p->config_storage) {
|
|
|
|
size_t i;
|
|
|
|
for (i = 0; i < srv->config_context->used; i++) {
|
|
|
|
plugin_config *s = p->config_storage[i];
|
2005-08-15 09:50:43 +00:00
|
|
|
|
2015-05-14 09:38:33 +00:00
|
|
|
if (NULL == s) continue;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
buffer_free(s->db_filename);
|
|
|
|
buffer_free(s->download_url);
|
|
|
|
buffer_free(s->trigger_url);
|
|
|
|
buffer_free(s->deny_url);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-08 22:28:46 +00:00
|
|
|
buffer_free(s->mc_namespace);
|
|
|
|
array_free(s->mc_hosts);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
#if defined(HAVE_PCRE_H)
|
|
|
|
if (s->trigger_regex) pcre_free(s->trigger_regex);
|
|
|
|
if (s->download_regex) pcre_free(s->download_regex);
|
|
|
|
#endif
|
|
|
|
#if defined(HAVE_GDBM_H)
|
2005-07-09 20:18:10 +00:00
|
|
|
if (s->db) gdbm_close(s->db);
|
2005-07-07 22:48:42 +00:00
|
|
|
#endif
|
2016-01-03 14:48:11 +00:00
|
|
|
#if defined(USE_MEMCACHED)
|
|
|
|
if (s->memc) memcached_free(s->memc);
|
2005-07-07 22:48:42 +00:00
|
|
|
#endif
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
free(s);
|
|
|
|
}
|
|
|
|
free(p->config_storage);
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-08 22:28:46 +00:00
|
|
|
buffer_free(p->tmp_buf);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
free(p);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
return HANDLER_GO_ON;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* handle plugin config and check values */
|
|
|
|
|
|
|
|
SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
|
|
|
|
plugin_data *p = p_d;
|
|
|
|
size_t i = 0;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
config_values_t cv[] = {
|
2005-07-07 22:48:42 +00:00
|
|
|
{ "trigger-before-download.gdbm-filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
|
|
|
|
{ "trigger-before-download.trigger-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
|
|
|
|
{ "trigger-before-download.download-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
|
|
|
|
{ "trigger-before-download.deny-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
|
|
|
|
{ "trigger-before-download.trigger-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
|
|
|
|
{ "trigger-before-download.memcache-hosts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
|
2005-07-08 22:28:46 +00:00
|
|
|
{ "trigger-before-download.memcache-namespace", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
|
2005-08-17 17:36:03 +00:00
|
|
|
{ "trigger-before-download.debug", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
|
2005-07-07 22:48:42 +00:00
|
|
|
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
|
|
|
|
};
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
if (!p) return HANDLER_ERROR;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2013-11-13 11:43:26 +00:00
|
|
|
p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
for (i = 0; i < srv->config_context->used; i++) {
|
2015-11-07 12:51:11 +00:00
|
|
|
data_config const* config = (data_config const*)srv->config_context->data[i];
|
2005-07-07 22:48:42 +00:00
|
|
|
plugin_config *s;
|
|
|
|
#if defined(HAVE_PCRE_H)
|
|
|
|
const char *errptr;
|
|
|
|
int erroff;
|
|
|
|
#endif
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
s = calloc(1, sizeof(plugin_config));
|
|
|
|
s->db_filename = buffer_init();
|
|
|
|
s->download_url = buffer_init();
|
|
|
|
s->trigger_url = buffer_init();
|
|
|
|
s->deny_url = buffer_init();
|
|
|
|
s->mc_hosts = array_init();
|
2005-07-09 20:18:10 +00:00
|
|
|
s->mc_namespace = buffer_init();
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
cv[0].destination = s->db_filename;
|
|
|
|
cv[1].destination = s->trigger_url;
|
|
|
|
cv[2].destination = s->download_url;
|
|
|
|
cv[3].destination = s->deny_url;
|
|
|
|
cv[4].destination = &(s->trigger_timeout);
|
|
|
|
cv[5].destination = s->mc_hosts;
|
2005-07-08 22:28:46 +00:00
|
|
|
cv[6].destination = s->mc_namespace;
|
2005-08-17 17:36:03 +00:00
|
|
|
cv[7].destination = &(s->debug);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
p->config_storage[i] = s;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-11-07 12:51:11 +00:00
|
|
|
if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
|
2005-07-07 22:48:42 +00:00
|
|
|
return HANDLER_ERROR;
|
|
|
|
}
|
|
|
|
#if defined(HAVE_GDBM_H)
|
2015-02-08 12:37:10 +00:00
|
|
|
if (!buffer_string_is_empty(s->db_filename)) {
|
2005-07-07 22:48:42 +00:00
|
|
|
if (NULL == (s->db = gdbm_open(s->db_filename->ptr, 4096, GDBM_WRCREAT | GDBM_NOLOCK, S_IRUSR | S_IWUSR, 0))) {
|
2006-10-04 13:26:23 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s",
|
2005-07-07 22:48:42 +00:00
|
|
|
"gdbm-open failed");
|
|
|
|
return HANDLER_ERROR;
|
|
|
|
}
|
2014-02-16 13:08:29 +00:00
|
|
|
fd_close_on_exec(gdbm_fdesc(s->db));
|
2005-07-07 22:48:42 +00:00
|
|
|
}
|
|
|
|
#endif
|
2006-10-04 13:26:23 +00:00
|
|
|
#if defined(HAVE_PCRE_H)
|
2015-02-08 12:37:10 +00:00
|
|
|
if (!buffer_string_is_empty(s->download_url)) {
|
2005-07-07 22:48:42 +00:00
|
|
|
if (NULL == (s->download_regex = pcre_compile(s->download_url->ptr,
|
|
|
|
0, &errptr, &erroff, NULL))) {
|
2006-10-04 13:26:23 +00:00
|
|
|
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sbss",
|
|
|
|
"compiling regex for download-url failed:",
|
2005-07-07 22:48:42 +00:00
|
|
|
s->download_url, "pos:", erroff);
|
|
|
|
return HANDLER_ERROR;
|
|
|
|
}
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-02-08 12:37:10 +00:00
|
|
|
if (!buffer_string_is_empty(s->trigger_url)) {
|
2005-07-07 22:48:42 +00:00
|
|
|
if (NULL == (s->trigger_regex = pcre_compile(s->trigger_url->ptr,
|
|
|
|
0, &errptr, &erroff, NULL))) {
|
2006-10-04 13:26:23 +00:00
|
|
|
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sbss",
|
|
|
|
"compiling regex for trigger-url failed:",
|
2005-07-07 22:48:42 +00:00
|
|
|
s->trigger_url, "pos:", erroff);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
return HANDLER_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (s->mc_hosts->used) {
|
2016-01-03 14:48:11 +00:00
|
|
|
#if defined(USE_MEMCACHED)
|
|
|
|
buffer *option_string = buffer_init();
|
2005-08-17 17:36:03 +00:00
|
|
|
size_t k;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2016-01-03 14:48:11 +00:00
|
|
|
{
|
|
|
|
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++) {
|
2005-07-07 22:48:42 +00:00
|
|
|
data_string *ds = (data_string *)s->mc_hosts->data[k];
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2016-01-03 14:48:11 +00:00
|
|
|
buffer_append_string_len(option_string, CONST_STR_LEN(" --SERVER="));
|
|
|
|
buffer_append_string_buffer(option_string, ds->value);
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2016-01-03 14:48:11 +00:00
|
|
|
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);
|
2005-07-07 22:48:42 +00:00
|
|
|
}
|
2016-01-03 14:48:11 +00:00
|
|
|
buffer_free(option_string);
|
|
|
|
|
|
|
|
if (NULL == s->memc) return HANDLER_ERROR;
|
2005-07-07 22:48:42 +00:00
|
|
|
#else
|
2006-10-04 13:26:23 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s",
|
2005-07-07 22:48:42 +00:00
|
|
|
"memcache support is not compiled in but trigger-before-download.memcache-hosts is set, aborting");
|
|
|
|
return HANDLER_ERROR;
|
|
|
|
#endif
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
|
2016-01-03 14:48:11 +00:00
|
|
|
#if (!defined(HAVE_GDBM_H) && !defined(USE_MEMCACHED)) || !defined(HAVE_PCRE_H)
|
2006-10-04 13:26:23 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s",
|
2005-07-07 22:48:42 +00:00
|
|
|
"(either gdbm or libmemcache) and pcre are require, but were not found, aborting");
|
|
|
|
return HANDLER_ERROR;
|
|
|
|
#endif
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +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_trigger_b4_dl_patch_connection(server *srv, connection *con, plugin_data *p) {
|
2005-07-07 22:48:42 +00:00
|
|
|
size_t i, j;
|
2005-08-08 10:27:07 +00:00
|
|
|
plugin_config *s = p->config_storage[0];
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-17 17:36:03 +00:00
|
|
|
#if defined(HAVE_GDBM)
|
2005-08-08 10:27:07 +00:00
|
|
|
PATCH(db);
|
2006-10-04 13:26:23 +00:00
|
|
|
#endif
|
2005-08-17 17:36:03 +00:00
|
|
|
#if defined(HAVE_PCRE_H)
|
2005-08-08 10:27:07 +00:00
|
|
|
PATCH(download_regex);
|
|
|
|
PATCH(trigger_regex);
|
2006-10-04 13:26:23 +00:00
|
|
|
#endif
|
2005-08-08 10:27:07 +00:00
|
|
|
PATCH(trigger_timeout);
|
|
|
|
PATCH(deny_url);
|
2005-08-17 17:36:03 +00:00
|
|
|
PATCH(mc_namespace);
|
|
|
|
PATCH(debug);
|
2016-01-03 14:48:11 +00:00
|
|
|
#if defined(USE_MEMCACHED)
|
|
|
|
PATCH(memc);
|
2005-08-17 17:36:03 +00:00
|
|
|
#endif
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +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];
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
/* condition didn't match */
|
|
|
|
if (!config_check_cond(srv, con, dc)) continue;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
/* 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("trigger-before-download.download-url"))) {
|
|
|
|
#if defined(HAVE_PCRE_H)
|
|
|
|
PATCH(download_regex);
|
|
|
|
#endif
|
|
|
|
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-url"))) {
|
|
|
|
# if defined(HAVE_PCRE_H)
|
|
|
|
PATCH(trigger_regex);
|
|
|
|
# endif
|
|
|
|
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.gdbm-filename"))) {
|
|
|
|
#if defined(HAVE_GDBM_H)
|
|
|
|
PATCH(db);
|
|
|
|
#endif
|
|
|
|
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-timeout"))) {
|
|
|
|
PATCH(trigger_timeout);
|
2005-08-17 17:36:03 +00:00
|
|
|
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.debug"))) {
|
|
|
|
PATCH(debug);
|
2005-07-07 22:48:42 +00:00
|
|
|
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.deny-url"))) {
|
|
|
|
PATCH(deny_url);
|
2005-07-08 22:28:46 +00:00
|
|
|
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-namespace"))) {
|
|
|
|
PATCH(mc_namespace);
|
2005-07-07 22:48:42 +00:00
|
|
|
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-hosts"))) {
|
2016-01-03 14:48:11 +00:00
|
|
|
#if defined(USE_MEMCACHED)
|
|
|
|
PATCH(memc);
|
2005-07-07 22:48:42 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#undef PATCH
|
|
|
|
|
|
|
|
URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
|
|
|
|
plugin_data *p = p_d;
|
|
|
|
const char *remote_ip;
|
|
|
|
data_string *ds;
|
|
|
|
|
|
|
|
#if defined(HAVE_PCRE_H)
|
|
|
|
int n;
|
|
|
|
# define N 10
|
|
|
|
int ovec[N * 3];
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2008-08-01 16:13:34 +00:00
|
|
|
if (con->mode != DIRECT) return HANDLER_GO_ON;
|
|
|
|
|
2015-02-08 19:10:44 +00:00
|
|
|
if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-08 10:27:07 +00:00
|
|
|
mod_trigger_b4_dl_patch_connection(srv, con, p);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-09 20:18:10 +00:00
|
|
|
if (!p->conf.trigger_regex || !p->conf.download_regex) return HANDLER_GO_ON;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2016-01-03 14:48:11 +00:00
|
|
|
# if !defined(HAVE_GDBM_H) && !defined(USE_MEMCACHED)
|
2005-07-09 20:18:10 +00:00
|
|
|
return HANDLER_GO_ON;
|
2016-01-03 14:48:11 +00:00
|
|
|
# elif defined(HAVE_GDBM_H) && defined(USE_MEMCACHED)
|
|
|
|
if (!p->conf.db && !p->conf.memc) return HANDLER_GO_ON;
|
|
|
|
if (p->conf.db && p->conf.memc) {
|
2005-07-09 20:18:10 +00:00
|
|
|
/* can't decide which one */
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-09 20:18:10 +00:00
|
|
|
return HANDLER_GO_ON;
|
|
|
|
}
|
|
|
|
# elif defined(HAVE_GDBM_H)
|
2005-07-10 06:25:10 +00:00
|
|
|
if (!p->conf.db) return HANDLER_GO_ON;
|
2005-07-09 20:18:10 +00:00
|
|
|
# else
|
2016-01-03 14:48:11 +00:00
|
|
|
if (!p->conf.memc) return HANDLER_GO_ON;
|
2005-07-09 20:18:10 +00:00
|
|
|
# endif
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "X-Forwarded-For"))) {
|
|
|
|
/* X-Forwarded-For contains the ip behind the proxy */
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
remote_ip = ds->value->ptr;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-12 18:25:18 +00:00
|
|
|
/* memcache can't handle spaces */
|
2005-07-07 22:48:42 +00:00
|
|
|
} else {
|
|
|
|
remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
|
|
|
|
}
|
2005-08-17 17:36:03 +00:00
|
|
|
|
|
|
|
if (p->conf.debug) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "ss", "(debug) remote-ip:", remote_ip);
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
/* check if URL is a trigger -> insert IP into DB */
|
2015-02-08 19:10:44 +00:00
|
|
|
if ((n = pcre_exec(p->conf.trigger_regex, NULL, CONST_BUF_LEN(con->uri.path), 0, 0, ovec, 3 * N)) < 0) {
|
2005-07-07 22:48:42 +00:00
|
|
|
if (n != PCRE_ERROR_NOMATCH) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sd",
|
|
|
|
"execution error while matching:", n);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
return HANDLER_ERROR;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
# if defined(HAVE_GDBM_H)
|
2005-07-09 20:18:10 +00:00
|
|
|
if (p->conf.db) {
|
2005-07-07 22:48:42 +00:00
|
|
|
/* the trigger matched */
|
|
|
|
datum key, val;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
key.dptr = (char *)remote_ip;
|
|
|
|
key.dsize = strlen(remote_ip);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
val.dptr = (char *)&(srv->cur_ts);
|
|
|
|
val.dsize = sizeof(srv->cur_ts);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s",
|
|
|
|
"insert failed");
|
|
|
|
}
|
2005-07-09 20:18:10 +00:00
|
|
|
}
|
2005-07-07 22:48:42 +00:00
|
|
|
# endif
|
2016-01-03 14:48:11 +00:00
|
|
|
# if defined(USE_MEMCACHED)
|
|
|
|
if (p->conf.memc) {
|
2015-02-08 19:10:44 +00:00
|
|
|
size_t i, len;
|
2015-02-08 12:37:10 +00:00
|
|
|
buffer_copy_buffer(p->tmp_buf, p->conf.mc_namespace);
|
2005-07-08 22:28:46 +00:00
|
|
|
buffer_append_string(p->tmp_buf, remote_ip);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-02-08 19:10:44 +00:00
|
|
|
len = buffer_string_length(p->tmp_buf);
|
|
|
|
for (i = 0; i < len; i++) {
|
2005-07-12 18:25:18 +00:00
|
|
|
if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-17 17:36:03 +00:00
|
|
|
if (p->conf.debug) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) triggered IP:", p->tmp_buf);
|
|
|
|
}
|
|
|
|
|
2016-01-03 14:48:11 +00:00
|
|
|
if (MEMCACHED_SUCCESS != memcached_set(p->conf.memc,
|
2005-07-08 22:28:46 +00:00
|
|
|
CONST_BUF_LEN(p->tmp_buf),
|
2016-01-03 14:48:11 +00:00
|
|
|
(const char *)&(srv->cur_ts), sizeof(srv->cur_ts),
|
2005-07-07 22:48:42 +00:00
|
|
|
p->conf.trigger_timeout, 0)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s",
|
2016-01-03 14:48:11 +00:00
|
|
|
"insert failed");
|
2005-07-07 22:48:42 +00:00
|
|
|
}
|
|
|
|
}
|
2005-07-09 20:18:10 +00:00
|
|
|
# endif
|
2005-07-07 22:48:42 +00:00
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
/* check if URL is a download -> check IP in DB, update timestamp */
|
2015-02-08 19:10:44 +00:00
|
|
|
if ((n = pcre_exec(p->conf.download_regex, NULL, CONST_BUF_LEN(con->uri.path), 0, 0, ovec, 3 * N)) < 0) {
|
2005-07-07 22:48:42 +00:00
|
|
|
if (n != PCRE_ERROR_NOMATCH) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sd",
|
|
|
|
"execution error while matching: ", n);
|
|
|
|
return HANDLER_ERROR;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* the download uri matched */
|
2006-10-04 13:26:23 +00:00
|
|
|
# if defined(HAVE_GDBM_H)
|
2005-07-07 22:48:42 +00:00
|
|
|
if (p->conf.db) {
|
|
|
|
datum key, val;
|
2005-07-09 20:18:10 +00:00
|
|
|
time_t last_hit;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
key.dptr = (char *)remote_ip;
|
|
|
|
key.dsize = strlen(remote_ip);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
val = gdbm_fetch(p->conf.db, key);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
if (val.dptr == NULL) {
|
|
|
|
/* not found, redirect */
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
|
|
|
|
con->http_status = 307;
|
2008-07-20 12:58:18 +00:00
|
|
|
con->file_finished = 1;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
return HANDLER_FINISHED;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2013-05-15 10:31:09 +00:00
|
|
|
memcpy(&last_hit, val.dptr, sizeof(time_t));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
free(val.dptr);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
if (srv->cur_ts - last_hit > p->conf.trigger_timeout) {
|
|
|
|
/* found, but timeout, redirect */
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
|
|
|
|
con->http_status = 307;
|
2008-07-20 12:58:18 +00:00
|
|
|
con->file_finished = 1;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
if (p->conf.db) {
|
|
|
|
if (0 != gdbm_delete(p->conf.db, key)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s",
|
|
|
|
"delete failed");
|
|
|
|
}
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
return HANDLER_FINISHED;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
val.dptr = (char *)&(srv->cur_ts);
|
|
|
|
val.dsize = sizeof(srv->cur_ts);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s",
|
|
|
|
"insert failed");
|
|
|
|
}
|
2005-07-09 20:18:10 +00:00
|
|
|
}
|
2005-07-07 22:48:42 +00:00
|
|
|
# endif
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2016-01-03 14:48:11 +00:00
|
|
|
# if defined(USE_MEMCACHED)
|
|
|
|
if (p->conf.memc) {
|
2015-02-08 19:10:44 +00:00
|
|
|
size_t i, len;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-02-08 12:37:10 +00:00
|
|
|
buffer_copy_buffer(p->tmp_buf, p->conf.mc_namespace);
|
2005-07-08 22:28:46 +00:00
|
|
|
buffer_append_string(p->tmp_buf, remote_ip);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2015-02-08 19:10:44 +00:00
|
|
|
len = buffer_string_length(p->tmp_buf);
|
|
|
|
for (i = 0; i < len; i++) {
|
2005-07-12 18:25:18 +00:00
|
|
|
if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-17 17:36:03 +00:00
|
|
|
if (p->conf.debug) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) checking IP:", p->tmp_buf);
|
|
|
|
}
|
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
/**
|
2006-10-04 13:26:23 +00:00
|
|
|
*
|
2005-07-07 22:48:42 +00:00
|
|
|
* memcached is do expiration for us, as long as we can fetch it every thing is ok
|
2006-10-04 13:26:23 +00:00
|
|
|
* and the timestamp is updated
|
|
|
|
*
|
2005-07-07 22:48:42 +00:00
|
|
|
*/
|
2016-01-03 14:48:11 +00:00
|
|
|
if (MEMCACHED_SUCCESS != memcached_exist(p->conf.memc, CONST_BUF_LEN(p->tmp_buf))) {
|
2005-07-07 22:48:42 +00:00
|
|
|
response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
con->http_status = 307;
|
2008-07-20 12:58:18 +00:00
|
|
|
con->file_finished = 1;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
return HANDLER_FINISHED;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
/* set a new timeout */
|
2016-01-03 14:48:11 +00:00
|
|
|
if (MEMCACHED_SUCCESS != memcached_set(p->conf.memc,
|
2005-07-08 22:28:46 +00:00
|
|
|
CONST_BUF_LEN(p->tmp_buf),
|
2016-01-03 14:48:11 +00:00
|
|
|
(const char *)&(srv->cur_ts), sizeof(srv->cur_ts),
|
2005-07-07 22:48:42 +00:00
|
|
|
p->conf.trigger_timeout, 0)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s",
|
2016-01-03 14:48:11 +00:00
|
|
|
"insert failed");
|
2005-07-07 22:48:42 +00:00
|
|
|
}
|
|
|
|
}
|
2005-07-09 20:18:10 +00:00
|
|
|
# endif
|
2005-07-07 22:48:42 +00:00
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
#else
|
|
|
|
UNUSED(srv);
|
|
|
|
UNUSED(con);
|
|
|
|
UNUSED(p_d);
|
|
|
|
#endif
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
return HANDLER_GO_ON;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(HAVE_GDBM_H)
|
2005-07-15 17:45:57 +00:00
|
|
|
TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
|
2005-07-07 22:48:42 +00:00
|
|
|
plugin_data *p = p_d;
|
|
|
|
size_t i;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
/* check DB each minute */
|
|
|
|
if (srv->cur_ts % 60 != 0) return HANDLER_GO_ON;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
/* cleanup */
|
|
|
|
for (i = 0; i < srv->config_context->used; i++) {
|
|
|
|
plugin_config *s = p->config_storage[i];
|
|
|
|
datum key, val, okey;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
if (!s->db) continue;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
okey.dptr = NULL;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
|
|
|
/* according to the manual this loop + delete does delete all entries on its way
|
|
|
|
*
|
2005-07-07 22:48:42 +00:00
|
|
|
* we don't care as the next round will remove them. We don't have to perfect here.
|
|
|
|
*/
|
|
|
|
for (key = gdbm_firstkey(s->db); key.dptr; key = gdbm_nextkey(s->db, okey)) {
|
|
|
|
time_t last_hit;
|
|
|
|
if (okey.dptr) {
|
|
|
|
free(okey.dptr);
|
|
|
|
okey.dptr = NULL;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
val = gdbm_fetch(s->db, key);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2013-05-15 10:31:09 +00:00
|
|
|
memcpy(&last_hit, val.dptr, sizeof(time_t));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
free(val.dptr);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
if (srv->cur_ts - last_hit > s->trigger_timeout) {
|
|
|
|
gdbm_delete(s->db, key);
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
okey = key;
|
|
|
|
}
|
|
|
|
if (okey.dptr) free(okey.dptr);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
/* reorg once a day */
|
|
|
|
if ((srv->cur_ts % (60 * 60 * 24) != 0)) gdbm_reorganize(s->db);
|
|
|
|
}
|
|
|
|
return HANDLER_GO_ON;
|
|
|
|
}
|
2005-07-15 17:45:57 +00:00
|
|
|
#endif
|
2005-07-07 22:48:42 +00:00
|
|
|
|
|
|
|
/* this function is called at dlopen() time and inits the callbacks */
|
|
|
|
|
2009-03-07 21:05:37 +00:00
|
|
|
int mod_trigger_b4_dl_plugin_init(plugin *p);
|
2005-07-07 22:48:42 +00:00
|
|
|
int mod_trigger_b4_dl_plugin_init(plugin *p) {
|
|
|
|
p->version = LIGHTTPD_VERSION_ID;
|
|
|
|
p->name = buffer_init_string("trigger_b4_dl");
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
p->init = mod_trigger_b4_dl_init;
|
|
|
|
p->handle_uri_clean = mod_trigger_b4_dl_uri_handler;
|
|
|
|
p->set_defaults = mod_trigger_b4_dl_set_defaults;
|
2005-07-15 17:45:57 +00:00
|
|
|
#if defined(HAVE_GDBM_H)
|
2005-07-07 22:48:42 +00:00
|
|
|
p->handle_trigger = mod_trigger_b4_dl_handle_trigger;
|
2005-07-15 17:45:57 +00:00
|
|
|
#endif
|
2005-07-07 22:48:42 +00:00
|
|
|
p->cleanup = mod_trigger_b4_dl_free;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
p->data = NULL;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-07-07 22:48:42 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2015-08-29 09:28:01 +00:00
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
#pragma message("(either gdbm or libmemcache) and pcre are required, but were not found")
|
|
|
|
|
|
|
|
int mod_trigger_b4_dl_plugin_init(plugin *p);
|
|
|
|
int mod_trigger_b4_dl_plugin_init(plugin *p) {
|
|
|
|
UNUSED(p);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|