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