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

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: 
1.1.1.2 ! misho     111:        p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
1.1       misho     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: 
1.1.1.2 ! misho     322: static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const char **l, size_t n, stat_cache_entry *sce) {
1.1       misho     323:        size_t i, ssicmd = 0;
                    324:        char buf[255];
                    325:        buffer *b = NULL;
                    326: 
                    327:        struct {
                    328:                const char *var;
                    329:                enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
                    330:                                SSI_CONFIG, SSI_PRINTENV, SSI_SET, SSI_IF, SSI_ELIF,
                    331:                                SSI_ELSE, SSI_ENDIF, SSI_EXEC } type;
                    332:        } ssicmds[] = {
                    333:                { "echo",     SSI_ECHO },
                    334:                { "include",  SSI_INCLUDE },
                    335:                { "flastmod", SSI_FLASTMOD },
                    336:                { "fsize",    SSI_FSIZE },
                    337:                { "config",   SSI_CONFIG },
                    338:                { "printenv", SSI_PRINTENV },
                    339:                { "set",      SSI_SET },
                    340:                { "if",       SSI_IF },
                    341:                { "elif",     SSI_ELIF },
                    342:                { "endif",    SSI_ENDIF },
                    343:                { "else",     SSI_ELSE },
                    344:                { "exec",     SSI_EXEC },
                    345: 
                    346:                { NULL, SSI_UNSET }
                    347:        };
                    348: 
                    349:        for (i = 0; ssicmds[i].var; i++) {
                    350:                if (0 == strcmp(l[1], ssicmds[i].var)) {
                    351:                        ssicmd = ssicmds[i].type;
                    352:                        break;
                    353:                }
                    354:        }
                    355: 
                    356:        switch(ssicmd) {
                    357:        case SSI_ECHO: {
                    358:                /* echo */
                    359:                int var = 0;
                    360:                /* int enc = 0; */
                    361:                const char *var_val = NULL;
                    362: 
                    363:                struct {
                    364:                        const char *var;
                    365:                        enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI,
                    366:                                        SSI_ECHO_LAST_MODIFIED, SSI_ECHO_USER_NAME } type;
                    367:                } echovars[] = {
                    368:                        { "DATE_GMT",      SSI_ECHO_DATE_GMT },
                    369:                        { "DATE_LOCAL",    SSI_ECHO_DATE_LOCAL },
                    370:                        { "DOCUMENT_NAME", SSI_ECHO_DOCUMENT_NAME },
                    371:                        { "DOCUMENT_URI",  SSI_ECHO_DOCUMENT_URI },
                    372:                        { "LAST_MODIFIED", SSI_ECHO_LAST_MODIFIED },
                    373:                        { "USER_NAME",     SSI_ECHO_USER_NAME },
                    374: 
                    375:                        { NULL, SSI_ECHO_UNSET }
                    376:                };
                    377: 
                    378: /*
                    379:                struct {
                    380:                        const char *var;
                    381:                        enum { SSI_ENC_UNSET, SSI_ENC_URL, SSI_ENC_NONE, SSI_ENC_ENTITY } type;
                    382:                } encvars[] = {
                    383:                        { "url",          SSI_ENC_URL },
                    384:                        { "none",         SSI_ENC_NONE },
                    385:                        { "entity",       SSI_ENC_ENTITY },
                    386: 
                    387:                        { NULL, SSI_ENC_UNSET }
                    388:                };
                    389: */
                    390: 
                    391:                for (i = 2; i < n; i += 2) {
                    392:                        if (0 == strcmp(l[i], "var")) {
                    393:                                int j;
                    394: 
                    395:                                var_val = l[i+1];
                    396: 
                    397:                                for (j = 0; echovars[j].var; j++) {
                    398:                                        if (0 == strcmp(l[i+1], echovars[j].var)) {
                    399:                                                var = echovars[j].type;
                    400:                                                break;
                    401:                                        }
                    402:                                }
                    403:                        } else if (0 == strcmp(l[i], "encoding")) {
                    404: /*
                    405:                                int j;
                    406: 
                    407:                                for (j = 0; encvars[j].var; j++) {
                    408:                                        if (0 == strcmp(l[i+1], encvars[j].var)) {
                    409:                                                enc = encvars[j].type;
                    410:                                                break;
                    411:                                        }
                    412:                                }
                    413: */
                    414:                        } else {
                    415:                                log_error_write(srv, __FILE__, __LINE__, "sss",
                    416:                                                "ssi: unknow attribute for ",
                    417:                                                l[1], l[i]);
                    418:                        }
                    419:                }
                    420: 
                    421:                if (p->if_is_false) break;
                    422: 
                    423:                if (!var_val) {
                    424:                        log_error_write(srv, __FILE__, __LINE__, "sss",
                    425:                                        "ssi: ",
                    426:                                        l[1], "var is missing");
                    427:                        break;
                    428:                }
                    429: 
                    430:                switch(var) {
                    431:                case SSI_ECHO_USER_NAME: {
                    432:                        struct passwd *pw;
                    433: 
                    434:                        b = chunkqueue_get_append_buffer(con->write_queue);
                    435: #ifdef HAVE_PWD_H
                    436:                        if (NULL == (pw = getpwuid(sce->st.st_uid))) {
                    437:                                buffer_copy_long(b, sce->st.st_uid);
                    438:                        } else {
                    439:                                buffer_copy_string(b, pw->pw_name);
                    440:                        }
                    441: #else
                    442:                        buffer_copy_long(b, sce->st.st_uid);
                    443: #endif
                    444:                        break;
                    445:                }
                    446:                case SSI_ECHO_LAST_MODIFIED:    {
                    447:                        time_t t = sce->st.st_mtime;
                    448: 
                    449:                        b = chunkqueue_get_append_buffer(con->write_queue);
                    450:                        if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
                    451:                                buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
                    452:                        } else {
                    453:                                buffer_copy_string(b, buf);
                    454:                        }
                    455:                        break;
                    456:                }
                    457:                case SSI_ECHO_DATE_LOCAL: {
                    458:                        time_t t = time(NULL);
                    459: 
                    460:                        b = chunkqueue_get_append_buffer(con->write_queue);
                    461:                        if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
                    462:                                buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
                    463:                        } else {
                    464:                                buffer_copy_string(b, buf);
                    465:                        }
                    466:                        break;
                    467:                }
                    468:                case SSI_ECHO_DATE_GMT: {
                    469:                        time_t t = time(NULL);
                    470: 
                    471:                        b = chunkqueue_get_append_buffer(con->write_queue);
                    472:                        if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) {
                    473:                                buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
                    474:                        } else {
                    475:                                buffer_copy_string(b, buf);
                    476:                        }
                    477:                        break;
                    478:                }
                    479:                case SSI_ECHO_DOCUMENT_NAME: {
                    480:                        char *sl;
                    481: 
                    482:                        b = chunkqueue_get_append_buffer(con->write_queue);
                    483:                        if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
                    484:                                buffer_copy_string_buffer(b, con->physical.path);
                    485:                        } else {
                    486:                                buffer_copy_string(b, sl + 1);
                    487:                        }
                    488:                        break;
                    489:                }
                    490:                case SSI_ECHO_DOCUMENT_URI: {
                    491:                        b = chunkqueue_get_append_buffer(con->write_queue);
                    492:                        buffer_copy_string_buffer(b, con->uri.path);
                    493:                        break;
                    494:                }
                    495:                default: {
                    496:                        data_string *ds;
                    497:                        /* check if it is a cgi-var */
                    498: 
                    499:                        b = chunkqueue_get_append_buffer(con->write_queue);
                    500: 
                    501:                        if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val))) {
                    502:                                buffer_copy_string_buffer(b, ds->value);
                    503:                        } else {
                    504:                                buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
                    505:                        }
                    506: 
                    507:                        break;
                    508:                }
                    509:                }
                    510:                break;
                    511:        }
                    512:        case SSI_INCLUDE:
                    513:        case SSI_FLASTMOD:
                    514:        case SSI_FSIZE: {
                    515:                const char * file_path = NULL, *virt_path = NULL;
                    516:                struct stat st;
                    517:                char *sl;
                    518: 
                    519:                for (i = 2; i < n; i += 2) {
                    520:                        if (0 == strcmp(l[i], "file")) {
                    521:                                file_path = l[i+1];
                    522:                        } else if (0 == strcmp(l[i], "virtual")) {
                    523:                                virt_path = l[i+1];
                    524:                        } else {
                    525:                                log_error_write(srv, __FILE__, __LINE__, "sss",
                    526:                                                "ssi: unknow attribute for ",
                    527:                                                l[1], l[i]);
                    528:                        }
                    529:                }
                    530: 
                    531:                if (!file_path && !virt_path) {
                    532:                        log_error_write(srv, __FILE__, __LINE__, "sss",
                    533:                                        "ssi: ",
                    534:                                        l[1], "file or virtual are missing");
                    535:                        break;
                    536:                }
                    537: 
                    538:                if (file_path && virt_path) {
                    539:                        log_error_write(srv, __FILE__, __LINE__, "sss",
                    540:                                        "ssi: ",
                    541:                                        l[1], "only one of file and virtual is allowed here");
                    542:                        break;
                    543:                }
                    544: 
                    545: 
                    546:                if (p->if_is_false) break;
                    547: 
                    548:                if (file_path) {
                    549:                        /* current doc-root */
                    550:                        if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
                    551:                                buffer_copy_string_len(p->stat_fn, CONST_STR_LEN("/"));
                    552:                        } else {
                    553:                                buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, sl - con->physical.path->ptr + 1);
                    554:                        }
                    555: 
                    556:                        buffer_copy_string(srv->tmp_buf, file_path);
                    557:                        buffer_urldecode_path(srv->tmp_buf);
                    558:                        buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
                    559:                        buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
                    560:                } else {
                    561:                        /* virtual */
                    562: 
                    563:                        if (virt_path[0] == '/') {
                    564:                                buffer_copy_string(p->stat_fn, virt_path);
                    565:                        } else {
                    566:                                /* there is always a / */
                    567:                                sl = strrchr(con->uri.path->ptr, '/');
                    568: 
                    569:                                buffer_copy_string_len(p->stat_fn, con->uri.path->ptr, sl - con->uri.path->ptr + 1);
                    570:                                buffer_append_string(p->stat_fn, virt_path);
                    571:                        }
                    572: 
                    573:                        buffer_urldecode_path(p->stat_fn);
                    574:                        buffer_path_simplify(srv->tmp_buf, p->stat_fn);
                    575: 
                    576:                        /* we have an uri */
                    577: 
                    578:                        buffer_copy_string_buffer(p->stat_fn, con->physical.doc_root);
                    579:                        buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
                    580:                }
                    581: 
                    582:                if (0 == stat(p->stat_fn->ptr, &st)) {
                    583:                        time_t t = st.st_mtime;
                    584: 
                    585:                        switch (ssicmd) {
                    586:                        case SSI_FSIZE:
                    587:                                b = chunkqueue_get_append_buffer(con->write_queue);
                    588:                                if (p->sizefmt) {
                    589:                                        int j = 0;
                    590:                                        const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL };
                    591: 
                    592:                                        off_t s = st.st_size;
                    593: 
                    594:                                        for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++);
                    595: 
                    596:                                        buffer_copy_off_t(b, s);
                    597:                                        buffer_append_string(b, abr[j]);
                    598:                                } else {
                    599:                                        buffer_copy_off_t(b, st.st_size);
                    600:                                }
                    601:                                break;
                    602:                        case SSI_FLASTMOD:
                    603:                                b = chunkqueue_get_append_buffer(con->write_queue);
                    604:                                if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
                    605:                                        buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
                    606:                                } else {
                    607:                                        buffer_copy_string(b, buf);
                    608:                                }
                    609:                                break;
                    610:                        case SSI_INCLUDE:
                    611:                                chunkqueue_append_file(con->write_queue, p->stat_fn, 0, st.st_size);
                    612: 
                    613:                                /* Keep the newest mtime of included files */
                    614:                                if (st.st_mtime > include_file_last_mtime)
                    615:                                  include_file_last_mtime = st.st_mtime;
                    616: 
                    617:                                break;
                    618:                        }
                    619:                } else {
                    620:                        log_error_write(srv, __FILE__, __LINE__, "sbs",
                    621:                                        "ssi: stating failed ",
                    622:                                        p->stat_fn, strerror(errno));
                    623:                }
                    624:                break;
                    625:        }
                    626:        case SSI_SET: {
                    627:                const char *key = NULL, *val = NULL;
                    628:                for (i = 2; i < n; i += 2) {
                    629:                        if (0 == strcmp(l[i], "var")) {
                    630:                                key = l[i+1];
                    631:                        } else if (0 == strcmp(l[i], "value")) {
                    632:                                val = l[i+1];
                    633:                        } else {
                    634:                                log_error_write(srv, __FILE__, __LINE__, "sss",
                    635:                                                "ssi: unknow attribute for ",
                    636:                                                l[1], l[i]);
                    637:                        }
                    638:                }
                    639: 
                    640:                if (p->if_is_false) break;
                    641: 
                    642:                if (key && val) {
                    643:                        data_string *ds;
                    644: 
                    645:                        if (NULL == (ds = (data_string *)array_get_unused_element(p->ssi_vars, TYPE_STRING))) {
                    646:                                ds = data_string_init();
                    647:                        }
                    648:                        buffer_copy_string(ds->key,   key);
                    649:                        buffer_copy_string(ds->value, val);
                    650: 
                    651:                        array_insert_unique(p->ssi_vars, (data_unset *)ds);
                    652:                } else {
                    653:                        log_error_write(srv, __FILE__, __LINE__, "sss",
                    654:                                        "ssi: var and value have to be set in",
                    655:                                        l[0], l[1]);
                    656:                }
                    657:                break;
                    658:        }
                    659:        case SSI_CONFIG:
                    660:                if (p->if_is_false) break;
                    661: 
                    662:                for (i = 2; i < n; i += 2) {
                    663:                        if (0 == strcmp(l[i], "timefmt")) {
                    664:                                buffer_copy_string(p->timefmt, l[i+1]);
                    665:                        } else if (0 == strcmp(l[i], "sizefmt")) {
                    666:                                if (0 == strcmp(l[i+1], "abbrev")) {
                    667:                                        p->sizefmt = 1;
                    668:                                } else if (0 == strcmp(l[i+1], "abbrev")) {
                    669:                                        p->sizefmt = 0;
                    670:                                } else {
                    671:                                        log_error_write(srv, __FILE__, __LINE__, "sssss",
                    672:                                                        "ssi: unknow value for attribute '",
                    673:                                                        l[i],
                    674:                                                        "' for ",
                    675:                                                        l[1], l[i+1]);
                    676:                                }
                    677:                        } else {
                    678:                                log_error_write(srv, __FILE__, __LINE__, "sss",
                    679:                                                "ssi: unknow attribute for ",
                    680:                                                l[1], l[i]);
                    681:                        }
                    682:                }
                    683:                break;
                    684:        case SSI_PRINTENV:
                    685:                if (p->if_is_false) break;
                    686: 
                    687:                b = chunkqueue_get_append_buffer(con->write_queue);
                    688:                for (i = 0; i < p->ssi_vars->used; i++) {
                    689:                        data_string *ds = (data_string *)p->ssi_vars->data[p->ssi_vars->sorted[i]];
                    690: 
                    691:                        buffer_append_string_buffer(b, ds->key);
                    692:                        buffer_append_string_len(b, CONST_STR_LEN("="));
                    693:                        buffer_append_string_encoded(b, CONST_BUF_LEN(ds->value), ENCODING_MINIMAL_XML);
                    694:                        buffer_append_string_len(b, CONST_STR_LEN("\n"));
                    695:                }
                    696:                for (i = 0; i < p->ssi_cgi_env->used; i++) {
                    697:                        data_string *ds = (data_string *)p->ssi_cgi_env->data[p->ssi_cgi_env->sorted[i]];
                    698: 
                    699:                        buffer_append_string_buffer(b, ds->key);
                    700:                        buffer_append_string_len(b, CONST_STR_LEN("="));
                    701:                        buffer_append_string_encoded(b, CONST_BUF_LEN(ds->value), ENCODING_MINIMAL_XML);
                    702:                        buffer_append_string_len(b, CONST_STR_LEN("\n"));
                    703:                }
                    704: 
                    705:                break;
                    706:        case SSI_EXEC: {
                    707:                const char *cmd = NULL;
                    708:                pid_t pid;
                    709:                int from_exec_fds[2];
                    710: 
                    711:                for (i = 2; i < n; i += 2) {
                    712:                        if (0 == strcmp(l[i], "cmd")) {
                    713:                                cmd = l[i+1];
                    714:                        } else {
                    715:                                log_error_write(srv, __FILE__, __LINE__, "sss",
                    716:                                                "ssi: unknow attribute for ",
                    717:                                                l[1], l[i]);
                    718:                        }
                    719:                }
                    720: 
                    721:                if (p->if_is_false) break;
                    722: 
                    723:                /* create a return pipe and send output to the html-page
                    724:                 *
                    725:                 * as exec is assumed evil it is implemented synchronously
                    726:                 */
                    727: 
                    728:                if (!cmd) break;
                    729: #ifdef HAVE_FORK
                    730:                if (pipe(from_exec_fds)) {
                    731:                        log_error_write(srv, __FILE__, __LINE__, "ss",
                    732:                                        "pipe failed: ", strerror(errno));
                    733:                        return -1;
                    734:                }
                    735: 
                    736:                /* fork, execve */
                    737:                switch (pid = fork()) {
                    738:                case 0: {
                    739:                        /* move stdout to from_rrdtool_fd[1] */
                    740:                        close(STDOUT_FILENO);
                    741:                        dup2(from_exec_fds[1], STDOUT_FILENO);
                    742:                        close(from_exec_fds[1]);
                    743:                        /* not needed */
                    744:                        close(from_exec_fds[0]);
                    745: 
                    746:                        /* close stdin */
                    747:                        close(STDIN_FILENO);
                    748: 
                    749:                        execl("/bin/sh", "sh", "-c", cmd, (char *)NULL);
                    750: 
                    751:                        log_error_write(srv, __FILE__, __LINE__, "sss", "spawing exec failed:", strerror(errno), cmd);
                    752: 
                    753:                        /* */
                    754:                        SEGFAULT();
                    755:                        break;
                    756:                }
                    757:                case -1:
                    758:                        /* error */
                    759:                        log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno));
                    760:                        break;
                    761:                default: {
                    762:                        /* father */
                    763:                        int status;
                    764:                        ssize_t r;
                    765:                        int was_interrupted = 0;
                    766: 
                    767:                        close(from_exec_fds[1]);
                    768: 
                    769:                        /* wait for the client to end */
                    770: 
                    771:                        /*
                    772:                         * OpenBSD and Solaris send a EINTR on SIGCHILD even if we ignore it
                    773:                         */
                    774:                        do {
                    775:                                if (-1 == waitpid(pid, &status, 0)) {
                    776:                                        if (errno == EINTR) {
                    777:                                                was_interrupted++;
                    778:                                        } else {
                    779:                                                was_interrupted = 0;
                    780:                                                log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno));
                    781:                                        }
                    782:                                } else if (WIFEXITED(status)) {
                    783:                                        int toread;
                    784:                                        /* read everything from client and paste it into the output */
                    785:                                        was_interrupted = 0;
                    786:        
                    787:                                        while(1) {
                    788:                                                if (ioctl(from_exec_fds[0], FIONREAD, &toread)) {
                    789:                                                        log_error_write(srv, __FILE__, __LINE__, "s",
                    790:                                                                "unexpected end-of-file (perhaps the ssi-exec process died)");
                    791:                                                        return -1;
                    792:                                                }
                    793:        
                    794:                                                if (toread > 0) {
                    795:                                                        b = chunkqueue_get_append_buffer(con->write_queue);
                    796:        
                    797:                                                        buffer_prepare_copy(b, toread + 1);
                    798:        
                    799:                                                        if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) {
                    800:                                                                /* read failed */
                    801:                                                                break;
                    802:                                                        } else {
                    803:                                                                b->used = r;
                    804:                                                                b->ptr[b->used++] = '\0';
                    805:                                                        }
                    806:                                                } else {
                    807:                                                        break;
                    808:                                                }
                    809:                                        }
                    810:                                } else {
                    811:                                        was_interrupted = 0;
                    812:                                        log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally");
                    813:                                }
                    814:                        } while (was_interrupted > 0 && was_interrupted < 4); /* if waitpid() gets interrupted, retry, but max 4 times */
                    815: 
                    816:                        close(from_exec_fds[0]);
                    817: 
                    818:                        break;
                    819:                }
                    820:                }
                    821: #else
                    822: 
                    823:                return -1;
                    824: #endif
                    825: 
                    826:                break;
                    827:        }
                    828:        case SSI_IF: {
                    829:                const char *expr = NULL;
                    830: 
                    831:                for (i = 2; i < n; i += 2) {
                    832:                        if (0 == strcmp(l[i], "expr")) {
                    833:                                expr = l[i+1];
                    834:                        } else {
                    835:                                log_error_write(srv, __FILE__, __LINE__, "sss",
                    836:                                                "ssi: unknow attribute for ",
                    837:                                                l[1], l[i]);
                    838:                        }
                    839:                }
                    840: 
                    841:                if (!expr) {
                    842:                        log_error_write(srv, __FILE__, __LINE__, "sss",
                    843:                                        "ssi: ",
                    844:                                        l[1], "expr missing");
                    845:                        break;
                    846:                }
                    847: 
                    848:                if ((!p->if_is_false) &&
                    849:                    ((p->if_is_false_level == 0) ||
                    850:                     (p->if_level < p->if_is_false_level))) {
                    851:                        switch (ssi_eval_expr(srv, con, p, expr)) {
                    852:                        case -1:
                    853:                        case 0:
                    854:                                p->if_is_false = 1;
                    855:                                p->if_is_false_level = p->if_level;
                    856:                                break;
                    857:                        case 1:
                    858:                                p->if_is_false = 0;
                    859:                                break;
                    860:                        }
                    861:                }
                    862: 
                    863:                p->if_level++;
                    864: 
                    865:                break;
                    866:        }
                    867:        case SSI_ELSE:
                    868:                p->if_level--;
                    869: 
                    870:                if (p->if_is_false) {
                    871:                        if ((p->if_level == p->if_is_false_level) &&
                    872:                            (p->if_is_false_endif == 0)) {
                    873:                                p->if_is_false = 0;
                    874:                        }
                    875:                } else {
                    876:                        p->if_is_false = 1;
                    877: 
                    878:                        p->if_is_false_level = p->if_level;
                    879:                }
                    880:                p->if_level++;
                    881: 
                    882:                break;
                    883:        case SSI_ELIF: {
                    884:                const char *expr = NULL;
                    885:                for (i = 2; i < n; i += 2) {
                    886:                        if (0 == strcmp(l[i], "expr")) {
                    887:                                expr = l[i+1];
                    888:                        } else {
                    889:                                log_error_write(srv, __FILE__, __LINE__, "sss",
                    890:                                                "ssi: unknow attribute for ",
                    891:                                                l[1], l[i]);
                    892:                        }
                    893:                }
                    894: 
                    895:                if (!expr) {
                    896:                        log_error_write(srv, __FILE__, __LINE__, "sss",
                    897:                                        "ssi: ",
                    898:                                        l[1], "expr missing");
                    899:                        break;
                    900:                }
                    901: 
                    902:                p->if_level--;
                    903: 
                    904:                if (p->if_level == p->if_is_false_level) {
                    905:                        if ((p->if_is_false) &&
                    906:                            (p->if_is_false_endif == 0)) {
                    907:                                switch (ssi_eval_expr(srv, con, p, expr)) {
                    908:                                case -1:
                    909:                                case 0:
                    910:                                        p->if_is_false = 1;
                    911:                                        p->if_is_false_level = p->if_level;
                    912:                                        break;
                    913:                                case 1:
                    914:                                        p->if_is_false = 0;
                    915:                                        break;
                    916:                                }
                    917:                        } else {
                    918:                                p->if_is_false = 1;
                    919:                                p->if_is_false_level = p->if_level;
                    920:                                p->if_is_false_endif = 1;
                    921:                        }
                    922:                }
                    923: 
                    924:                p->if_level++;
                    925: 
                    926:                break;
                    927:        }
                    928:        case SSI_ENDIF:
                    929:                p->if_level--;
                    930: 
                    931:                if (p->if_level == p->if_is_false_level) {
                    932:                        p->if_is_false = 0;
                    933:                        p->if_is_false_endif = 0;
                    934:                }
                    935: 
                    936:                break;
                    937:        default:
                    938:                log_error_write(srv, __FILE__, __LINE__, "ss",
                    939:                                "ssi: unknow ssi-command:",
                    940:                                l[1]);
                    941:                break;
                    942:        }
                    943: 
                    944:        return 0;
                    945: 
                    946: }
                    947: 
                    948: static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) {
                    949:        stream s;
                    950: #ifdef  HAVE_PCRE_H
                    951:        int i, n;
                    952: 
                    953: #define N 10
                    954:        int ovec[N * 3];
                    955: #endif
                    956: 
1.1.1.2 ! misho     957:        stat_cache_entry *sce = NULL;
        !           958: 
        !           959: 
1.1       misho     960:        /* get a stream to the file */
                    961: 
                    962:        array_reset(p->ssi_vars);
                    963:        array_reset(p->ssi_cgi_env);
                    964:        buffer_copy_string_len(p->timefmt, CONST_STR_LEN("%a, %d %b %Y %H:%M:%S %Z"));
                    965:        p->sizefmt = 0;
                    966:        build_ssi_cgi_vars(srv, con, p);
                    967:        p->if_is_false = 0;
                    968: 
                    969:        /* Reset the modified time of included files */
                    970:        include_file_last_mtime = 0;
                    971: 
1.1.1.2 ! misho     972:        if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
        !           973:                log_error_write(srv, __FILE__, __LINE__,  "SB", "stat_cache_get_entry failed: ", con->physical.path);
        !           974:                return -1;
        !           975:        }
        !           976: 
1.1       misho     977:        if (-1 == stream_open(&s, con->physical.path)) {
                    978:                log_error_write(srv, __FILE__, __LINE__, "sb",
                    979:                                "stream-open: ", con->physical.path);
                    980:                return -1;
                    981:        }
                    982: 
                    983: 
                    984:        /**
                    985:         * <!--#element attribute=value attribute=value ... -->
                    986:         *
                    987:         * config       DONE
                    988:         *   errmsg     -- missing
                    989:         *   sizefmt    DONE
                    990:         *   timefmt    DONE
                    991:         * echo         DONE
                    992:         *   var        DONE
                    993:         *   encoding   -- missing
                    994:         * exec         DONE
                    995:         *   cgi        -- never
                    996:         *   cmd        DONE
                    997:         * fsize        DONE
                    998:         *   file       DONE
                    999:         *   virtual    DONE
                   1000:         * flastmod     DONE
                   1001:         *   file       DONE
                   1002:         *   virtual    DONE
                   1003:         * include      DONE
                   1004:         *   file       DONE
                   1005:         *   virtual    DONE
                   1006:         * printenv     DONE
                   1007:         * set          DONE
                   1008:         *   var        DONE
                   1009:         *   value      DONE
                   1010:         *
                   1011:         * if           DONE
                   1012:         * elif         DONE
                   1013:         * else         DONE
                   1014:         * endif        DONE
                   1015:         *
                   1016:         *
                   1017:         * expressions
                   1018:         * AND, OR      DONE
                   1019:         * comp         DONE
                   1020:         * ${...}       -- missing
                   1021:         * $...         DONE
                   1022:         * '...'        DONE
                   1023:         * ( ... )      DONE
                   1024:         *
                   1025:         *
                   1026:         *
                   1027:         * ** all DONE **
                   1028:         * DATE_GMT
                   1029:         *   The current date in Greenwich Mean Time.
                   1030:         * DATE_LOCAL
                   1031:         *   The current date in the local time zone.
                   1032:         * DOCUMENT_NAME
                   1033:         *   The filename (excluding directories) of the document requested by the user.
                   1034:         * DOCUMENT_URI
                   1035:         *   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.
                   1036:         * LAST_MODIFIED
                   1037:         *   The last modification date of the document requested by the user.
                   1038:         * USER_NAME
                   1039:         *   Contains the owner of the file which included it.
                   1040:         *
                   1041:         */
                   1042: #ifdef HAVE_PCRE_H
                   1043:        for (i = 0; (n = pcre_exec(p->ssi_regex, NULL, s.start, s.size, i, 0, ovec, N * 3)) > 0; i = ovec[1]) {
                   1044:                const char **l;
                   1045:                /* take everything from last offset to current match pos */
                   1046: 
                   1047:                if (!p->if_is_false) chunkqueue_append_file(con->write_queue, con->physical.path, i, ovec[0] - i);
                   1048: 
                   1049:                pcre_get_substring_list(s.start, ovec, n, &l);
1.1.1.2 ! misho    1050:                process_ssi_stmt(srv, con, p, l, n, sce);
1.1       misho    1051:                pcre_free_substring_list(l);
                   1052:        }
                   1053: 
                   1054:        switch(n) {
                   1055:        case PCRE_ERROR_NOMATCH:
                   1056:                /* copy everything/the rest */
                   1057:                chunkqueue_append_file(con->write_queue, con->physical.path, i, s.size - i);
                   1058: 
                   1059:                break;
                   1060:        default:
                   1061:                log_error_write(srv, __FILE__, __LINE__, "sd",
                   1062:                                "execution error while matching: ", n);
                   1063:                break;
                   1064:        }
                   1065: #endif
                   1066: 
                   1067: 
                   1068:        stream_close(&s);
                   1069: 
                   1070:        con->file_started  = 1;
                   1071:        con->file_finished = 1;
                   1072:        con->mode = p->id;
                   1073: 
                   1074:        if (p->conf.content_type->used <= 1) {
                   1075:                response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
                   1076:        } else {
                   1077:                response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->conf.content_type));
                   1078:        }
                   1079: 
                   1080:        {
1.1.1.2 ! misho    1081:                /* Generate "ETag" & "Last-Modified" headers */
1.1       misho    1082:                time_t lm_time = 0;
                   1083:                buffer *mtime = NULL;
                   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>