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

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

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