Annotation of embedaddon/lighttpd/src/mod_cgi.c, revision 1.1.1.3

1.1.1.3 ! misho       1: #include "first.h"
        !             2: 
1.1       misho       3: #include "server.h"
                      4: #include "stat_cache.h"
                      5: #include "keyvalue.h"
                      6: #include "log.h"
                      7: #include "connections.h"
                      8: #include "joblist.h"
1.1.1.3 ! misho       9: #include "response.h"
1.1       misho      10: #include "http_chunk.h"
1.1.1.3 ! misho      11: #include "network_backends.h"
1.1       misho      12: 
                     13: #include "plugin.h"
                     14: 
                     15: #include <sys/types.h>
1.1.1.3 ! misho      16: #include "sys-mmap.h"
1.1       misho      17: 
                     18: #ifdef __WIN32
                     19: # include <winsock2.h>
                     20: #else
                     21: # include <sys/socket.h>
                     22: # include <sys/wait.h>
                     23: # include <netinet/in.h>
                     24: # include <arpa/inet.h>
                     25: #endif
                     26: 
                     27: #include <unistd.h>
                     28: #include <errno.h>
                     29: #include <stdlib.h>
                     30: #include <string.h>
                     31: #include <fdevent.h>
                     32: #include <signal.h>
                     33: #include <ctype.h>
                     34: #include <assert.h>
                     35: 
                     36: #include <stdio.h>
                     37: #include <fcntl.h>
                     38: 
                     39: enum {EOL_UNSET, EOL_N, EOL_RN};
                     40: 
                     41: typedef struct {
                     42:        char **ptr;
                     43: 
                     44:        size_t size;
                     45:        size_t used;
                     46: } char_array;
                     47: 
                     48: typedef struct {
                     49:        pid_t *ptr;
                     50:        size_t used;
                     51:        size_t size;
                     52: } buffer_pid_t;
                     53: 
                     54: typedef struct {
                     55:        array *cgi;
                     56:        unsigned short execute_x_only;
1.1.1.3 ! misho      57:        unsigned short xsendfile_allow;
        !            58:        array *xsendfile_docroot;
1.1       misho      59: } plugin_config;
                     60: 
                     61: typedef struct {
                     62:        PLUGIN_DATA;
                     63:        buffer_pid_t cgi_pid;
                     64: 
                     65:        buffer *tmp_buf;
                     66:        buffer *parse_response;
                     67: 
                     68:        plugin_config **config_storage;
                     69: 
                     70:        plugin_config conf;
                     71: } plugin_data;
                     72: 
                     73: typedef struct {
                     74:        pid_t pid;
                     75:        int fd;
1.1.1.3 ! misho      76:        int fdtocgi;
1.1       misho      77:        int fde_ndx; /* index into the fd-event buffer */
1.1.1.3 ! misho      78:        int fde_ndx_tocgi; /* index into the fd-event buffer */
1.1       misho      79: 
                     80:        connection *remote_conn;  /* dumb pointer */
                     81:        plugin_data *plugin_data; /* dumb pointer */
                     82: 
                     83:        buffer *response;
                     84:        buffer *response_header;
                     85: } handler_ctx;
                     86: 
                     87: static handler_ctx * cgi_handler_ctx_init(void) {
                     88:        handler_ctx *hctx = calloc(1, sizeof(*hctx));
                     89: 
1.1.1.2   misho      90:        force_assert(hctx);
1.1       misho      91: 
                     92:        hctx->response = buffer_init();
                     93:        hctx->response_header = buffer_init();
1.1.1.3 ! misho      94:        hctx->fd = -1;
        !            95:        hctx->fdtocgi = -1;
1.1       misho      96: 
                     97:        return hctx;
                     98: }
                     99: 
                    100: static void cgi_handler_ctx_free(handler_ctx *hctx) {
                    101:        buffer_free(hctx->response);
                    102:        buffer_free(hctx->response_header);
                    103: 
                    104:        free(hctx);
                    105: }
                    106: 
1.1.1.3 ! misho     107: enum {FDEVENT_HANDLED_UNSET, FDEVENT_HANDLED_FINISHED, FDEVENT_HANDLED_NOT_FINISHED, FDEVENT_HANDLED_COMEBACK, FDEVENT_HANDLED_ERROR};
1.1       misho     108: 
                    109: INIT_FUNC(mod_cgi_init) {
                    110:        plugin_data *p;
                    111: 
                    112:        p = calloc(1, sizeof(*p));
                    113: 
1.1.1.2   misho     114:        force_assert(p);
1.1       misho     115: 
                    116:        p->tmp_buf = buffer_init();
                    117:        p->parse_response = buffer_init();
                    118: 
                    119:        return p;
                    120: }
                    121: 
                    122: 
                    123: FREE_FUNC(mod_cgi_free) {
                    124:        plugin_data *p = p_d;
                    125:        buffer_pid_t *r = &(p->cgi_pid);
                    126: 
                    127:        UNUSED(srv);
                    128: 
                    129:        if (p->config_storage) {
                    130:                size_t i;
                    131:                for (i = 0; i < srv->config_context->used; i++) {
                    132:                        plugin_config *s = p->config_storage[i];
                    133: 
1.1.1.3 ! misho     134:                        if (NULL == s) continue;
        !           135: 
1.1       misho     136:                        array_free(s->cgi);
1.1.1.3 ! misho     137:                        array_free(s->xsendfile_docroot);
1.1       misho     138: 
                    139:                        free(s);
                    140:                }
                    141:                free(p->config_storage);
                    142:        }
                    143: 
                    144: 
                    145:        if (r->ptr) free(r->ptr);
                    146: 
                    147:        buffer_free(p->tmp_buf);
                    148:        buffer_free(p->parse_response);
                    149: 
                    150:        free(p);
                    151: 
                    152:        return HANDLER_GO_ON;
                    153: }
                    154: 
                    155: SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
                    156:        plugin_data *p = p_d;
                    157:        size_t i = 0;
                    158: 
                    159:        config_values_t cv[] = {
                    160:                { "cgi.assign",                  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
                    161:                { "cgi.execute-x-only",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },     /* 1 */
1.1.1.3 ! misho     162:                { "cgi.x-sendfile",              NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },     /* 2 */
        !           163:                { "cgi.x-sendfile-docroot",      NULL, T_CONFIG_ARRAY,   T_CONFIG_SCOPE_CONNECTION },     /* 3 */
1.1       misho     164:                { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET}
                    165:        };
                    166: 
                    167:        if (!p) return HANDLER_ERROR;
                    168: 
1.1.1.2   misho     169:        p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
1.1.1.3 ! misho     170:        force_assert(p->config_storage);
1.1       misho     171: 
                    172:        for (i = 0; i < srv->config_context->used; i++) {
1.1.1.3 ! misho     173:                data_config const* config = (data_config const*)srv->config_context->data[i];
1.1       misho     174:                plugin_config *s;
                    175: 
                    176:                s = calloc(1, sizeof(plugin_config));
1.1.1.2   misho     177:                force_assert(s);
1.1       misho     178: 
                    179:                s->cgi    = array_init();
                    180:                s->execute_x_only = 0;
1.1.1.3 ! misho     181:                s->xsendfile_allow= 0;
        !           182:                s->xsendfile_docroot = array_init();
1.1       misho     183: 
                    184:                cv[0].destination = s->cgi;
                    185:                cv[1].destination = &(s->execute_x_only);
1.1.1.3 ! misho     186:                cv[2].destination = &(s->xsendfile_allow);
        !           187:                cv[3].destination = s->xsendfile_docroot;
1.1       misho     188: 
                    189:                p->config_storage[i] = s;
                    190: 
1.1.1.3 ! misho     191:                if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
1.1       misho     192:                        return HANDLER_ERROR;
                    193:                }
1.1.1.3 ! misho     194: 
        !           195:                if (s->xsendfile_docroot->used) {
        !           196:                        size_t j;
        !           197:                        for (j = 0; j < s->xsendfile_docroot->used; ++j) {
        !           198:                                data_string *ds = (data_string *)s->xsendfile_docroot->data[j];
        !           199:                                if (ds->type != TYPE_STRING) {
        !           200:                                        log_error_write(srv, __FILE__, __LINE__, "s",
        !           201:                                                "unexpected type for key cgi.x-sendfile-docroot; expected: cgi.x-sendfile-docroot = ( \"/allowed/path\", ... )");
        !           202:                                        return HANDLER_ERROR;
        !           203:                                }
        !           204:                                if (ds->value->ptr[0] != '/') {
        !           205:                                        log_error_write(srv, __FILE__, __LINE__, "SBs",
        !           206:                                                "cgi.x-sendfile-docroot paths must begin with '/'; invalid: \"", ds->value, "\"");
        !           207:                                        return HANDLER_ERROR;
        !           208:                                }
        !           209:                                buffer_path_simplify(ds->value, ds->value);
        !           210:                                buffer_append_slash(ds->value);
        !           211:                        }
        !           212:                }
1.1       misho     213:        }
                    214: 
                    215:        return HANDLER_GO_ON;
                    216: }
                    217: 
                    218: 
                    219: static int cgi_pid_add(server *srv, plugin_data *p, pid_t pid) {
                    220:        int m = -1;
                    221:        size_t i;
                    222:        buffer_pid_t *r = &(p->cgi_pid);
                    223: 
                    224:        UNUSED(srv);
                    225: 
                    226:        for (i = 0; i < r->used; i++) {
                    227:                if (r->ptr[i] > m) m = r->ptr[i];
                    228:        }
                    229: 
                    230:        if (r->size == 0) {
                    231:                r->size = 16;
                    232:                r->ptr = malloc(sizeof(*r->ptr) * r->size);
1.1.1.3 ! misho     233:                force_assert(r->ptr);
1.1       misho     234:        } else if (r->used == r->size) {
                    235:                r->size += 16;
                    236:                r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
1.1.1.3 ! misho     237:                force_assert(r->ptr);
1.1       misho     238:        }
                    239: 
                    240:        r->ptr[r->used++] = pid;
                    241: 
                    242:        return m;
                    243: }
                    244: 
                    245: static int cgi_pid_del(server *srv, plugin_data *p, pid_t pid) {
                    246:        size_t i;
                    247:        buffer_pid_t *r = &(p->cgi_pid);
                    248: 
                    249:        UNUSED(srv);
                    250: 
                    251:        for (i = 0; i < r->used; i++) {
                    252:                if (r->ptr[i] == pid) break;
                    253:        }
                    254: 
                    255:        if (i != r->used) {
                    256:                /* found */
                    257: 
                    258:                if (i != r->used - 1) {
                    259:                        r->ptr[i] = r->ptr[r->used - 1];
                    260:                }
                    261:                r->used--;
                    262:        }
                    263: 
                    264:        return 0;
                    265: }
                    266: 
                    267: static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
                    268:        char *ns;
                    269:        const char *s;
                    270:        int line = 0;
                    271: 
                    272:        UNUSED(srv);
                    273: 
1.1.1.3 ! misho     274:        buffer_copy_buffer(p->parse_response, in);
1.1       misho     275: 
                    276:        for (s = p->parse_response->ptr;
                    277:             NULL != (ns = strchr(s, '\n'));
                    278:             s = ns + 1, line++) {
                    279:                const char *key, *value;
                    280:                int key_len;
                    281:                data_string *ds;
                    282: 
                    283:                /* strip the \n */
                    284:                ns[0] = '\0';
                    285: 
                    286:                if (ns > s && ns[-1] == '\r') ns[-1] = '\0';
                    287: 
                    288:                if (line == 0 &&
                    289:                    0 == strncmp(s, "HTTP/1.", 7)) {
                    290:                        /* non-parsed header ... we parse them anyway */
                    291: 
                    292:                        if ((s[7] == '1' ||
                    293:                             s[7] == '0') &&
                    294:                            s[8] == ' ') {
                    295:                                int status;
                    296:                                /* after the space should be a status code for us */
                    297: 
                    298:                                status = strtol(s+9, NULL, 10);
                    299: 
                    300:                                if (status >= 100 &&
                    301:                                    status < 1000) {
                    302:                                        /* we expected 3 digits and didn't got them */
                    303:                                        con->parsed_response |= HTTP_STATUS;
                    304:                                        con->http_status = status;
                    305:                                }
                    306:                        }
                    307:                } else {
                    308:                        /* parse the headers */
                    309:                        key = s;
                    310:                        if (NULL == (value = strchr(s, ':'))) {
                    311:                                /* we expect: "<key>: <value>\r\n" */
                    312:                                continue;
                    313:                        }
                    314: 
                    315:                        key_len = value - key;
                    316:                        value += 1;
                    317: 
                    318:                        /* skip LWS */
                    319:                        while (*value == ' ' || *value == '\t') value++;
                    320: 
                    321:                        if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
                    322:                                ds = data_response_init();
                    323:                        }
                    324:                        buffer_copy_string_len(ds->key, key, key_len);
                    325:                        buffer_copy_string(ds->value, value);
                    326: 
                    327:                        array_insert_unique(con->response.headers, (data_unset *)ds);
                    328: 
                    329:                        switch(key_len) {
                    330:                        case 4:
                    331:                                if (0 == strncasecmp(key, "Date", key_len)) {
                    332:                                        con->parsed_response |= HTTP_DATE;
                    333:                                }
                    334:                                break;
                    335:                        case 6:
                    336:                                if (0 == strncasecmp(key, "Status", key_len)) {
1.1.1.3 ! misho     337:                                        int status = strtol(value, NULL, 10);
        !           338:                                        if (status >= 100 && status < 1000) {
        !           339:                                                con->http_status = status;
        !           340:                                                con->parsed_response |= HTTP_STATUS;
        !           341:                                        } else {
        !           342:                                                con->http_status = 502;
        !           343:                                        }
1.1       misho     344:                                }
                    345:                                break;
                    346:                        case 8:
                    347:                                if (0 == strncasecmp(key, "Location", key_len)) {
                    348:                                        con->parsed_response |= HTTP_LOCATION;
                    349:                                }
                    350:                                break;
                    351:                        case 10:
                    352:                                if (0 == strncasecmp(key, "Connection", key_len)) {
                    353:                                        con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
                    354:                                        con->parsed_response |= HTTP_CONNECTION;
                    355:                                }
                    356:                                break;
                    357:                        case 14:
                    358:                                if (0 == strncasecmp(key, "Content-Length", key_len)) {
1.1.1.3 ! misho     359:                                        con->response.content_length = strtoul(value, NULL, 10);
1.1       misho     360:                                        con->parsed_response |= HTTP_CONTENT_LENGTH;
                    361:                                }
                    362:                                break;
                    363:                        default:
                    364:                                break;
                    365:                        }
                    366:                }
                    367:        }
                    368: 
                    369:        /* CGI/1.1 rev 03 - 7.2.1.2 */
                    370:        if ((con->parsed_response & HTTP_LOCATION) &&
                    371:            !(con->parsed_response & HTTP_STATUS)) {
                    372:                con->http_status = 302;
                    373:        }
                    374: 
                    375:        return 0;
                    376: }
                    377: 
                    378: 
                    379: static int cgi_demux_response(server *srv, handler_ctx *hctx) {
                    380:        plugin_data *p    = hctx->plugin_data;
                    381:        connection  *con  = hctx->remote_conn;
                    382: 
                    383:        while(1) {
                    384:                int n;
                    385:                int toread;
                    386: 
                    387: #if defined(__WIN32)
1.1.1.3 ! misho     388:                buffer_string_prepare_copy(hctx->response, 4 * 1024);
1.1       misho     389: #else
1.1.1.3 ! misho     390:                if (ioctl(con->fd, FIONREAD, &toread) || toread <= 4*1024) {
        !           391:                        buffer_string_prepare_copy(hctx->response, 4 * 1024);
1.1       misho     392:                } else {
                    393:                        if (toread > MAX_READ_LIMIT) toread = MAX_READ_LIMIT;
1.1.1.3 ! misho     394:                        buffer_string_prepare_copy(hctx->response, toread);
1.1       misho     395:                }
                    396: #endif
                    397: 
                    398:                if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
                    399:                        if (errno == EAGAIN || errno == EINTR) {
                    400:                                /* would block, wait for signal */
1.1.1.3 ! misho     401:                                fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
1.1       misho     402:                                return FDEVENT_HANDLED_NOT_FINISHED;
                    403:                        }
                    404:                        /* error */
                    405:                        log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
                    406:                        return FDEVENT_HANDLED_ERROR;
                    407:                }
                    408: 
                    409:                if (n == 0) {
                    410:                        /* read finished */
                    411:                        return FDEVENT_HANDLED_FINISHED;
                    412:                }
                    413: 
1.1.1.3 ! misho     414:                buffer_commit(hctx->response, n);
1.1       misho     415: 
                    416:                /* split header from body */
                    417: 
                    418:                if (con->file_started == 0) {
                    419:                        int is_header = 0;
                    420:                        int is_header_end = 0;
                    421:                        size_t last_eol = 0;
1.1.1.3 ! misho     422:                        size_t i, header_len;
1.1       misho     423: 
                    424:                        buffer_append_string_buffer(hctx->response_header, hctx->response);
                    425: 
                    426:                        /**
                    427:                         * we have to handle a few cases:
                    428:                         *
                    429:                         * nph:
                    430:                         * 
                    431:                         *   HTTP/1.0 200 Ok\n
                    432:                         *   Header: Value\n
                    433:                         *   \n
                    434:                         *
                    435:                         * CGI:
                    436:                         *   Header: Value\n
                    437:                         *   Status: 200\n
                    438:                         *   \n
                    439:                         *
                    440:                         * and different mixes of \n and \r\n combinations
                    441:                         * 
                    442:                         * Some users also forget about CGI and just send a response and hope 
                    443:                         * we handle it. No headers, no header-content seperator
                    444:                         * 
                    445:                         */
                    446:                        
                    447:                        /* nph (non-parsed headers) */
                    448:                        if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) is_header = 1;
1.1.1.3 ! misho     449: 
        !           450:                        header_len = buffer_string_length(hctx->response_header);
        !           451:                        for (i = 0; !is_header_end && i < header_len; i++) {
1.1       misho     452:                                char c = hctx->response_header->ptr[i];
                    453: 
                    454:                                switch (c) {
                    455:                                case ':':
                    456:                                        /* we found a colon
                    457:                                         *
                    458:                                         * looks like we have a normal header 
                    459:                                         */
                    460:                                        is_header = 1;
                    461:                                        break;
                    462:                                case '\n':
                    463:                                        /* EOL */
                    464:                                        if (is_header == 0) {
                    465:                                                /* we got a EOL but we don't seem to got a HTTP header */
                    466: 
                    467:                                                is_header_end = 1;
                    468: 
                    469:                                                break;
                    470:                                        }
                    471: 
                    472:                                        /**
                    473:                                         * check if we saw a \n(\r)?\n sequence 
                    474:                                         */
                    475:                                        if (last_eol > 0 && 
                    476:                                            ((i - last_eol == 1) || 
                    477:                                             (i - last_eol == 2 && hctx->response_header->ptr[i - 1] == '\r'))) {
                    478:                                                is_header_end = 1;
                    479:                                                break;
                    480:                                        }
                    481: 
                    482:                                        last_eol = i;
                    483: 
                    484:                                        break;
                    485:                                }
                    486:                        }
                    487: 
                    488:                        if (is_header_end) {
                    489:                                if (!is_header) {
                    490:                                        /* no header, but a body */
1.1.1.3 ! misho     491:                                        if (0 != http_chunk_append_buffer(srv, con, hctx->response_header)) {
        !           492:                                                return FDEVENT_HANDLED_ERROR;
1.1       misho     493:                                        }
                    494:                                } else {
                    495:                                        const char *bstart;
                    496:                                        size_t blen;
1.1.1.3 ! misho     497: 
        !           498:                                        /* the body starts after the EOL */
        !           499:                                        bstart = hctx->response_header->ptr + i;
        !           500:                                        blen = header_len - i;
        !           501: 
1.1       misho     502:                                        /**
                    503:                                         * i still points to the char after the terminating EOL EOL
                    504:                                         *
                    505:                                         * put it on the last \n again
                    506:                                         */
                    507:                                        i--;
1.1.1.3 ! misho     508: 
1.1       misho     509:                                        /* string the last \r?\n */
                    510:                                        if (i > 0 && (hctx->response_header->ptr[i - 1] == '\r')) {
                    511:                                                i--;
                    512:                                        }
                    513: 
1.1.1.3 ! misho     514:                                        buffer_string_set_length(hctx->response_header, i);
        !           515: 
1.1       misho     516:                                        /* parse the response header */
                    517:                                        cgi_response_parse(srv, con, p, hctx->response_header);
                    518: 
1.1.1.3 ! misho     519:                                        if (con->http_status >= 300 && con->http_status < 400) {
        !           520:                                                /*(con->parsed_response & HTTP_LOCATION)*/
        !           521:                                                data_string *ds;
        !           522:                                                if (NULL != (ds = (data_string *) array_get_element(con->response.headers, "Location"))
        !           523:                                                    && ds->value->ptr[0] == '/') {
        !           524:                                                        if (++con->loops_per_request > 5) {
        !           525:                                                                log_error_write(srv, __FILE__, __LINE__, "sb", "too many internal loops while processing request:", con->request.orig_uri);
        !           526:                                                                con->http_status = 500; /* Internal Server Error */
        !           527:                                                                con->mode = DIRECT;
        !           528:                                                                return FDEVENT_HANDLED_FINISHED;
        !           529:                                                        }
        !           530: 
        !           531:                                                        buffer_copy_buffer(con->request.uri, ds->value);
        !           532: 
        !           533:                                                        if (con->request.content_length) {
        !           534:                                                                if ((off_t)con->request.content_length != chunkqueue_length(con->request_content_queue)) {
        !           535:                                                                        con->keep_alive = 0;
        !           536:                                                                }
        !           537:                                                                con->request.content_length = 0;
        !           538:                                                                chunkqueue_reset(con->request_content_queue);
        !           539:                                                        }
        !           540: 
        !           541:                                                        if (con->http_status != 307 && con->http_status != 308) {
        !           542:                                                                /* Note: request body (if any) sent to initial dynamic handler
        !           543:                                                                 * and is not available to the internal redirect */
        !           544:                                                                con->request.http_method = HTTP_METHOD_GET;
        !           545:                                                        }
        !           546: 
        !           547:                                                        connection_response_reset(srv, con); /*(includes con->http_status = 0)*/
        !           548: 
        !           549:                                                        con->mode = DIRECT;
        !           550:                                                        return FDEVENT_HANDLED_COMEBACK;
        !           551:                                                }
        !           552:                                        }
        !           553: 
        !           554:                                        if (p->conf.xsendfile_allow) {
        !           555:                                                data_string *ds;
        !           556:                                                if (NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-Sendfile"))) {
        !           557:                                                        http_response_xsendfile(srv, con, ds->value, p->conf.xsendfile_docroot);
        !           558:                                                        return FDEVENT_HANDLED_FINISHED;
        !           559:                                                }
1.1       misho     560:                                        }
                    561: 
                    562:                                        if (blen > 0) {
1.1.1.3 ! misho     563:                                                if (0 != http_chunk_append_mem(srv, con, bstart, blen)) {
        !           564:                                                        return FDEVENT_HANDLED_ERROR;
        !           565:                                                }
1.1       misho     566:                                        }
                    567:                                }
                    568: 
                    569:                                con->file_started = 1;
1.1.1.3 ! misho     570:                        } else {
        !           571:                                /*(reuse MAX_HTTP_REQUEST_HEADER as max size for response headers from backends)*/
        !           572:                                if (header_len > MAX_HTTP_REQUEST_HEADER) {
        !           573:                                        log_error_write(srv, __FILE__, __LINE__, "sb", "response headers too large for", con->uri.path);
        !           574:                                        con->http_status = 502; /* Bad Gateway */
        !           575:                                        con->mode = DIRECT;
        !           576:                                        return FDEVENT_HANDLED_FINISHED;
        !           577:                                }
1.1       misho     578:                        }
                    579:                } else {
1.1.1.3 ! misho     580:                        if (0 != http_chunk_append_buffer(srv, con, hctx->response)) {
        !           581:                                return FDEVENT_HANDLED_ERROR;
        !           582:                        }
        !           583:                        if ((con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN)
        !           584:                            && chunkqueue_length(con->write_queue) > 65536 - 4096) {
        !           585:                                if (!con->is_writable) {
        !           586:                                        /*(defer removal of FDEVENT_IN interest since
        !           587:                                         * connection_state_machine() might be able to send data
        !           588:                                         * immediately, unless !con->is_writable, where
        !           589:                                         * connection_state_machine() might not loop back to call
        !           590:                                         * mod_cgi_handle_subrequest())*/
        !           591:                                        fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
        !           592:                                }
        !           593:                                break;
        !           594:                        }
1.1       misho     595:                }
                    596: 
                    597: #if 0
                    598:                log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
                    599: #endif
                    600:        }
                    601: 
                    602:        return FDEVENT_HANDLED_NOT_FINISHED;
                    603: }
                    604: 
1.1.1.3 ! misho     605: static void cgi_connection_close_fdtocgi(server *srv, handler_ctx *hctx) {
        !           606:        /*(closes only hctx->fdtocgi)*/
        !           607:        fdevent_event_del(srv->ev, &(hctx->fde_ndx_tocgi), hctx->fdtocgi);
        !           608:        fdevent_unregister(srv->ev, hctx->fdtocgi);
1.1       misho     609: 
1.1.1.3 ! misho     610:        if (close(hctx->fdtocgi)) {
        !           611:                log_error_write(srv, __FILE__, __LINE__, "sds", "cgi stdin close failed ", hctx->fdtocgi, strerror(errno));
        !           612:        }
        !           613:        hctx->fdtocgi = -1;
        !           614: }
1.1       misho     615: 
1.1.1.3 ! misho     616: static void cgi_connection_close(server *srv, handler_ctx *hctx) {
        !           617:        int status;
        !           618:        pid_t pid;
        !           619:        plugin_data *p = hctx->plugin_data;
        !           620:        connection *con = hctx->remote_conn;
1.1       misho     621: 
                    622: #ifndef __WIN32
                    623: 
                    624:        /* the connection to the browser went away, but we still have a connection
                    625:         * to the CGI script
                    626:         *
                    627:         * close cgi-connection
                    628:         */
                    629: 
                    630:        if (hctx->fd != -1) {
                    631:                /* close connection to the cgi-script */
                    632:                fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
                    633:                fdevent_unregister(srv->ev, hctx->fd);
                    634: 
                    635:                if (close(hctx->fd)) {
                    636:                        log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
                    637:                }
1.1.1.3 ! misho     638:        }
1.1       misho     639: 
1.1.1.3 ! misho     640:        if (hctx->fdtocgi != -1) {
        !           641:                cgi_connection_close_fdtocgi(srv, hctx); /*(closes only hctx->fdtocgi)*/
1.1       misho     642:        }
                    643: 
                    644:        pid = hctx->pid;
                    645: 
                    646:        con->plugin_ctx[p->id] = NULL;
                    647: 
                    648:        cgi_handler_ctx_free(hctx);
                    649: 
                    650:        /* if waitpid hasn't been called by response.c yet, do it here */
                    651:        if (pid) {
                    652:                /* check if the CGI-script is already gone */
                    653:                switch(waitpid(pid, &status, WNOHANG)) {
                    654:                case 0:
                    655:                        /* not finished yet */
                    656: #if 0
                    657:                        log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) child isn't done yet, pid:", pid);
                    658: #endif
                    659:                        break;
                    660:                case -1:
                    661:                        /* */
                    662:                        if (errno == EINTR) break;
                    663: 
                    664:                        /*
                    665:                         * errno == ECHILD happens if _subrequest catches the process-status before
                    666:                         * we have read the response of the cgi process
                    667:                         *
                    668:                         * -> catch status
                    669:                         * -> WAIT_FOR_EVENT
                    670:                         * -> read response
                    671:                         * -> we get here with waitpid == ECHILD
                    672:                         *
                    673:                         */
1.1.1.3 ! misho     674:                        if (errno != ECHILD) {
        !           675:                                log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
1.1       misho     676:                        }
1.1.1.3 ! misho     677:                        /* anyway: don't wait for it anymore */
        !           678:                        pid = 0;
        !           679:                        break;
        !           680:                default:
1.1       misho     681:                        if (WIFEXITED(status)) {
                    682: #if 0
                    683:                                log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", pid);
                    684: #endif
                    685:                        } else {
                    686:                                log_error_write(srv, __FILE__, __LINE__, "sd", "cgi died, pid:", pid);
                    687:                        }
                    688: 
1.1.1.3 ! misho     689:                        pid = 0;
        !           690:                        break;
        !           691:                }
1.1       misho     692: 
1.1.1.3 ! misho     693:                if (pid) {
        !           694:                        kill(pid, SIGTERM);
1.1       misho     695: 
1.1.1.3 ! misho     696:                        /* cgi-script is still alive, queue the PID for removal */
        !           697:                        cgi_pid_add(srv, p, pid);
        !           698:                }
1.1       misho     699:        }
                    700: #endif
1.1.1.3 ! misho     701: 
        !           702:        /* finish response (if not already con->file_started, con->file_finished) */
        !           703:        if (con->mode == p->id) {
        !           704:                http_response_backend_done(srv, con);
        !           705:        }
1.1       misho     706: }
                    707: 
                    708: static handler_t cgi_connection_close_callback(server *srv, connection *con, void *p_d) {
                    709:        plugin_data *p = p_d;
1.1.1.3 ! misho     710:        handler_ctx *hctx = con->plugin_ctx[p->id];
        !           711:        if (hctx) cgi_connection_close(srv, hctx);
1.1       misho     712: 
1.1.1.3 ! misho     713:        return HANDLER_GO_ON;
1.1       misho     714: }
                    715: 
                    716: 
1.1.1.3 ! misho     717: static int cgi_write_request(server *srv, handler_ctx *hctx, int fd);
        !           718: 
        !           719: 
        !           720: static handler_t cgi_handle_fdevent_send (server *srv, void *ctx, int revents) {
1.1       misho     721:        handler_ctx *hctx = ctx;
                    722:        connection  *con  = hctx->remote_conn;
                    723: 
1.1.1.3 ! misho     724:        /*(joblist only actually necessary here in mod_cgi fdevent send if returning HANDLER_ERROR)*/
1.1       misho     725:        joblist_append(srv, con);
                    726: 
1.1.1.3 ! misho     727:        if (revents & FDEVENT_OUT) {
        !           728:                if (0 != cgi_write_request(srv, hctx, hctx->fdtocgi)) {
        !           729:                        cgi_connection_close(srv, hctx);
        !           730:                        return HANDLER_ERROR;
        !           731:                }
        !           732:                /* more request body to be sent to CGI */
        !           733:        }
        !           734: 
        !           735:        if (revents & FDEVENT_HUP) {
        !           736:                /* skip sending remaining data to CGI */
        !           737:                if (con->request.content_length) {
        !           738:                        chunkqueue *cq = con->request_content_queue;
        !           739:                        chunkqueue_mark_written(cq, chunkqueue_length(cq));
        !           740:                        if (cq->bytes_in != (off_t)con->request.content_length) {
        !           741:                                con->keep_alive = 0;
        !           742:                        }
        !           743:                }
1.1       misho     744: 
1.1.1.3 ! misho     745:                cgi_connection_close_fdtocgi(srv, hctx); /*(closes only hctx->fdtocgi)*/
        !           746:        } else if (revents & FDEVENT_ERR) {
        !           747:                /* kill all connections to the cgi process */
        !           748: #if 1
        !           749:                log_error_write(srv, __FILE__, __LINE__, "s", "cgi-FDEVENT_ERR");
        !           750: #endif
        !           751:                cgi_connection_close(srv, hctx);
1.1       misho     752:                return HANDLER_ERROR;
                    753:        }
                    754: 
1.1.1.3 ! misho     755:        return HANDLER_FINISHED;
        !           756: }
        !           757: 
        !           758: 
        !           759: static int cgi_recv_response(server *srv, handler_ctx *hctx) {
1.1       misho     760:                switch (cgi_demux_response(srv, hctx)) {
                    761:                case FDEVENT_HANDLED_NOT_FINISHED:
                    762:                        break;
                    763:                case FDEVENT_HANDLED_FINISHED:
                    764:                        /* we are done */
                    765: 
                    766: #if 0
                    767:                        log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "finished");
                    768: #endif
                    769:                        cgi_connection_close(srv, hctx);
                    770: 
                    771:                        /* if we get a IN|HUP and have read everything don't exec the close twice */
                    772:                        return HANDLER_FINISHED;
1.1.1.3 ! misho     773:                case FDEVENT_HANDLED_COMEBACK:
        !           774:                        cgi_connection_close(srv, hctx);
        !           775:                        return HANDLER_COMEBACK;
1.1       misho     776:                case FDEVENT_HANDLED_ERROR:
                    777:                        log_error_write(srv, __FILE__, __LINE__, "s", "demuxer failed: ");
1.1.1.3 ! misho     778: 
        !           779:                        cgi_connection_close(srv, hctx);
        !           780:                        return HANDLER_FINISHED;
1.1       misho     781:                }
                    782: 
1.1.1.3 ! misho     783:                return HANDLER_GO_ON;
        !           784: }
        !           785: 
        !           786: 
        !           787: static handler_t cgi_handle_fdevent(server *srv, void *ctx, int revents) {
        !           788:        handler_ctx *hctx = ctx;
        !           789:        connection  *con  = hctx->remote_conn;
        !           790: 
        !           791:        joblist_append(srv, con);
        !           792: 
        !           793:        if (revents & FDEVENT_IN) {
        !           794:                handler_t rc = cgi_recv_response(srv, hctx);/*(might invalidate hctx)*/
        !           795:                if (rc != HANDLER_GO_ON) return rc;         /*(unless HANDLER_GO_ON)*/
1.1       misho     796:        }
                    797: 
                    798:        /* perhaps this issue is already handled */
                    799:        if (revents & FDEVENT_HUP) {
1.1.1.3 ! misho     800:                if (con->file_started) {
        !           801:                        /* drain any remaining data from kernel pipe buffers
        !           802:                         * even if (con->conf.stream_response_body
        !           803:                         *          & FDEVENT_STREAM_RESPONSE_BUFMIN)
        !           804:                         * since event loop will spin on fd FDEVENT_HUP event
        !           805:                         * until unregistered. */
        !           806:                        handler_t rc;
        !           807:                        do {
        !           808:                                rc = cgi_recv_response(srv,hctx);/*(might invalidate hctx)*/
        !           809:                        } while (rc == HANDLER_GO_ON);           /*(unless HANDLER_GO_ON)*/
        !           810:                        return rc; /* HANDLER_FINISHED or HANDLER_COMEBACK or HANDLER_ERROR */
        !           811:                } else if (!buffer_string_is_empty(hctx->response_header)) {
        !           812:                        /* unfinished header package which is a body in reality */
1.1       misho     813:                        con->file_started = 1;
1.1.1.3 ! misho     814:                        if (0 != http_chunk_append_buffer(srv, con, hctx->response_header)) {
        !           815:                                cgi_connection_close(srv, hctx);
        !           816:                                return HANDLER_ERROR;
        !           817:                        }
1.1       misho     818:                } else {
                    819: # if 0
1.1.1.3 ! misho     820:                        log_error_write(srv, __FILE__, __LINE__, "sddd", "got HUP from cgi", con->fd, hctx->fd, revents);
1.1       misho     821: # endif
1.1.1.3 ! misho     822:                }
1.1       misho     823:                cgi_connection_close(srv, hctx);
                    824:        } else if (revents & FDEVENT_ERR) {
                    825:                /* kill all connections to the cgi process */
                    826:                cgi_connection_close(srv, hctx);
                    827: #if 1
                    828:                log_error_write(srv, __FILE__, __LINE__, "s", "cgi-FDEVENT_ERR");
                    829: #endif
                    830:                return HANDLER_ERROR;
                    831:        }
                    832: 
                    833:        return HANDLER_FINISHED;
                    834: }
                    835: 
                    836: 
                    837: static int cgi_env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
                    838:        char *dst;
                    839: 
                    840:        if (!key || !val) return -1;
                    841: 
                    842:        dst = malloc(key_len + val_len + 2);
1.1.1.3 ! misho     843:        force_assert(dst);
1.1       misho     844:        memcpy(dst, key, key_len);
                    845:        dst[key_len] = '=';
                    846:        memcpy(dst + key_len + 1, val, val_len);
                    847:        dst[key_len + 1 + val_len] = '\0';
                    848: 
                    849:        if (env->size == 0) {
                    850:                env->size = 16;
                    851:                env->ptr = malloc(env->size * sizeof(*env->ptr));
1.1.1.3 ! misho     852:                force_assert(env->ptr);
1.1       misho     853:        } else if (env->size == env->used) {
                    854:                env->size += 16;
                    855:                env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
1.1.1.3 ! misho     856:                force_assert(env->ptr);
1.1       misho     857:        }
                    858: 
                    859:        env->ptr[env->used++] = dst;
                    860: 
                    861:        return 0;
                    862: }
                    863: 
1.1.1.3 ! misho     864: /* returns: 0: continue, -1: fatal error, -2: connection reset */
        !           865: /* similar to network_write_file_chunk_mmap, but doesn't use send on windows (because we're on pipes),
        !           866:  * also mmaps and sends complete chunk instead of only small parts - the files
        !           867:  * are supposed to be temp files with reasonable chunk sizes.
        !           868:  *
        !           869:  * Also always use mmap; the files are "trusted", as we created them.
        !           870:  */
        !           871: static ssize_t cgi_write_file_chunk_mmap(server *srv, connection *con, int fd, chunkqueue *cq) {
        !           872:        chunk* const c = cq->first;
        !           873:        off_t offset, toSend, file_end;
        !           874:        ssize_t r;
        !           875:        size_t mmap_offset, mmap_avail;
        !           876:        char *data;
        !           877: 
        !           878:        force_assert(NULL != c);
        !           879:        force_assert(FILE_CHUNK == c->type);
        !           880:        force_assert(c->offset >= 0 && c->offset <= c->file.length);
        !           881: 
        !           882:        offset = c->file.start + c->offset;
        !           883:        toSend = c->file.length - c->offset;
        !           884:        file_end = c->file.start + c->file.length; /* offset to file end in this chunk */
        !           885: 
        !           886:        if (0 == toSend) {
        !           887:                chunkqueue_remove_finished_chunks(cq);
        !           888:                return 0;
        !           889:        }
        !           890: 
        !           891:        if (0 != network_open_file_chunk(srv, con, cq)) return -1;
        !           892: 
        !           893:        /* (re)mmap the buffer if range is not covered completely */
        !           894:        if (MAP_FAILED == c->file.mmap.start
        !           895:                || offset < c->file.mmap.offset
        !           896:                || file_end > (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
        !           897: 
        !           898:                if (MAP_FAILED != c->file.mmap.start) {
        !           899:                        munmap(c->file.mmap.start, c->file.mmap.length);
        !           900:                        c->file.mmap.start = MAP_FAILED;
        !           901:                }
        !           902: 
        !           903:                c->file.mmap.offset = mmap_align_offset(offset);
        !           904:                c->file.mmap.length = file_end - c->file.mmap.offset;
        !           905: 
        !           906:                if (MAP_FAILED == (c->file.mmap.start = mmap(NULL, c->file.mmap.length, PROT_READ, MAP_PRIVATE, c->file.fd, c->file.mmap.offset))) {
        !           907:                        if (toSend > 65536) toSend = 65536;
        !           908:                        data = malloc(toSend);
        !           909:                        force_assert(data);
        !           910:                        if (-1 == lseek(c->file.fd, offset, SEEK_SET)
        !           911:                            || 0 >= (toSend = read(c->file.fd, data, toSend))) {
        !           912:                                if (-1 == toSend) {
        !           913:                                        log_error_write(srv, __FILE__, __LINE__, "ssbdo", "lseek/read failed:",
        !           914:                                                strerror(errno), c->file.name, c->file.fd, offset);
        !           915:                                } else { /*(0 == toSend)*/
        !           916:                                        log_error_write(srv, __FILE__, __LINE__, "sbdo", "unexpected EOF (input truncated?):",
        !           917:                                                c->file.name, c->file.fd, offset);
        !           918:                                }
        !           919:                                free(data);
        !           920:                                return -1;
        !           921:                        }
        !           922:                }
        !           923:        }
        !           924: 
        !           925:        if (MAP_FAILED != c->file.mmap.start) {
        !           926:                force_assert(offset >= c->file.mmap.offset);
        !           927:                mmap_offset = offset - c->file.mmap.offset;
        !           928:                force_assert(c->file.mmap.length > mmap_offset);
        !           929:                mmap_avail = c->file.mmap.length - mmap_offset;
        !           930:                force_assert(toSend <= (off_t) mmap_avail);
        !           931: 
        !           932:                data = c->file.mmap.start + mmap_offset;
        !           933:        }
        !           934: 
        !           935:        r = write(fd, data, toSend);
        !           936: 
        !           937:        if (MAP_FAILED == c->file.mmap.start) free(data);
        !           938: 
        !           939:        if (r < 0) {
        !           940:                switch (errno) {
        !           941:                case EAGAIN:
        !           942:                case EINTR:
        !           943:                        return 0;
        !           944:                case EPIPE:
        !           945:                case ECONNRESET:
        !           946:                        return -2;
        !           947:                default:
        !           948:                        log_error_write(srv, __FILE__, __LINE__, "ssd",
        !           949:                                "write failed:", strerror(errno), fd);
        !           950:                        return -1;
        !           951:                }
        !           952:        }
        !           953: 
        !           954:        if (r >= 0) {
        !           955:                chunkqueue_mark_written(cq, r);
        !           956:        }
        !           957: 
        !           958:        return r;
        !           959: }
        !           960: 
        !           961: static int cgi_write_request(server *srv, handler_ctx *hctx, int fd) {
        !           962:        connection *con = hctx->remote_conn;
        !           963:        chunkqueue *cq = con->request_content_queue;
        !           964:        chunk *c;
        !           965: 
        !           966:        /* old comment: windows doesn't support select() on pipes - wouldn't be easy to fix for all platforms.
        !           967:         * solution: if this is still a problem on windows, then substitute
        !           968:         * socketpair() for pipe() and closesocket() for close() on windows.
        !           969:         */
        !           970: 
        !           971:        for (c = cq->first; c; c = cq->first) {
        !           972:                ssize_t r = -1;
        !           973: 
        !           974:                switch(c->type) {
        !           975:                case FILE_CHUNK:
        !           976:                        r = cgi_write_file_chunk_mmap(srv, con, fd, cq);
        !           977:                        break;
        !           978: 
        !           979:                case MEM_CHUNK:
        !           980:                        if ((r = write(fd, c->mem->ptr + c->offset, buffer_string_length(c->mem) - c->offset)) < 0) {
        !           981:                                switch(errno) {
        !           982:                                case EAGAIN:
        !           983:                                case EINTR:
        !           984:                                        /* ignore and try again */
        !           985:                                        r = 0;
        !           986:                                        break;
        !           987:                                case EPIPE:
        !           988:                                case ECONNRESET:
        !           989:                                        /* connection closed */
        !           990:                                        r = -2;
        !           991:                                        break;
        !           992:                                default:
        !           993:                                        /* fatal error */
        !           994:                                        log_error_write(srv, __FILE__, __LINE__, "ss", "write failed due to: ", strerror(errno));
        !           995:                                        r = -1;
        !           996:                                        break;
        !           997:                                }
        !           998:                        } else if (r > 0) {
        !           999:                                chunkqueue_mark_written(cq, r);
        !          1000:                        }
        !          1001:                        break;
        !          1002:                }
        !          1003: 
        !          1004:                if (0 == r) break; /*(might block)*/
        !          1005: 
        !          1006:                switch (r) {
        !          1007:                case -1:
        !          1008:                        /* fatal error */
        !          1009:                        return -1;
        !          1010:                case -2:
        !          1011:                        /* connection reset */
        !          1012:                        log_error_write(srv, __FILE__, __LINE__, "s", "failed to send post data to cgi, connection closed by CGI");
        !          1013:                        /* skip all remaining data */
        !          1014:                        chunkqueue_mark_written(cq, chunkqueue_length(cq));
        !          1015:                        break;
        !          1016:                default:
        !          1017:                        break;
        !          1018:                }
        !          1019:        }
        !          1020: 
        !          1021:        if (cq->bytes_out == (off_t)con->request.content_length) {
        !          1022:                /* sent all request body input */
        !          1023:                /* close connection to the cgi-script */
        !          1024:                if (-1 == hctx->fdtocgi) { /*(received request body sent in initial send to pipe buffer)*/
        !          1025:                        if (close(fd)) {
        !          1026:                                log_error_write(srv, __FILE__, __LINE__, "sds", "cgi stdin close failed ", fd, strerror(errno));
        !          1027:                        }
        !          1028:                } else {
        !          1029:                        cgi_connection_close_fdtocgi(srv, hctx); /*(closes only hctx->fdtocgi)*/
        !          1030:                }
        !          1031:        } else {
        !          1032:                off_t cqlen = cq->bytes_in - cq->bytes_out;
        !          1033:                if (cq->bytes_in < (off_t)con->request.content_length && cqlen < 65536 - 16384) {
        !          1034:                        /*(con->conf.stream_request_body & FDEVENT_STREAM_REQUEST)*/
        !          1035:                        if (!(con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_POLLIN)) {
        !          1036:                                con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLIN;
        !          1037:                                con->is_readable = 1; /* trigger optimistic read from client */
        !          1038:                        }
        !          1039:                }
        !          1040:                if (-1 == hctx->fdtocgi) { /*(not registered yet)*/
        !          1041:                        hctx->fdtocgi = fd;
        !          1042:                        hctx->fde_ndx_tocgi = -1;
        !          1043:                        fdevent_register(srv->ev, hctx->fdtocgi, cgi_handle_fdevent_send, hctx);
        !          1044:                }
        !          1045:                if (0 == cqlen) { /*(chunkqueue_is_empty(cq))*/
        !          1046:                        if ((fdevent_event_get_interest(srv->ev, hctx->fdtocgi) & FDEVENT_OUT)) {
        !          1047:                                fdevent_event_set(srv->ev, &(hctx->fde_ndx_tocgi), hctx->fdtocgi, 0);
        !          1048:                        }
        !          1049:                } else {
        !          1050:                        /* more request body remains to be sent to CGI so register for fdevents */
        !          1051:                        fdevent_event_set(srv->ev, &(hctx->fde_ndx_tocgi), hctx->fdtocgi, FDEVENT_OUT);
        !          1052:                }
        !          1053:        }
        !          1054: 
        !          1055:        return 0;
        !          1056: }
        !          1057: 
        !          1058: static int cgi_create_env(server *srv, connection *con, plugin_data *p, handler_ctx *hctx, buffer *cgi_handler) {
1.1       misho    1059:        pid_t pid;
                   1060: 
                   1061: #ifdef HAVE_IPV6
                   1062:        char b2[INET6_ADDRSTRLEN + 1];
                   1063: #endif
                   1064: 
                   1065:        int to_cgi_fds[2];
                   1066:        int from_cgi_fds[2];
                   1067:        struct stat st;
                   1068: 
                   1069: #ifndef __WIN32
                   1070: 
1.1.1.3 ! misho    1071:        if (!buffer_string_is_empty(cgi_handler)) {
1.1       misho    1072:                /* stat the exec file */
                   1073:                if (-1 == (stat(cgi_handler->ptr, &st))) {
                   1074:                        log_error_write(srv, __FILE__, __LINE__, "sbss",
                   1075:                                        "stat for cgi-handler", cgi_handler,
                   1076:                                        "failed:", strerror(errno));
                   1077:                        return -1;
                   1078:                }
                   1079:        }
                   1080: 
                   1081:        if (pipe(to_cgi_fds)) {
                   1082:                log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
                   1083:                return -1;
                   1084:        }
                   1085: 
                   1086:        if (pipe(from_cgi_fds)) {
                   1087:                close(to_cgi_fds[0]);
                   1088:                close(to_cgi_fds[1]);
                   1089:                log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
                   1090:                return -1;
                   1091:        }
                   1092: 
                   1093:        /* fork, execve */
                   1094:        switch (pid = fork()) {
                   1095:        case 0: {
                   1096:                /* child */
                   1097:                char **args;
                   1098:                int argc;
                   1099:                int i = 0;
1.1.1.3 ! misho    1100:                char buf[LI_ITOSTRING_LENGTH];
1.1       misho    1101:                size_t n;
                   1102:                char_array env;
                   1103:                char *c;
                   1104:                const char *s;
                   1105:                server_socket *srv_sock = con->srv_socket;
                   1106: 
                   1107:                /* move stdout to from_cgi_fd[1] */
                   1108:                close(STDOUT_FILENO);
                   1109:                dup2(from_cgi_fds[1], STDOUT_FILENO);
                   1110:                close(from_cgi_fds[1]);
                   1111:                /* not needed */
                   1112:                close(from_cgi_fds[0]);
                   1113: 
                   1114:                /* move the stdin to to_cgi_fd[0] */
                   1115:                close(STDIN_FILENO);
                   1116:                dup2(to_cgi_fds[0], STDIN_FILENO);
                   1117:                close(to_cgi_fds[0]);
                   1118:                /* not needed */
                   1119:                close(to_cgi_fds[1]);
                   1120: 
                   1121:                /* create environment */
                   1122:                env.ptr = NULL;
                   1123:                env.size = 0;
                   1124:                env.used = 0;
                   1125: 
1.1.1.3 ! misho    1126:                cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_BUF_LEN(con->conf.server_tag));
1.1       misho    1127: 
1.1.1.3 ! misho    1128:                if (!buffer_string_is_empty(con->server_name)) {
        !          1129:                        size_t len = buffer_string_length(con->server_name);
1.1       misho    1130: 
                   1131:                        if (con->server_name->ptr[0] == '[') {
                   1132:                                const char *colon = strstr(con->server_name->ptr, "]:");
                   1133:                                if (colon) len = (colon + 1) - con->server_name->ptr;
                   1134:                        } else {
                   1135:                                const char *colon = strchr(con->server_name->ptr, ':');
                   1136:                                if (colon) len = colon - con->server_name->ptr;
                   1137:                        }
                   1138: 
                   1139:                        cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), con->server_name->ptr, len);
                   1140:                } else {
                   1141: #ifdef HAVE_IPV6
1.1.1.3 ! misho    1142:                        s = inet_ntop(
        !          1143:                                srv_sock->addr.plain.sa_family,
        !          1144:                                srv_sock->addr.plain.sa_family == AF_INET6 ?
        !          1145:                                (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
        !          1146:                                (const void *) &(srv_sock->addr.ipv4.sin_addr),
        !          1147:                                b2, sizeof(b2)-1);
1.1       misho    1148: #else
                   1149:                        s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
                   1150: #endif
1.1.1.3 ! misho    1151:                        force_assert(s);
1.1       misho    1152:                        cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
                   1153:                }
                   1154:                cgi_env_add(&env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
                   1155: 
                   1156:                s = get_http_version_name(con->request.http_version);
1.1.1.3 ! misho    1157:                force_assert(s);
1.1       misho    1158:                cgi_env_add(&env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
                   1159: 
1.1.1.3 ! misho    1160:                li_utostrn(buf, sizeof(buf),
1.1       misho    1161: #ifdef HAVE_IPV6
                   1162:                        ntohs(srv_sock->addr.plain.sa_family == AF_INET6 ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
                   1163: #else
                   1164:                        ntohs(srv_sock->addr.ipv4.sin_port)
                   1165: #endif
                   1166:                        );
                   1167:                cgi_env_add(&env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
                   1168: 
                   1169:                switch (srv_sock->addr.plain.sa_family) {
                   1170: #ifdef HAVE_IPV6
                   1171:                case AF_INET6:
1.1.1.3 ! misho    1172:                        s = inet_ntop(
        !          1173:                                srv_sock->addr.plain.sa_family,
        !          1174:                                (const void *) &(srv_sock->addr.ipv6.sin6_addr),
        !          1175:                                b2, sizeof(b2)-1);
1.1       misho    1176:                        break;
                   1177:                case AF_INET:
1.1.1.3 ! misho    1178:                        s = inet_ntop(
        !          1179:                                srv_sock->addr.plain.sa_family,
        !          1180:                                (const void *) &(srv_sock->addr.ipv4.sin_addr),
        !          1181:                                b2, sizeof(b2)-1);
1.1       misho    1182:                        break;
                   1183: #else
                   1184:                case AF_INET:
                   1185:                        s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
                   1186:                        break;
                   1187: #endif
                   1188:                default:
                   1189:                        s = "";
                   1190:                        break;
                   1191:                }
1.1.1.3 ! misho    1192:                force_assert(s);
1.1       misho    1193:                cgi_env_add(&env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
                   1194: 
                   1195:                s = get_http_method_name(con->request.http_method);
1.1.1.3 ! misho    1196:                force_assert(s);
1.1       misho    1197:                cgi_env_add(&env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
                   1198: 
1.1.1.3 ! misho    1199:                if (!buffer_string_is_empty(con->request.pathinfo)) {
1.1       misho    1200:                        cgi_env_add(&env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
                   1201:                }
1.1.1.3 ! misho    1202:                if (!buffer_string_is_empty(con->uri.query)) {
1.1       misho    1203:                        cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
1.1.1.3 ! misho    1204:                } else {
        !          1205:                        cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
1.1       misho    1206:                }
1.1.1.3 ! misho    1207:                cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
        !          1208:                if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {
        !          1209:                        cgi_env_add(&env, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.uri));
        !          1210:                }
        !          1211:                /* set REDIRECT_STATUS for php compiled with --force-redirect
        !          1212:                 * (if REDIRECT_STATUS has not already been set by error handler) */
        !          1213:                if (0 == con->error_handler_saved_status) {
        !          1214:                        cgi_env_add(&env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200"));
1.1       misho    1215:                }
                   1216: 
                   1217: 
                   1218:                switch (con->dst_addr.plain.sa_family) {
                   1219: #ifdef HAVE_IPV6
                   1220:                case AF_INET6:
1.1.1.3 ! misho    1221:                        s = inet_ntop(
        !          1222:                                con->dst_addr.plain.sa_family,
        !          1223:                                (const void *) &(con->dst_addr.ipv6.sin6_addr),
        !          1224:                                b2, sizeof(b2)-1);
1.1       misho    1225:                        break;
                   1226:                case AF_INET:
1.1.1.3 ! misho    1227:                        s = inet_ntop(
        !          1228:                                con->dst_addr.plain.sa_family,
        !          1229:                                (const void *) &(con->dst_addr.ipv4.sin_addr),
        !          1230:                                b2, sizeof(b2)-1);
1.1       misho    1231:                        break;
                   1232: #else
                   1233:                case AF_INET:
                   1234:                        s = inet_ntoa(con->dst_addr.ipv4.sin_addr);
                   1235:                        break;
                   1236: #endif
                   1237:                default:
                   1238:                        s = "";
                   1239:                        break;
                   1240:                }
1.1.1.3 ! misho    1241:                force_assert(s);
1.1       misho    1242:                cgi_env_add(&env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
                   1243: 
1.1.1.3 ! misho    1244:                li_utostrn(buf, sizeof(buf),
1.1       misho    1245: #ifdef HAVE_IPV6
                   1246:                        ntohs(con->dst_addr.plain.sa_family == AF_INET6 ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
                   1247: #else
                   1248:                        ntohs(con->dst_addr.ipv4.sin_port)
                   1249: #endif
                   1250:                        );
                   1251:                cgi_env_add(&env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
                   1252: 
                   1253:                if (buffer_is_equal_caseless_string(con->uri.scheme, CONST_STR_LEN("https"))) {
                   1254:                        cgi_env_add(&env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
                   1255:                }
                   1256: 
1.1.1.3 ! misho    1257:                li_itostrn(buf, sizeof(buf), con->request.content_length);
1.1       misho    1258:                cgi_env_add(&env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
                   1259:                cgi_env_add(&env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
                   1260:                cgi_env_add(&env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
                   1261:                cgi_env_add(&env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir));
                   1262: 
                   1263:                /* for valgrind */
                   1264:                if (NULL != (s = getenv("LD_PRELOAD"))) {
                   1265:                        cgi_env_add(&env, CONST_STR_LEN("LD_PRELOAD"), s, strlen(s));
                   1266:                }
                   1267: 
                   1268:                if (NULL != (s = getenv("LD_LIBRARY_PATH"))) {
                   1269:                        cgi_env_add(&env, CONST_STR_LEN("LD_LIBRARY_PATH"), s, strlen(s));
                   1270:                }
                   1271: #ifdef __CYGWIN__
                   1272:                /* CYGWIN needs SYSTEMROOT */
                   1273:                if (NULL != (s = getenv("SYSTEMROOT"))) {
                   1274:                        cgi_env_add(&env, CONST_STR_LEN("SYSTEMROOT"), s, strlen(s));
                   1275:                }
                   1276: #endif
                   1277: 
                   1278:                for (n = 0; n < con->request.headers->used; n++) {
                   1279:                        data_string *ds;
                   1280: 
                   1281:                        ds = (data_string *)con->request.headers->data[n];
                   1282: 
1.1.1.3 ! misho    1283:                        if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
        !          1284:                                /* Do not emit HTTP_PROXY in environment.
        !          1285:                                 * Some executables use HTTP_PROXY to configure
        !          1286:                                 * outgoing proxy.  See also https://httpoxy.org/ */
        !          1287:                                if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy"))) {
        !          1288:                                        continue;
1.1       misho    1289:                                }
                   1290: 
1.1.1.3 ! misho    1291:                                buffer_copy_string_encoded_cgi_varnames(p->tmp_buf, CONST_BUF_LEN(ds->key), 1);
1.1       misho    1292: 
                   1293:                                cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
                   1294:                        }
                   1295:                }
                   1296: 
                   1297:                for (n = 0; n < con->environment->used; n++) {
                   1298:                        data_string *ds;
                   1299: 
                   1300:                        ds = (data_string *)con->environment->data[n];
                   1301: 
1.1.1.3 ! misho    1302:                        if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
        !          1303:                                buffer_copy_string_encoded_cgi_varnames(p->tmp_buf, CONST_BUF_LEN(ds->key), 0);
1.1       misho    1304: 
                   1305:                                cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
                   1306:                        }
                   1307:                }
                   1308: 
                   1309:                if (env.size == env.used) {
                   1310:                        env.size += 16;
                   1311:                        env.ptr = realloc(env.ptr, env.size * sizeof(*env.ptr));
                   1312:                }
                   1313: 
                   1314:                env.ptr[env.used] = NULL;
                   1315: 
                   1316:                /* set up args */
                   1317:                argc = 3;
                   1318:                args = malloc(sizeof(*args) * argc);
1.1.1.3 ! misho    1319:                force_assert(args);
1.1       misho    1320:                i = 0;
                   1321: 
1.1.1.3 ! misho    1322:                if (!buffer_string_is_empty(cgi_handler)) {
1.1       misho    1323:                        args[i++] = cgi_handler->ptr;
                   1324:                }
                   1325:                args[i++] = con->physical.path->ptr;
                   1326:                args[i  ] = NULL;
                   1327: 
                   1328:                /* search for the last / */
                   1329:                if (NULL != (c = strrchr(con->physical.path->ptr, '/'))) {
1.1.1.3 ! misho    1330:                        /* handle special case of file in root directory */
        !          1331:                        const char* physdir = (c == con->physical.path->ptr) ? "/" : con->physical.path->ptr;
1.1       misho    1332: 
1.1.1.3 ! misho    1333:                        /* temporarily shorten con->physical.path to directory without terminating '/' */
        !          1334:                        *c = '\0';
1.1       misho    1335:                        /* change to the physical directory */
1.1.1.3 ! misho    1336:                        if (-1 == chdir(physdir)) {
1.1       misho    1337:                                log_error_write(srv, __FILE__, __LINE__, "ssb", "chdir failed:", strerror(errno), con->physical.path);
                   1338:                        }
                   1339:                        *c = '/';
                   1340:                }
                   1341: 
                   1342:                /* we don't need the client socket */
                   1343:                for (i = 3; i < 256; i++) {
                   1344:                        if (i != srv->errorlog_fd) close(i);
                   1345:                }
                   1346: 
                   1347:                /* exec the cgi */
                   1348:                execve(args[0], args, env.ptr);
                   1349: 
1.1.1.3 ! misho    1350:                /* most log files may have been closed/redirected by this point,
        !          1351:                 * though stderr might still point to lighttpd.breakage.log */
        !          1352:                perror(args[0]);
        !          1353:                _exit(1);
1.1       misho    1354:        }
                   1355:        case -1:
                   1356:                /* error */
                   1357:                log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno));
                   1358:                close(from_cgi_fds[0]);
                   1359:                close(from_cgi_fds[1]);
                   1360:                close(to_cgi_fds[0]);
                   1361:                close(to_cgi_fds[1]);
                   1362:                return -1;
                   1363:        default: {
1.1.1.3 ! misho    1364:                /* parent process */
1.1       misho    1365: 
                   1366:                close(from_cgi_fds[1]);
                   1367:                close(to_cgi_fds[0]);
                   1368: 
1.1.1.3 ! misho    1369:                /* register PID and wait for them asynchronously */
1.1       misho    1370: 
1.1.1.3 ! misho    1371:                hctx->pid = pid;
        !          1372:                hctx->fd = from_cgi_fds[0];
        !          1373:                hctx->fde_ndx = -1;
1.1       misho    1374: 
1.1.1.3 ! misho    1375:                if (0 == con->request.content_length) {
        !          1376:                        close(to_cgi_fds[1]);
        !          1377:                } else {
1.1       misho    1378:                        /* there is content to send */
1.1.1.3 ! misho    1379:                        if (-1 == fdevent_fcntl_set(srv->ev, to_cgi_fds[1])) {
        !          1380:                                log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
        !          1381:                                close(to_cgi_fds[1]);
        !          1382:                                cgi_connection_close(srv, hctx);
        !          1383:                                return -1;
        !          1384:                        }
1.1       misho    1385: 
1.1.1.3 ! misho    1386:                        if (0 != cgi_write_request(srv, hctx, to_cgi_fds[1])) {
        !          1387:                                close(to_cgi_fds[1]);
        !          1388:                                cgi_connection_close(srv, hctx);
        !          1389:                                return -1;
1.1       misho    1390:                        }
                   1391:                }
                   1392: 
                   1393:                fdevent_register(srv->ev, hctx->fd, cgi_handle_fdevent, hctx);
                   1394:                fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
                   1395: 
                   1396:                if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
                   1397:                        log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
1.1.1.3 ! misho    1398:                        cgi_connection_close(srv, hctx);
1.1       misho    1399:                        return -1;
                   1400:                }
                   1401: 
                   1402:                break;
                   1403:        }
                   1404:        }
                   1405: 
                   1406:        return 0;
                   1407: #else
                   1408:        return -1;
                   1409: #endif
                   1410: }
                   1411: 
1.1.1.3 ! misho    1412: static buffer * cgi_get_handler(array *a, buffer *fn) {
        !          1413:        size_t k, s_len = buffer_string_length(fn);
        !          1414:        for (k = 0; k < a->used; ++k) {
        !          1415:                data_string *ds = (data_string *)a->data[k];
        !          1416:                size_t ct_len = buffer_string_length(ds->key);
        !          1417: 
        !          1418:                if (buffer_is_empty(ds->key)) continue;
        !          1419:                if (s_len < ct_len) continue;
        !          1420: 
        !          1421:                if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
        !          1422:                        return ds->value;
        !          1423:                }
        !          1424:        }
        !          1425: 
        !          1426:        return NULL;
        !          1427: }
        !          1428: 
1.1       misho    1429: #define PATCH(x) \
                   1430:        p->conf.x = s->x;
                   1431: static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p) {
                   1432:        size_t i, j;
                   1433:        plugin_config *s = p->config_storage[0];
                   1434: 
                   1435:        PATCH(cgi);
                   1436:        PATCH(execute_x_only);
1.1.1.3 ! misho    1437:        PATCH(xsendfile_allow);
        !          1438:        PATCH(xsendfile_docroot);
1.1       misho    1439: 
                   1440:        /* skip the first, the global context */
                   1441:        for (i = 1; i < srv->config_context->used; i++) {
                   1442:                data_config *dc = (data_config *)srv->config_context->data[i];
                   1443:                s = p->config_storage[i];
                   1444: 
                   1445:                /* condition didn't match */
                   1446:                if (!config_check_cond(srv, con, dc)) continue;
                   1447: 
                   1448:                /* merge config */
                   1449:                for (j = 0; j < dc->value->used; j++) {
                   1450:                        data_unset *du = dc->value->data[j];
                   1451: 
                   1452:                        if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.assign"))) {
                   1453:                                PATCH(cgi);
                   1454:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.execute-x-only"))) {
                   1455:                                PATCH(execute_x_only);
1.1.1.3 ! misho    1456:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.x-sendfile"))) {
        !          1457:                                PATCH(xsendfile_allow);
        !          1458:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.x-sendfile-docroot"))) {
        !          1459:                                PATCH(xsendfile_docroot);
1.1       misho    1460:                        }
                   1461:                }
                   1462:        }
                   1463: 
                   1464:        return 0;
                   1465: }
                   1466: #undef PATCH
                   1467: 
                   1468: URIHANDLER_FUNC(cgi_is_handled) {
                   1469:        plugin_data *p = p_d;
                   1470:        buffer *fn = con->physical.path;
                   1471:        stat_cache_entry *sce = NULL;
                   1472: 
                   1473:        if (con->mode != DIRECT) return HANDLER_GO_ON;
                   1474: 
1.1.1.3 ! misho    1475:        if (buffer_is_empty(fn)) return HANDLER_GO_ON;
1.1       misho    1476: 
                   1477:        mod_cgi_patch_connection(srv, con, p);
                   1478: 
                   1479:        if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) return HANDLER_GO_ON;
                   1480:        if (!S_ISREG(sce->st.st_mode)) return HANDLER_GO_ON;
                   1481:        if (p->conf.execute_x_only == 1 && (sce->st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) return HANDLER_GO_ON;
                   1482: 
1.1.1.3 ! misho    1483:        if (NULL != cgi_get_handler(p->conf.cgi, fn)) {
        !          1484:                handler_ctx *hctx = cgi_handler_ctx_init();
        !          1485:                hctx->remote_conn = con;
        !          1486:                hctx->plugin_data = p;
        !          1487:                con->plugin_ctx[p->id] = hctx;
        !          1488:                con->mode = p->id;
1.1       misho    1489:        }
                   1490: 
                   1491:        return HANDLER_GO_ON;
                   1492: }
                   1493: 
                   1494: TRIGGER_FUNC(cgi_trigger) {
                   1495:        plugin_data *p = p_d;
                   1496:        size_t ndx;
                   1497:        /* the trigger handle only cares about lonely PID which we have to wait for */
                   1498: #ifndef __WIN32
                   1499: 
                   1500:        for (ndx = 0; ndx < p->cgi_pid.used; ndx++) {
                   1501:                int status;
                   1502: 
                   1503:                switch(waitpid(p->cgi_pid.ptr[ndx], &status, WNOHANG)) {
                   1504:                case 0:
                   1505:                        /* not finished yet */
                   1506: #if 0
                   1507:                        log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) child isn't done yet, pid:", p->cgi_pid.ptr[ndx]);
                   1508: #endif
                   1509:                        break;
                   1510:                case -1:
                   1511:                        if (errno == ECHILD) {
                   1512:                                /* someone else called waitpid... remove the pid to stop looping the error each time */
                   1513:                                log_error_write(srv, __FILE__, __LINE__, "s", "cgi child vanished, probably someone else called waitpid");
                   1514: 
                   1515:                                cgi_pid_del(srv, p, p->cgi_pid.ptr[ndx]);
                   1516:                                ndx--;
                   1517:                                continue;
                   1518:                        }
                   1519: 
                   1520:                        log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
                   1521: 
                   1522:                        return HANDLER_ERROR;
                   1523:                default:
                   1524: 
                   1525:                        if (WIFEXITED(status)) {
                   1526: #if 0
                   1527:                                log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", p->cgi_pid.ptr[ndx]);
                   1528: #endif
                   1529:                        } else if (WIFSIGNALED(status)) {
                   1530:                                /* FIXME: what if we killed the CGI script with a kill(..., SIGTERM) ?
                   1531:                                 */
                   1532:                                if (WTERMSIG(status) != SIGTERM) {
                   1533:                                        log_error_write(srv, __FILE__, __LINE__, "sd", "cleaning up CGI: process died with signal", WTERMSIG(status));
                   1534:                                }
                   1535:                        } else {
                   1536:                                log_error_write(srv, __FILE__, __LINE__, "s", "cleaning up CGI: ended unexpectedly");
                   1537:                        }
                   1538: 
                   1539:                        cgi_pid_del(srv, p, p->cgi_pid.ptr[ndx]);
                   1540:                        /* del modified the buffer structure
                   1541:                         * and copies the last entry to the current one
                   1542:                         * -> recheck the current index
                   1543:                         */
                   1544:                        ndx--;
                   1545:                }
                   1546:        }
                   1547: #endif
                   1548:        return HANDLER_GO_ON;
                   1549: }
                   1550: 
                   1551: /*
                   1552:  * - HANDLER_GO_ON : not our job
1.1.1.3 ! misho    1553:  * - HANDLER_FINISHED: got response
        !          1554:  * - HANDLER_WAIT_FOR_EVENT: waiting for response
1.1       misho    1555:  */
                   1556: SUBREQUEST_FUNC(mod_cgi_handle_subrequest) {
                   1557:        plugin_data *p = p_d;
                   1558:        handler_ctx *hctx = con->plugin_ctx[p->id];
1.1.1.3 ! misho    1559:        chunkqueue *cq = con->request_content_queue;
1.1       misho    1560: 
                   1561:        if (con->mode != p->id) return HANDLER_GO_ON;
                   1562:        if (NULL == hctx) return HANDLER_GO_ON;
                   1563: 
1.1.1.3 ! misho    1564:        if ((con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN)
        !          1565:            && con->file_started) {
        !          1566:                if (chunkqueue_length(con->write_queue) > 65536 - 4096) {
        !          1567:                        fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
        !          1568:                } else if (!(fdevent_event_get_interest(srv->ev, hctx->fd) & FDEVENT_IN)) {
        !          1569:                        /* optimistic read from backend, which might re-enable FDEVENT_IN */
        !          1570:                        handler_t rc = cgi_recv_response(srv, hctx); /*(might invalidate hctx)*/
        !          1571:                        if (rc != HANDLER_GO_ON) return rc;          /*(unless HANDLER_GO_ON)*/
1.1       misho    1572:                }
1.1.1.3 ! misho    1573:        }
1.1       misho    1574: 
1.1.1.3 ! misho    1575:        if (cq->bytes_in != (off_t)con->request.content_length) {
        !          1576:                /*(64k - 4k to attempt to avoid temporary files
        !          1577:                 * in conjunction with FDEVENT_STREAM_REQUEST_BUFMIN)*/
        !          1578:                if (cq->bytes_in - cq->bytes_out > 65536 - 4096
        !          1579:                    && (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_BUFMIN)){
        !          1580:                        con->conf.stream_request_body &= ~FDEVENT_STREAM_REQUEST_POLLIN;
        !          1581:                        if (-1 != hctx->fd) return HANDLER_WAIT_FOR_EVENT;
        !          1582:                } else {
        !          1583:                        handler_t r = connection_handle_read_post_state(srv, con);
        !          1584:                        if (!chunkqueue_is_empty(cq)) {
        !          1585:                                if (fdevent_event_get_interest(srv->ev, hctx->fdtocgi) & FDEVENT_OUT) {
        !          1586:                                        return (r == HANDLER_GO_ON) ? HANDLER_WAIT_FOR_EVENT : r;
        !          1587:                                }
        !          1588:                        }
        !          1589:                        if (r != HANDLER_GO_ON) return r;
1.1       misho    1590:                }
1.1.1.3 ! misho    1591:        }
1.1       misho    1592: 
1.1.1.3 ! misho    1593:        if (-1 == hctx->fd) {
        !          1594:                buffer *handler = cgi_get_handler(p->conf.cgi, con->physical.path);
        !          1595:                if (!handler) return HANDLER_GO_ON; /*(should not happen; checked in cgi_is_handled())*/
        !          1596:                if (cgi_create_env(srv, con, p, hctx, handler)) {
        !          1597:                        con->http_status = 500;
        !          1598:                        con->mode = DIRECT;
1.1       misho    1599: 
1.1.1.3 ! misho    1600:                        return HANDLER_FINISHED;
1.1       misho    1601:                }
1.1.1.3 ! misho    1602: #if 0
        !          1603:        log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", hctx, hctx->pid);
        !          1604: #endif
        !          1605:        } else if (!chunkqueue_is_empty(con->request_content_queue)) {
        !          1606:                if (0 != cgi_write_request(srv, hctx, hctx->fdtocgi)) {
        !          1607:                        cgi_connection_close(srv, hctx);
        !          1608:                        return HANDLER_ERROR;
1.1       misho    1609:                }
                   1610:        }
1.1.1.3 ! misho    1611: 
        !          1612:        /* if not done, wait for CGI to close stdout, so we read EOF on pipe */
        !          1613:        return HANDLER_WAIT_FOR_EVENT;
1.1       misho    1614: }
                   1615: 
                   1616: 
                   1617: int mod_cgi_plugin_init(plugin *p);
                   1618: int mod_cgi_plugin_init(plugin *p) {
                   1619:        p->version     = LIGHTTPD_VERSION_ID;
                   1620:        p->name        = buffer_init_string("cgi");
                   1621: 
                   1622:        p->connection_reset = cgi_connection_close_callback;
                   1623:        p->handle_subrequest_start = cgi_is_handled;
                   1624:        p->handle_subrequest = mod_cgi_handle_subrequest;
                   1625:        p->handle_trigger = cgi_trigger;
                   1626:        p->init           = mod_cgi_init;
                   1627:        p->cleanup        = mod_cgi_free;
                   1628:        p->set_defaults   = mod_fastcgi_set_defaults;
                   1629: 
                   1630:        p->data        = NULL;
                   1631: 
                   1632:        return 0;
                   1633: }

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