Annotation of embedaddon/lighttpd/src/mod_trigger_b4_dl.c, revision 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>