added trigger-b4-dl, upped version number to .15
git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.3.x@429 152afb58-edef-0310-8abb-c4023f1b3aa9
This commit is contained in:
parent
6d60bcb040
commit
a3f7300ec9
30
configure.in
30
configure.in
|
@ -1,7 +1,7 @@
|
|||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
AC_PREREQ(2.57)
|
||||
AC_INIT(lighttpd, 1.3.14, jan@kneschke.de)
|
||||
AC_INIT(lighttpd, 1.3.15, jan@kneschke.de)
|
||||
AC_CONFIG_SRCDIR([src/server.c])
|
||||
|
||||
AC_CANONICAL_TARGET
|
||||
|
@ -245,6 +245,34 @@ AC_CHECK_LIB(bz2, BZ2_bzCompress, [
|
|||
])
|
||||
AC_SUBST(BZ_LIB)
|
||||
|
||||
|
||||
AC_MSG_CHECKING(for gdbm)
|
||||
AC_ARG_WITH(gdbm, AC_HELP_STRING([--with-gdbm],[gdbm storage for mod_trigger_b4_dl]),
|
||||
[AC_MSG_RESULT(yes)
|
||||
AC_CHECK_LIB(gdbm, gdbm_open, [
|
||||
AC_CHECK_HEADERS([gdbm.h],[
|
||||
GDBM_LIB=-lgdbm
|
||||
AC_DEFINE([HAVE_GDBM], [1], [libgdbm])
|
||||
AC_DEFINE([HAVE_GDBM_H], [1])
|
||||
])
|
||||
])
|
||||
],[AC_MSG_RESULT(no)])
|
||||
AC_SUBST(GDBM_LIB)
|
||||
|
||||
AC_MSG_CHECKING(for libmemcache)
|
||||
AC_ARG_WITH(gdbm, AC_HELP_STRING([--with-libmemcache],[memcached storage for mod_trigger_b4_dl]),
|
||||
[AC_MSG_RESULT(yes)
|
||||
AC_CHECK_LIB(memcache, mc_new, [
|
||||
AC_CHECK_HEADERS([memcache.h],[
|
||||
MEMCACHE_LIB=-lmemcache
|
||||
AC_DEFINE([HAVE_MEMCACHE], [1], [libmemcache])
|
||||
AC_DEFINE([HAVE_MEMCACHE_H], [1])
|
||||
])
|
||||
])
|
||||
],[AC_MSG_RESULT(no)])
|
||||
AC_SUBST(MEMCACHE_LIB)
|
||||
|
||||
|
||||
AC_SEARCH_LIBS(socket,socket)
|
||||
AC_SEARCH_LIBS(gethostbyname,nsl socket)
|
||||
AC_SEARCH_LIBS(hstrerror,resolv)
|
||||
|
|
|
@ -30,7 +30,8 @@ traffic-shaping.txt \
|
|||
setenv.txt \
|
||||
status.txt \
|
||||
scgi.txt \
|
||||
cml.txt
|
||||
cml.txt \
|
||||
trigger_b4_dl.txt
|
||||
|
||||
HTMLDOCS=accesslog.html \
|
||||
authentication.html \
|
||||
|
@ -61,7 +62,8 @@ HTMLDOCS=accesslog.html \
|
|||
setenv.html \
|
||||
status.html \
|
||||
scgi.html \
|
||||
cml.html
|
||||
cml.html \
|
||||
trigger_b4_dl.html
|
||||
|
||||
EXTRA_DIST=lighttpd.conf lighttpd.user \
|
||||
rc.lighttpd rc.lighttpd.redhat sysconfig.lighttpd \
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
=======================
|
||||
Trigger before Download
|
||||
=======================
|
||||
|
||||
-------------------------
|
||||
Module: mod_trigger_b4_dl
|
||||
-------------------------
|
||||
|
||||
:Author: Jan Kneschke
|
||||
:Date: $Date: 2004/11/03 22:26:05 $
|
||||
:Revision: $Revision: 1.2 $
|
||||
|
||||
:abstract:
|
||||
another anti hot-linking module
|
||||
|
||||
.. meta::
|
||||
:keywords: lighttpd, hot-linking, deep-linking
|
||||
|
||||
.. contents:: Table of Contents
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
Anti Hotlinking:
|
||||
|
||||
* if user requests ''download-url'' directly the request is denied and he is redirected to ''deny-url'
|
||||
* if user visits ''trigger-url'' before requesting ''download-url'' access is granted
|
||||
* if user visits ''download-url'' again after ''trigger-timeout'' has run down to the request is denied and he is redirected to ''deny-url''
|
||||
|
||||
The storage for the trigger information is either stored locally in a gdbm file or remotly in memcached.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
* libpcre
|
||||
* libgdbm
|
||||
* libmemcache
|
||||
|
||||
Options
|
||||
=======
|
||||
|
||||
::
|
||||
|
||||
trigger-before-download.gdbm-filename = "/home/weigon/testbase/trigger.db"
|
||||
trigger-before-download.memcache-hosts = ( "127.0.0.1:11211" )
|
||||
trigger-before-download.trigger-url = "^/trigger/"
|
||||
trigger-before-download.download-url = "^/download/"
|
||||
trigger-before-download.deny-url = "http://192.168.1.5:1025/index.html"
|
||||
trigger-before-download.trigger-timeout = 10
|
||||
|
||||
If both trigger-before-download.gdbm-filename and
|
||||
trigger-before-download.memcache-hosts is set gdbm will be prefered.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
memcached should be started with the option -M as we don't want to remove entry if the memory is full.
|
||||
|
|
@ -73,6 +73,11 @@ mod_cml_la_SOURCES = mod_cml.c mod_cml_funcs.c mod_cml_logic.c
|
|||
mod_cml_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
|
||||
mod_cml_la_LIBADD = $(MYSQL_LIBS) $(common_libadd)
|
||||
|
||||
lib_LTLIBRARIES += mod_trigger_b4_dl.la
|
||||
mod_trigger_b4_dl_la_SOURCES = mod_trigger_b4_dl.c
|
||||
mod_trigger_b4_dl_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
|
||||
mod_trigger_b4_dl_la_LIBADD = $(GDBM_LIB) $(MEMCACHE_LIB) $(common_libadd)
|
||||
|
||||
lib_LTLIBRARIES += mod_mysql_vhost.la
|
||||
mod_mysql_vhost_la_SOURCES = mod_mysql_vhost.c
|
||||
mod_mysql_vhost_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
|
||||
|
|
|
@ -0,0 +1,541 @@
|
|||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
#include "base.h"
|
||||
#include "log.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#include "plugin.h"
|
||||
#include "response.h"
|
||||
#include "inet_ntop_cache.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined(HAVE_GDBM_H)
|
||||
#include <gdbm.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_PCRE_H)
|
||||
#include <pcre.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_MEMCACHE_H)
|
||||
#include <memcache.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* this is a trigger_b4_dl for a lighttpd plugin
|
||||
*
|
||||
*/
|
||||
|
||||
/* plugin config for all request/connections */
|
||||
|
||||
typedef struct {
|
||||
buffer *db_filename;
|
||||
|
||||
buffer *trigger_url;
|
||||
buffer *download_url;
|
||||
buffer *deny_url;
|
||||
|
||||
array *mc_hosts;
|
||||
#if defined(HAVE_PCRE_H)
|
||||
pcre *trigger_regex;
|
||||
pcre *download_regex;
|
||||
#endif
|
||||
#if defined(HAVE_GDBM_H)
|
||||
GDBM_FILE db;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_MEMCACHE_H)
|
||||
struct memcache *mc;
|
||||
#endif
|
||||
|
||||
unsigned short trigger_timeout;
|
||||
} plugin_config;
|
||||
|
||||
typedef struct {
|
||||
PLUGIN_DATA;
|
||||
|
||||
plugin_config **config_storage;
|
||||
|
||||
plugin_config conf;
|
||||
} plugin_data;
|
||||
|
||||
/* init the plugin data */
|
||||
INIT_FUNC(mod_trigger_b4_dl_init) {
|
||||
plugin_data *p;
|
||||
|
||||
p = calloc(1, sizeof(*p));
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/* detroy the plugin data */
|
||||
FREE_FUNC(mod_trigger_b4_dl_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];
|
||||
|
||||
buffer_free(s->db_filename);
|
||||
buffer_free(s->download_url);
|
||||
buffer_free(s->trigger_url);
|
||||
buffer_free(s->deny_url);
|
||||
|
||||
#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)
|
||||
if (s->db) {
|
||||
gdbm_close(s->db);
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_MEMCACHE_H)
|
||||
if (s->mc) {
|
||||
mc_free(s->mc);
|
||||
}
|
||||
#endif
|
||||
|
||||
free(s);
|
||||
}
|
||||
free(p->config_storage);
|
||||
}
|
||||
|
||||
free(p);
|
||||
|
||||
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;
|
||||
|
||||
|
||||
config_values_t cv[] = {
|
||||
{ "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 */
|
||||
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
|
||||
};
|
||||
|
||||
if (!p) return HANDLER_ERROR;
|
||||
|
||||
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
|
||||
|
||||
for (i = 0; i < srv->config_context->used; i++) {
|
||||
plugin_config *s;
|
||||
size_t k;
|
||||
#if defined(HAVE_PCRE_H)
|
||||
const char *errptr;
|
||||
int erroff;
|
||||
#endif
|
||||
|
||||
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();
|
||||
|
||||
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;
|
||||
|
||||
p->config_storage[i] = s;
|
||||
|
||||
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
#if defined(HAVE_GDBM_H)
|
||||
if (!buffer_is_empty(s->db_filename)) {
|
||||
if (NULL == (s->db = gdbm_open(s->db_filename->ptr, 4096, GDBM_WRCREAT | GDBM_NOLOCK, S_IRUSR | S_IWUSR, 0))) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"gdbm-open failed");
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_PCRE_H)
|
||||
if (!buffer_is_empty(s->download_url)) {
|
||||
if (NULL == (s->download_regex = pcre_compile(s->download_url->ptr,
|
||||
0, &errptr, &erroff, NULL))) {
|
||||
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbss",
|
||||
"compiling regex for download-url failed:",
|
||||
s->download_url, "pos:", erroff);
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (!buffer_is_empty(s->trigger_url)) {
|
||||
if (NULL == (s->trigger_regex = pcre_compile(s->trigger_url->ptr,
|
||||
0, &errptr, &erroff, NULL))) {
|
||||
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbss",
|
||||
"compiling regex for trigger-url failed:",
|
||||
s->trigger_url, "pos:", erroff);
|
||||
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (s->mc_hosts->used) {
|
||||
#if defined(HAVE_MEMCACHE_H)
|
||||
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 trigger-before-download.memcache-hosts is set, aborting");
|
||||
return HANDLER_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if (!defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)) || !defined(HAVE_PCRE_H)
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"(either gdbm or libmemcache) and pcre are require, but were not found, aborting");
|
||||
return HANDLER_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
return HANDLER_GO_ON;
|
||||
}
|
||||
|
||||
#define PATCH(x) \
|
||||
p->conf.x = s->x;
|
||||
static int mod_trigger_b4_dl_patch_connection(server *srv, connection *con, plugin_data *p, const char *stage, size_t stage_len) {
|
||||
size_t i, j;
|
||||
|
||||
/* 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];
|
||||
plugin_config *s = p->config_storage[i];
|
||||
|
||||
/* not our stage */
|
||||
if (!buffer_is_equal_string(dc->comp_key, stage, stage_len)) continue;
|
||||
|
||||
/* 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];
|
||||
|
||||
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);
|
||||
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.deny-url"))) {
|
||||
PATCH(deny_url);
|
||||
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-hosts"))) {
|
||||
#if defined(HAVE_MEMCACHE_H)
|
||||
PATCH(mc);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mod_trigger_b4_dl_setup_connection(server *srv, connection *con, plugin_data *p) {
|
||||
plugin_config *s = p->config_storage[0];
|
||||
UNUSED(srv);
|
||||
UNUSED(con);
|
||||
#if defined(HAVE_GDBM_H)
|
||||
PATCH(db);
|
||||
#endif
|
||||
#if defined(HAVE_PCRE_H)
|
||||
PATCH(download_regex);
|
||||
PATCH(trigger_regex);
|
||||
#endif
|
||||
PATCH(trigger_timeout);
|
||||
PATCH(deny_url);
|
||||
#if defined(HAVE_MEMCACHE_H)
|
||||
PATCH(mc);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#undef PATCH
|
||||
|
||||
URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
|
||||
plugin_data *p = p_d;
|
||||
size_t i;
|
||||
const char *remote_ip;
|
||||
data_string *ds;
|
||||
|
||||
#if defined(HAVE_PCRE_H)
|
||||
int n;
|
||||
# define N 10
|
||||
int ovec[N * 3];
|
||||
|
||||
if (con->uri.path->used == 0) return HANDLER_GO_ON;
|
||||
|
||||
mod_trigger_b4_dl_setup_connection(srv, con, p);
|
||||
for (i = 0; i < srv->config_patches->used; i++) {
|
||||
buffer *patch = srv->config_patches->ptr[i];
|
||||
|
||||
mod_trigger_b4_dl_patch_connection(srv, con, p, CONST_BUF_LEN(patch));
|
||||
}
|
||||
|
||||
if (!p->conf.trigger_regex || !p->conf.download_regex || (!p->conf.db && !p->conf.mc)) return HANDLER_GO_ON;
|
||||
|
||||
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "X-Forwarded-For"))) {
|
||||
/* X-Forwarded-For contains the ip behind the proxy */
|
||||
|
||||
remote_ip = ds->value->ptr;
|
||||
} else {
|
||||
remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
|
||||
}
|
||||
|
||||
/* check if URL is a trigger -> insert IP into DB */
|
||||
if ((n = pcre_exec(p->conf.trigger_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
|
||||
if (n != PCRE_ERROR_NOMATCH) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sd",
|
||||
"execution error while matching:", n);
|
||||
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
} else {
|
||||
if (p->conf.db) {
|
||||
# if defined(HAVE_GDBM_H)
|
||||
/* the trigger matched */
|
||||
datum key, val;
|
||||
|
||||
key.dptr = (char *)remote_ip;
|
||||
key.dsize = strlen(remote_ip);
|
||||
|
||||
val.dptr = (char *)&(srv->cur_ts);
|
||||
val.dsize = sizeof(srv->cur_ts);
|
||||
|
||||
if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"insert failed");
|
||||
}
|
||||
# endif
|
||||
} else if (p->conf.mc) {
|
||||
# if defined(HAVE_MEMCACHE_H)
|
||||
if (0 != mc_set(p->conf.mc,
|
||||
(char *)remote_ip, strlen(remote_ip),
|
||||
(char *)&(srv->cur_ts), sizeof(srv->cur_ts),
|
||||
p->conf.trigger_timeout, 0)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"insert failed");
|
||||
}
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
/* check if URL is a download -> check IP in DB, update timestamp */
|
||||
if ((n = pcre_exec(p->conf.download_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
|
||||
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 */
|
||||
time_t last_hit;
|
||||
|
||||
if (p->conf.db) {
|
||||
# if defined(HAVE_GDBM_H)
|
||||
datum key, val;
|
||||
|
||||
key.dptr = (char *)remote_ip;
|
||||
key.dsize = strlen(remote_ip);
|
||||
|
||||
val = gdbm_fetch(p->conf.db, key);
|
||||
|
||||
if (val.dptr == NULL) {
|
||||
/* not found, redirect */
|
||||
|
||||
response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
|
||||
|
||||
con->http_status = 307;
|
||||
|
||||
return HANDLER_FINISHED;
|
||||
}
|
||||
|
||||
last_hit = *(time_t *)(val.dptr);
|
||||
|
||||
free(val.dptr);
|
||||
|
||||
if (srv->cur_ts - last_hit > p->conf.trigger_timeout) {
|
||||
/* found, but timeout, redirect */
|
||||
|
||||
response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
|
||||
con->http_status = 307;
|
||||
|
||||
if (p->conf.db) {
|
||||
if (0 != gdbm_delete(p->conf.db, key)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"delete failed");
|
||||
}
|
||||
} else if (p->conf.mc) {
|
||||
if (0 != mc_delete(p->conf.mc,
|
||||
(char *)remote_ip, strlen(remote_ip),
|
||||
0)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"insert failed");
|
||||
}
|
||||
}
|
||||
|
||||
return HANDLER_FINISHED;
|
||||
}
|
||||
|
||||
val.dptr = (char *)&(srv->cur_ts);
|
||||
val.dsize = sizeof(srv->cur_ts);
|
||||
|
||||
if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"insert failed");
|
||||
}
|
||||
# endif
|
||||
} else if (p->conf.mc) {
|
||||
# if defined(HAVE_MEMCACHE_H)
|
||||
void *r;
|
||||
|
||||
/**
|
||||
*
|
||||
* memcached is do expiration for us, as long as we can fetch it every thing is ok
|
||||
* and the timestamp is updated
|
||||
*
|
||||
*/
|
||||
if (NULL == (r = mc_aget(p->conf.mc,
|
||||
(char *)remote_ip, strlen(remote_ip)))) {
|
||||
|
||||
response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
|
||||
|
||||
con->http_status = 307;
|
||||
|
||||
return HANDLER_FINISHED;
|
||||
}
|
||||
|
||||
free(r);
|
||||
|
||||
/* set a new timeout */
|
||||
if (0 != mc_set(p->conf.mc,
|
||||
(char *)remote_ip, strlen(remote_ip),
|
||||
(char *)&(srv->cur_ts), sizeof(srv->cur_ts),
|
||||
p->conf.trigger_timeout, 0)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"insert failed");
|
||||
}
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
UNUSED(srv);
|
||||
UNUSED(con);
|
||||
UNUSED(p_d);
|
||||
#endif
|
||||
|
||||
return HANDLER_GO_ON;
|
||||
}
|
||||
|
||||
TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
|
||||
#if defined(HAVE_GDBM_H)
|
||||
plugin_data *p = p_d;
|
||||
size_t i;
|
||||
|
||||
/* check DB each minute */
|
||||
if (srv->cur_ts % 60 != 0) return HANDLER_GO_ON;
|
||||
|
||||
/* cleanup */
|
||||
for (i = 0; i < srv->config_context->used; i++) {
|
||||
plugin_config *s = p->config_storage[i];
|
||||
datum key, val, okey;
|
||||
|
||||
if (!s->db) continue;
|
||||
|
||||
okey.dptr = NULL;
|
||||
|
||||
/* according to the manual this loop + delete does delete all entries on its way
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
val = gdbm_fetch(s->db, key);
|
||||
|
||||
last_hit = *(time_t *)(val.dptr);
|
||||
|
||||
free(val.dptr);
|
||||
|
||||
if (srv->cur_ts - last_hit > s->trigger_timeout) {
|
||||
gdbm_delete(s->db, key);
|
||||
}
|
||||
|
||||
okey = key;
|
||||
}
|
||||
if (okey.dptr) free(okey.dptr);
|
||||
|
||||
/* reorg once a day */
|
||||
if ((srv->cur_ts % (60 * 60 * 24) != 0)) gdbm_reorganize(s->db);
|
||||
}
|
||||
#endif
|
||||
return HANDLER_GO_ON;
|
||||
}
|
||||
|
||||
/* this function is called at dlopen() time and inits the callbacks */
|
||||
|
||||
int mod_trigger_b4_dl_plugin_init(plugin *p) {
|
||||
p->version = LIGHTTPD_VERSION_ID;
|
||||
p->name = buffer_init_string("trigger_b4_dl");
|
||||
|
||||
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;
|
||||
p->handle_trigger = mod_trigger_b4_dl_handle_trigger;
|
||||
p->cleanup = mod_trigger_b4_dl_free;
|
||||
|
||||
p->data = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue