Annotation of embedaddon/lighttpd/src/mod_trigger_b4_dl.c, revision 1.1.1.3

1.1.1.3 ! misho       1: #include "first.h"
        !             2: 
1.1       misho       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: 
1.1.1.3 ! misho      16: #if (defined(HAVE_GDBM_H) || defined(USE_MEMCACHED)) && defined(HAVE_PCRE_H)
        !            17: 
1.1       misho      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: 
1.1.1.3 ! misho      26: #if defined(USE_MEMCACHED)
        !            27: # include <libmemcached/memcached.h>
1.1       misho      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: 
1.1.1.3 ! misho      54: #if defined(USE_MEMCACHED)
        !            55:        memcached_st *memc;
1.1       misho      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: 
1.1.1.3 ! misho      96:                        if (NULL == s) continue;
1.1       misho      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
1.1.1.3 ! misho     113: #if defined(USE_MEMCACHED)
        !           114:                        if (s->memc) memcached_free(s->memc);
1.1       misho     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: 
1.1.1.2   misho     150:        p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
1.1       misho     151: 
                    152:        for (i = 0; i < srv->config_context->used; i++) {
1.1.1.3 ! misho     153:                data_config const* config = (data_config const*)srv->config_context->data[i];
1.1       misho     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: 
1.1.1.3 ! misho     179:                if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
1.1       misho     180:                        return HANDLER_ERROR;
                    181:                }
                    182: #if defined(HAVE_GDBM_H)
1.1.1.3 ! misho     183:                if (!buffer_string_is_empty(s->db_filename)) {
1.1       misho     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:                        }
1.1.1.2   misho     189:                        fd_close_on_exec(gdbm_fdesc(s->db));
1.1       misho     190:                }
                    191: #endif
                    192: #if defined(HAVE_PCRE_H)
1.1.1.3 ! misho     193:                if (!buffer_string_is_empty(s->download_url)) {
1.1       misho     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: 
1.1.1.3 ! misho     204:                if (!buffer_string_is_empty(s->trigger_url)) {
1.1       misho     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) {
1.1.1.3 ! misho     218: #if defined(USE_MEMCACHED)
        !           219:                        buffer *option_string = buffer_init();
1.1       misho     220:                        size_t k;
                    221: 
1.1.1.3 ! misho     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++) {
1.1       misho     230:                                data_string *ds = (data_string *)s->mc_hosts->data[k];
                    231: 
1.1.1.3 ! misho     232:                                buffer_append_string_len(option_string, CONST_STR_LEN(" --SERVER="));
        !           233:                                buffer_append_string_buffer(option_string, ds->value);
        !           234:                        }
1.1       misho     235: 
1.1.1.3 ! misho     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);
1.1       misho     242:                        }
1.1.1.3 ! misho     243:                        buffer_free(option_string);
        !           244: 
        !           245:                        if (NULL == s->memc) return HANDLER_ERROR;
1.1       misho     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: 
1.1.1.3 ! misho     254: #if (!defined(HAVE_GDBM_H) && !defined(USE_MEMCACHED)) || !defined(HAVE_PCRE_H)
1.1       misho     255:                log_error_write(srv, __FILE__, __LINE__, "s",
1.1.1.3 ! misho     256:                                "(either gdbm or libmemcached) and pcre are require, but were not found, aborting");
1.1       misho     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);
1.1.1.3 ! misho     281: #if defined(USE_MEMCACHED)
        !           282:        PATCH(memc);
1.1       misho     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"))) {
1.1.1.3 ! misho     318: #if defined(USE_MEMCACHED)
        !           319:                                PATCH(memc);
1.1       misho     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: 
1.1.1.3 ! misho     341:        if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
1.1       misho     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: 
1.1.1.3 ! misho     347: # if !defined(HAVE_GDBM_H) && !defined(USE_MEMCACHED)
1.1       misho     348:        return HANDLER_GO_ON;
1.1.1.3 ! misho     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) {
1.1       misho     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
1.1.1.3 ! misho     359:        if (!p->conf.memc) return HANDLER_GO_ON;
1.1       misho     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 */
1.1.1.3 ! misho     377:        if ((n = pcre_exec(p->conf.trigger_regex, NULL, CONST_BUF_LEN(con->uri.path), 0, 0, ovec, 3 * N)) < 0) {
1.1       misho     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
1.1.1.3 ! misho     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);
1.1       misho     406:                        buffer_append_string(p->tmp_buf, remote_ip);
                    407: 
1.1.1.3 ! misho     408:                        len = buffer_string_length(p->tmp_buf);
        !           409:                        for (i = 0; i < len; i++) {
1.1       misho     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: 
1.1.1.3 ! misho     417:                        if (MEMCACHED_SUCCESS != memcached_set(p->conf.memc,
1.1       misho     418:                                        CONST_BUF_LEN(p->tmp_buf),
1.1.1.3 ! misho     419:                                        (const char *)&(srv->cur_ts), sizeof(srv->cur_ts),
1.1       misho     420:                                        p->conf.trigger_timeout, 0)) {
                    421:                                log_error_write(srv, __FILE__, __LINE__, "s",
1.1.1.3 ! misho     422:                                        "insert failed");
1.1       misho     423:                        }
                    424:                }
                    425: # endif
                    426:        }
                    427: 
                    428:        /* check if URL is a download -> check IP in DB, update timestamp */
1.1.1.3 ! misho     429:        if ((n = pcre_exec(p->conf.download_regex, NULL, CONST_BUF_LEN(con->uri.path), 0, 0, ovec, 3 * N)) < 0) {
1.1       misho     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: 
1.1.1.3 ! misho     488: # if defined(USE_MEMCACHED)
        !           489:                if (p->conf.memc) {
        !           490:                        size_t i, len;
1.1       misho     491: 
1.1.1.3 ! misho     492:                        buffer_copy_buffer(p->tmp_buf, p->conf.mc_namespace);
1.1       misho     493:                        buffer_append_string(p->tmp_buf, remote_ip);
                    494: 
1.1.1.3 ! misho     495:                        len = buffer_string_length(p->tmp_buf);
        !           496:                        for (i = 0; i < len; i++) {
1.1       misho     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:                         */
1.1.1.3 ! misho     510:                        if (MEMCACHED_SUCCESS != memcached_exist(p->conf.memc, CONST_BUF_LEN(p->tmp_buf))) {
1.1       misho     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 */
1.1.1.3 ! misho     520:                        if (MEMCACHED_SUCCESS != memcached_set(p->conf.memc,
1.1       misho     521:                                        CONST_BUF_LEN(p->tmp_buf),
1.1.1.3 ! misho     522:                                        (const char *)&(srv->cur_ts), sizeof(srv->cur_ts),
1.1       misho     523:                                        p->conf.trigger_timeout, 0)) {
                    524:                                log_error_write(srv, __FILE__, __LINE__, "s",
1.1.1.3 ! misho     525:                                        "insert failed");
1.1       misho     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: }
1.1.1.3 ! misho     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>