Annotation of embedaddon/lighttpd/src/mod_ssi.c, revision 1.1

1.1     ! misho       1: #include "base.h"
        !             2: #include "log.h"
        !             3: #include "buffer.h"
        !             4: #include "stat_cache.h"
        !             5: 
        !             6: #include "plugin.h"
        !             7: #include "stream.h"
        !             8: 
        !             9: #include "response.h"
        !            10: 
        !            11: #include "mod_ssi.h"
        !            12: 
        !            13: #include "inet_ntop_cache.h"
        !            14: 
        !            15: #include "sys-socket.h"
        !            16: 
        !            17: #include <sys/types.h>
        !            18: 
        !            19: #include <ctype.h>
        !            20: #include <stdlib.h>
        !            21: #include <stdio.h>
        !            22: #include <string.h>
        !            23: #include <errno.h>
        !            24: #include <time.h>
        !            25: #include <unistd.h>
        !            26: 
        !            27: #ifdef HAVE_PWD_H
        !            28: # include <pwd.h>
        !            29: #endif
        !            30: 
        !            31: #ifdef HAVE_FORK
        !            32: # include <sys/wait.h>
        !            33: #endif
        !            34: 
        !            35: #ifdef HAVE_SYS_FILIO_H
        !            36: # include <sys/filio.h>
        !            37: #endif
        !            38: 
        !            39: #include "etag.h"
        !            40: #include "version.h"
        !            41: 
        !            42: /* The newest modified time of included files for include statement */
        !            43: static volatile time_t include_file_last_mtime = 0;
        !            44: 
        !            45: /* init the plugin data */
        !            46: INIT_FUNC(mod_ssi_init) {
        !            47:        plugin_data *p;
        !            48: 
        !            49:        p = calloc(1, sizeof(*p));
        !            50: 
        !            51:        p->timefmt = buffer_init();
        !            52:        p->stat_fn = buffer_init();
        !            53: 
        !            54:        p->ssi_vars = array_init();
        !            55:        p->ssi_cgi_env = array_init();
        !            56: 
        !            57:        return p;
        !            58: }
        !            59: 
        !            60: /* detroy the plugin data */
        !            61: FREE_FUNC(mod_ssi_free) {
        !            62:        plugin_data *p = p_d;
        !            63:        UNUSED(srv);
        !            64: 
        !            65:        if (!p) return HANDLER_GO_ON;
        !            66: 
        !            67:        if (p->config_storage) {
        !            68:                size_t i;
        !            69:                for (i = 0; i < srv->config_context->used; i++) {
        !            70:                        plugin_config *s = p->config_storage[i];
        !            71: 
        !            72:                        array_free(s->ssi_extension);
        !            73:                        buffer_free(s->content_type);
        !            74: 
        !            75:                        free(s);
        !            76:                }
        !            77:                free(p->config_storage);
        !            78:        }
        !            79: 
        !            80:        array_free(p->ssi_vars);
        !            81:        array_free(p->ssi_cgi_env);
        !            82: #ifdef HAVE_PCRE_H
        !            83:        pcre_free(p->ssi_regex);
        !            84: #endif
        !            85:        buffer_free(p->timefmt);
        !            86:        buffer_free(p->stat_fn);
        !            87: 
        !            88:        free(p);
        !            89: 
        !            90:        return HANDLER_GO_ON;
        !            91: }
        !            92: 
        !            93: /* handle plugin config and check values */
        !            94: 
        !            95: SETDEFAULTS_FUNC(mod_ssi_set_defaults) {
        !            96:        plugin_data *p = p_d;
        !            97:        size_t i = 0;
        !            98: #ifdef HAVE_PCRE_H
        !            99:        const char *errptr;
        !           100:        int erroff;
        !           101: #endif
        !           102: 
        !           103:        config_values_t cv[] = {
        !           104:                { "ssi.extension",              NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
        !           105:                { "ssi.content-type",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 1 */
        !           106:                { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
        !           107:        };
        !           108: 
        !           109:        if (!p) return HANDLER_ERROR;
        !           110: 
        !           111:        p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
        !           112: 
        !           113:        for (i = 0; i < srv->config_context->used; i++) {
        !           114:                plugin_config *s;
        !           115: 
        !           116:                s = calloc(1, sizeof(plugin_config));
        !           117:                s->ssi_extension  = array_init();
        !           118:                s->content_type = buffer_init();
        !           119: 
        !           120:                cv[0].destination = s->ssi_extension;
        !           121:                cv[1].destination = s->content_type;
        !           122: 
        !           123:                p->config_storage[i] = s;
        !           124: 
        !           125:                if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
        !           126:                        return HANDLER_ERROR;
        !           127:                }
        !           128:        }
        !           129: 
        !           130: #ifdef HAVE_PCRE_H
        !           131:        /* allow 2 params */
        !           132:        if (NULL == (p->ssi_regex = pcre_compile("<!--#([a-z]+)\\s+(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?-->", 0, &errptr, &erroff, NULL))) {
        !           133:                log_error_write(srv, __FILE__, __LINE__, "sds",
        !           134:                                "ssi: pcre ",
        !           135:                                erroff, errptr);
        !           136:                return HANDLER_ERROR;
        !           137:        }
        !           138: #else
        !           139:        log_error_write(srv, __FILE__, __LINE__, "s",
        !           140:                        "mod_ssi: pcre support is missing, please recompile with pcre support or remove mod_ssi from the list of modules");
        !           141:        return HANDLER_ERROR;
        !           142: #endif
        !           143: 
        !           144:        return HANDLER_GO_ON;
        !           145: }
        !           146: 
        !           147: static int ssi_env_add(array *env, const char *key, const char *val) {
        !           148:        data_string *ds;
        !           149: 
        !           150:        if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
        !           151:                ds = data_string_init();
        !           152:        }
        !           153:        buffer_copy_string(ds->key,   key);
        !           154:        buffer_copy_string(ds->value, val);
        !           155: 
        !           156:        array_insert_unique(env, (data_unset *)ds);
        !           157: 
        !           158:        return 0;
        !           159: }
        !           160: 
        !           161: /**
        !           162:  *
        !           163:  *  the next two functions are take from fcgi.c
        !           164:  *
        !           165:  */
        !           166: 
        !           167: static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
        !           168:        size_t i;
        !           169: 
        !           170:        for (i = 0; i < con->request.headers->used; i++) {
        !           171:                data_string *ds;
        !           172: 
        !           173:                ds = (data_string *)con->request.headers->data[i];
        !           174: 
        !           175:                if (ds->value->used && ds->key->used) {
        !           176:                        size_t j;
        !           177:                        buffer_reset(srv->tmp_buf);
        !           178: 
        !           179:                        /* don't forward the Authorization: Header */
        !           180:                        if (0 == strcasecmp(ds->key->ptr, "AUTHORIZATION")) {
        !           181:                                continue;
        !           182:                        }
        !           183: 
        !           184:                        if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
        !           185:                                buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("HTTP_"));
        !           186:                                srv->tmp_buf->used--;
        !           187:                        }
        !           188: 
        !           189:                        buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
        !           190:                        for (j = 0; j < ds->key->used - 1; j++) {
        !           191:                                char c = '_';
        !           192:                                if (light_isalpha(ds->key->ptr[j])) {
        !           193:                                        /* upper-case */
        !           194:                                        c = ds->key->ptr[j] & ~32;
        !           195:                                } else if (light_isdigit(ds->key->ptr[j])) {
        !           196:                                        /* copy */
        !           197:                                        c = ds->key->ptr[j];
        !           198:                                }
        !           199:                                srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
        !           200:                        }
        !           201:                        srv->tmp_buf->ptr[srv->tmp_buf->used] = '\0';
        !           202: 
        !           203:                        ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
        !           204:                }
        !           205:        }
        !           206: 
        !           207:        for (i = 0; i < con->environment->used; i++) {
        !           208:                data_string *ds;
        !           209: 
        !           210:                ds = (data_string *)con->environment->data[i];
        !           211: 
        !           212:                if (ds->value->used && ds->key->used) {
        !           213:                        size_t j;
        !           214: 
        !           215:                        buffer_reset(srv->tmp_buf);
        !           216:                        buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
        !           217: 
        !           218:                        for (j = 0; j < ds->key->used - 1; j++) {
        !           219:                                char c = '_';
        !           220:                                if (light_isalpha(ds->key->ptr[j])) {
        !           221:                                        /* upper-case */
        !           222:                                        c = ds->key->ptr[j] & ~32;
        !           223:                                } else if (light_isdigit(ds->key->ptr[j])) {
        !           224:                                        /* copy */
        !           225:                                        c = ds->key->ptr[j];
        !           226:                                }
        !           227:                                srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
        !           228:                        }
        !           229:                        srv->tmp_buf->ptr[srv->tmp_buf->used] = '\0';
        !           230: 
        !           231:                        ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
        !           232:                }
        !           233:        }
        !           234: 
        !           235:        return 0;
        !           236: }
        !           237: 
        !           238: static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
        !           239:        char buf[32];
        !           240: 
        !           241:        server_socket *srv_sock = con->srv_socket;
        !           242: 
        !           243: #ifdef HAVE_IPV6
        !           244:        char b2[INET6_ADDRSTRLEN + 1];
        !           245: #endif
        !           246: 
        !           247: #define CONST_STRING(x) \
        !           248:                x
        !           249: 
        !           250:        array_reset(p->ssi_cgi_env);
        !           251: 
        !           252:        ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_SOFTWARE"), PACKAGE_DESC);
        !           253:        ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_NAME"),
        !           254: #ifdef HAVE_IPV6
        !           255:                     inet_ntop(srv_sock->addr.plain.sa_family,
        !           256:                               srv_sock->addr.plain.sa_family == AF_INET6 ?
        !           257:                               (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
        !           258:                               (const void *) &(srv_sock->addr.ipv4.sin_addr),
        !           259:                               b2, sizeof(b2)-1)
        !           260: #else
        !           261:                     inet_ntoa(srv_sock->addr.ipv4.sin_addr)
        !           262: #endif
        !           263:                     );
        !           264:        ssi_env_add(p->ssi_cgi_env, CONST_STRING("GATEWAY_INTERFACE"), "CGI/1.1");
        !           265: 
        !           266:        LI_ltostr(buf,
        !           267: #ifdef HAVE_IPV6
        !           268:               ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
        !           269: #else
        !           270:               ntohs(srv_sock->addr.ipv4.sin_port)
        !           271: #endif
        !           272:               );
        !           273: 
        !           274:        ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PORT"), buf);
        !           275: 
        !           276:        ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_ADDR"),
        !           277:                    inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
        !           278: 
        !           279:        if (con->request.content_length > 0) {
        !           280:                /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
        !           281: 
        !           282:                /* request.content_length < SSIZE_MAX, see request.c */
        !           283:                LI_ltostr(buf, con->request.content_length);
        !           284:                ssi_env_add(p->ssi_cgi_env, CONST_STRING("CONTENT_LENGTH"), buf);
        !           285:        }
        !           286: 
        !           287:        /*
        !           288:         * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
        !           289:         * http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html
        !           290:         * (6.1.14, 6.1.6, 6.1.7)
        !           291:         */
        !           292: 
        !           293:        ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_NAME"), con->uri.path->ptr);
        !           294:        ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), "");
        !           295: 
        !           296:        /*
        !           297:         * SCRIPT_FILENAME and DOCUMENT_ROOT for php. The PHP manual
        !           298:         * http://www.php.net/manual/en/reserved.variables.php
        !           299:         * treatment of PATH_TRANSLATED is different from the one of CGI specs.
        !           300:         * TODO: this code should be checked against cgi.fix_pathinfo php
        !           301:         * parameter.
        !           302:         */
        !           303: 
        !           304:        if (con->request.pathinfo->used) {
        !           305:                ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), con->request.pathinfo->ptr);
        !           306:        }
        !           307: 
        !           308:        ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_FILENAME"), con->physical.path->ptr);
        !           309:        ssi_env_add(p->ssi_cgi_env, CONST_STRING("DOCUMENT_ROOT"), con->physical.doc_root->ptr);
        !           310: 
        !           311:        ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_URI"), con->request.uri->ptr);
        !           312:        ssi_env_add(p->ssi_cgi_env, CONST_STRING("QUERY_STRING"), con->uri.query->used ? con->uri.query->ptr : "");
        !           313:        ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_METHOD"), get_http_method_name(con->request.http_method));
        !           314:        ssi_env_add(p->ssi_cgi_env, CONST_STRING("REDIRECT_STATUS"), "200");
        !           315:        ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PROTOCOL"), get_http_version_name(con->request.http_version));
        !           316: 
        !           317:        ssi_env_add_request_headers(srv, con, p);
        !           318: 
        !           319:        return 0;
        !           320: }
        !           321: 
        !           322: static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
        !           323:                            const char **l, size_t n) {
        !           324:        size_t i, ssicmd = 0;
        !           325:        char buf[255];
        !           326:        buffer *b = NULL;
        !           327: 
        !           328:        struct {
        !           329:                const char *var;
        !           330:                enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
        !           331:                                SSI_CONFIG, SSI_PRINTENV, SSI_SET, SSI_IF, SSI_ELIF,
        !           332:                                SSI_ELSE, SSI_ENDIF, SSI_EXEC } type;
        !           333:        } ssicmds[] = {
        !           334:                { "echo",     SSI_ECHO },
        !           335:                { "include",  SSI_INCLUDE },
        !           336:                { "flastmod", SSI_FLASTMOD },
        !           337:                { "fsize",    SSI_FSIZE },
        !           338:                { "config",   SSI_CONFIG },
        !           339:                { "printenv", SSI_PRINTENV },
        !           340:                { "set",      SSI_SET },
        !           341:                { "if",       SSI_IF },
        !           342:                { "elif",     SSI_ELIF },
        !           343:                { "endif",    SSI_ENDIF },
        !           344:                { "else",     SSI_ELSE },
        !           345:                { "exec",     SSI_EXEC },
        !           346: 
        !           347:                { NULL, SSI_UNSET }
        !           348:        };
        !           349: 
        !           350:        for (i = 0; ssicmds[i].var; i++) {
        !           351:                if (0 == strcmp(l[1], ssicmds[i].var)) {
        !           352:                        ssicmd = ssicmds[i].type;
        !           353:                        break;
        !           354:                }
        !           355:        }
        !           356: 
        !           357:        switch(ssicmd) {
        !           358:        case SSI_ECHO: {
        !           359:                /* echo */
        !           360:                int var = 0;
        !           361:                /* int enc = 0; */
        !           362:                const char *var_val = NULL;
        !           363:                stat_cache_entry *sce = NULL;
        !           364: 
        !           365:                struct {
        !           366:                        const char *var;
        !           367:                        enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI,
        !           368:                                        SSI_ECHO_LAST_MODIFIED, SSI_ECHO_USER_NAME } type;
        !           369:                } echovars[] = {
        !           370:                        { "DATE_GMT",      SSI_ECHO_DATE_GMT },
        !           371:                        { "DATE_LOCAL",    SSI_ECHO_DATE_LOCAL },
        !           372:                        { "DOCUMENT_NAME", SSI_ECHO_DOCUMENT_NAME },
        !           373:                        { "DOCUMENT_URI",  SSI_ECHO_DOCUMENT_URI },
        !           374:                        { "LAST_MODIFIED", SSI_ECHO_LAST_MODIFIED },
        !           375:                        { "USER_NAME",     SSI_ECHO_USER_NAME },
        !           376: 
        !           377:                        { NULL, SSI_ECHO_UNSET }
        !           378:                };
        !           379: 
        !           380: /*
        !           381:                struct {
        !           382:                        const char *var;
        !           383:                        enum { SSI_ENC_UNSET, SSI_ENC_URL, SSI_ENC_NONE, SSI_ENC_ENTITY } type;
        !           384:                } encvars[] = {
        !           385:                        { "url",          SSI_ENC_URL },
        !           386:                        { "none",         SSI_ENC_NONE },
        !           387:                        { "entity",       SSI_ENC_ENTITY },
        !           388: 
        !           389:                        { NULL, SSI_ENC_UNSET }
        !           390:                };
        !           391: */
        !           392: 
        !           393:                for (i = 2; i < n; i += 2) {
        !           394:                        if (0 == strcmp(l[i], "var")) {
        !           395:                                int j;
        !           396: 
        !           397:                                var_val = l[i+1];
        !           398: 
        !           399:                                for (j = 0; echovars[j].var; j++) {
        !           400:                                        if (0 == strcmp(l[i+1], echovars[j].var)) {
        !           401:                                                var = echovars[j].type;
        !           402:                                                break;
        !           403:                                        }
        !           404:                                }
        !           405:                        } else if (0 == strcmp(l[i], "encoding")) {
        !           406: /*
        !           407:                                int j;
        !           408: 
        !           409:                                for (j = 0; encvars[j].var; j++) {
        !           410:                                        if (0 == strcmp(l[i+1], encvars[j].var)) {
        !           411:                                                enc = encvars[j].type;
        !           412:                                                break;
        !           413:                                        }
        !           414:                                }
        !           415: */
        !           416:                        } else {
        !           417:                                log_error_write(srv, __FILE__, __LINE__, "sss",
        !           418:                                                "ssi: unknow attribute for ",
        !           419:                                                l[1], l[i]);
        !           420:                        }
        !           421:                }
        !           422: 
        !           423:                if (p->if_is_false) break;
        !           424: 
        !           425:                if (!var_val) {
        !           426:                        log_error_write(srv, __FILE__, __LINE__, "sss",
        !           427:                                        "ssi: ",
        !           428:                                        l[1], "var is missing");
        !           429:                        break;
        !           430:                }
        !           431: 
        !           432:                stat_cache_get_entry(srv, con, con->physical.path, &sce);
        !           433: 
        !           434:                switch(var) {
        !           435:                case SSI_ECHO_USER_NAME: {
        !           436:                        struct passwd *pw;
        !           437: 
        !           438:                        b = chunkqueue_get_append_buffer(con->write_queue);
        !           439: #ifdef HAVE_PWD_H
        !           440:                        if (NULL == (pw = getpwuid(sce->st.st_uid))) {
        !           441:                                buffer_copy_long(b, sce->st.st_uid);
        !           442:                        } else {
        !           443:                                buffer_copy_string(b, pw->pw_name);
        !           444:                        }
        !           445: #else
        !           446:                        buffer_copy_long(b, sce->st.st_uid);
        !           447: #endif
        !           448:                        break;
        !           449:                }
        !           450:                case SSI_ECHO_LAST_MODIFIED:    {
        !           451:                        time_t t = sce->st.st_mtime;
        !           452: 
        !           453:                        b = chunkqueue_get_append_buffer(con->write_queue);
        !           454:                        if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
        !           455:                                buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
        !           456:                        } else {
        !           457:                                buffer_copy_string(b, buf);
        !           458:                        }
        !           459:                        break;
        !           460:                }
        !           461:                case SSI_ECHO_DATE_LOCAL: {
        !           462:                        time_t t = time(NULL);
        !           463: 
        !           464:                        b = chunkqueue_get_append_buffer(con->write_queue);
        !           465:                        if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
        !           466:                                buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
        !           467:                        } else {
        !           468:                                buffer_copy_string(b, buf);
        !           469:                        }
        !           470:                        break;
        !           471:                }
        !           472:                case SSI_ECHO_DATE_GMT: {
        !           473:                        time_t t = time(NULL);
        !           474: 
        !           475:                        b = chunkqueue_get_append_buffer(con->write_queue);
        !           476:                        if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) {
        !           477:                                buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
        !           478:                        } else {
        !           479:                                buffer_copy_string(b, buf);
        !           480:                        }
        !           481:                        break;
        !           482:                }
        !           483:                case SSI_ECHO_DOCUMENT_NAME: {
        !           484:                        char *sl;
        !           485: 
        !           486:                        b = chunkqueue_get_append_buffer(con->write_queue);
        !           487:                        if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
        !           488:                                buffer_copy_string_buffer(b, con->physical.path);
        !           489:                        } else {
        !           490:                                buffer_copy_string(b, sl + 1);
        !           491:                        }
        !           492:                        break;
        !           493:                }
        !           494:                case SSI_ECHO_DOCUMENT_URI: {
        !           495:                        b = chunkqueue_get_append_buffer(con->write_queue);
        !           496:                        buffer_copy_string_buffer(b, con->uri.path);
        !           497:                        break;
        !           498:                }
        !           499:                default: {
        !           500:                        data_string *ds;
        !           501:                        /* check if it is a cgi-var */
        !           502: 
        !           503:                        b = chunkqueue_get_append_buffer(con->write_queue);
        !           504: 
        !           505:                        if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val))) {
        !           506:                                buffer_copy_string_buffer(b, ds->value);
        !           507:                        } else {
        !           508:                                buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
        !           509:                        }
        !           510: 
        !           511:                        break;
        !           512:                }
        !           513:                }
        !           514:                break;
        !           515:        }
        !           516:        case SSI_INCLUDE:
        !           517:        case SSI_FLASTMOD:
        !           518:        case SSI_FSIZE: {
        !           519:                const char * file_path = NULL, *virt_path = NULL;
        !           520:                struct stat st;
        !           521:                char *sl;
        !           522: 
        !           523:                for (i = 2; i < n; i += 2) {
        !           524:                        if (0 == strcmp(l[i], "file")) {
        !           525:                                file_path = l[i+1];
        !           526:                        } else if (0 == strcmp(l[i], "virtual")) {
        !           527:                                virt_path = l[i+1];
        !           528:                        } else {
        !           529:                                log_error_write(srv, __FILE__, __LINE__, "sss",
        !           530:                                                "ssi: unknow attribute for ",
        !           531:                                                l[1], l[i]);
        !           532:                        }
        !           533:                }
        !           534: 
        !           535:                if (!file_path && !virt_path) {
        !           536:                        log_error_write(srv, __FILE__, __LINE__, "sss",
        !           537:                                        "ssi: ",
        !           538:                                        l[1], "file or virtual are missing");
        !           539:                        break;
        !           540:                }
        !           541: 
        !           542:                if (file_path && virt_path) {
        !           543:                        log_error_write(srv, __FILE__, __LINE__, "sss",
        !           544:                                        "ssi: ",
        !           545:                                        l[1], "only one of file and virtual is allowed here");
        !           546:                        break;
        !           547:                }
        !           548: 
        !           549: 
        !           550:                if (p->if_is_false) break;
        !           551: 
        !           552:                if (file_path) {
        !           553:                        /* current doc-root */
        !           554:                        if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
        !           555:                                buffer_copy_string_len(p->stat_fn, CONST_STR_LEN("/"));
        !           556:                        } else {
        !           557:                                buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, sl - con->physical.path->ptr + 1);
        !           558:                        }
        !           559: 
        !           560:                        buffer_copy_string(srv->tmp_buf, file_path);
        !           561:                        buffer_urldecode_path(srv->tmp_buf);
        !           562:                        buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
        !           563:                        buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
        !           564:                } else {
        !           565:                        /* virtual */
        !           566: 
        !           567:                        if (virt_path[0] == '/') {
        !           568:                                buffer_copy_string(p->stat_fn, virt_path);
        !           569:                        } else {
        !           570:                                /* there is always a / */
        !           571:                                sl = strrchr(con->uri.path->ptr, '/');
        !           572: 
        !           573:                                buffer_copy_string_len(p->stat_fn, con->uri.path->ptr, sl - con->uri.path->ptr + 1);
        !           574:                                buffer_append_string(p->stat_fn, virt_path);
        !           575:                        }
        !           576: 
        !           577:                        buffer_urldecode_path(p->stat_fn);
        !           578:                        buffer_path_simplify(srv->tmp_buf, p->stat_fn);
        !           579: 
        !           580:                        /* we have an uri */
        !           581: 
        !           582:                        buffer_copy_string_buffer(p->stat_fn, con->physical.doc_root);
        !           583:                        buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
        !           584:                }
        !           585: 
        !           586:                if (0 == stat(p->stat_fn->ptr, &st)) {
        !           587:                        time_t t = st.st_mtime;
        !           588: 
        !           589:                        switch (ssicmd) {
        !           590:                        case SSI_FSIZE:
        !           591:                                b = chunkqueue_get_append_buffer(con->write_queue);
        !           592:                                if (p->sizefmt) {
        !           593:                                        int j = 0;
        !           594:                                        const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL };
        !           595: 
        !           596:                                        off_t s = st.st_size;
        !           597: 
        !           598:                                        for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++);
        !           599: 
        !           600:                                        buffer_copy_off_t(b, s);
        !           601:                                        buffer_append_string(b, abr[j]);
        !           602:                                } else {
        !           603:                                        buffer_copy_off_t(b, st.st_size);
        !           604:                                }
        !           605:                                break;
        !           606:                        case SSI_FLASTMOD:
        !           607:                                b = chunkqueue_get_append_buffer(con->write_queue);
        !           608:                                if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
        !           609:                                        buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
        !           610:                                } else {
        !           611:                                        buffer_copy_string(b, buf);
        !           612:                                }
        !           613:                                break;
        !           614:                        case SSI_INCLUDE:
        !           615:                                chunkqueue_append_file(con->write_queue, p->stat_fn, 0, st.st_size);
        !           616: 
        !           617:                                /* Keep the newest mtime of included files */
        !           618:                                if (st.st_mtime > include_file_last_mtime)
        !           619:                                  include_file_last_mtime = st.st_mtime;
        !           620: 
        !           621:                                break;
        !           622:                        }
        !           623:                } else {
        !           624:                        log_error_write(srv, __FILE__, __LINE__, "sbs",
        !           625:                                        "ssi: stating failed ",
        !           626:                                        p->stat_fn, strerror(errno));
        !           627:                }
        !           628:                break;
        !           629:        }
        !           630:        case SSI_SET: {
        !           631:                const char *key = NULL, *val = NULL;
        !           632:                for (i = 2; i < n; i += 2) {
        !           633:                        if (0 == strcmp(l[i], "var")) {
        !           634:                                key = l[i+1];
        !           635:                        } else if (0 == strcmp(l[i], "value")) {
        !           636:                                val = l[i+1];
        !           637:                        } else {
        !           638:                                log_error_write(srv, __FILE__, __LINE__, "sss",
        !           639:                                                "ssi: unknow attribute for ",
        !           640:                                                l[1], l[i]);
        !           641:                        }
        !           642:                }
        !           643: 
        !           644:                if (p->if_is_false) break;
        !           645: 
        !           646:                if (key && val) {
        !           647:                        data_string *ds;
        !           648: 
        !           649:                        if (NULL == (ds = (data_string *)array_get_unused_element(p->ssi_vars, TYPE_STRING))) {
        !           650:                                ds = data_string_init();
        !           651:                        }
        !           652:                        buffer_copy_string(ds->key,   key);
        !           653:                        buffer_copy_string(ds->value, val);
        !           654: 
        !           655:                        array_insert_unique(p->ssi_vars, (data_unset *)ds);
        !           656:                } else {
        !           657:                        log_error_write(srv, __FILE__, __LINE__, "sss",
        !           658:                                        "ssi: var and value have to be set in",
        !           659:                                        l[0], l[1]);
        !           660:                }
        !           661:                break;
        !           662:        }
        !           663:        case SSI_CONFIG:
        !           664:                if (p->if_is_false) break;
        !           665: 
        !           666:                for (i = 2; i < n; i += 2) {
        !           667:                        if (0 == strcmp(l[i], "timefmt")) {
        !           668:                                buffer_copy_string(p->timefmt, l[i+1]);
        !           669:                        } else if (0 == strcmp(l[i], "sizefmt")) {
        !           670:                                if (0 == strcmp(l[i+1], "abbrev")) {
        !           671:                                        p->sizefmt = 1;
        !           672:                                } else if (0 == strcmp(l[i+1], "abbrev")) {
        !           673:                                        p->sizefmt = 0;
        !           674:                                } else {
        !           675:                                        log_error_write(srv, __FILE__, __LINE__, "sssss",
        !           676:                                                        "ssi: unknow value for attribute '",
        !           677:                                                        l[i],
        !           678:                                                        "' for ",
        !           679:                                                        l[1], l[i+1]);
        !           680:                                }
        !           681:                        } else {
        !           682:                                log_error_write(srv, __FILE__, __LINE__, "sss",
        !           683:                                                "ssi: unknow attribute for ",
        !           684:                                                l[1], l[i]);
        !           685:                        }
        !           686:                }
        !           687:                break;
        !           688:        case SSI_PRINTENV:
        !           689:                if (p->if_is_false) break;
        !           690: 
        !           691:                b = chunkqueue_get_append_buffer(con->write_queue);
        !           692:                for (i = 0; i < p->ssi_vars->used; i++) {
        !           693:                        data_string *ds = (data_string *)p->ssi_vars->data[p->ssi_vars->sorted[i]];
        !           694: 
        !           695:                        buffer_append_string_buffer(b, ds->key);
        !           696:                        buffer_append_string_len(b, CONST_STR_LEN("="));
        !           697:                        buffer_append_string_encoded(b, CONST_BUF_LEN(ds->value), ENCODING_MINIMAL_XML);
        !           698:                        buffer_append_string_len(b, CONST_STR_LEN("\n"));
        !           699:                }
        !           700:                for (i = 0; i < p->ssi_cgi_env->used; i++) {
        !           701:                        data_string *ds = (data_string *)p->ssi_cgi_env->data[p->ssi_cgi_env->sorted[i]];
        !           702: 
        !           703:                        buffer_append_string_buffer(b, ds->key);
        !           704:                        buffer_append_string_len(b, CONST_STR_LEN("="));
        !           705:                        buffer_append_string_encoded(b, CONST_BUF_LEN(ds->value), ENCODING_MINIMAL_XML);
        !           706:                        buffer_append_string_len(b, CONST_STR_LEN("\n"));
        !           707:                }
        !           708: 
        !           709:                break;
        !           710:        case SSI_EXEC: {
        !           711:                const char *cmd = NULL;
        !           712:                pid_t pid;
        !           713:                int from_exec_fds[2];
        !           714: 
        !           715:                for (i = 2; i < n; i += 2) {
        !           716:                        if (0 == strcmp(l[i], "cmd")) {
        !           717:                                cmd = l[i+1];
        !           718:                        } else {
        !           719:                                log_error_write(srv, __FILE__, __LINE__, "sss",
        !           720:                                                "ssi: unknow attribute for ",
        !           721:                                                l[1], l[i]);
        !           722:                        }
        !           723:                }
        !           724: 
        !           725:                if (p->if_is_false) break;
        !           726: 
        !           727:                /* create a return pipe and send output to the html-page
        !           728:                 *
        !           729:                 * as exec is assumed evil it is implemented synchronously
        !           730:                 */
        !           731: 
        !           732:                if (!cmd) break;
        !           733: #ifdef HAVE_FORK
        !           734:                if (pipe(from_exec_fds)) {
        !           735:                        log_error_write(srv, __FILE__, __LINE__, "ss",
        !           736:                                        "pipe failed: ", strerror(errno));
        !           737:                        return -1;
        !           738:                }
        !           739: 
        !           740:                /* fork, execve */
        !           741:                switch (pid = fork()) {
        !           742:                case 0: {
        !           743:                        /* move stdout to from_rrdtool_fd[1] */
        !           744:                        close(STDOUT_FILENO);
        !           745:                        dup2(from_exec_fds[1], STDOUT_FILENO);
        !           746:                        close(from_exec_fds[1]);
        !           747:                        /* not needed */
        !           748:                        close(from_exec_fds[0]);
        !           749: 
        !           750:                        /* close stdin */
        !           751:                        close(STDIN_FILENO);
        !           752: 
        !           753:                        execl("/bin/sh", "sh", "-c", cmd, (char *)NULL);
        !           754: 
        !           755:                        log_error_write(srv, __FILE__, __LINE__, "sss", "spawing exec failed:", strerror(errno), cmd);
        !           756: 
        !           757:                        /* */
        !           758:                        SEGFAULT();
        !           759:                        break;
        !           760:                }
        !           761:                case -1:
        !           762:                        /* error */
        !           763:                        log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno));
        !           764:                        break;
        !           765:                default: {
        !           766:                        /* father */
        !           767:                        int status;
        !           768:                        ssize_t r;
        !           769:                        int was_interrupted = 0;
        !           770: 
        !           771:                        close(from_exec_fds[1]);
        !           772: 
        !           773:                        /* wait for the client to end */
        !           774: 
        !           775:                        /*
        !           776:                         * OpenBSD and Solaris send a EINTR on SIGCHILD even if we ignore it
        !           777:                         */
        !           778:                        do {
        !           779:                                if (-1 == waitpid(pid, &status, 0)) {
        !           780:                                        if (errno == EINTR) {
        !           781:                                                was_interrupted++;
        !           782:                                        } else {
        !           783:                                                was_interrupted = 0;
        !           784:                                                log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno));
        !           785:                                        }
        !           786:                                } else if (WIFEXITED(status)) {
        !           787:                                        int toread;
        !           788:                                        /* read everything from client and paste it into the output */
        !           789:                                        was_interrupted = 0;
        !           790:        
        !           791:                                        while(1) {
        !           792:                                                if (ioctl(from_exec_fds[0], FIONREAD, &toread)) {
        !           793:                                                        log_error_write(srv, __FILE__, __LINE__, "s",
        !           794:                                                                "unexpected end-of-file (perhaps the ssi-exec process died)");
        !           795:                                                        return -1;
        !           796:                                                }
        !           797:        
        !           798:                                                if (toread > 0) {
        !           799:                                                        b = chunkqueue_get_append_buffer(con->write_queue);
        !           800:        
        !           801:                                                        buffer_prepare_copy(b, toread + 1);
        !           802:        
        !           803:                                                        if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) {
        !           804:                                                                /* read failed */
        !           805:                                                                break;
        !           806:                                                        } else {
        !           807:                                                                b->used = r;
        !           808:                                                                b->ptr[b->used++] = '\0';
        !           809:                                                        }
        !           810:                                                } else {
        !           811:                                                        break;
        !           812:                                                }
        !           813:                                        }
        !           814:                                } else {
        !           815:                                        was_interrupted = 0;
        !           816:                                        log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally");
        !           817:                                }
        !           818:                        } while (was_interrupted > 0 && was_interrupted < 4); /* if waitpid() gets interrupted, retry, but max 4 times */
        !           819: 
        !           820:                        close(from_exec_fds[0]);
        !           821: 
        !           822:                        break;
        !           823:                }
        !           824:                }
        !           825: #else
        !           826: 
        !           827:                return -1;
        !           828: #endif
        !           829: 
        !           830:                break;
        !           831:        }
        !           832:        case SSI_IF: {
        !           833:                const char *expr = NULL;
        !           834: 
        !           835:                for (i = 2; i < n; i += 2) {
        !           836:                        if (0 == strcmp(l[i], "expr")) {
        !           837:                                expr = l[i+1];
        !           838:                        } else {
        !           839:                                log_error_write(srv, __FILE__, __LINE__, "sss",
        !           840:                                                "ssi: unknow attribute for ",
        !           841:                                                l[1], l[i]);
        !           842:                        }
        !           843:                }
        !           844: 
        !           845:                if (!expr) {
        !           846:                        log_error_write(srv, __FILE__, __LINE__, "sss",
        !           847:                                        "ssi: ",
        !           848:                                        l[1], "expr missing");
        !           849:                        break;
        !           850:                }
        !           851: 
        !           852:                if ((!p->if_is_false) &&
        !           853:                    ((p->if_is_false_level == 0) ||
        !           854:                     (p->if_level < p->if_is_false_level))) {
        !           855:                        switch (ssi_eval_expr(srv, con, p, expr)) {
        !           856:                        case -1:
        !           857:                        case 0:
        !           858:                                p->if_is_false = 1;
        !           859:                                p->if_is_false_level = p->if_level;
        !           860:                                break;
        !           861:                        case 1:
        !           862:                                p->if_is_false = 0;
        !           863:                                break;
        !           864:                        }
        !           865:                }
        !           866: 
        !           867:                p->if_level++;
        !           868: 
        !           869:                break;
        !           870:        }
        !           871:        case SSI_ELSE:
        !           872:                p->if_level--;
        !           873: 
        !           874:                if (p->if_is_false) {
        !           875:                        if ((p->if_level == p->if_is_false_level) &&
        !           876:                            (p->if_is_false_endif == 0)) {
        !           877:                                p->if_is_false = 0;
        !           878:                        }
        !           879:                } else {
        !           880:                        p->if_is_false = 1;
        !           881: 
        !           882:                        p->if_is_false_level = p->if_level;
        !           883:                }
        !           884:                p->if_level++;
        !           885: 
        !           886:                break;
        !           887:        case SSI_ELIF: {
        !           888:                const char *expr = NULL;
        !           889:                for (i = 2; i < n; i += 2) {
        !           890:                        if (0 == strcmp(l[i], "expr")) {
        !           891:                                expr = l[i+1];
        !           892:                        } else {
        !           893:                                log_error_write(srv, __FILE__, __LINE__, "sss",
        !           894:                                                "ssi: unknow attribute for ",
        !           895:                                                l[1], l[i]);
        !           896:                        }
        !           897:                }
        !           898: 
        !           899:                if (!expr) {
        !           900:                        log_error_write(srv, __FILE__, __LINE__, "sss",
        !           901:                                        "ssi: ",
        !           902:                                        l[1], "expr missing");
        !           903:                        break;
        !           904:                }
        !           905: 
        !           906:                p->if_level--;
        !           907: 
        !           908:                if (p->if_level == p->if_is_false_level) {
        !           909:                        if ((p->if_is_false) &&
        !           910:                            (p->if_is_false_endif == 0)) {
        !           911:                                switch (ssi_eval_expr(srv, con, p, expr)) {
        !           912:                                case -1:
        !           913:                                case 0:
        !           914:                                        p->if_is_false = 1;
        !           915:                                        p->if_is_false_level = p->if_level;
        !           916:                                        break;
        !           917:                                case 1:
        !           918:                                        p->if_is_false = 0;
        !           919:                                        break;
        !           920:                                }
        !           921:                        } else {
        !           922:                                p->if_is_false = 1;
        !           923:                                p->if_is_false_level = p->if_level;
        !           924:                                p->if_is_false_endif = 1;
        !           925:                        }
        !           926:                }
        !           927: 
        !           928:                p->if_level++;
        !           929: 
        !           930:                break;
        !           931:        }
        !           932:        case SSI_ENDIF:
        !           933:                p->if_level--;
        !           934: 
        !           935:                if (p->if_level == p->if_is_false_level) {
        !           936:                        p->if_is_false = 0;
        !           937:                        p->if_is_false_endif = 0;
        !           938:                }
        !           939: 
        !           940:                break;
        !           941:        default:
        !           942:                log_error_write(srv, __FILE__, __LINE__, "ss",
        !           943:                                "ssi: unknow ssi-command:",
        !           944:                                l[1]);
        !           945:                break;
        !           946:        }
        !           947: 
        !           948:        return 0;
        !           949: 
        !           950: }
        !           951: 
        !           952: static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) {
        !           953:        stream s;
        !           954: #ifdef  HAVE_PCRE_H
        !           955:        int i, n;
        !           956: 
        !           957: #define N 10
        !           958:        int ovec[N * 3];
        !           959: #endif
        !           960: 
        !           961:        /* get a stream to the file */
        !           962: 
        !           963:        array_reset(p->ssi_vars);
        !           964:        array_reset(p->ssi_cgi_env);
        !           965:        buffer_copy_string_len(p->timefmt, CONST_STR_LEN("%a, %d %b %Y %H:%M:%S %Z"));
        !           966:        p->sizefmt = 0;
        !           967:        build_ssi_cgi_vars(srv, con, p);
        !           968:        p->if_is_false = 0;
        !           969: 
        !           970:        /* Reset the modified time of included files */
        !           971:        include_file_last_mtime = 0;
        !           972: 
        !           973:        if (-1 == stream_open(&s, con->physical.path)) {
        !           974:                log_error_write(srv, __FILE__, __LINE__, "sb",
        !           975:                                "stream-open: ", con->physical.path);
        !           976:                return -1;
        !           977:        }
        !           978: 
        !           979: 
        !           980:        /**
        !           981:         * <!--#element attribute=value attribute=value ... -->
        !           982:         *
        !           983:         * config       DONE
        !           984:         *   errmsg     -- missing
        !           985:         *   sizefmt    DONE
        !           986:         *   timefmt    DONE
        !           987:         * echo         DONE
        !           988:         *   var        DONE
        !           989:         *   encoding   -- missing
        !           990:         * exec         DONE
        !           991:         *   cgi        -- never
        !           992:         *   cmd        DONE
        !           993:         * fsize        DONE
        !           994:         *   file       DONE
        !           995:         *   virtual    DONE
        !           996:         * flastmod     DONE
        !           997:         *   file       DONE
        !           998:         *   virtual    DONE
        !           999:         * include      DONE
        !          1000:         *   file       DONE
        !          1001:         *   virtual    DONE
        !          1002:         * printenv     DONE
        !          1003:         * set          DONE
        !          1004:         *   var        DONE
        !          1005:         *   value      DONE
        !          1006:         *
        !          1007:         * if           DONE
        !          1008:         * elif         DONE
        !          1009:         * else         DONE
        !          1010:         * endif        DONE
        !          1011:         *
        !          1012:         *
        !          1013:         * expressions
        !          1014:         * AND, OR      DONE
        !          1015:         * comp         DONE
        !          1016:         * ${...}       -- missing
        !          1017:         * $...         DONE
        !          1018:         * '...'        DONE
        !          1019:         * ( ... )      DONE
        !          1020:         *
        !          1021:         *
        !          1022:         *
        !          1023:         * ** all DONE **
        !          1024:         * DATE_GMT
        !          1025:         *   The current date in Greenwich Mean Time.
        !          1026:         * DATE_LOCAL
        !          1027:         *   The current date in the local time zone.
        !          1028:         * DOCUMENT_NAME
        !          1029:         *   The filename (excluding directories) of the document requested by the user.
        !          1030:         * DOCUMENT_URI
        !          1031:         *   The (%-decoded) URL path of the document requested by the user. Note that in the case of nested include files, this is not then URL for the current document.
        !          1032:         * LAST_MODIFIED
        !          1033:         *   The last modification date of the document requested by the user.
        !          1034:         * USER_NAME
        !          1035:         *   Contains the owner of the file which included it.
        !          1036:         *
        !          1037:         */
        !          1038: #ifdef HAVE_PCRE_H
        !          1039:        for (i = 0; (n = pcre_exec(p->ssi_regex, NULL, s.start, s.size, i, 0, ovec, N * 3)) > 0; i = ovec[1]) {
        !          1040:                const char **l;
        !          1041:                /* take everything from last offset to current match pos */
        !          1042: 
        !          1043:                if (!p->if_is_false) chunkqueue_append_file(con->write_queue, con->physical.path, i, ovec[0] - i);
        !          1044: 
        !          1045:                pcre_get_substring_list(s.start, ovec, n, &l);
        !          1046:                process_ssi_stmt(srv, con, p, l, n);
        !          1047:                pcre_free_substring_list(l);
        !          1048:        }
        !          1049: 
        !          1050:        switch(n) {
        !          1051:        case PCRE_ERROR_NOMATCH:
        !          1052:                /* copy everything/the rest */
        !          1053:                chunkqueue_append_file(con->write_queue, con->physical.path, i, s.size - i);
        !          1054: 
        !          1055:                break;
        !          1056:        default:
        !          1057:                log_error_write(srv, __FILE__, __LINE__, "sd",
        !          1058:                                "execution error while matching: ", n);
        !          1059:                break;
        !          1060:        }
        !          1061: #endif
        !          1062: 
        !          1063: 
        !          1064:        stream_close(&s);
        !          1065: 
        !          1066:        con->file_started  = 1;
        !          1067:        con->file_finished = 1;
        !          1068:        con->mode = p->id;
        !          1069: 
        !          1070:        if (p->conf.content_type->used <= 1) {
        !          1071:                response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
        !          1072:        } else {
        !          1073:                response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->conf.content_type));
        !          1074:        }
        !          1075: 
        !          1076:        {
        !          1077:        /* Generate "ETag" & "Last-Modified" headers */
        !          1078: 
        !          1079:                stat_cache_entry *sce = NULL;
        !          1080:                time_t lm_time = 0;
        !          1081:                buffer *mtime = NULL;
        !          1082: 
        !          1083:                stat_cache_get_entry(srv, con, con->physical.path, &sce);
        !          1084: 
        !          1085:                etag_mutate(con->physical.etag, sce->etag);
        !          1086:                response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
        !          1087: 
        !          1088:                if (sce->st.st_mtime > include_file_last_mtime)
        !          1089:                        lm_time = sce->st.st_mtime;
        !          1090:                else
        !          1091:                        lm_time = include_file_last_mtime;
        !          1092: 
        !          1093:                mtime = strftime_cache_get(srv, lm_time);
        !          1094:                response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
        !          1095:        }
        !          1096: 
        !          1097:        /* Reset the modified time of included files */
        !          1098:        include_file_last_mtime = 0;
        !          1099: 
        !          1100:        /* reset physical.path */
        !          1101:        buffer_reset(con->physical.path);
        !          1102: 
        !          1103:        return 0;
        !          1104: }
        !          1105: 
        !          1106: #define PATCH(x) \
        !          1107:        p->conf.x = s->x;
        !          1108: static int mod_ssi_patch_connection(server *srv, connection *con, plugin_data *p) {
        !          1109:        size_t i, j;
        !          1110:        plugin_config *s = p->config_storage[0];
        !          1111: 
        !          1112:        PATCH(ssi_extension);
        !          1113:        PATCH(content_type);
        !          1114: 
        !          1115:        /* skip the first, the global context */
        !          1116:        for (i = 1; i < srv->config_context->used; i++) {
        !          1117:                data_config *dc = (data_config *)srv->config_context->data[i];
        !          1118:                s = p->config_storage[i];
        !          1119: 
        !          1120:                /* condition didn't match */
        !          1121:                if (!config_check_cond(srv, con, dc)) continue;
        !          1122: 
        !          1123:                /* merge config */
        !          1124:                for (j = 0; j < dc->value->used; j++) {
        !          1125:                        data_unset *du = dc->value->data[j];
        !          1126: 
        !          1127:                        if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.extension"))) {
        !          1128:                                PATCH(ssi_extension);
        !          1129:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.content-type"))) {
        !          1130:                                PATCH(content_type);
        !          1131:                        }
        !          1132:                }
        !          1133:        }
        !          1134: 
        !          1135:        return 0;
        !          1136: }
        !          1137: #undef PATCH
        !          1138: 
        !          1139: URIHANDLER_FUNC(mod_ssi_physical_path) {
        !          1140:        plugin_data *p = p_d;
        !          1141:        size_t k;
        !          1142: 
        !          1143:        if (con->mode != DIRECT) return HANDLER_GO_ON;
        !          1144: 
        !          1145:        if (con->physical.path->used == 0) return HANDLER_GO_ON;
        !          1146: 
        !          1147:        mod_ssi_patch_connection(srv, con, p);
        !          1148: 
        !          1149:        for (k = 0; k < p->conf.ssi_extension->used; k++) {
        !          1150:                data_string *ds = (data_string *)p->conf.ssi_extension->data[k];
        !          1151: 
        !          1152:                if (ds->value->used == 0) continue;
        !          1153: 
        !          1154:                if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
        !          1155:                        /* handle ssi-request */
        !          1156: 
        !          1157:                        if (mod_ssi_handle_request(srv, con, p)) {
        !          1158:                                /* on error */
        !          1159:                                con->http_status = 500;
        !          1160:                                con->mode = DIRECT;
        !          1161:                        }
        !          1162: 
        !          1163:                        return HANDLER_FINISHED;
        !          1164:                }
        !          1165:        }
        !          1166: 
        !          1167:        /* not found */
        !          1168:        return HANDLER_GO_ON;
        !          1169: }
        !          1170: 
        !          1171: /* this function is called at dlopen() time and inits the callbacks */
        !          1172: 
        !          1173: int mod_ssi_plugin_init(plugin *p);
        !          1174: int mod_ssi_plugin_init(plugin *p) {
        !          1175:        p->version     = LIGHTTPD_VERSION_ID;
        !          1176:        p->name        = buffer_init_string("ssi");
        !          1177: 
        !          1178:        p->init        = mod_ssi_init;
        !          1179:        p->handle_subrequest_start = mod_ssi_physical_path;
        !          1180:        p->set_defaults  = mod_ssi_set_defaults;
        !          1181:        p->cleanup     = mod_ssi_free;
        !          1182: 
        !          1183:        p->data        = NULL;
        !          1184: 
        !          1185:        return 0;
        !          1186: }

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