Annotation of embedaddon/lighttpd/src/mod_fastcgi.c, revision 1.1.1.1

1.1       misho       1: #include "buffer.h"
                      2: #include "server.h"
                      3: #include "keyvalue.h"
                      4: #include "log.h"
                      5: 
                      6: #include "http_chunk.h"
                      7: #include "fdevent.h"
                      8: #include "connections.h"
                      9: #include "response.h"
                     10: #include "joblist.h"
                     11: 
                     12: #include "plugin.h"
                     13: 
                     14: #include "inet_ntop_cache.h"
                     15: #include "stat_cache.h"
                     16: #include "status_counter.h"
                     17: 
                     18: #include <sys/types.h>
                     19: #include <unistd.h>
                     20: #include <errno.h>
                     21: #include <fcntl.h>
                     22: #include <string.h>
                     23: #include <stdlib.h>
                     24: #include <ctype.h>
                     25: #include <assert.h>
                     26: #include <signal.h>
                     27: 
                     28: #ifdef HAVE_FASTCGI_FASTCGI_H
                     29: # include <fastcgi/fastcgi.h>
                     30: #else
                     31: # ifdef HAVE_FASTCGI_H
                     32: #  include <fastcgi.h>
                     33: # else
                     34: #  include "fastcgi.h"
                     35: # endif
                     36: #endif /* HAVE_FASTCGI_FASTCGI_H */
                     37: 
                     38: #include <stdio.h>
                     39: 
                     40: #ifdef HAVE_SYS_FILIO_H
                     41: # include <sys/filio.h>
                     42: #endif
                     43: 
                     44: #include "sys-socket.h"
                     45: 
                     46: #ifdef HAVE_SYS_UIO_H
                     47: #include <sys/uio.h>
                     48: #endif
                     49: #ifdef HAVE_SYS_WAIT_H
                     50: #include <sys/wait.h>
                     51: #endif
                     52: 
                     53: #include "version.h"
                     54: 
                     55: #define FCGI_ENV_ADD_CHECK(ret, con) \
                     56:        if (ret == -1) { \
                     57:                con->http_status = 400; \
                     58:                con->file_finished = 1; \
                     59:                return -1; \
                     60:        };
                     61: 
                     62: /*
                     63:  *
                     64:  * TODO:
                     65:  *
                     66:  * - add timeout for a connect to a non-fastcgi process
                     67:  *   (use state_timestamp + state)
                     68:  *
                     69:  */
                     70: 
                     71: typedef struct fcgi_proc {
                     72:        size_t id; /* id will be between 1 and max_procs */
                     73:        buffer *unixsocket; /* config.socket + "-" + id */
                     74:        unsigned port;  /* config.port + pno */
                     75: 
                     76:        buffer *connection_name; /* either tcp:<host>:<port> or unix:<socket> for debugging purposes */
                     77: 
                     78:        pid_t pid;   /* PID of the spawned process (0 if not spawned locally) */
                     79: 
                     80: 
                     81:        size_t load; /* number of requests waiting on this process */
                     82: 
                     83:        size_t requests;  /* see max_requests */
                     84:        struct fcgi_proc *prev, *next; /* see first */
                     85: 
                     86:        time_t disabled_until; /* this proc is disabled until, use something else until then */
                     87: 
                     88:        int is_local;
                     89: 
                     90:        enum {
                     91:                PROC_STATE_UNSET,    /* init-phase */
                     92:                PROC_STATE_RUNNING,  /* alive */
                     93:                PROC_STATE_OVERLOADED, /* listen-queue is full,
                     94:                                          don't send anything to this proc for the next 2 seconds */
                     95:                PROC_STATE_DIED_WAIT_FOR_PID, /* */
                     96:                PROC_STATE_DIED,     /* marked as dead, should be restarted */
                     97:                PROC_STATE_KILLED    /* was killed as we don't have the load anymore */
                     98:        } state;
                     99: } fcgi_proc;
                    100: 
                    101: typedef struct {
                    102:        /* the key that is used to reference this value */
                    103:        buffer *id;
                    104: 
                    105:        /* list of processes handling this extension
                    106:         * sorted by lowest load
                    107:         *
                    108:         * whenever a job is done move it up in the list
                    109:         * until it is sorted, move it down as soon as the
                    110:         * job is started
                    111:         */
                    112:        fcgi_proc *first;
                    113:        fcgi_proc *unused_procs;
                    114: 
                    115:        /*
                    116:         * spawn at least min_procs, at max_procs.
                    117:         *
                    118:         * as soon as the load of the first entry
                    119:         * is max_load_per_proc we spawn a new one
                    120:         * and add it to the first entry and give it
                    121:         * the load
                    122:         *
                    123:         */
                    124: 
                    125:        unsigned short max_procs;
                    126:        size_t num_procs;    /* how many procs are started */
                    127:        size_t active_procs; /* how many of them are really running, i.e. state = PROC_STATE_RUNNING */
                    128: 
                    129:        /*
                    130:         * time after a disabled remote connection is tried to be re-enabled
                    131:         *
                    132:         *
                    133:         */
                    134: 
                    135:        unsigned short disable_time;
                    136: 
                    137:        /*
                    138:         * some fastcgi processes get a little bit larger
                    139:         * than wanted. max_requests_per_proc kills a
                    140:         * process after a number of handled requests.
                    141:         *
                    142:         */
                    143:        size_t max_requests_per_proc;
                    144: 
                    145: 
                    146:        /* config */
                    147: 
                    148:        /*
                    149:         * host:port
                    150:         *
                    151:         * if host is one of the local IP adresses the
                    152:         * whole connection is local
                    153:         *
                    154:         * if port is not 0, and host is not specified,
                    155:         * "localhost" (INADDR_LOOPBACK) is assumed.
                    156:         *
                    157:         */
                    158:        buffer *host;
                    159:        unsigned short port;
                    160: 
                    161:        /*
                    162:         * Unix Domain Socket
                    163:         *
                    164:         * instead of TCP/IP we can use Unix Domain Sockets
                    165:         * - more secure (you have fileperms to play with)
                    166:         * - more control (on locally)
                    167:         * - more speed (no extra overhead)
                    168:         */
                    169:        buffer *unixsocket;
                    170: 
                    171:        /* if socket is local we can start the fastcgi
                    172:         * process ourself
                    173:         *
                    174:         * bin-path is the path to the binary
                    175:         *
                    176:         * check min_procs and max_procs for the number
                    177:         * of process to start up
                    178:         */
                    179:        buffer *bin_path;
                    180: 
                    181:        /* bin-path is set bin-environment is taken to
                    182:         * create the environement before starting the
                    183:         * FastCGI process
                    184:         *
                    185:         */
                    186:        array *bin_env;
                    187: 
                    188:        array *bin_env_copy;
                    189: 
                    190:        /*
                    191:         * docroot-translation between URL->phys and the
                    192:         * remote host
                    193:         *
                    194:         * reasons:
                    195:         * - different dir-layout if remote
                    196:         * - chroot if local
                    197:         *
                    198:         */
                    199:        buffer *docroot;
                    200: 
                    201:        /*
                    202:         * fastcgi-mode:
                    203:         * - responser
                    204:         * - authorizer
                    205:         *
                    206:         */
                    207:        unsigned short mode;
                    208: 
                    209:        /*
                    210:         * check_local tells you if the phys file is stat()ed
                    211:         * or not. FastCGI doesn't care if the service is
                    212:         * remote. If the web-server side doesn't contain
                    213:         * the fastcgi-files we should not stat() for them
                    214:         * and say '404 not found'.
                    215:         */
                    216:        unsigned short check_local;
                    217: 
                    218:        /*
                    219:         * append PATH_INFO to SCRIPT_FILENAME
                    220:         *
                    221:         * php needs this if cgi.fix_pathinfo is provided
                    222:         *
                    223:         */
                    224: 
                    225:        unsigned short break_scriptfilename_for_php;
                    226: 
                    227:        /*
                    228:         * workaround for program when prefix="/"
                    229:         *
                    230:         * rule to build PATH_INFO is hardcoded for when check_local is disabled
                    231:         * enable this option to use the workaround
                    232:         *
                    233:         */
                    234: 
                    235:        unsigned short fix_root_path_name;
                    236: 
                    237:        /*
                    238:         * If the backend includes X-LIGHTTPD-send-file in the response
                    239:         * we use the value as filename and ignore the content.
                    240:         *
                    241:         */
                    242:        unsigned short allow_xsendfile;
                    243: 
                    244:        ssize_t load; /* replace by host->load */
                    245: 
                    246:        size_t max_id; /* corresponds most of the time to
                    247:        num_procs.
                    248: 
                    249:        only if a process is killed max_id waits for the process itself
                    250:        to die and decrements it afterwards */
                    251: 
                    252:        buffer *strip_request_uri;
                    253: 
                    254:        unsigned short kill_signal; /* we need a setting for this as libfcgi
                    255:                                       applications prefer SIGUSR1 while the
                    256:                                       rest of the world would use SIGTERM
                    257:                                       *sigh* */
                    258: } fcgi_extension_host;
                    259: 
                    260: /*
                    261:  * one extension can have multiple hosts assigned
                    262:  * one host can spawn additional processes on the same
                    263:  *   socket (if we control it)
                    264:  *
                    265:  * ext -> host -> procs
                    266:  *    1:n     1:n
                    267:  *
                    268:  * if the fastcgi process is remote that whole goes down
                    269:  * to
                    270:  *
                    271:  * ext -> host -> procs
                    272:  *    1:n     1:1
                    273:  *
                    274:  * in case of PHP and FCGI_CHILDREN we have again a procs
                    275:  * but we don't control it directly.
                    276:  *
                    277:  */
                    278: 
                    279: typedef struct {
                    280:        buffer *key; /* like .php */
                    281: 
                    282:        int note_is_sent;
                    283:        int last_used_ndx;
                    284: 
                    285:        fcgi_extension_host **hosts;
                    286: 
                    287:        size_t used;
                    288:        size_t size;
                    289: } fcgi_extension;
                    290: 
                    291: typedef struct {
                    292:        fcgi_extension **exts;
                    293: 
                    294:        size_t used;
                    295:        size_t size;
                    296: } fcgi_exts;
                    297: 
                    298: 
                    299: typedef struct {
                    300:        fcgi_exts *exts;
                    301: 
                    302:        array *ext_mapping;
                    303: 
                    304:        unsigned int debug;
                    305: } plugin_config;
                    306: 
                    307: typedef struct {
                    308:        char **ptr;
                    309: 
                    310:        size_t size;
                    311:        size_t used;
                    312: } char_array;
                    313: 
                    314: /* generic plugin data, shared between all connections */
                    315: typedef struct {
                    316:        PLUGIN_DATA;
                    317: 
                    318:        buffer *fcgi_env;
                    319: 
                    320:        buffer *path;
                    321:        buffer *parse_response;
                    322: 
                    323:        buffer *statuskey;
                    324: 
                    325:        plugin_config **config_storage;
                    326: 
                    327:        plugin_config conf; /* this is only used as long as no handler_ctx is setup */
                    328: } plugin_data;
                    329: 
                    330: /* connection specific data */
                    331: typedef enum {
                    332:        FCGI_STATE_UNSET,
                    333:        FCGI_STATE_INIT,
                    334:        FCGI_STATE_CONNECT_DELAYED,
                    335:        FCGI_STATE_PREPARE_WRITE,
                    336:        FCGI_STATE_WRITE,
                    337:        FCGI_STATE_READ
                    338: } fcgi_connection_state_t;
                    339: 
                    340: typedef struct {
                    341:        fcgi_proc *proc;
                    342:        fcgi_extension_host *host;
                    343:        fcgi_extension *ext;
                    344: 
                    345:        fcgi_connection_state_t state;
                    346:        time_t   state_timestamp;
                    347: 
                    348:        int      reconnects; /* number of reconnect attempts */
                    349: 
                    350:        chunkqueue *rb; /* read queue */
                    351:        chunkqueue *wb; /* write queue */
                    352: 
                    353:        buffer   *response_header;
                    354: 
                    355:        size_t    request_id;
                    356:        int       fd;        /* fd to the fastcgi process */
                    357:        int       fde_ndx;   /* index into the fd-event buffer */
                    358: 
                    359:        pid_t     pid;
                    360:        int       got_proc;
                    361: 
                    362:        int       send_content_body;
                    363: 
                    364:        plugin_config conf;
                    365: 
                    366:        connection *remote_conn;  /* dumb pointer */
                    367:        plugin_data *plugin_data; /* dumb pointer */
                    368: } handler_ctx;
                    369: 
                    370: 
                    371: /* ok, we need a prototype */
                    372: static handler_t fcgi_handle_fdevent(server *srv, void *ctx, int revents);
                    373: 
                    374: static void reset_signals(void) {
                    375: #ifdef SIGTTOU
                    376:        signal(SIGTTOU, SIG_DFL);
                    377: #endif
                    378: #ifdef SIGTTIN
                    379:        signal(SIGTTIN, SIG_DFL);
                    380: #endif
                    381: #ifdef SIGTSTP
                    382:        signal(SIGTSTP, SIG_DFL);
                    383: #endif
                    384:        signal(SIGHUP, SIG_DFL);
                    385:        signal(SIGPIPE, SIG_DFL);
                    386:        signal(SIGUSR1, SIG_DFL);
                    387: }
                    388: 
                    389: static void fastcgi_status_copy_procname(buffer *b, fcgi_extension_host *host, fcgi_proc *proc) {
                    390:        buffer_copy_string_len(b, CONST_STR_LEN("fastcgi.backend."));
                    391:        buffer_append_string_buffer(b, host->id);
                    392:        if (proc) {
                    393:                buffer_append_string_len(b, CONST_STR_LEN("."));
                    394:                buffer_append_long(b, proc->id);
                    395:        }
                    396: }
                    397: 
                    398: static void fcgi_proc_load_inc(server *srv, handler_ctx *hctx) {
                    399:        plugin_data *p = hctx->plugin_data;
                    400:        hctx->proc->load++;
                    401: 
                    402:        status_counter_inc(srv, CONST_STR_LEN("fastcgi.active-requests"));
                    403: 
                    404:        fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
                    405:        buffer_append_string_len(p->statuskey, CONST_STR_LEN(".load"));
                    406: 
                    407:        status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
                    408: }
                    409: 
                    410: static void fcgi_proc_load_dec(server *srv, handler_ctx *hctx) {
                    411:        plugin_data *p = hctx->plugin_data;
                    412:        hctx->proc->load--;
                    413: 
                    414:        status_counter_dec(srv, CONST_STR_LEN("fastcgi.active-requests"));
                    415: 
                    416:        fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
                    417:        buffer_append_string_len(p->statuskey, CONST_STR_LEN(".load"));
                    418: 
                    419:        status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
                    420: }
                    421: 
                    422: static void fcgi_host_assign(server *srv, handler_ctx *hctx, fcgi_extension_host *host) {
                    423:        plugin_data *p = hctx->plugin_data;
                    424:        hctx->host = host;
                    425:        hctx->host->load++;
                    426: 
                    427:        fastcgi_status_copy_procname(p->statuskey, hctx->host, NULL);
                    428:        buffer_append_string_len(p->statuskey, CONST_STR_LEN(".load"));
                    429: 
                    430:        status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->host->load);
                    431: }
                    432: 
                    433: static void fcgi_host_reset(server *srv, handler_ctx *hctx) {
                    434:        plugin_data *p = hctx->plugin_data;
                    435:        hctx->host->load--;
                    436: 
                    437:        fastcgi_status_copy_procname(p->statuskey, hctx->host, NULL);
                    438:        buffer_append_string_len(p->statuskey, CONST_STR_LEN(".load"));
                    439: 
                    440:        status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->host->load);
                    441: 
                    442:        hctx->host = NULL;
                    443: }
                    444: 
                    445: static void fcgi_host_disable(server *srv, handler_ctx *hctx) {
                    446:        plugin_data *p    = hctx->plugin_data;
                    447: 
                    448:        if (hctx->host->disable_time || hctx->proc->is_local) {
                    449:                if (hctx->proc->state == PROC_STATE_RUNNING) hctx->host->active_procs--;
                    450:                hctx->proc->disabled_until = srv->cur_ts + hctx->host->disable_time;
                    451:                hctx->proc->state = hctx->proc->is_local ? PROC_STATE_DIED_WAIT_FOR_PID : PROC_STATE_DIED;
                    452: 
                    453:                if (p->conf.debug) {
                    454:                        log_error_write(srv, __FILE__, __LINE__, "sds",
                    455:                                "backend disabled for", hctx->host->disable_time, "seconds");
                    456:                }
                    457:        }
                    458: }
                    459: 
                    460: static int fastcgi_status_init(server *srv, buffer *b, fcgi_extension_host *host, fcgi_proc *proc) {
                    461: #define CLEAN(x) \
                    462:        fastcgi_status_copy_procname(b, host, proc); \
                    463:        buffer_append_string_len(b, CONST_STR_LEN(x)); \
                    464:        status_counter_set(srv, CONST_BUF_LEN(b), 0);
                    465: 
                    466:        CLEAN(".disabled");
                    467:        CLEAN(".died");
                    468:        CLEAN(".overloaded");
                    469:        CLEAN(".connected");
                    470:        CLEAN(".load");
                    471: 
                    472: #undef CLEAN
                    473: 
                    474: #define CLEAN(x) \
                    475:        fastcgi_status_copy_procname(b, host, NULL); \
                    476:        buffer_append_string_len(b, CONST_STR_LEN(x)); \
                    477:        status_counter_set(srv, CONST_BUF_LEN(b), 0);
                    478: 
                    479:        CLEAN(".load");
                    480: 
                    481: #undef CLEAN
                    482: 
                    483:        return 0;
                    484: }
                    485: 
                    486: static handler_ctx * handler_ctx_init(void) {
                    487:        handler_ctx * hctx;
                    488: 
                    489:        hctx = calloc(1, sizeof(*hctx));
                    490:        assert(hctx);
                    491: 
                    492:        hctx->fde_ndx = -1;
                    493: 
                    494:        hctx->response_header = buffer_init();
                    495: 
                    496:        hctx->request_id = 0;
                    497:        hctx->state = FCGI_STATE_INIT;
                    498:        hctx->proc = NULL;
                    499: 
                    500:        hctx->fd = -1;
                    501: 
                    502:        hctx->reconnects = 0;
                    503:        hctx->send_content_body = 1;
                    504: 
                    505:        hctx->rb = chunkqueue_init();
                    506:        hctx->wb = chunkqueue_init();
                    507: 
                    508:        return hctx;
                    509: }
                    510: 
                    511: static void handler_ctx_free(server *srv, handler_ctx *hctx) {
                    512:        if (hctx->host) {
                    513:                fcgi_host_reset(srv, hctx);
                    514:        }
                    515: 
                    516:        buffer_free(hctx->response_header);
                    517: 
                    518:        chunkqueue_free(hctx->rb);
                    519:        chunkqueue_free(hctx->wb);
                    520: 
                    521:        free(hctx);
                    522: }
                    523: 
                    524: static fcgi_proc *fastcgi_process_init(void) {
                    525:        fcgi_proc *f;
                    526: 
                    527:        f = calloc(1, sizeof(*f));
                    528:        f->unixsocket = buffer_init();
                    529:        f->connection_name = buffer_init();
                    530: 
                    531:        f->prev = NULL;
                    532:        f->next = NULL;
                    533: 
                    534:        return f;
                    535: }
                    536: 
                    537: static void fastcgi_process_free(fcgi_proc *f) {
                    538:        if (!f) return;
                    539: 
                    540:        fastcgi_process_free(f->next);
                    541: 
                    542:        buffer_free(f->unixsocket);
                    543:        buffer_free(f->connection_name);
                    544: 
                    545:        free(f);
                    546: }
                    547: 
                    548: static fcgi_extension_host *fastcgi_host_init(void) {
                    549:        fcgi_extension_host *f;
                    550: 
                    551:        f = calloc(1, sizeof(*f));
                    552: 
                    553:        f->id = buffer_init();
                    554:        f->host = buffer_init();
                    555:        f->unixsocket = buffer_init();
                    556:        f->docroot = buffer_init();
                    557:        f->bin_path = buffer_init();
                    558:        f->bin_env = array_init();
                    559:        f->bin_env_copy = array_init();
                    560:        f->strip_request_uri = buffer_init();
                    561: 
                    562:        return f;
                    563: }
                    564: 
                    565: static void fastcgi_host_free(fcgi_extension_host *h) {
                    566:        if (!h) return;
                    567: 
                    568:        buffer_free(h->id);
                    569:        buffer_free(h->host);
                    570:        buffer_free(h->unixsocket);
                    571:        buffer_free(h->docroot);
                    572:        buffer_free(h->bin_path);
                    573:        buffer_free(h->strip_request_uri);
                    574:        array_free(h->bin_env);
                    575:        array_free(h->bin_env_copy);
                    576: 
                    577:        fastcgi_process_free(h->first);
                    578:        fastcgi_process_free(h->unused_procs);
                    579: 
                    580:        free(h);
                    581: 
                    582: }
                    583: 
                    584: static fcgi_exts *fastcgi_extensions_init(void) {
                    585:        fcgi_exts *f;
                    586: 
                    587:        f = calloc(1, sizeof(*f));
                    588: 
                    589:        return f;
                    590: }
                    591: 
                    592: static void fastcgi_extensions_free(fcgi_exts *f) {
                    593:        size_t i;
                    594: 
                    595:        if (!f) return;
                    596: 
                    597:        for (i = 0; i < f->used; i++) {
                    598:                fcgi_extension *fe;
                    599:                size_t j;
                    600: 
                    601:                fe = f->exts[i];
                    602: 
                    603:                for (j = 0; j < fe->used; j++) {
                    604:                        fcgi_extension_host *h;
                    605: 
                    606:                        h = fe->hosts[j];
                    607: 
                    608:                        fastcgi_host_free(h);
                    609:                }
                    610: 
                    611:                buffer_free(fe->key);
                    612:                free(fe->hosts);
                    613: 
                    614:                free(fe);
                    615:        }
                    616: 
                    617:        free(f->exts);
                    618: 
                    619:        free(f);
                    620: }
                    621: 
                    622: static int fastcgi_extension_insert(fcgi_exts *ext, buffer *key, fcgi_extension_host *fh) {
                    623:        fcgi_extension *fe;
                    624:        size_t i;
                    625: 
                    626:        /* there is something */
                    627: 
                    628:        for (i = 0; i < ext->used; i++) {
                    629:                if (buffer_is_equal(key, ext->exts[i]->key)) {
                    630:                        break;
                    631:                }
                    632:        }
                    633: 
                    634:        if (i == ext->used) {
                    635:                /* filextension is new */
                    636:                fe = calloc(1, sizeof(*fe));
                    637:                assert(fe);
                    638:                fe->key = buffer_init();
                    639:                fe->last_used_ndx = -1;
                    640:                buffer_copy_string_buffer(fe->key, key);
                    641: 
                    642:                /* */
                    643: 
                    644:                if (ext->size == 0) {
                    645:                        ext->size = 8;
                    646:                        ext->exts = malloc(ext->size * sizeof(*(ext->exts)));
                    647:                        assert(ext->exts);
                    648:                } else if (ext->used == ext->size) {
                    649:                        ext->size += 8;
                    650:                        ext->exts = realloc(ext->exts, ext->size * sizeof(*(ext->exts)));
                    651:                        assert(ext->exts);
                    652:                }
                    653:                ext->exts[ext->used++] = fe;
                    654:        } else {
                    655:                fe = ext->exts[i];
                    656:        }
                    657: 
                    658:        if (fe->size == 0) {
                    659:                fe->size = 4;
                    660:                fe->hosts = malloc(fe->size * sizeof(*(fe->hosts)));
                    661:                assert(fe->hosts);
                    662:        } else if (fe->size == fe->used) {
                    663:                fe->size += 4;
                    664:                fe->hosts = realloc(fe->hosts, fe->size * sizeof(*(fe->hosts)));
                    665:                assert(fe->hosts);
                    666:        }
                    667: 
                    668:        fe->hosts[fe->used++] = fh;
                    669: 
                    670:        return 0;
                    671: 
                    672: }
                    673: 
                    674: INIT_FUNC(mod_fastcgi_init) {
                    675:        plugin_data *p;
                    676: 
                    677:        p = calloc(1, sizeof(*p));
                    678: 
                    679:        p->fcgi_env = buffer_init();
                    680: 
                    681:        p->path = buffer_init();
                    682:        p->parse_response = buffer_init();
                    683: 
                    684:        p->statuskey = buffer_init();
                    685: 
                    686:        return p;
                    687: }
                    688: 
                    689: 
                    690: FREE_FUNC(mod_fastcgi_free) {
                    691:        plugin_data *p = p_d;
                    692: 
                    693:        UNUSED(srv);
                    694: 
                    695:        buffer_free(p->fcgi_env);
                    696:        buffer_free(p->path);
                    697:        buffer_free(p->parse_response);
                    698:        buffer_free(p->statuskey);
                    699: 
                    700:        if (p->config_storage) {
                    701:                size_t i, j, n;
                    702:                for (i = 0; i < srv->config_context->used; i++) {
                    703:                        plugin_config *s = p->config_storage[i];
                    704:                        fcgi_exts *exts;
                    705: 
                    706:                        if (!s) continue;
                    707: 
                    708:                        exts = s->exts;
                    709: 
                    710:                        for (j = 0; j < exts->used; j++) {
                    711:                                fcgi_extension *ex;
                    712: 
                    713:                                ex = exts->exts[j];
                    714: 
                    715:                                for (n = 0; n < ex->used; n++) {
                    716:                                        fcgi_proc *proc;
                    717:                                        fcgi_extension_host *host;
                    718: 
                    719:                                        host = ex->hosts[n];
                    720: 
                    721:                                        for (proc = host->first; proc; proc = proc->next) {
                    722:                                                if (proc->pid != 0) {
                    723:                                                        kill(proc->pid, host->kill_signal);
                    724:                                                }
                    725: 
                    726:                                                if (proc->is_local &&
                    727:                                                    !buffer_is_empty(proc->unixsocket)) {
                    728:                                                        unlink(proc->unixsocket->ptr);
                    729:                                                }
                    730:                                        }
                    731: 
                    732:                                        for (proc = host->unused_procs; proc; proc = proc->next) {
                    733:                                                if (proc->pid != 0) {
                    734:                                                        kill(proc->pid, host->kill_signal);
                    735:                                                }
                    736:                                                if (proc->is_local &&
                    737:                                                    !buffer_is_empty(proc->unixsocket)) {
                    738:                                                        unlink(proc->unixsocket->ptr);
                    739:                                                }
                    740:                                        }
                    741:                                }
                    742:                        }
                    743: 
                    744:                        fastcgi_extensions_free(s->exts);
                    745:                        array_free(s->ext_mapping);
                    746: 
                    747:                        free(s);
                    748:                }
                    749:                free(p->config_storage);
                    750:        }
                    751: 
                    752:        free(p);
                    753: 
                    754:        return HANDLER_GO_ON;
                    755: }
                    756: 
                    757: static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
                    758:        char *dst;
                    759:        size_t i;
                    760: 
                    761:        if (!key || !val) return -1;
                    762: 
                    763:        dst = malloc(key_len + val_len + 3);
                    764:        memcpy(dst, key, key_len);
                    765:        dst[key_len] = '=';
                    766:        memcpy(dst + key_len + 1, val, val_len);
                    767:        dst[key_len + 1 + val_len] = '\0';
                    768: 
                    769:        for (i = 0; i < env->used; i++) {
                    770:                if (0 == strncmp(dst, env->ptr[i], key_len + 1)) {
                    771:                        /* don't care about free as we are in a forked child which is going to exec(...) */
                    772:                        /* free(env->ptr[i]); */
                    773:                        env->ptr[i] = dst;
                    774:                        return 0;
                    775:                }
                    776:        }
                    777: 
                    778:        if (env->size == 0) {
                    779:                env->size = 16;
                    780:                env->ptr = malloc(env->size * sizeof(*env->ptr));
                    781:        } else if (env->size == env->used + 1) {
                    782:                env->size += 16;
                    783:                env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
                    784:        }
                    785: 
                    786:        env->ptr[env->used++] = dst;
                    787: 
                    788:        return 0;
                    789: }
                    790: 
                    791: static int parse_binpath(char_array *env, buffer *b) {
                    792:        char *start;
                    793:        size_t i;
                    794:        /* search for spaces */
                    795: 
                    796:        start = b->ptr;
                    797:        for (i = 0; i < b->used - 1; i++) {
                    798:                switch(b->ptr[i]) {
                    799:                case ' ':
                    800:                case '\t':
                    801:                        /* a WS, stop here and copy the argument */
                    802: 
                    803:                        if (env->size == 0) {
                    804:                                env->size = 16;
                    805:                                env->ptr = malloc(env->size * sizeof(*env->ptr));
                    806:                        } else if (env->size == env->used) {
                    807:                                env->size += 16;
                    808:                                env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
                    809:                        }
                    810: 
                    811:                        b->ptr[i] = '\0';
                    812: 
                    813:                        env->ptr[env->used++] = start;
                    814: 
                    815:                        start = b->ptr + i + 1;
                    816:                        break;
                    817:                default:
                    818:                        break;
                    819:                }
                    820:        }
                    821: 
                    822:        if (env->size == 0) {
                    823:                env->size = 16;
                    824:                env->ptr = malloc(env->size * sizeof(*env->ptr));
                    825:        } else if (env->size == env->used) { /* we need one extra for the terminating NULL */
                    826:                env->size += 16;
                    827:                env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
                    828:        }
                    829: 
                    830:        /* the rest */
                    831:        env->ptr[env->used++] = start;
                    832: 
                    833:        if (env->size == 0) {
                    834:                env->size = 16;
                    835:                env->ptr = malloc(env->size * sizeof(*env->ptr));
                    836:        } else if (env->size == env->used) { /* we need one extra for the terminating NULL */
                    837:                env->size += 16;
                    838:                env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
                    839:        }
                    840: 
                    841:        /* terminate */
                    842:        env->ptr[env->used++] = NULL;
                    843: 
                    844:        return 0;
                    845: }
                    846: 
                    847: static int fcgi_spawn_connection(server *srv,
                    848:                                 plugin_data *p,
                    849:                                 fcgi_extension_host *host,
                    850:                                 fcgi_proc *proc) {
                    851:        int fcgi_fd;
                    852:        int socket_type, status;
                    853:        struct timeval tv = { 0, 100 * 1000 };
                    854: #ifdef HAVE_SYS_UN_H
                    855:        struct sockaddr_un fcgi_addr_un;
                    856: #endif
                    857:        struct sockaddr_in fcgi_addr_in;
                    858:        struct sockaddr *fcgi_addr;
                    859: 
                    860:        socklen_t servlen;
                    861: 
                    862: #ifndef HAVE_FORK
                    863:        return -1;
                    864: #endif
                    865: 
                    866:        if (p->conf.debug) {
                    867:                log_error_write(srv, __FILE__, __LINE__, "sdb",
                    868:                                "new proc, socket:", proc->port, proc->unixsocket);
                    869:        }
                    870: 
                    871:        if (!buffer_is_empty(proc->unixsocket)) {
                    872:                memset(&fcgi_addr, 0, sizeof(fcgi_addr));
                    873: 
                    874: #ifdef HAVE_SYS_UN_H
                    875:                fcgi_addr_un.sun_family = AF_UNIX;
                    876:                strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
                    877: 
                    878: #ifdef SUN_LEN
                    879:                servlen = SUN_LEN(&fcgi_addr_un);
                    880: #else
                    881:                /* stevens says: */
                    882:                servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
                    883: #endif
                    884:                socket_type = AF_UNIX;
                    885:                fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
                    886: 
                    887:                buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("unix:"));
                    888:                buffer_append_string_buffer(proc->connection_name, proc->unixsocket);
                    889: 
                    890: #else
                    891:                log_error_write(srv, __FILE__, __LINE__, "s",
                    892:                                "ERROR: Unix Domain sockets are not supported.");
                    893:                return -1;
                    894: #endif
                    895:        } else {
                    896:                fcgi_addr_in.sin_family = AF_INET;
                    897: 
                    898:                if (buffer_is_empty(host->host)) {
                    899:                        fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
                    900:                } else {
                    901:                        struct hostent *he;
                    902: 
                    903:                        /* set a useful default */
                    904:                        fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
                    905: 
                    906: 
                    907:                        if (NULL == (he = gethostbyname(host->host->ptr))) {
                    908:                                log_error_write(srv, __FILE__, __LINE__,
                    909:                                                "sdb", "gethostbyname failed: ",
                    910:                                                h_errno, host->host);
                    911:                                return -1;
                    912:                        }
                    913: 
                    914:                        if (he->h_addrtype != AF_INET) {
                    915:                                log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
                    916:                                return -1;
                    917:                        }
                    918: 
                    919:                        if (he->h_length != sizeof(struct in_addr)) {
                    920:                                log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
                    921:                                return -1;
                    922:                        }
                    923: 
                    924:                        memcpy(&(fcgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
                    925: 
                    926:                }
                    927:                fcgi_addr_in.sin_port = htons(proc->port);
                    928:                servlen = sizeof(fcgi_addr_in);
                    929: 
                    930:                socket_type = AF_INET;
                    931:                fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
                    932: 
                    933:                buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("tcp:"));
                    934:                if (!buffer_is_empty(host->host)) {
                    935:                        buffer_append_string_buffer(proc->connection_name, host->host);
                    936:                } else {
                    937:                        buffer_append_string_len(proc->connection_name, CONST_STR_LEN("localhost"));
                    938:                }
                    939:                buffer_append_string_len(proc->connection_name, CONST_STR_LEN(":"));
                    940:                buffer_append_long(proc->connection_name, proc->port);
                    941:        }
                    942: 
                    943:        if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
                    944:                log_error_write(srv, __FILE__, __LINE__, "ss",
                    945:                                "failed:", strerror(errno));
                    946:                return -1;
                    947:        }
                    948: 
                    949:        if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
                    950:                /* server is not up, spawn it  */
                    951:                pid_t child;
                    952:                int val;
                    953: 
                    954:                if (errno != ENOENT &&
                    955:                    !buffer_is_empty(proc->unixsocket)) {
                    956:                        unlink(proc->unixsocket->ptr);
                    957:                }
                    958: 
                    959:                close(fcgi_fd);
                    960: 
                    961:                /* reopen socket */
                    962:                if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
                    963:                        log_error_write(srv, __FILE__, __LINE__, "ss",
                    964:                                "socket failed:", strerror(errno));
                    965:                        return -1;
                    966:                }
                    967: 
                    968:                val = 1;
                    969:                if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
                    970:                        log_error_write(srv, __FILE__, __LINE__, "ss",
                    971:                                        "socketsockopt failed:", strerror(errno));
                    972:                        return -1;
                    973:                }
                    974: 
                    975:                /* create socket */
                    976:                if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
                    977:                        log_error_write(srv, __FILE__, __LINE__, "sbs",
                    978:                                "bind failed for:",
                    979:                                proc->connection_name,
                    980:                                strerror(errno));
                    981:                        return -1;
                    982:                }
                    983: 
                    984:                if (-1 == listen(fcgi_fd, 1024)) {
                    985:                        log_error_write(srv, __FILE__, __LINE__, "ss",
                    986:                                "listen failed:", strerror(errno));
                    987:                        return -1;
                    988:                }
                    989: 
                    990: #ifdef HAVE_FORK
                    991:                switch ((child = fork())) {
                    992:                case 0: {
                    993:                        size_t i = 0;
                    994:                        char *c;
                    995:                        char_array env;
                    996:                        char_array arg;
                    997: 
                    998:                        /* create environment */
                    999:                        env.ptr = NULL;
                   1000:                        env.size = 0;
                   1001:                        env.used = 0;
                   1002: 
                   1003:                        arg.ptr = NULL;
                   1004:                        arg.size = 0;
                   1005:                        arg.used = 0;
                   1006: 
                   1007:                        if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
                   1008:                                close(FCGI_LISTENSOCK_FILENO);
                   1009:                                dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
                   1010:                                close(fcgi_fd);
                   1011:                        }
                   1012: 
                   1013:                        /* we don't need the client socket */
                   1014:                        for (i = 3; i < 256; i++) {
                   1015:                                close(i);
                   1016:                        }
                   1017: 
                   1018:                        /* build clean environment */
                   1019:                        if (host->bin_env_copy->used) {
                   1020:                                for (i = 0; i < host->bin_env_copy->used; i++) {
                   1021:                                        data_string *ds = (data_string *)host->bin_env_copy->data[i];
                   1022:                                        char *ge;
                   1023: 
                   1024:                                        if (NULL != (ge = getenv(ds->value->ptr))) {
                   1025:                                                env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
                   1026:                                        }
                   1027:                                }
                   1028:                        } else {
                   1029:                                for (i = 0; environ[i]; i++) {
                   1030:                                        char *eq;
                   1031: 
                   1032:                                        if (NULL != (eq = strchr(environ[i], '='))) {
                   1033:                                                env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
                   1034:                                        }
                   1035:                                }
                   1036:                        }
                   1037: 
                   1038:                        /* create environment */
                   1039:                        for (i = 0; i < host->bin_env->used; i++) {
                   1040:                                data_string *ds = (data_string *)host->bin_env->data[i];
                   1041: 
                   1042:                                env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
                   1043:                        }
                   1044: 
                   1045:                        for (i = 0; i < env.used; i++) {
                   1046:                                /* search for PHP_FCGI_CHILDREN */
                   1047:                                if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
                   1048:                        }
                   1049: 
                   1050:                        /* not found, add a default */
                   1051:                        if (i == env.used) {
                   1052:                                env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
                   1053:                        }
                   1054: 
                   1055:                        env.ptr[env.used] = NULL;
                   1056: 
                   1057:                        parse_binpath(&arg, host->bin_path);
                   1058: 
                   1059:                        /* chdir into the base of the bin-path,
                   1060:                         * search for the last / */
                   1061:                        if (NULL != (c = strrchr(arg.ptr[0], '/'))) {
                   1062:                                *c = '\0';
                   1063: 
                   1064:                                /* change to the physical directory */
                   1065:                                if (-1 == chdir(arg.ptr[0])) {
                   1066:                                        *c = '/';
                   1067:                                        log_error_write(srv, __FILE__, __LINE__, "sss", "chdir failed:", strerror(errno), arg.ptr[0]);
                   1068:                                }
                   1069:                                *c = '/';
                   1070:                        }
                   1071: 
                   1072:                        reset_signals();
                   1073: 
                   1074:                        /* exec the cgi */
                   1075:                        execve(arg.ptr[0], arg.ptr, env.ptr);
                   1076: 
                   1077:                        /* log_error_write(srv, __FILE__, __LINE__, "sbs",
                   1078:                                        "execve failed for:", host->bin_path, strerror(errno)); */
                   1079: 
                   1080:                        exit(errno);
                   1081: 
                   1082:                        break;
                   1083:                }
                   1084:                case -1:
                   1085:                        /* error */
                   1086:                        break;
                   1087:                default:
                   1088:                        /* father */
                   1089: 
                   1090:                        /* wait */
                   1091:                        select(0, NULL, NULL, NULL, &tv);
                   1092: 
                   1093:                        switch (waitpid(child, &status, WNOHANG)) {
                   1094:                        case 0:
                   1095:                                /* child still running after timeout, good */
                   1096:                                break;
                   1097:                        case -1:
                   1098:                                /* no PID found ? should never happen */
                   1099:                                log_error_write(srv, __FILE__, __LINE__, "ss",
                   1100:                                                "pid not found:", strerror(errno));
                   1101:                                return -1;
                   1102:                        default:
                   1103:                                log_error_write(srv, __FILE__, __LINE__, "sbs",
                   1104:                                                "the fastcgi-backend", host->bin_path, "failed to start:");
                   1105:                                /* the child should not terminate at all */
                   1106:                                if (WIFEXITED(status)) {
                   1107:                                        log_error_write(srv, __FILE__, __LINE__, "sdb",
                   1108:                                                        "child exited with status",
                   1109:                                                        WEXITSTATUS(status), host->bin_path);
                   1110:                                        log_error_write(srv, __FILE__, __LINE__, "s",
                   1111:                                                        "If you're trying to run your app as a FastCGI backend, make sure you're using the FastCGI-enabled version.\n"
                   1112:                                                        "If this is PHP on Gentoo, add 'fastcgi' to the USE flags.");
                   1113:                                } else if (WIFSIGNALED(status)) {
                   1114:                                        log_error_write(srv, __FILE__, __LINE__, "sd",
                   1115:                                                        "terminated by signal:",
                   1116:                                                        WTERMSIG(status));
                   1117: 
                   1118:                                        if (WTERMSIG(status) == 11) {
                   1119:                                                log_error_write(srv, __FILE__, __LINE__, "s",
                   1120:                                                                "to be exact: it segfaulted, crashed, died, ... you get the idea." );
                   1121:                                                log_error_write(srv, __FILE__, __LINE__, "s",
                   1122:                                                                "If this is PHP, try removing the bytecode caches for now and try again.");
                   1123:                                        }
                   1124:                                } else {
                   1125:                                        log_error_write(srv, __FILE__, __LINE__, "sd",
                   1126:                                                        "child died somehow:",
                   1127:                                                        status);
                   1128:                                }
                   1129:                                return -1;
                   1130:                        }
                   1131: 
                   1132:                        /* register process */
                   1133:                        proc->pid = child;
                   1134:                        proc->is_local = 1;
                   1135: 
                   1136:                        break;
                   1137:                }
                   1138: #endif
                   1139:        } else {
                   1140:                proc->is_local = 0;
                   1141:                proc->pid = 0;
                   1142: 
                   1143:                if (p->conf.debug) {
                   1144:                        log_error_write(srv, __FILE__, __LINE__, "sb",
                   1145:                                        "(debug) socket is already used; won't spawn:",
                   1146:                                        proc->connection_name);
                   1147:                }
                   1148:        }
                   1149: 
                   1150:        proc->state = PROC_STATE_RUNNING;
                   1151:        host->active_procs++;
                   1152: 
                   1153:        close(fcgi_fd);
                   1154: 
                   1155:        return 0;
                   1156: }
                   1157: 
                   1158: 
                   1159: SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
                   1160:        plugin_data *p = p_d;
                   1161:        data_unset *du;
                   1162:        size_t i = 0;
                   1163:        buffer *fcgi_mode = buffer_init();
                   1164: 
                   1165:        config_values_t cv[] = {
                   1166:                { "fastcgi.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
                   1167:                { "fastcgi.debug",               NULL, T_CONFIG_INT  , T_CONFIG_SCOPE_CONNECTION },       /* 1 */
                   1168:                { "fastcgi.map-extensions",      NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
                   1169:                { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
                   1170:        };
                   1171: 
                   1172:        p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
                   1173: 
                   1174:        for (i = 0; i < srv->config_context->used; i++) {
                   1175:                plugin_config *s;
                   1176:                array *ca;
                   1177: 
                   1178:                s = malloc(sizeof(plugin_config));
                   1179:                s->exts          = fastcgi_extensions_init();
                   1180:                s->debug         = 0;
                   1181:                s->ext_mapping   = array_init();
                   1182: 
                   1183:                cv[0].destination = s->exts;
                   1184:                cv[1].destination = &(s->debug);
                   1185:                cv[2].destination = s->ext_mapping;
                   1186: 
                   1187:                p->config_storage[i] = s;
                   1188:                ca = ((data_config *)srv->config_context->data[i])->value;
                   1189: 
                   1190:                if (0 != config_insert_values_global(srv, ca, cv)) {
                   1191:                        return HANDLER_ERROR;
                   1192:                }
                   1193: 
                   1194:                /*
                   1195:                 * <key> = ( ... )
                   1196:                 */
                   1197: 
                   1198:                if (NULL != (du = array_get_element(ca, "fastcgi.server"))) {
                   1199:                        size_t j;
                   1200:                        data_array *da = (data_array *)du;
                   1201: 
                   1202:                        if (du->type != TYPE_ARRAY) {
                   1203:                                log_error_write(srv, __FILE__, __LINE__, "sss",
                   1204:                                                "unexpected type for key: ", "fastcgi.server", "array of strings");
                   1205: 
                   1206:                                return HANDLER_ERROR;
                   1207:                        }
                   1208: 
                   1209: 
                   1210:                        /*
                   1211:                         * fastcgi.server = ( "<ext>" => ( ... ),
                   1212:                         *                    "<ext>" => ( ... ) )
                   1213:                         */
                   1214: 
                   1215:                        for (j = 0; j < da->value->used; j++) {
                   1216:                                size_t n;
                   1217:                                data_array *da_ext = (data_array *)da->value->data[j];
                   1218: 
                   1219:                                if (da->value->data[j]->type != TYPE_ARRAY) {
                   1220:                                        log_error_write(srv, __FILE__, __LINE__, "sssbs",
                   1221:                                                        "unexpected type for key: ", "fastcgi.server",
                   1222:                                                        "[", da->value->data[j]->key, "](string)");
                   1223: 
                   1224:                                        return HANDLER_ERROR;
                   1225:                                }
                   1226: 
                   1227:                                /*
                   1228:                                 * da_ext->key == name of the extension
                   1229:                                 */
                   1230: 
                   1231:                                /*
                   1232:                                 * fastcgi.server = ( "<ext>" =>
                   1233:                                 *                     ( "<host>" => ( ... ),
                   1234:                                 *                       "<host>" => ( ... )
                   1235:                                 *                     ),
                   1236:                                 *                    "<ext>" => ... )
                   1237:                                 */
                   1238: 
                   1239:                                for (n = 0; n < da_ext->value->used; n++) {
                   1240:                                        data_array *da_host = (data_array *)da_ext->value->data[n];
                   1241: 
                   1242:                                        fcgi_extension_host *host;
                   1243: 
                   1244:                                        config_values_t fcv[] = {
                   1245:                                                { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
                   1246:                                                { "docroot",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
                   1247:                                                { "mode",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
                   1248:                                                { "socket",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
                   1249:                                                { "bin-path",          NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 4 */
                   1250: 
                   1251:                                                { "check-local",       NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 5 */
                   1252:                                                { "port",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 6 */
                   1253:                                                { "max-procs",         NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 7 */
                   1254:                                                { "disable-time",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },        /* 8 */
                   1255: 
                   1256:                                                { "bin-environment",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 9 */
                   1257:                                                { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },     /* 10 */
                   1258: 
                   1259:                                                { "broken-scriptfilename", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },  /* 11 */
                   1260:                                                { "allow-x-send-file",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },     /* 12 */
                   1261:                                                { "strip-request-uri",  NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 13 */
                   1262:                                                { "kill-signal",        NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 14 */
                   1263:                                                { "fix-root-scriptname",   NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },  /* 15 */
                   1264: 
                   1265:                                                { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
                   1266:                                        };
                   1267: 
                   1268:                                        if (da_host->type != TYPE_ARRAY) {
                   1269:                                                log_error_write(srv, __FILE__, __LINE__, "ssSBS",
                   1270:                                                                "unexpected type for key:",
                   1271:                                                                "fastcgi.server",
                   1272:                                                                "[", da_host->key, "](string)");
                   1273: 
                   1274:                                                return HANDLER_ERROR;
                   1275:                                        }
                   1276: 
                   1277:                                        host = fastcgi_host_init();
                   1278:                                        buffer_reset(fcgi_mode);
                   1279: 
                   1280:                                        buffer_copy_string_buffer(host->id, da_host->key);
                   1281: 
                   1282:                                        host->check_local  = 1;
                   1283:                                        host->max_procs    = 4;
                   1284:                                        host->mode = FCGI_RESPONDER;
                   1285:                                        host->disable_time = 1;
                   1286:                                        host->break_scriptfilename_for_php = 0;
                   1287:                                        host->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */
                   1288:                                        host->kill_signal = SIGTERM;
                   1289:                                        host->fix_root_path_name = 0;
                   1290: 
                   1291:                                        fcv[0].destination = host->host;
                   1292:                                        fcv[1].destination = host->docroot;
                   1293:                                        fcv[2].destination = fcgi_mode;
                   1294:                                        fcv[3].destination = host->unixsocket;
                   1295:                                        fcv[4].destination = host->bin_path;
                   1296: 
                   1297:                                        fcv[5].destination = &(host->check_local);
                   1298:                                        fcv[6].destination = &(host->port);
                   1299:                                        fcv[7].destination = &(host->max_procs);
                   1300:                                        fcv[8].destination = &(host->disable_time);
                   1301: 
                   1302:                                        fcv[9].destination = host->bin_env;
                   1303:                                        fcv[10].destination = host->bin_env_copy;
                   1304:                                        fcv[11].destination = &(host->break_scriptfilename_for_php);
                   1305:                                        fcv[12].destination = &(host->allow_xsendfile);
                   1306:                                        fcv[13].destination = host->strip_request_uri;
                   1307:                                        fcv[14].destination = &(host->kill_signal);
                   1308:                                        fcv[15].destination = &(host->fix_root_path_name);
                   1309: 
                   1310:                                        if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
                   1311:                                                return HANDLER_ERROR;
                   1312:                                        }
                   1313: 
                   1314:                                        if ((!buffer_is_empty(host->host) || host->port) &&
                   1315:                                            !buffer_is_empty(host->unixsocket)) {
                   1316:                                                log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
                   1317:                                                                "either host/port or socket have to be set in:",
                   1318:                                                                da->key, "= (",
                   1319:                                                                da_ext->key, " => (",
                   1320:                                                                da_host->key, " ( ...");
                   1321: 
                   1322:                                                return HANDLER_ERROR;
                   1323:                                        }
                   1324: 
                   1325:                                        if (!buffer_is_empty(host->unixsocket)) {
                   1326:                                                /* unix domain socket */
                   1327:                                                struct sockaddr_un un;
                   1328: 
                   1329:                                                if (host->unixsocket->used > sizeof(un.sun_path) - 2) {
                   1330:                                                        log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
                   1331:                                                                        "unixsocket is too long in:",
                   1332:                                                                        da->key, "= (",
                   1333:                                                                        da_ext->key, " => (",
                   1334:                                                                        da_host->key, " ( ...");
                   1335: 
                   1336:                                                        return HANDLER_ERROR;
                   1337:                                                }
                   1338:                                        } else {
                   1339:                                                /* tcp/ip */
                   1340: 
                   1341:                                                if (buffer_is_empty(host->host) &&
                   1342:                                                    buffer_is_empty(host->bin_path)) {
                   1343:                                                        log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
                   1344:                                                                        "host or binpath have to be set in:",
                   1345:                                                                        da->key, "= (",
                   1346:                                                                        da_ext->key, " => (",
                   1347:                                                                        da_host->key, " ( ...");
                   1348: 
                   1349:                                                        return HANDLER_ERROR;
                   1350:                                                } else if (host->port == 0) {
                   1351:                                                        log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
                   1352:                                                                        "port has to be set in:",
                   1353:                                                                        da->key, "= (",
                   1354:                                                                        da_ext->key, " => (",
                   1355:                                                                        da_host->key, " ( ...");
                   1356: 
                   1357:                                                        return HANDLER_ERROR;
                   1358:                                                }
                   1359:                                        }
                   1360: 
                   1361:                                        if (!buffer_is_empty(host->bin_path)) {
                   1362:                                                /* a local socket + self spawning */
                   1363:                                                size_t pno;
                   1364: 
                   1365:                                                if (s->debug) {
                   1366:                                                        log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsd",
                   1367:                                                                        "--- fastcgi spawning local",
                   1368:                                                                        "\n\tproc:", host->bin_path,
                   1369:                                                                        "\n\tport:", host->port,
                   1370:                                                                        "\n\tsocket", host->unixsocket,
                   1371:                                                                        "\n\tmax-procs:", host->max_procs);
                   1372:                                                }
                   1373: 
                   1374:                                                for (pno = 0; pno < host->max_procs; pno++) {
                   1375:                                                        fcgi_proc *proc;
                   1376: 
                   1377:                                                        proc = fastcgi_process_init();
                   1378:                                                        proc->id = host->num_procs++;
                   1379:                                                        host->max_id++;
                   1380: 
                   1381:                                                        if (buffer_is_empty(host->unixsocket)) {
                   1382:                                                                proc->port = host->port + pno;
                   1383:                                                        } else {
                   1384:                                                                buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
                   1385:                                                                buffer_append_string_len(proc->unixsocket, CONST_STR_LEN("-"));
                   1386:                                                                buffer_append_long(proc->unixsocket, pno);
                   1387:                                                        }
                   1388: 
                   1389:                                                        if (s->debug) {
                   1390:                                                                log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
                   1391:                                                                                "--- fastcgi spawning",
                   1392:                                                                                "\n\tport:", host->port,
                   1393:                                                                                "\n\tsocket", host->unixsocket,
                   1394:                                                                                "\n\tcurrent:", pno, "/", host->max_procs);
                   1395:                                                        }
                   1396: 
                   1397:                                                        if (fcgi_spawn_connection(srv, p, host, proc)) {
                   1398:                                                                log_error_write(srv, __FILE__, __LINE__, "s",
                   1399:                                                                                "[ERROR]: spawning fcgi failed.");
                   1400:                                                                return HANDLER_ERROR;
                   1401:                                                        }
                   1402: 
                   1403:                                                        fastcgi_status_init(srv, p->statuskey, host, proc);
                   1404: 
                   1405:                                                        proc->next = host->first;
                   1406:                                                        if (host->first)        host->first->prev = proc;
                   1407: 
                   1408:                                                        host->first = proc;
                   1409:                                                }
                   1410:                                        } else {
                   1411:                                                fcgi_proc *proc;
                   1412: 
                   1413:                                                proc = fastcgi_process_init();
                   1414:                                                proc->id = host->num_procs++;
                   1415:                                                host->max_id++;
                   1416:                                                host->active_procs++;
                   1417:                                                proc->state = PROC_STATE_RUNNING;
                   1418: 
                   1419:                                                if (buffer_is_empty(host->unixsocket)) {
                   1420:                                                        proc->port = host->port;
                   1421:                                                } else {
                   1422:                                                        buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
                   1423:                                                }
                   1424: 
                   1425:                                                fastcgi_status_init(srv, p->statuskey, host, proc);
                   1426: 
                   1427:                                                host->first = proc;
                   1428: 
                   1429:                                                host->max_procs = 1;
                   1430:                                        }
                   1431: 
                   1432:                                        if (!buffer_is_empty(fcgi_mode)) {
                   1433:                                                if (strcmp(fcgi_mode->ptr, "responder") == 0) {
                   1434:                                                        host->mode = FCGI_RESPONDER;
                   1435:                                                } else if (strcmp(fcgi_mode->ptr, "authorizer") == 0) {
                   1436:                                                        host->mode = FCGI_AUTHORIZER;
                   1437:                                                        if (buffer_is_empty(host->docroot)) {
                   1438:                                                                log_error_write(srv, __FILE__, __LINE__, "s",
                   1439:                                                                                "ERROR: docroot is required for authorizer mode.");
                   1440:                                                                return HANDLER_ERROR;
                   1441:                                                        }
                   1442:                                                } else {
                   1443:                                                        log_error_write(srv, __FILE__, __LINE__, "sbs",
                   1444:                                                                        "WARNING: unknown fastcgi mode:",
                   1445:                                                                        fcgi_mode, "(ignored, mode set to responder)");
                   1446:                                                }
                   1447:                                        }
                   1448: 
                   1449:                                        /* if extension already exists, take it */
                   1450:                                        fastcgi_extension_insert(s->exts, da_ext->key, host);
                   1451:                                }
                   1452:                        }
                   1453:                }
                   1454:        }
                   1455: 
                   1456:        buffer_free(fcgi_mode);
                   1457: 
                   1458:        return HANDLER_GO_ON;
                   1459: }
                   1460: 
                   1461: static int fcgi_set_state(server *srv, handler_ctx *hctx, fcgi_connection_state_t state) {
                   1462:        hctx->state = state;
                   1463:        hctx->state_timestamp = srv->cur_ts;
                   1464: 
                   1465:        return 0;
                   1466: }
                   1467: 
                   1468: 
                   1469: static void fcgi_connection_close(server *srv, handler_ctx *hctx) {
                   1470:        plugin_data *p;
                   1471:        connection  *con;
                   1472: 
                   1473:        if (NULL == hctx) return;
                   1474: 
                   1475:        p    = hctx->plugin_data;
                   1476:        con  = hctx->remote_conn;
                   1477: 
                   1478:        if (hctx->fd != -1) {
                   1479:                fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
                   1480:                fdevent_unregister(srv->ev, hctx->fd);
                   1481:                close(hctx->fd);
                   1482:                srv->cur_fds--;
                   1483:        }
                   1484: 
                   1485:        if (hctx->host && hctx->proc) {
                   1486:                if (hctx->got_proc) {
                   1487:                        /* after the connect the process gets a load */
                   1488:                        fcgi_proc_load_dec(srv, hctx);
                   1489: 
                   1490:                        if (p->conf.debug) {
                   1491:                                log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
                   1492:                                                "released proc:",
                   1493:                                                "pid:", hctx->proc->pid,
                   1494:                                                "socket:", hctx->proc->connection_name,
                   1495:                                                "load:", hctx->proc->load);
                   1496:                        }
                   1497:                }
                   1498:        }
                   1499: 
                   1500: 
                   1501:        handler_ctx_free(srv, hctx);
                   1502:        con->plugin_ctx[p->id] = NULL;
                   1503: }
                   1504: 
                   1505: static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
                   1506:        plugin_data *p    = hctx->plugin_data;
                   1507: 
                   1508:        /* child died
                   1509:         *
                   1510:         * 1.
                   1511:         *
                   1512:         * connect was ok, connection was accepted
                   1513:         * but the php accept loop checks after the accept if it should die or not.
                   1514:         *
                   1515:         * if yes we can only detect it at a write()
                   1516:         *
                   1517:         * next step is resetting this attemp and setup a connection again
                   1518:         *
                   1519:         * if we have more than 5 reconnects for the same request, die
                   1520:         *
                   1521:         * 2.
                   1522:         *
                   1523:         * we have a connection but the child died by some other reason
                   1524:         *
                   1525:         */
                   1526: 
                   1527:        if (hctx->fd != -1) {
                   1528:                fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
                   1529:                fdevent_unregister(srv->ev, hctx->fd);
                   1530:                close(hctx->fd);
                   1531:                srv->cur_fds--;
                   1532:                hctx->fd = -1;
                   1533:        }
                   1534: 
                   1535:        fcgi_set_state(srv, hctx, FCGI_STATE_INIT);
                   1536: 
                   1537:        hctx->request_id = 0;
                   1538:        hctx->reconnects++;
                   1539: 
                   1540:        if (p->conf.debug > 2) {
                   1541:                if (hctx->proc) {
                   1542:                        log_error_write(srv, __FILE__, __LINE__, "sdb",
                   1543:                                        "release proc for reconnect:",
                   1544:                                        hctx->proc->pid, hctx->proc->connection_name);
                   1545:                } else {
                   1546:                        log_error_write(srv, __FILE__, __LINE__, "sb",
                   1547:                                        "release proc for reconnect:",
                   1548:                                        hctx->host->unixsocket);
                   1549:                }
                   1550:        }
                   1551: 
                   1552:        if (hctx->proc && hctx->got_proc) {
                   1553:                fcgi_proc_load_dec(srv, hctx);
                   1554:        }
                   1555: 
                   1556:        /* perhaps another host gives us more luck */
                   1557:        fcgi_host_reset(srv, hctx);
                   1558: 
                   1559:        return 0;
                   1560: }
                   1561: 
                   1562: 
                   1563: static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d) {
                   1564:        plugin_data *p = p_d;
                   1565: 
                   1566:        fcgi_connection_close(srv, con->plugin_ctx[p->id]);
                   1567: 
                   1568:        return HANDLER_GO_ON;
                   1569: }
                   1570: 
                   1571: 
                   1572: static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
                   1573:        size_t len;
                   1574: 
                   1575:        if (!key || !val) return -1;
                   1576: 
                   1577:        len = key_len + val_len;
                   1578: 
                   1579:        len += key_len > 127 ? 4 : 1;
                   1580:        len += val_len > 127 ? 4 : 1;
                   1581: 
                   1582:        if (env->used + len >= FCGI_MAX_LENGTH) {
                   1583:                /**
                   1584:                 * we can't append more headers, ignore it
                   1585:                 */
                   1586:                return -1;
                   1587:        }
                   1588: 
                   1589:        /**
                   1590:         * field length can be 31bit max
                   1591:         *
                   1592:         * HINT: this can't happen as FCGI_MAX_LENGTH is only 16bit
                   1593:         */
                   1594:        if (key_len > 0x7fffffff) key_len = 0x7fffffff;
                   1595:        if (val_len > 0x7fffffff) val_len = 0x7fffffff;
                   1596: 
                   1597:        buffer_prepare_append(env, len);
                   1598: 
                   1599:        if (key_len > 127) {
                   1600:                env->ptr[env->used++] = ((key_len >> 24) & 0xff) | 0x80;
                   1601:                env->ptr[env->used++] = (key_len >> 16) & 0xff;
                   1602:                env->ptr[env->used++] = (key_len >> 8) & 0xff;
                   1603:                env->ptr[env->used++] = (key_len >> 0) & 0xff;
                   1604:        } else {
                   1605:                env->ptr[env->used++] = (key_len >> 0) & 0xff;
                   1606:        }
                   1607: 
                   1608:        if (val_len > 127) {
                   1609:                env->ptr[env->used++] = ((val_len >> 24) & 0xff) | 0x80;
                   1610:                env->ptr[env->used++] = (val_len >> 16) & 0xff;
                   1611:                env->ptr[env->used++] = (val_len >> 8) & 0xff;
                   1612:                env->ptr[env->used++] = (val_len >> 0) & 0xff;
                   1613:        } else {
                   1614:                env->ptr[env->used++] = (val_len >> 0) & 0xff;
                   1615:        }
                   1616: 
                   1617:        memcpy(env->ptr + env->used, key, key_len);
                   1618:        env->used += key_len;
                   1619:        memcpy(env->ptr + env->used, val, val_len);
                   1620:        env->used += val_len;
                   1621: 
                   1622:        return 0;
                   1623: }
                   1624: 
                   1625: static int fcgi_header(FCGI_Header * header, unsigned char type, size_t request_id, int contentLength, unsigned char paddingLength) {
                   1626:        assert(contentLength <= FCGI_MAX_LENGTH);
                   1627:        
                   1628:        header->version = FCGI_VERSION_1;
                   1629:        header->type = type;
                   1630:        header->requestIdB0 = request_id & 0xff;
                   1631:        header->requestIdB1 = (request_id >> 8) & 0xff;
                   1632:        header->contentLengthB0 = contentLength & 0xff;
                   1633:        header->contentLengthB1 = (contentLength >> 8) & 0xff;
                   1634:        header->paddingLength = paddingLength;
                   1635:        header->reserved = 0;
                   1636: 
                   1637:        return 0;
                   1638: }
                   1639: 
                   1640: typedef enum {
                   1641:        CONNECTION_OK,
                   1642:        CONNECTION_DELAYED, /* retry after event, take same host */
                   1643:        CONNECTION_OVERLOADED, /* disable for 1 second, take another backend */
                   1644:        CONNECTION_DEAD /* disable for 60 seconds, take another backend */
                   1645: } connection_result_t;
                   1646: 
                   1647: static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *hctx) {
                   1648:        struct sockaddr *fcgi_addr;
                   1649:        struct sockaddr_in fcgi_addr_in;
                   1650: #ifdef HAVE_SYS_UN_H
                   1651:        struct sockaddr_un fcgi_addr_un;
                   1652: #endif
                   1653:        socklen_t servlen;
                   1654: 
                   1655:        fcgi_extension_host *host = hctx->host;
                   1656:        fcgi_proc *proc   = hctx->proc;
                   1657:        int fcgi_fd       = hctx->fd;
                   1658: 
                   1659:        memset(&fcgi_addr, 0, sizeof(fcgi_addr));
                   1660: 
                   1661:        if (!buffer_is_empty(proc->unixsocket)) {
                   1662: #ifdef HAVE_SYS_UN_H
                   1663:                /* use the unix domain socket */
                   1664:                fcgi_addr_un.sun_family = AF_UNIX;
                   1665:                strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
                   1666: #ifdef SUN_LEN
                   1667:                servlen = SUN_LEN(&fcgi_addr_un);
                   1668: #else
                   1669:                /* stevens says: */
                   1670:                servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
                   1671: #endif
                   1672:                fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
                   1673: 
                   1674:                if (buffer_is_empty(proc->connection_name)) {
                   1675:                        /* on remote spawing we have to set the connection-name now */
                   1676:                        buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("unix:"));
                   1677:                        buffer_append_string_buffer(proc->connection_name, proc->unixsocket);
                   1678:                }
                   1679: #else
                   1680:                return CONNECTION_DEAD;
                   1681: #endif
                   1682:        } else {
                   1683:                fcgi_addr_in.sin_family = AF_INET;
                   1684:                if (!buffer_is_empty(host->host)) {
                   1685:                        if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) {
                   1686:                                log_error_write(srv, __FILE__, __LINE__, "sbs",
                   1687:                                                "converting IP address failed for", host->host,
                   1688:                                                "\nBe sure to specify an IP address here");
                   1689:        
                   1690:                                return CONNECTION_DEAD;
                   1691:                        }
                   1692:                } else {
                   1693:                        fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
                   1694:                }
                   1695:                fcgi_addr_in.sin_port = htons(proc->port);
                   1696:                servlen = sizeof(fcgi_addr_in);
                   1697: 
                   1698:                fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
                   1699: 
                   1700:                if (buffer_is_empty(proc->connection_name)) {
                   1701:                        /* on remote spawing we have to set the connection-name now */
                   1702:                        buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("tcp:"));
                   1703:                        if (!buffer_is_empty(host->host)) {
                   1704:                                buffer_append_string_buffer(proc->connection_name, host->host);
                   1705:                        } else {
                   1706:                                buffer_append_string_len(proc->connection_name, CONST_STR_LEN("localhost"));
                   1707:                        }
                   1708:                        buffer_append_string_len(proc->connection_name, CONST_STR_LEN(":"));
                   1709:                        buffer_append_long(proc->connection_name, proc->port);
                   1710:                }
                   1711:        }
                   1712: 
                   1713:        if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
                   1714:                if (errno == EINPROGRESS ||
                   1715:                    errno == EALREADY ||
                   1716:                    errno == EINTR) {
                   1717:                        if (hctx->conf.debug > 2) {
                   1718:                                log_error_write(srv, __FILE__, __LINE__, "sb",
                   1719:                                        "connect delayed; will continue later:", proc->connection_name);
                   1720:                        }
                   1721: 
                   1722:                        return CONNECTION_DELAYED;
                   1723:                } else if (errno == EAGAIN) {
                   1724:                        if (hctx->conf.debug) {
                   1725:                                log_error_write(srv, __FILE__, __LINE__, "sbsd",
                   1726:                                        "This means that you have more incoming requests than your FastCGI backend can handle in parallel."
                   1727:                                        "It might help to spawn more FastCGI backends or PHP children; if not, decrease server.max-connections."
                   1728:                                        "The load for this FastCGI backend", proc->connection_name, "is", proc->load);
                   1729:                        }
                   1730: 
                   1731:                        return CONNECTION_OVERLOADED;
                   1732:                } else {
                   1733:                        log_error_write(srv, __FILE__, __LINE__, "sssb",
                   1734:                                        "connect failed:",
                   1735:                                        strerror(errno), "on",
                   1736:                                        proc->connection_name);
                   1737: 
                   1738:                        return CONNECTION_DEAD;
                   1739:                }
                   1740:        }
                   1741: 
                   1742:        hctx->reconnects = 0;
                   1743:        if (hctx->conf.debug > 1) {
                   1744:                log_error_write(srv, __FILE__, __LINE__, "sd",
                   1745:                                "connect succeeded: ", fcgi_fd);
                   1746:        }
                   1747: 
                   1748:        return CONNECTION_OK;
                   1749: }
                   1750: 
                   1751: static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
                   1752:        size_t i;
                   1753: 
                   1754:        for (i = 0; i < con->request.headers->used; i++) {
                   1755:                data_string *ds;
                   1756: 
                   1757:                ds = (data_string *)con->request.headers->data[i];
                   1758: 
                   1759:                if (ds->value->used && ds->key->used) {
                   1760:                        size_t j;
                   1761:                        buffer_reset(srv->tmp_buf);
                   1762: 
                   1763:                        if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
                   1764:                                buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("HTTP_"));
                   1765:                                srv->tmp_buf->used--;
                   1766:                        }
                   1767: 
                   1768:                        buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
                   1769:                        for (j = 0; j < ds->key->used - 1; j++) {
                   1770:                                char c = '_';
                   1771:                                if (light_isalpha(ds->key->ptr[j])) {
                   1772:                                        /* upper-case */
                   1773:                                        c = ds->key->ptr[j] & ~32;
                   1774:                                } else if (light_isdigit(ds->key->ptr[j])) {
                   1775:                                        /* copy */
                   1776:                                        c = ds->key->ptr[j];
                   1777:                                }
                   1778:                                srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
                   1779:                        }
                   1780:                        srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
                   1781: 
                   1782:                        FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)),con);
                   1783:                }
                   1784:        }
                   1785: 
                   1786:        for (i = 0; i < con->environment->used; i++) {
                   1787:                data_string *ds;
                   1788: 
                   1789:                ds = (data_string *)con->environment->data[i];
                   1790: 
                   1791:                if (ds->value->used && ds->key->used) {
                   1792:                        size_t j;
                   1793:                        buffer_reset(srv->tmp_buf);
                   1794: 
                   1795:                        buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
                   1796:                        for (j = 0; j < ds->key->used - 1; j++) {
                   1797:                                char c = '_';
                   1798:                                if (light_isalpha(ds->key->ptr[j])) {
                   1799:                                        /* upper-case */
                   1800:                                        c = ds->key->ptr[j] & ~32;
                   1801:                                } else if (light_isdigit(ds->key->ptr[j])) {
                   1802:                                        /* copy */
                   1803:                                        c = ds->key->ptr[j];
                   1804:                                }
                   1805:                                srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
                   1806:                        }
                   1807:                        srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
                   1808: 
                   1809:                        FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)), con);
                   1810:                }
                   1811:        }
                   1812: 
                   1813:        return 0;
                   1814: }
                   1815: 
                   1816: 
                   1817: static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
                   1818:        FCGI_BeginRequestRecord beginRecord;
                   1819:        FCGI_Header header;
                   1820:        buffer *b;
                   1821: 
                   1822:        char buf[32];
                   1823:        const char *s;
                   1824: #ifdef HAVE_IPV6
                   1825:        char b2[INET6_ADDRSTRLEN + 1];
                   1826: #endif
                   1827: 
                   1828:        plugin_data *p    = hctx->plugin_data;
                   1829:        fcgi_extension_host *host= hctx->host;
                   1830: 
                   1831:        connection *con   = hctx->remote_conn;
                   1832:        server_socket *srv_sock = con->srv_socket;
                   1833: 
                   1834:        sock_addr our_addr;
                   1835:        socklen_t our_addr_len;
                   1836: 
                   1837:        /* send FCGI_BEGIN_REQUEST */
                   1838: 
                   1839:        fcgi_header(&(beginRecord.header), FCGI_BEGIN_REQUEST, request_id, sizeof(beginRecord.body), 0);
                   1840:        beginRecord.body.roleB0 = host->mode;
                   1841:        beginRecord.body.roleB1 = 0;
                   1842:        beginRecord.body.flags = 0;
                   1843:        memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));
                   1844: 
                   1845:        b = chunkqueue_get_append_buffer(hctx->wb);
                   1846: 
                   1847:        buffer_copy_memory(b, (const char *)&beginRecord, sizeof(beginRecord));
                   1848: 
                   1849:        /* send FCGI_PARAMS */
                   1850:        buffer_prepare_copy(p->fcgi_env, 1024);
                   1851: 
                   1852: 
                   1853:        if (buffer_is_empty(con->conf.server_tag)) {
                   1854:                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_DESC)),con)
                   1855:        } else {
                   1856:                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_BUF_LEN(con->conf.server_tag)),con)
                   1857:        }
                   1858: 
                   1859:        if (con->server_name->used) {
                   1860:                size_t len = con->server_name->used - 1;
                   1861: 
                   1862:                if (con->server_name->ptr[0] == '[') {
                   1863:                        const char *colon = strstr(con->server_name->ptr, "]:");
                   1864:                        if (colon) len = (colon + 1) - con->server_name->ptr;
                   1865:                } else {
                   1866:                        const char *colon = strchr(con->server_name->ptr, ':');
                   1867:                        if (colon) len = colon - con->server_name->ptr;
                   1868:                }
                   1869: 
                   1870:                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), con->server_name->ptr, len),con)
                   1871:        } else {
                   1872: #ifdef HAVE_IPV6
                   1873:                s = inet_ntop(srv_sock->addr.plain.sa_family,
                   1874:                              srv_sock->addr.plain.sa_family == AF_INET6 ?
                   1875:                              (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
                   1876:                              (const void *) &(srv_sock->addr.ipv4.sin_addr),
                   1877:                              b2, sizeof(b2)-1);
                   1878: #else
                   1879:                s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
                   1880: #endif
                   1881:                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s)),con)
                   1882:        }
                   1883: 
                   1884:        FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1")),con)
                   1885: 
                   1886:        LI_ltostr(buf,
                   1887: #ifdef HAVE_IPV6
                   1888:               ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
                   1889: #else
                   1890:               ntohs(srv_sock->addr.ipv4.sin_port)
                   1891: #endif
                   1892:               );
                   1893: 
                   1894:        FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf)),con)
                   1895: 
                   1896:        /* get the server-side of the connection to the client */
                   1897:        our_addr_len = sizeof(our_addr);
                   1898: 
                   1899:        if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
                   1900:                s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
                   1901:        } else {
                   1902:                s = inet_ntop_cache_get_ip(srv, &(our_addr));
                   1903:        }
                   1904:        FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s)),con)
                   1905: 
                   1906:        LI_ltostr(buf,
                   1907: #ifdef HAVE_IPV6
                   1908:               ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
                   1909: #else
                   1910:               ntohs(con->dst_addr.ipv4.sin_port)
                   1911: #endif
                   1912:               );
                   1913: 
                   1914:        FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf)),con)
                   1915: 
                   1916:        s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
                   1917:        FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s)),con)
                   1918: 
                   1919:        if (con->request.content_length > 0 && host->mode != FCGI_AUTHORIZER) {
                   1920:                /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
                   1921: 
                   1922:                /* request.content_length < SSIZE_MAX, see request.c */
                   1923:                LI_ltostr(buf, con->request.content_length);
                   1924:                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf)),con)
                   1925:        }
                   1926: 
                   1927:        if (host->mode != FCGI_AUTHORIZER) {
                   1928:                /*
                   1929:                 * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
                   1930:                 * http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html
                   1931:                 * (6.1.14, 6.1.6, 6.1.7)
                   1932:                 * For AUTHORIZER mode these headers should be omitted.
                   1933:                 */
                   1934: 
                   1935:                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path)),con)
                   1936: 
                   1937:                if (!buffer_is_empty(con->request.pathinfo)) {
                   1938:                        FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo)),con)
                   1939: 
                   1940:                        /* PATH_TRANSLATED is only defined if PATH_INFO is set */
                   1941: 
                   1942:                        if (!buffer_is_empty(host->docroot)) {
                   1943:                                buffer_copy_string_buffer(p->path, host->docroot);
                   1944:                        } else {
                   1945:                                buffer_copy_string_buffer(p->path, con->physical.basedir);
                   1946:                        }
                   1947:                        buffer_append_string_buffer(p->path, con->request.pathinfo);
                   1948:                        FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_TRANSLATED"), CONST_BUF_LEN(p->path)),con)
                   1949:                } else {
                   1950:                        FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_STR_LEN("")),con)
                   1951:                }
                   1952:        }
                   1953: 
                   1954:        /*
                   1955:         * SCRIPT_FILENAME and DOCUMENT_ROOT for php. The PHP manual
                   1956:         * http://www.php.net/manual/en/reserved.variables.php
                   1957:         * treatment of PATH_TRANSLATED is different from the one of CGI specs.
                   1958:         * TODO: this code should be checked against cgi.fix_pathinfo php
                   1959:         * parameter.
                   1960:         */
                   1961: 
                   1962:        if (!buffer_is_empty(host->docroot)) {
                   1963:                /*
                   1964:                 * rewrite SCRIPT_FILENAME
                   1965:                 *
                   1966:                 */
                   1967: 
                   1968:                buffer_copy_string_buffer(p->path, host->docroot);
                   1969:                buffer_append_string_buffer(p->path, con->uri.path);
                   1970: 
                   1971:                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path)),con)
                   1972:                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot)),con)
                   1973:        } else {
                   1974:                buffer_copy_string_buffer(p->path, con->physical.path);
                   1975: 
                   1976:                /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself
                   1977:                 *
                   1978:                 * see src/sapi/cgi_main.c, init_request_info()
                   1979:                 */
                   1980:                if (host->break_scriptfilename_for_php) {
                   1981:                        buffer_append_string_buffer(p->path, con->request.pathinfo);
                   1982:                }
                   1983: 
                   1984:                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path)),con)
                   1985:                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir)),con)
                   1986:        }
                   1987: 
                   1988:        if (host->strip_request_uri->used > 1) {
                   1989:                /* we need at least one char to strip off */
                   1990:                /**
                   1991:                 * /app1/index/list
                   1992:                 *
                   1993:                 * stripping /app1 or /app1/ should lead to
                   1994:                 *
                   1995:                 * /index/list
                   1996:                 *
                   1997:                 */
                   1998:                if ('/' != host->strip_request_uri->ptr[host->strip_request_uri->used - 2]) {
                   1999:                        /* fix the user-input to have / as last char */
                   2000:                        buffer_append_string_len(host->strip_request_uri, CONST_STR_LEN("/"));
                   2001:                }
                   2002: 
                   2003:                if (con->request.orig_uri->used >= host->strip_request_uri->used &&
                   2004:                    0 == strncmp(con->request.orig_uri->ptr, host->strip_request_uri->ptr, host->strip_request_uri->used - 1)) {
                   2005:                        /* the left is the same */
                   2006: 
                   2007:                        fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
                   2008:                                        con->request.orig_uri->ptr + (host->strip_request_uri->used - 2),
                   2009:                                        con->request.orig_uri->used - (host->strip_request_uri->used - 2) - 1);
                   2010:                } else {
                   2011:                        FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)),con)
                   2012:                }
                   2013:        } else {
                   2014:                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)),con)
                   2015:        }
                   2016:        if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {
                   2017:                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.uri)),con)
                   2018:        }
                   2019:        if (!buffer_is_empty(con->uri.query)) {
                   2020:                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query)),con)
                   2021:        } else {
                   2022:                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN("")),con)
                   2023:        }
                   2024: 
                   2025:        s = get_http_method_name(con->request.http_method);
                   2026:        FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s)),con)
                   2027:        FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")),con) /* if php is compiled with --force-redirect */
                   2028:        s = get_http_version_name(con->request.http_version);
                   2029:        FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s)),con)
                   2030: 
                   2031:        if (buffer_is_equal_caseless_string(con->uri.scheme, CONST_STR_LEN("https"))) {
                   2032:                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on")),con)
                   2033:        }
                   2034: 
                   2035:        FCGI_ENV_ADD_CHECK(fcgi_env_add_request_headers(srv, con, p), con);
                   2036: 
                   2037:        fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0);
                   2038:        buffer_append_memory(b, (const char *)&header, sizeof(header));
                   2039:        buffer_append_memory(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used);
                   2040: 
                   2041:        fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);
                   2042:        buffer_append_memory(b, (const char *)&header, sizeof(header));
                   2043: 
                   2044:        b->used++; /* add virtual \0 */
                   2045:        hctx->wb->bytes_in += b->used - 1;
                   2046: 
                   2047:        if (con->request.content_length) {
                   2048:                chunkqueue *req_cq = con->request_content_queue;
                   2049:                chunk *req_c;
                   2050:                off_t offset;
                   2051: 
                   2052:                /* something to send ? */
                   2053:                for (offset = 0, req_c = req_cq->first; offset != req_cq->bytes_in; ) {
                   2054:                        off_t weWant = req_cq->bytes_in - offset > FCGI_MAX_LENGTH ? FCGI_MAX_LENGTH : req_cq->bytes_in - offset;
                   2055:                        off_t written = 0;
                   2056:                        off_t weHave = 0;
                   2057: 
                   2058:                        /* we announce toWrite octets
                   2059:                         * now take all the request_content chunks that we need to fill this request
                   2060:                         * */
                   2061: 
                   2062:                        b = chunkqueue_get_append_buffer(hctx->wb);
                   2063:                        fcgi_header(&(header), FCGI_STDIN, request_id, weWant, 0);
                   2064:                        buffer_copy_memory(b, (const char *)&header, sizeof(header));
                   2065:                        hctx->wb->bytes_in += sizeof(header);
                   2066: 
                   2067:                        if (p->conf.debug > 10) {
                   2068:                                log_error_write(srv, __FILE__, __LINE__, "soso", "tosend:", offset, "/", req_cq->bytes_in);
                   2069:                        }
                   2070: 
                   2071:                        for (written = 0; written != weWant; ) {
                   2072:                                if (p->conf.debug > 10) {
                   2073:                                        log_error_write(srv, __FILE__, __LINE__, "soso", "chunk:", written, "/", weWant);
                   2074:                                }
                   2075: 
                   2076:                                switch (req_c->type) {
                   2077:                                case FILE_CHUNK:
                   2078:                                        weHave = req_c->file.length - req_c->offset;
                   2079: 
                   2080:                                        if (weHave > weWant - written) weHave = weWant - written;
                   2081: 
                   2082:                                        if (p->conf.debug > 10) {
                   2083:                                                log_error_write(srv, __FILE__, __LINE__, "soSosOsb",
                   2084:                                                        "sending", weHave, "bytes from (",
                   2085:                                                        req_c->offset, "/", req_c->file.length, ")",
                   2086:                                                        req_c->file.name);
                   2087:                                        }
                   2088: 
                   2089:                                        assert(weHave != 0);
                   2090: 
                   2091:                                        chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave);
                   2092: 
                   2093:                                        req_c->offset += weHave;
                   2094:                                        req_cq->bytes_out += weHave;
                   2095:                                        written += weHave;
                   2096: 
                   2097:                                        hctx->wb->bytes_in += weHave;
                   2098: 
                   2099:                                        /* steal the tempfile
                   2100:                                         *
                   2101:                                         * This is tricky:
                   2102:                                         * - we reference the tempfile from the request-content-queue several times
                   2103:                                         *   if the req_c is larger than FCGI_MAX_LENGTH
                   2104:                                         * - we can't simply cleanup the request-content-queue as soon as possible
                   2105:                                         *   as it would remove the tempfiles
                   2106:                                         * - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last
                   2107:                                         *   referencing chunk of the fastcgi-write-queue
                   2108:                                         *
                   2109:                                         *  */
                   2110: 
                   2111:                                        if (req_c->offset == req_c->file.length) {
                   2112:                                                chunk *c;
                   2113: 
                   2114:                                                if (p->conf.debug > 10) {
                   2115:                                                        log_error_write(srv, __FILE__, __LINE__, "s", "next chunk");
                   2116:                                                }
                   2117:                                                c = hctx->wb->last;
                   2118: 
                   2119:                                                assert(c->type == FILE_CHUNK);
                   2120:                                                assert(req_c->file.is_temp == 1);
                   2121: 
                   2122:                                                c->file.is_temp = 1;
                   2123:                                                req_c->file.is_temp = 0;
                   2124: 
                   2125:                                                chunkqueue_remove_finished_chunks(req_cq);
                   2126: 
                   2127:                                                req_c = req_cq->first;
                   2128:                                        }
                   2129: 
                   2130:                                        break;
                   2131:                                case MEM_CHUNK:
                   2132:                                        /* append to the buffer */
                   2133:                                        weHave = req_c->mem->used - 1 - req_c->offset;
                   2134: 
                   2135:                                        if (weHave > weWant - written) weHave = weWant - written;
                   2136: 
                   2137:                                        buffer_append_memory(b, req_c->mem->ptr + req_c->offset, weHave);
                   2138: 
                   2139:                                        req_c->offset += weHave;
                   2140:                                        req_cq->bytes_out += weHave;
                   2141:                                        written += weHave;
                   2142: 
                   2143:                                        hctx->wb->bytes_in += weHave;
                   2144: 
                   2145:                                        if (req_c->offset == (off_t) req_c->mem->used - 1) {
                   2146:                                                chunkqueue_remove_finished_chunks(req_cq);
                   2147: 
                   2148:                                                req_c = req_cq->first;
                   2149:                                        }
                   2150: 
                   2151:                                        break;
                   2152:                                default:
                   2153:                                        break;
                   2154:                                }
                   2155:                        }
                   2156: 
                   2157:                        b->used++; /* add virtual \0 */
                   2158:                        offset += weWant;
                   2159:                }
                   2160:        }
                   2161: 
                   2162:        b = chunkqueue_get_append_buffer(hctx->wb);
                   2163:        /* terminate STDIN */
                   2164:        fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0);
                   2165:        buffer_copy_memory(b, (const char *)&header, sizeof(header));
                   2166:        b->used++; /* add virtual \0 */
                   2167: 
                   2168:        hctx->wb->bytes_in += sizeof(header);
                   2169: 
                   2170:        return 0;
                   2171: }
                   2172: 
                   2173: static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
                   2174:        char *s, *ns;
                   2175: 
                   2176:        handler_ctx *hctx = con->plugin_ctx[p->id];
                   2177:        fcgi_extension_host *host= hctx->host;
                   2178:        int have_sendfile2 = 0;
                   2179:        off_t sendfile2_content_length = 0;
                   2180: 
                   2181:        UNUSED(srv);
                   2182: 
                   2183:        buffer_copy_string_buffer(p->parse_response, in);
                   2184: 
                   2185:        /* search for \n */
                   2186:        for (s = p->parse_response->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) {
                   2187:                char *key, *value;
                   2188:                int key_len;
                   2189:                data_string *ds = NULL;
                   2190: 
                   2191:                /* a good day. Someone has read the specs and is sending a \r\n to us */
                   2192: 
                   2193:                if (ns > p->parse_response->ptr &&
                   2194:                    *(ns-1) == '\r') {
                   2195:                        *(ns-1) = '\0';
                   2196:                }
                   2197: 
                   2198:                ns[0] = '\0';
                   2199: 
                   2200:                key = s;
                   2201:                if (NULL == (value = strchr(s, ':'))) {
                   2202:                        /* we expect: "<key>: <value>\n" */
                   2203:                        continue;
                   2204:                }
                   2205: 
                   2206:                key_len = value - key;
                   2207: 
                   2208:                value++;
                   2209:                /* strip WS */
                   2210:                while (*value == ' ' || *value == '\t') value++;
                   2211: 
                   2212:                if (host->mode != FCGI_AUTHORIZER ||
                   2213:                    !(con->http_status == 0 ||
                   2214:                      con->http_status == 200)) {
                   2215:                        /* authorizers shouldn't affect the response headers sent back to the client */
                   2216: 
                   2217:                        /* don't forward Status: */
                   2218:                        if (0 != strncasecmp(key, "Status", key_len)) {
                   2219:                                if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
                   2220:                                        ds = data_response_init();
                   2221:                                }
                   2222:                                buffer_copy_string_len(ds->key, key, key_len);
                   2223:                                buffer_copy_string(ds->value, value);
                   2224: 
                   2225:                                array_insert_unique(con->response.headers, (data_unset *)ds);
                   2226:                        }
                   2227:                }
                   2228: 
                   2229:                switch(key_len) {
                   2230:                case 4:
                   2231:                        if (0 == strncasecmp(key, "Date", key_len)) {
                   2232:                                con->parsed_response |= HTTP_DATE;
                   2233:                        }
                   2234:                        break;
                   2235:                case 6:
                   2236:                        if (0 == strncasecmp(key, "Status", key_len)) {
                   2237:                                con->http_status = strtol(value, NULL, 10);
                   2238:                                con->parsed_response |= HTTP_STATUS;
                   2239:                        }
                   2240:                        break;
                   2241:                case 8:
                   2242:                        if (0 == strncasecmp(key, "Location", key_len)) {
                   2243:                                con->parsed_response |= HTTP_LOCATION;
                   2244:                        }
                   2245:                        break;
                   2246:                case 10:
                   2247:                        if (0 == strncasecmp(key, "Connection", key_len)) {
                   2248:                                con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
                   2249:                                con->parsed_response |= HTTP_CONNECTION;
                   2250:                        }
                   2251:                        break;
                   2252:                case 11:
                   2253:                        if (host->allow_xsendfile && 0 == strncasecmp(key, "X-Sendfile2", key_len)&& hctx->send_content_body) {
                   2254:                                char *pos = value;
                   2255:                                have_sendfile2 = 1;
                   2256: 
                   2257:                                while (*pos) {
                   2258:                                        char *filename, *range;
                   2259:                                        stat_cache_entry *sce;
                   2260:                                        off_t begin_range, end_range, range_len;
                   2261: 
                   2262:                                        while (' ' == *pos) pos++;
                   2263:                                        if (!*pos) break;
                   2264: 
                   2265:                                        filename = pos;
                   2266:                                        if (NULL == (range = strchr(pos, ' '))) {
                   2267:                                                /* missing range */
                   2268:                                                if (p->conf.debug) {
                   2269:                                                        log_error_write(srv, __FILE__, __LINE__, "ss", "Couldn't find range after filename:", filename);
                   2270:                                                }
                   2271:                                                return 1;
                   2272:                                        }
                   2273:                                        buffer_copy_string_len(srv->tmp_buf, filename, range - filename);
                   2274: 
                   2275:                                        /* find end of range */
                   2276:                                        for (pos = ++range; *pos && *pos != ' ' && *pos != ','; pos++) ;
                   2277: 
                   2278:                                        buffer_urldecode_path(srv->tmp_buf);
                   2279:                                        if (HANDLER_ERROR == stat_cache_get_entry(srv, con, srv->tmp_buf, &sce)) {
                   2280:                                                if (p->conf.debug) {
                   2281:                                                        log_error_write(srv, __FILE__, __LINE__, "sb",
                   2282:                                                                "send-file error: couldn't get stat_cache entry for X-Sendfile2:",
                   2283:                                                                srv->tmp_buf);
                   2284:                                                }
                   2285:                                                return 1;
                   2286:                                        } else if (!S_ISREG(sce->st.st_mode)) {
                   2287:                                                if (p->conf.debug) {
                   2288:                                                        log_error_write(srv, __FILE__, __LINE__, "sb",
                   2289:                                                                "send-file error: wrong filetype for X-Sendfile2:",
                   2290:                                                                srv->tmp_buf);
                   2291:                                                }
                   2292:                                                return 1;
                   2293:                                        }
                   2294:                                        /* found the file */
                   2295: 
                   2296:                                        /* parse range */
                   2297:                                        begin_range = 0; end_range = sce->st.st_size - 1;
                   2298:                                        {
                   2299:                                                char *rpos = NULL;
                   2300:                                                errno = 0;
                   2301:                                                begin_range = strtoll(range, &rpos, 10);
                   2302:                                                if (errno != 0 || begin_range < 0 || rpos == range) goto range_failed;
                   2303:                                                if ('-' != *rpos++) goto range_failed;
                   2304:                                                if (rpos != pos) {
                   2305:                                                        range = rpos;
                   2306:                                                        end_range = strtoll(range, &rpos, 10);
                   2307:                                                        if (errno != 0 || end_range < 0 || rpos == range) goto range_failed;
                   2308:                                                }
                   2309:                                                if (rpos != pos) goto range_failed;
                   2310: 
                   2311:                                                goto range_success;
                   2312: 
                   2313: range_failed:
                   2314:                                                if (p->conf.debug) {
                   2315:                                                        log_error_write(srv, __FILE__, __LINE__, "ss", "Couldn't decode range after filename:", filename);
                   2316:                                                }
                   2317:                                                return 1;
                   2318: 
                   2319: range_success: ;
                   2320:                                        }
                   2321: 
                   2322:                                        /* no parameters accepted */
                   2323: 
                   2324:                                        while (*pos == ' ') pos++;
                   2325:                                        if (*pos != '\0' && *pos != ',') return 1;
                   2326: 
                   2327:                                        range_len = end_range - begin_range + 1;
                   2328:                                        if (range_len < 0) return 1;
                   2329:                                        if (range_len != 0) {
                   2330:                                                http_chunk_append_file(srv, con, srv->tmp_buf, begin_range, range_len);
                   2331:                                        }
                   2332:                                        sendfile2_content_length += range_len;
                   2333: 
                   2334:                                        if (*pos == ',') pos++;
                   2335:                                }
                   2336:                        }
                   2337:                        break;
                   2338:                case 14:
                   2339:                        if (0 == strncasecmp(key, "Content-Length", key_len)) {
                   2340:                                con->response.content_length = strtol(value, NULL, 10);
                   2341:                                con->parsed_response |= HTTP_CONTENT_LENGTH;
                   2342: 
                   2343:                                if (con->response.content_length < 0) con->response.content_length = 0;
                   2344:                        }
                   2345:                        break;
                   2346:                default:
                   2347:                        break;
                   2348:                }
                   2349:        }
                   2350: 
                   2351:        if (have_sendfile2) {
                   2352:                data_string *dcls;
                   2353: 
                   2354:                hctx->send_content_body = 0;
                   2355:                joblist_append(srv, con);
                   2356: 
                   2357:                /* fix content-length */
                   2358:                if (NULL == (dcls = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
                   2359:                        dcls = data_response_init();
                   2360:                }
                   2361: 
                   2362:                buffer_copy_string_len(dcls->key, "Content-Length", sizeof("Content-Length")-1);
                   2363:                buffer_copy_off_t(dcls->value, sendfile2_content_length);
                   2364:                dcls = (data_string*) array_replace(con->response.headers, (data_unset *)dcls);
                   2365:                if (dcls) dcls->free((data_unset*)dcls);
                   2366: 
                   2367:                con->parsed_response |= HTTP_CONTENT_LENGTH;
                   2368:                con->response.content_length = sendfile2_content_length;
                   2369:        }
                   2370: 
                   2371:        /* CGI/1.1 rev 03 - 7.2.1.2 */
                   2372:        if ((con->parsed_response & HTTP_LOCATION) &&
                   2373:            !(con->parsed_response & HTTP_STATUS)) {
                   2374:                con->http_status = 302;
                   2375:        }
                   2376: 
                   2377:        return 0;
                   2378: }
                   2379: 
                   2380: typedef struct {
                   2381:        buffer  *b;
                   2382:        size_t   len;
                   2383:        int      type;
                   2384:        int      padding;
                   2385:        size_t   request_id;
                   2386: } fastcgi_response_packet;
                   2387: 
                   2388: static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_packet *packet) {
                   2389:        chunk * c;
                   2390:        size_t offset;
                   2391:        size_t toread;
                   2392:        FCGI_Header *header;
                   2393: 
                   2394:        if (!hctx->rb->first) return -1;
                   2395: 
                   2396:        packet->b = buffer_init();
                   2397:        packet->len = 0;
                   2398:        packet->type = 0;
                   2399:        packet->padding = 0;
                   2400:        packet->request_id = 0;
                   2401: 
                   2402:        offset = 0; toread = 8;
                   2403:        /* get at least the FastCGI header */
                   2404:        for (c = hctx->rb->first; c; c = c->next) {
                   2405:                size_t weHave = c->mem->used - c->offset - 1;
                   2406: 
                   2407:                if (weHave > toread) weHave = toread;
                   2408: 
                   2409:                if (packet->b->used == 0) {
                   2410:                        buffer_copy_string_len(packet->b, c->mem->ptr + c->offset, weHave);
                   2411:                } else {
                   2412:                        buffer_append_string_len(packet->b, c->mem->ptr + c->offset, weHave);
                   2413:                }
                   2414:                toread -= weHave;
                   2415:                offset = weHave; /* skip offset bytes in chunk for "real" data */
                   2416: 
                   2417:                if (0 == toread) break;
                   2418:        }
                   2419: 
                   2420:        if ((packet->b->used == 0) ||
                   2421:            (packet->b->used - 1 < sizeof(FCGI_Header))) {
                   2422:                /* no header */
                   2423:                buffer_free(packet->b);
                   2424: 
                   2425:                if (hctx->plugin_data->conf.debug) {
                   2426:                        log_error_write(srv, __FILE__, __LINE__, "sdsds", "FastCGI: header too small:", packet->b->used, "bytes <", sizeof(FCGI_Header), "bytes, waiting for more data");
                   2427:                }
                   2428:                return -1;
                   2429:        }
                   2430: 
                   2431:        /* we have at least a header, now check how much me have to fetch */
                   2432:        header = (FCGI_Header *)(packet->b->ptr);
                   2433: 
                   2434:        packet->len = (header->contentLengthB0 | (header->contentLengthB1 << 8)) + header->paddingLength;
                   2435:        packet->request_id = (header->requestIdB0 | (header->requestIdB1 << 8));
                   2436:        packet->type = header->type;
                   2437:        packet->padding = header->paddingLength;
                   2438: 
                   2439:        /* ->b should only be the content */
                   2440:        buffer_copy_string_len(packet->b, CONST_STR_LEN("")); /* used == 1 */
                   2441: 
                   2442:        if (packet->len) {
                   2443:                /* copy the content */
                   2444:                for (; c && (packet->b->used < packet->len + 1); c = c->next) {
                   2445:                        size_t weWant = packet->len - (packet->b->used - 1);
                   2446:                        size_t weHave = c->mem->used - c->offset - offset - 1;
                   2447: 
                   2448:                        if (weHave > weWant) weHave = weWant;
                   2449: 
                   2450:                        buffer_append_string_len(packet->b, c->mem->ptr + c->offset + offset, weHave);
                   2451: 
                   2452:                        /* we only skipped the first bytes as they belonged to the fcgi header */
                   2453:                        offset = 0;
                   2454:                }
                   2455: 
                   2456:                if (packet->b->used < packet->len + 1) {
                   2457:                        /* we didn't get the full packet */
                   2458: 
                   2459:                        buffer_free(packet->b);
                   2460:                        return -1;
                   2461:                }
                   2462: 
                   2463:                packet->b->used -= packet->padding;
                   2464:                packet->b->ptr[packet->b->used - 1] = '\0';
                   2465:        }
                   2466: 
                   2467:        /* tag the chunks as read */
                   2468:        toread = packet->len + sizeof(FCGI_Header);
                   2469:        for (c = hctx->rb->first; c && toread; c = c->next) {
                   2470:                if (c->mem->used - c->offset - 1 <= toread) {
                   2471:                        /* we read this whole buffer, move it to unused */
                   2472:                        toread -= c->mem->used - c->offset - 1;
                   2473:                        c->offset = c->mem->used - 1; /* everthing has been written */
                   2474:                } else {
                   2475:                        c->offset += toread;
                   2476:                        toread = 0;
                   2477:                }
                   2478:        }
                   2479: 
                   2480:        chunkqueue_remove_finished_chunks(hctx->rb);
                   2481: 
                   2482:        return 0;
                   2483: }
                   2484: 
                   2485: static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
                   2486:        int fin = 0;
                   2487:        int toread;
                   2488:        ssize_t r;
                   2489: 
                   2490:        plugin_data *p    = hctx->plugin_data;
                   2491:        connection *con   = hctx->remote_conn;
                   2492:        int fcgi_fd       = hctx->fd;
                   2493:        fcgi_extension_host *host= hctx->host;
                   2494:        fcgi_proc *proc   = hctx->proc;
                   2495: 
                   2496:        /*
                   2497:         * check how much we have to read
                   2498:         */
                   2499:        if (ioctl(hctx->fd, FIONREAD, &toread)) {
                   2500:                if (errno == EAGAIN) return 0;
                   2501:                log_error_write(srv, __FILE__, __LINE__, "sd",
                   2502:                                "unexpected end-of-file (perhaps the fastcgi process died):",
                   2503:                                fcgi_fd);
                   2504:                return -1;
                   2505:        }
                   2506: 
                   2507:        /* init read-buffer */
                   2508: 
                   2509:        if (toread > 0) {
                   2510:                buffer *b;
                   2511:                chunk *cq_first = hctx->rb->first;
                   2512:                chunk *cq_last = hctx->rb->last;
                   2513: 
                   2514:                b = chunkqueue_get_append_buffer(hctx->rb);
                   2515:                buffer_prepare_copy(b, toread + 1);
                   2516: 
                   2517:                /* append to read-buffer */
                   2518:                if (-1 == (r = read(hctx->fd, b->ptr, toread))) {
                   2519:                        if (errno == EAGAIN) {
                   2520:                                /* roll back the last chunk allocation,
                   2521:                                    and continue on next iteration        */
                   2522:                                buffer_free(hctx->rb->last->mem);
                   2523:                                free(hctx->rb->last);
                   2524:                                hctx->rb->first = cq_first;
                   2525:                                hctx->rb->last = cq_last;
                   2526:                                return 0;
                   2527:                        }
                   2528:                        log_error_write(srv, __FILE__, __LINE__, "sds",
                   2529:                                        "unexpected end-of-file (perhaps the fastcgi process died):",
                   2530:                                        fcgi_fd, strerror(errno));
                   2531:                        return -1;
                   2532:                }
                   2533: 
                   2534:                /* this should be catched by the b > 0 above */
                   2535:                assert(r);
                   2536: 
                   2537:                b->used = r + 1; /* one extra for the fake \0 */
                   2538:                b->ptr[b->used - 1] = '\0';
                   2539:        } else {
                   2540:                log_error_write(srv, __FILE__, __LINE__, "ssdsb",
                   2541:                                "unexpected end-of-file (perhaps the fastcgi process died):",
                   2542:                                "pid:", proc->pid,
                   2543:                                "socket:", proc->connection_name);
                   2544: 
                   2545:                return -1;
                   2546:        }
                   2547: 
                   2548:        /*
                   2549:         * parse the fastcgi packets and forward the content to the write-queue
                   2550:         *
                   2551:         */
                   2552:        while (fin == 0) {
                   2553:                fastcgi_response_packet packet;
                   2554: 
                   2555:                /* check if we have at least one packet */
                   2556:                if (0 != fastcgi_get_packet(srv, hctx, &packet)) {
                   2557:                        /* no full packet */
                   2558:                        break;
                   2559:                }
                   2560: 
                   2561:                switch(packet.type) {
                   2562:                case FCGI_STDOUT:
                   2563:                        if (packet.len == 0) break;
                   2564: 
                   2565:                        /* is the header already finished */
                   2566:                        if (0 == con->file_started) {
                   2567:                                char *c;
                   2568:                                size_t blen;
                   2569:                                data_string *ds;
                   2570: 
                   2571:                                /* search for header terminator
                   2572:                                 *
                   2573:                                 * if we start with \r\n check if last packet terminated with \r\n
                   2574:                                 * if we start with \n check if last packet terminated with \n
                   2575:                                 * search for \r\n\r\n
                   2576:                                 * search for \n\n
                   2577:                                 */
                   2578: 
                   2579:                                if (hctx->response_header->used == 0) {
                   2580:                                        buffer_copy_string_buffer(hctx->response_header, packet.b);
                   2581:                                } else {
                   2582:                                        buffer_append_string_buffer(hctx->response_header, packet.b);
                   2583:                                }
                   2584: 
                   2585:                                if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\r\n\r\n")))) {
                   2586:                                        blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 4;
                   2587:                                        hctx->response_header->used = (c - hctx->response_header->ptr) + 3;
                   2588:                                        c += 4; /* point the the start of the response */
                   2589:                                } else if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\n\n")))) {
                   2590:                                        blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 2;
                   2591:                                        hctx->response_header->used = c - hctx->response_header->ptr + 2;
                   2592:                                        c += 2; /* point the the start of the response */
                   2593:                                } else {
                   2594:                                        /* no luck, no header found */
                   2595:                                        break;
                   2596:                                }
                   2597: 
                   2598:                                /* parse the response header */
                   2599:                                if (fcgi_response_parse(srv, con, p, hctx->response_header)) {
                   2600:                                        con->http_status = 502;
                   2601:                                        hctx->send_content_body = 0;
                   2602:                                        con->file_started = 1;
                   2603:                                        break;
                   2604:                                }
                   2605: 
                   2606:                                con->file_started = 1;
                   2607: 
                   2608:                                if (host->mode == FCGI_AUTHORIZER &&
                   2609:                                    (con->http_status == 0 ||
                   2610:                                     con->http_status == 200)) {
                   2611:                                        /* a authorizer with approved the static request, ignore the content here */
                   2612:                                        hctx->send_content_body = 0;
                   2613:                                }
                   2614: 
                   2615:                                if (host->allow_xsendfile && hctx->send_content_body &&
                   2616:                                    (NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file"))
                   2617:                                          || NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-Sendfile")))) {
                   2618:                                        stat_cache_entry *sce;
                   2619: 
                   2620:                                        if (HANDLER_ERROR != stat_cache_get_entry(srv, con, ds->value, &sce)) {
                   2621:                                                data_string *dcls;
                   2622:                                                if (NULL == (dcls = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
                   2623:                                                        dcls = data_response_init();
                   2624:                                                }
                   2625:                                                /* found */
                   2626:                                                http_chunk_append_file(srv, con, ds->value, 0, sce->st.st_size);
                   2627:                                                hctx->send_content_body = 0; /* ignore the content */
                   2628:                                                joblist_append(srv, con);
                   2629: 
                   2630:                                                buffer_copy_string_len(dcls->key, "Content-Length", sizeof("Content-Length")-1);
                   2631:                                                buffer_copy_off_t(dcls->value, sce->st.st_size);
                   2632:                                                dcls = (data_string*) array_replace(con->response.headers, (data_unset *)dcls);
                   2633:                                                if (dcls) dcls->free((data_unset*)dcls);
                   2634: 
                   2635:                                                con->parsed_response |= HTTP_CONTENT_LENGTH;
                   2636:                                                con->response.content_length = sce->st.st_size;
                   2637:                                        } else {
                   2638:                                                log_error_write(srv, __FILE__, __LINE__, "sb",
                   2639:                                                        "send-file error: couldn't get stat_cache entry for:",
                   2640:                                                        ds->value);
                   2641:                                                con->http_status = 502;
                   2642:                                                hctx->send_content_body = 0;
                   2643:                                                con->file_started = 1;
                   2644:                                                break;
                   2645:                                        }
                   2646:                                }
                   2647: 
                   2648: 
                   2649:                                if (hctx->send_content_body && blen > 1) {
                   2650:                                        /* enable chunked-transfer-encoding */
                   2651:                                        if (con->request.http_version == HTTP_VERSION_1_1 &&
                   2652:                                            !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
                   2653:                                                con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
                   2654:                                        }
                   2655: 
                   2656:                                        http_chunk_append_mem(srv, con, c, blen);
                   2657:                                        joblist_append(srv, con);
                   2658:                                }
                   2659:                        } else if (hctx->send_content_body && packet.b->used > 1) {
                   2660:                                if (con->request.http_version == HTTP_VERSION_1_1 &&
                   2661:                                    !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
                   2662:                                        /* enable chunked-transfer-encoding */
                   2663:                                        con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
                   2664:                                }
                   2665: 
                   2666:                                http_chunk_append_mem(srv, con, packet.b->ptr, packet.b->used);
                   2667:                                joblist_append(srv, con);
                   2668:                        }
                   2669:                        break;
                   2670:                case FCGI_STDERR:
                   2671:                        if (packet.len == 0) break;
                   2672: 
                   2673:                        log_error_write_multiline_buffer(srv, __FILE__, __LINE__, packet.b, "s",
                   2674:                                        "FastCGI-stderr:");
                   2675: 
                   2676:                        break;
                   2677:                case FCGI_END_REQUEST:
                   2678:                        con->file_finished = 1;
                   2679: 
                   2680:                        if (host->mode != FCGI_AUTHORIZER ||
                   2681:                            !(con->http_status == 0 ||
                   2682:                              con->http_status == 200)) {
                   2683:                                /* send chunk-end if necessary */
                   2684:                                http_chunk_append_mem(srv, con, NULL, 0);
                   2685:                                joblist_append(srv, con);
                   2686:                        }
                   2687: 
                   2688:                        fin = 1;
                   2689:                        break;
                   2690:                default:
                   2691:                        log_error_write(srv, __FILE__, __LINE__, "sd",
                   2692:                                        "FastCGI: header.type not handled: ", packet.type);
                   2693:                        break;
                   2694:                }
                   2695:                buffer_free(packet.b);
                   2696:        }
                   2697: 
                   2698:        return fin;
                   2699: }
                   2700: 
                   2701: static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_host *host) {
                   2702:        fcgi_proc *proc;
                   2703: 
                   2704:        for (proc = host->first; proc; proc = proc->next) {
                   2705:                int status;
                   2706: 
                   2707:                if (p->conf.debug > 2) {
                   2708:                        log_error_write(srv, __FILE__, __LINE__,  "sbdddd",
                   2709:                                        "proc:",
                   2710:                                        proc->connection_name,
                   2711:                                        proc->state,
                   2712:                                        proc->is_local,
                   2713:                                        proc->load,
                   2714:                                        proc->pid);
                   2715:                }
                   2716: 
                   2717:                /*
                   2718:                 * if the remote side is overloaded, we check back after <n> seconds
                   2719:                 *
                   2720:                 */
                   2721:                switch (proc->state) {
                   2722:                case PROC_STATE_KILLED:
                   2723:                case PROC_STATE_UNSET:
                   2724:                        /* this should never happen as long as adaptive spawing is disabled */
                   2725:                        assert(0);
                   2726: 
                   2727:                        break;
                   2728:                case PROC_STATE_RUNNING:
                   2729:                        break;
                   2730:                case PROC_STATE_OVERLOADED:
                   2731:                        if (srv->cur_ts <= proc->disabled_until) break;
                   2732: 
                   2733:                        proc->state = PROC_STATE_RUNNING;
                   2734:                        host->active_procs++;
                   2735: 
                   2736:                        log_error_write(srv, __FILE__, __LINE__,  "sbdb",
                   2737:                                        "fcgi-server re-enabled:",
                   2738:                                        host->host, host->port,
                   2739:                                        host->unixsocket);
                   2740:                        break;
                   2741:                case PROC_STATE_DIED_WAIT_FOR_PID:
                   2742:                        /* non-local procs don't have PIDs to wait for */
                   2743:                        if (!proc->is_local) {
                   2744:                                proc->state = PROC_STATE_DIED;
                   2745:                        } else {
                   2746:                                /* the child should not terminate at all */
                   2747: 
                   2748:                                for ( ;; ) {
                   2749:                                        switch(waitpid(proc->pid, &status, WNOHANG)) {
                   2750:                                        case 0:
                   2751:                                                /* child is still alive */
                   2752:                                                if (srv->cur_ts <= proc->disabled_until) break;
                   2753: 
                   2754:                                                proc->state = PROC_STATE_RUNNING;
                   2755:                                                host->active_procs++;
                   2756: 
                   2757:                                                log_error_write(srv, __FILE__, __LINE__,  "sbdb",
                   2758:                                                        "fcgi-server re-enabled:",
                   2759:                                                        host->host, host->port,
                   2760:                                                        host->unixsocket);
                   2761:                                                break;
                   2762:                                        case -1:
                   2763:                                                if (errno == EINTR) continue;
                   2764: 
                   2765:                                                log_error_write(srv, __FILE__, __LINE__, "sd",
                   2766:                                                        "child died somehow, waitpid failed:",
                   2767:                                                        errno);
                   2768:                                                proc->state = PROC_STATE_DIED;
                   2769:                                                break;
                   2770:                                        default:
                   2771:                                                if (WIFEXITED(status)) {
                   2772: #if 0
                   2773:                                                        log_error_write(srv, __FILE__, __LINE__, "sdsd",
                   2774:                                                                "child exited, pid:", proc->pid,
                   2775:                                                                "status:", WEXITSTATUS(status));
                   2776: #endif
                   2777:                                                } else if (WIFSIGNALED(status)) {
                   2778:                                                        log_error_write(srv, __FILE__, __LINE__, "sd",
                   2779:                                                                "child signaled:",
                   2780:                                                                WTERMSIG(status));
                   2781:                                                } else {
                   2782:                                                        log_error_write(srv, __FILE__, __LINE__, "sd",
                   2783:                                                                "child died somehow:",
                   2784:                                                                status);
                   2785:                                                }
                   2786: 
                   2787:                                                proc->state = PROC_STATE_DIED;
                   2788:                                                break;
                   2789:                                        }
                   2790:                                        break;
                   2791:                                }
                   2792:                        }
                   2793: 
                   2794:                        /* fall through if we have a dead proc now */
                   2795:                        if (proc->state != PROC_STATE_DIED) break;
                   2796: 
                   2797:                case PROC_STATE_DIED:
                   2798:                        /* local procs get restarted by us,
                   2799:                         * remote ones hopefully by the admin */
                   2800: 
                   2801:                        if (!buffer_is_empty(host->bin_path)) {
                   2802:                                /* we still have connections bound to this proc,
                   2803:                                 * let them terminate first */
                   2804:                                if (proc->load != 0) break;
                   2805: 
                   2806:                                /* restart the child */
                   2807: 
                   2808:                                if (p->conf.debug) {
                   2809:                                        log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
                   2810:                                                        "--- fastcgi spawning",
                   2811:                                                        "\n\tsocket", proc->connection_name,
                   2812:                                                        "\n\tcurrent:", 1, "/", host->max_procs);
                   2813:                                }
                   2814: 
                   2815:                                if (fcgi_spawn_connection(srv, p, host, proc)) {
                   2816:                                        log_error_write(srv, __FILE__, __LINE__, "s",
                   2817:                                                        "ERROR: spawning fcgi failed.");
                   2818:                                        return HANDLER_ERROR;
                   2819:                                }
                   2820:                        } else {
                   2821:                                if (srv->cur_ts <= proc->disabled_until) break;
                   2822: 
                   2823:                                proc->state = PROC_STATE_RUNNING;
                   2824:                                host->active_procs++;
                   2825: 
                   2826:                                log_error_write(srv, __FILE__, __LINE__,  "sb",
                   2827:                                                "fcgi-server re-enabled:",
                   2828:                                                proc->connection_name);
                   2829:                        }
                   2830:                        break;
                   2831:                }
                   2832:        }
                   2833: 
                   2834:        return 0;
                   2835: }
                   2836: 
                   2837: static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
                   2838:        plugin_data *p    = hctx->plugin_data;
                   2839:        fcgi_extension_host *host= hctx->host;
                   2840:        connection *con   = hctx->remote_conn;
                   2841:        fcgi_proc  *proc;
                   2842: 
                   2843:        int ret;
                   2844: 
                   2845:        /* sanity check:
                   2846:         *  - host != NULL
                   2847:         *  - either:
                   2848:         *     - tcp socket (do not check host->host->uses, as it may be not set which means INADDR_LOOPBACK)
                   2849:         *     - unix socket
                   2850:         */
                   2851:        if (!host) {
                   2852:                log_error_write(srv, __FILE__, __LINE__, "s", "fatal error: host = NULL");
                   2853:                return HANDLER_ERROR;
                   2854:        }
                   2855:        if ((!host->port && !host->unixsocket->used)) {
                   2856:                log_error_write(srv, __FILE__, __LINE__, "s", "fatal error: neither host->port nor host->unixsocket is set");
                   2857:                return HANDLER_ERROR;
                   2858:        }
                   2859: 
                   2860:        /* we can't handle this in the switch as we have to fall through in it */
                   2861:        if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
                   2862:                int socket_error;
                   2863:                socklen_t socket_error_len = sizeof(socket_error);
                   2864: 
                   2865:                /* try to finish the connect() */
                   2866:                if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
                   2867:                        log_error_write(srv, __FILE__, __LINE__, "ss",
                   2868:                                        "getsockopt failed:", strerror(errno));
                   2869: 
                   2870:                        fcgi_host_disable(srv, hctx);
                   2871: 
                   2872:                        return HANDLER_ERROR;
                   2873:                }
                   2874:                if (socket_error != 0) {
                   2875:                        if (!hctx->proc->is_local || p->conf.debug) {
                   2876:                                /* local procs get restarted */
                   2877: 
                   2878:                                log_error_write(srv, __FILE__, __LINE__, "sssb",
                   2879:                                                "establishing connection failed:", strerror(socket_error),
                   2880:                                                "socket:", hctx->proc->connection_name);
                   2881:                        }
                   2882: 
                   2883:                        fcgi_host_disable(srv, hctx);
                   2884:                        log_error_write(srv, __FILE__, __LINE__, "sdssdsd",
                   2885:                                "backend is overloaded; we'll disable it for", hctx->host->disable_time, "seconds and send the request to another backend instead:",
                   2886:                                "reconnects:", hctx->reconnects,
                   2887:                                "load:", host->load);
                   2888: 
                   2889:                        fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
                   2890:                        buffer_append_string_len(p->statuskey, CONST_STR_LEN(".died"));
                   2891: 
                   2892:                        status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
                   2893: 
                   2894:                        return HANDLER_ERROR;
                   2895:                }
                   2896:                /* go on with preparing the request */
                   2897:                hctx->state = FCGI_STATE_PREPARE_WRITE;
                   2898:        }
                   2899: 
                   2900: 
                   2901:        switch(hctx->state) {
                   2902:        case FCGI_STATE_CONNECT_DELAYED:
                   2903:                /* should never happen */
                   2904:                break;
                   2905:        case FCGI_STATE_INIT:
                   2906:                /* do we have a running process for this host (max-procs) ? */
                   2907:                hctx->proc = NULL;
                   2908: 
                   2909:                for (proc = hctx->host->first;
                   2910:                     proc && proc->state != PROC_STATE_RUNNING;
                   2911:                     proc = proc->next);
                   2912: 
                   2913:                /* all children are dead */
                   2914:                if (proc == NULL) {
                   2915:                        hctx->fde_ndx = -1;
                   2916: 
                   2917:                        return HANDLER_ERROR;
                   2918:                }
                   2919: 
                   2920:                hctx->proc = proc;
                   2921: 
                   2922:                /* check the other procs if they have a lower load */
                   2923:                for (proc = proc->next; proc; proc = proc->next) {
                   2924:                        if (proc->state != PROC_STATE_RUNNING) continue;
                   2925:                        if (proc->load < hctx->proc->load) hctx->proc = proc;
                   2926:                }
                   2927: 
                   2928:                ret = host->unixsocket->used ? AF_UNIX : AF_INET;
                   2929: 
                   2930:                if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
                   2931:                        if (errno == EMFILE ||
                   2932:                            errno == EINTR) {
                   2933:                                log_error_write(srv, __FILE__, __LINE__, "sd",
                   2934:                                                "wait for fd at connection:", con->fd);
                   2935: 
                   2936:                                return HANDLER_WAIT_FOR_FD;
                   2937:                        }
                   2938: 
                   2939:                        log_error_write(srv, __FILE__, __LINE__, "ssdd",
                   2940:                                        "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
                   2941:                        return HANDLER_ERROR;
                   2942:                }
                   2943:                hctx->fde_ndx = -1;
                   2944: 
                   2945:                srv->cur_fds++;
                   2946: 
                   2947:                fdevent_register(srv->ev, hctx->fd, fcgi_handle_fdevent, hctx);
                   2948: 
                   2949:                if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
                   2950:                        log_error_write(srv, __FILE__, __LINE__, "ss",
                   2951:                                        "fcntl failed:", strerror(errno));
                   2952: 
                   2953:                        return HANDLER_ERROR;
                   2954:                }
                   2955: 
                   2956:                if (hctx->proc->is_local) {
                   2957:                        hctx->pid = hctx->proc->pid;
                   2958:                }
                   2959: 
                   2960:                switch (fcgi_establish_connection(srv, hctx)) {
                   2961:                case CONNECTION_DELAYED:
                   2962:                        /* connection is in progress, wait for an event and call getsockopt() below */
                   2963: 
                   2964:                        fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
                   2965: 
                   2966:                        fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT_DELAYED);
                   2967:                        return HANDLER_WAIT_FOR_EVENT;
                   2968:                case CONNECTION_OVERLOADED:
                   2969:                        /* cool down the backend, it is overloaded
                   2970:                         * -> EAGAIN */
                   2971: 
                   2972:                        if (hctx->host->disable_time) {
                   2973:                                log_error_write(srv, __FILE__, __LINE__, "sdssdsd",
                   2974:                                        "backend is overloaded; we'll disable it for", hctx->host->disable_time, "seconds and send the request to another backend instead:",
                   2975:                                        "reconnects:", hctx->reconnects,
                   2976:                                        "load:", host->load);
                   2977: 
                   2978:                                hctx->proc->disabled_until = srv->cur_ts + hctx->host->disable_time;
                   2979:                                if (hctx->proc->state == PROC_STATE_RUNNING) hctx->host->active_procs--;
                   2980:                                hctx->proc->state = PROC_STATE_OVERLOADED;
                   2981:                        }
                   2982: 
                   2983:                        fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
                   2984:                        buffer_append_string_len(p->statuskey, CONST_STR_LEN(".overloaded"));
                   2985: 
                   2986:                        status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
                   2987: 
                   2988:                        return HANDLER_ERROR;
                   2989:                case CONNECTION_DEAD:
                   2990:                        /* we got a hard error from the backend like
                   2991:                         * - ECONNREFUSED for tcp-ip sockets
                   2992:                         * - ENOENT for unix-domain-sockets
                   2993:                         *
                   2994:                         * for check if the host is back in hctx->host->disable_time seconds
                   2995:                         *  */
                   2996: 
                   2997:                        fcgi_host_disable(srv, hctx);
                   2998: 
                   2999:                        log_error_write(srv, __FILE__, __LINE__, "sdssdsd",
                   3000:                                "backend died; we'll disable it for", hctx->host->disable_time, "seconds and send the request to another backend instead:",
                   3001:                                "reconnects:", hctx->reconnects,
                   3002:                                "load:", host->load);
                   3003: 
                   3004:                        fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
                   3005:                        buffer_append_string_len(p->statuskey, CONST_STR_LEN(".died"));
                   3006: 
                   3007:                        status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
                   3008: 
                   3009:                        return HANDLER_ERROR;
                   3010:                case CONNECTION_OK:
                   3011:                        /* everything is ok, go on */
                   3012: 
                   3013:                        fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
                   3014: 
                   3015:                        break;
                   3016:                }
                   3017: 
                   3018:        case FCGI_STATE_PREPARE_WRITE:
                   3019:                /* ok, we have the connection */
                   3020: 
                   3021:                fcgi_proc_load_inc(srv, hctx);
                   3022:                hctx->got_proc = 1;
                   3023: 
                   3024:                status_counter_inc(srv, CONST_STR_LEN("fastcgi.requests"));
                   3025: 
                   3026:                fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
                   3027:                buffer_append_string_len(p->statuskey, CONST_STR_LEN(".connected"));
                   3028: 
                   3029:                status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
                   3030: 
                   3031:                if (p->conf.debug) {
                   3032:                        log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
                   3033:                                "got proc:",
                   3034:                                "pid:", hctx->proc->pid,
                   3035:                                "socket:", hctx->proc->connection_name,
                   3036:                                "load:", hctx->proc->load);
                   3037:                }
                   3038: 
                   3039:                /* move the proc-list entry down the list */
                   3040:                if (hctx->request_id == 0) {
                   3041:                        hctx->request_id = 1; /* always use id 1 as we don't use multiplexing */
                   3042:                } else {
                   3043:                        log_error_write(srv, __FILE__, __LINE__, "sd",
                   3044:                                        "fcgi-request is already in use:", hctx->request_id);
                   3045:                }
                   3046: 
                   3047:                /* fall through */
                   3048:                if (-1 == fcgi_create_env(srv, hctx, hctx->request_id)) return HANDLER_ERROR;
                   3049:                fcgi_set_state(srv, hctx, FCGI_STATE_WRITE);
                   3050:                /* fall through */
                   3051:        case FCGI_STATE_WRITE:
                   3052:                ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb, MAX_WRITE_LIMIT);
                   3053: 
                   3054:                chunkqueue_remove_finished_chunks(hctx->wb);
                   3055: 
                   3056:                if (ret < 0) {
                   3057:                        switch(errno) {
                   3058:                        case EPIPE:
                   3059:                        case ENOTCONN:
                   3060:                        case ECONNRESET:
                   3061:                                /* the connection got dropped after accept()
                   3062:                                 * we don't care about that - if you accept() it, you have to handle it.
                   3063:                                 */
                   3064: 
                   3065:                                log_error_write(srv, __FILE__, __LINE__, "ssosb",
                   3066:                                                        "connection was dropped after accept() (perhaps the fastcgi process died),",
                   3067:                                                "write-offset:", hctx->wb->bytes_out,
                   3068:                                                "socket:", hctx->proc->connection_name);
                   3069: 
                   3070:                                return HANDLER_ERROR;
                   3071:                        default:
                   3072:                                log_error_write(srv, __FILE__, __LINE__, "ssd",
                   3073:                                                "write failed:", strerror(errno), errno);
                   3074: 
                   3075:                                return HANDLER_ERROR;
                   3076:                        }
                   3077:                }
                   3078: 
                   3079:                if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
                   3080:                        /* we don't need the out event anymore */
                   3081:                        fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
                   3082:                        fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
                   3083:                        fcgi_set_state(srv, hctx, FCGI_STATE_READ);
                   3084:                } else {
                   3085:                        fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
                   3086: 
                   3087:                        return HANDLER_WAIT_FOR_EVENT;
                   3088:                }
                   3089: 
                   3090:                break;
                   3091:        case FCGI_STATE_READ:
                   3092:                /* waiting for a response */
                   3093:                break;
                   3094:        default:
                   3095:                log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
                   3096:                return HANDLER_ERROR;
                   3097:        }
                   3098: 
                   3099:        return HANDLER_WAIT_FOR_EVENT;
                   3100: }
                   3101: 
                   3102: 
                   3103: /* might be called on fdevent after a connect() is delay too
                   3104:  * */
                   3105: SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
                   3106:        plugin_data *p = p_d;
                   3107: 
                   3108:        handler_ctx *hctx = con->plugin_ctx[p->id];
                   3109:        fcgi_extension_host *host;
                   3110: 
                   3111:        if (NULL == hctx) return HANDLER_GO_ON;
                   3112: 
                   3113:        /* not my job */
                   3114:        if (con->mode != p->id) return HANDLER_GO_ON;
                   3115: 
                   3116:        /* we don't have a host yet, choose one
                   3117:         * -> this happens in the first round
                   3118:         *    and when the host died and we have to select a new one */
                   3119:        if (hctx->host == NULL) {
                   3120:                size_t k;
                   3121:                int ndx, used = -1;
                   3122: 
                   3123:                /* check if the next server has no load. */
                   3124:                ndx = hctx->ext->last_used_ndx + 1;
                   3125:                if(ndx >= (int) hctx->ext->used || ndx < 0) ndx = 0;
                   3126:                host = hctx->ext->hosts[ndx];
                   3127:                if (host->load > 0) {
                   3128:                        /* get backend with the least load. */
                   3129:                        for (k = 0, ndx = -1; k < hctx->ext->used; k++) {
                   3130:                                host = hctx->ext->hosts[k];
                   3131: 
                   3132:                                /* we should have at least one proc that can do something */
                   3133:                                if (host->active_procs == 0) continue;
                   3134: 
                   3135:                                if (used == -1 || host->load < used) {
                   3136:                                        used = host->load;
                   3137: 
                   3138:                                        ndx = k;
                   3139:                                }
                   3140:                        }
                   3141:                }
                   3142: 
                   3143:                /* found a server */
                   3144:                if (ndx == -1) {
                   3145:                        /* all hosts are down */
                   3146: 
                   3147:                        fcgi_connection_close(srv, hctx);
                   3148: 
                   3149:                        con->http_status = 500;
                   3150:                        con->mode = DIRECT;
                   3151: 
                   3152:                        return HANDLER_FINISHED;
                   3153:                }
                   3154: 
                   3155:                hctx->ext->last_used_ndx = ndx;
                   3156:                host = hctx->ext->hosts[ndx];
                   3157: 
                   3158:                /*
                   3159:                 * if check-local is disabled, use the uri.path handler
                   3160:                 *
                   3161:                 */
                   3162: 
                   3163:                /* init handler-context */
                   3164: 
                   3165:                /* we put a connection on this host, move the other new connections to other hosts
                   3166:                 *
                   3167:                 * as soon as hctx->host is unassigned, decrease the load again */
                   3168:                fcgi_host_assign(srv, hctx, host);
                   3169:                hctx->proc = NULL;
                   3170:        } else {
                   3171:                host = hctx->host;
                   3172:        }
                   3173: 
                   3174:        /* ok, create the request */
                   3175:        switch(fcgi_write_request(srv, hctx)) {
                   3176:        case HANDLER_ERROR:
                   3177:                host = hctx->host;
                   3178: 
                   3179:                if (hctx->state == FCGI_STATE_INIT ||
                   3180:                    hctx->state == FCGI_STATE_CONNECT_DELAYED) {
                   3181:                        fcgi_restart_dead_procs(srv, p, host);
                   3182: 
                   3183:                        /* cleanup this request and let the request handler start this request again */
                   3184:                        if (hctx->reconnects < 5) {
                   3185:                                fcgi_reconnect(srv, hctx);
                   3186:                                joblist_append(srv, con); /* in case we come from the event-handler */
                   3187: 
                   3188:                                return HANDLER_WAIT_FOR_FD;
                   3189:                        } else {
                   3190:                                fcgi_connection_close(srv, hctx);
                   3191: 
                   3192:                                buffer_reset(con->physical.path);
                   3193:                                con->mode = DIRECT;
                   3194:                                con->http_status = 503;
                   3195:                                joblist_append(srv, con); /* in case we come from the event-handler */
                   3196: 
                   3197:                                return HANDLER_FINISHED;
                   3198:                        }
                   3199:                } else {
                   3200:                        fcgi_connection_close(srv, hctx);
                   3201: 
                   3202:                        buffer_reset(con->physical.path);
                   3203:                        con->mode = DIRECT;
                   3204:                        if (con->http_status != 400) con->http_status = 503;
                   3205:                        joblist_append(srv, con); /* really ? */
                   3206: 
                   3207:                        return HANDLER_FINISHED;
                   3208:                }
                   3209:        case HANDLER_WAIT_FOR_EVENT:
                   3210:                if (con->file_started == 1) {
                   3211:                        return HANDLER_FINISHED;
                   3212:                } else {
                   3213:                        return HANDLER_WAIT_FOR_EVENT;
                   3214:                }
                   3215:        case HANDLER_WAIT_FOR_FD:
                   3216:                return HANDLER_WAIT_FOR_FD;
                   3217:        default:
                   3218:                log_error_write(srv, __FILE__, __LINE__, "s", "subrequest write-req default");
                   3219:                return HANDLER_ERROR;
                   3220:        }
                   3221: }
                   3222: 
                   3223: static handler_t fcgi_handle_fdevent(server *srv, void *ctx, int revents) {
                   3224:        handler_ctx *hctx = ctx;
                   3225:        connection  *con  = hctx->remote_conn;
                   3226:        plugin_data *p    = hctx->plugin_data;
                   3227: 
                   3228:        fcgi_proc *proc   = hctx->proc;
                   3229:        fcgi_extension_host *host= hctx->host;
                   3230: 
                   3231:        if ((revents & FDEVENT_IN) &&
                   3232:            hctx->state == FCGI_STATE_READ) {
                   3233:                switch (fcgi_demux_response(srv, hctx)) {
                   3234:                case 0:
                   3235:                        break;
                   3236:                case 1:
                   3237: 
                   3238:                        if (host->mode == FCGI_AUTHORIZER &&
                   3239:                            (con->http_status == 200 ||
                   3240:                             con->http_status == 0)) {
                   3241:                                /*
                   3242:                                 * If we are here in AUTHORIZER mode then a request for authorizer
                   3243:                                 * was processed already, and status 200 has been returned. We need
                   3244:                                 * now to handle authorized request.
                   3245:                                 */
                   3246: 
                   3247:                                buffer_copy_string_buffer(con->physical.doc_root, host->docroot);
                   3248:                                buffer_copy_string_buffer(con->physical.basedir, host->docroot);
                   3249: 
                   3250:                                buffer_copy_string_buffer(con->physical.path, host->docroot);
                   3251:                                buffer_append_string_buffer(con->physical.path, con->uri.path);
                   3252:                                fcgi_connection_close(srv, hctx);
                   3253: 
                   3254:                                con->mode = DIRECT;
                   3255:                                con->http_status = 0;
                   3256:                                con->file_started = 1; /* fcgi_extension won't touch the request afterwards */
                   3257:                        } else {
                   3258:                                /* we are done */
                   3259:                                fcgi_connection_close(srv, hctx);
                   3260:                        }
                   3261: 
                   3262:                        joblist_append(srv, con);
                   3263:                        return HANDLER_FINISHED;
                   3264:                case -1:
                   3265:                        if (proc->pid && proc->state != PROC_STATE_DIED) {
                   3266:                                int status;
                   3267: 
                   3268:                                /* only fetch the zombie if it is not already done */
                   3269: 
                   3270:                                switch(waitpid(proc->pid, &status, WNOHANG)) {
                   3271:                                case 0:
                   3272:                                        /* child is still alive */
                   3273:                                        break;
                   3274:                                case -1:
                   3275:                                        break;
                   3276:                                default:
                   3277:                                        /* the child should not terminate at all */
                   3278:                                        if (WIFEXITED(status)) {
                   3279:                                                log_error_write(srv, __FILE__, __LINE__, "sdsd",
                   3280:                                                                "child exited, pid:", proc->pid,
                   3281:                                                                "status:", WEXITSTATUS(status));
                   3282:                                        } else if (WIFSIGNALED(status)) {
                   3283:                                                log_error_write(srv, __FILE__, __LINE__, "sd",
                   3284:                                                                "child signaled:",
                   3285:                                                                WTERMSIG(status));
                   3286:                                        } else {
                   3287:                                                log_error_write(srv, __FILE__, __LINE__, "sd",
                   3288:                                                                "child died somehow:",
                   3289:                                                                status);
                   3290:                                        }
                   3291: 
                   3292:                                        if (p->conf.debug) {
                   3293:                                                log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
                   3294:                                                                "--- fastcgi spawning",
                   3295:                                                                "\n\tsocket", proc->connection_name,
                   3296:                                                                "\n\tcurrent:", 1, "/", host->max_procs);
                   3297:                                        }
                   3298: 
                   3299:                                        if (fcgi_spawn_connection(srv, p, host, proc)) {
                   3300:                                                /* respawning failed, retry later */
                   3301:                                                proc->state = PROC_STATE_DIED;
                   3302: 
                   3303:                                                log_error_write(srv, __FILE__, __LINE__, "s",
                   3304:                                                                "respawning failed, will retry later");
                   3305:                                        }
                   3306: 
                   3307:                                        break;
                   3308:                                }
                   3309:                        }
                   3310: 
                   3311:                        if (con->file_started == 0) {
                   3312:                                /* nothing has been sent out yet, try to use another child */
                   3313: 
                   3314:                                if (hctx->wb->bytes_out == 0 &&
                   3315:                                    hctx->reconnects < 5) {
                   3316:                                        fcgi_reconnect(srv, hctx);
                   3317: 
                   3318:                                        log_error_write(srv, __FILE__, __LINE__, "ssbsBSBs",
                   3319:                                                "response not received, request not sent",
                   3320:                                                "on socket:", proc->connection_name,
                   3321:                                                "for", con->uri.path, "?", con->uri.query, ", reconnecting");
                   3322: 
                   3323:                                        return HANDLER_WAIT_FOR_FD;
                   3324:                                }
                   3325: 
                   3326:                                log_error_write(srv, __FILE__, __LINE__, "sosbsBSBs",
                   3327:                                                "response not received, request sent:", hctx->wb->bytes_out,
                   3328:                                                "on socket:", proc->connection_name,
                   3329:                                                "for", con->uri.path, "?", con->uri.query, ", closing connection");
                   3330: 
                   3331:                                fcgi_connection_close(srv, hctx);
                   3332: 
                   3333:                                connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
                   3334:                                buffer_reset(con->physical.path);
                   3335:                                con->http_status = 500;
                   3336:                                con->mode = DIRECT;
                   3337:                        } else {
                   3338:                                /* response might have been already started, kill the connection */
                   3339:                                fcgi_connection_close(srv, hctx);
                   3340: 
                   3341:                                log_error_write(srv, __FILE__, __LINE__, "ssbsBSBs",
                   3342:                                                "response already sent out, but backend returned error",
                   3343:                                                "on socket:", proc->connection_name,
                   3344:                                                "for", con->uri.path, "?", con->uri.query, ", terminating connection");
                   3345: 
                   3346:                                connection_set_state(srv, con, CON_STATE_ERROR);
                   3347:                        }
                   3348: 
                   3349:                        /* */
                   3350: 
                   3351: 
                   3352:                        joblist_append(srv, con);
                   3353:                        return HANDLER_FINISHED;
                   3354:                }
                   3355:        }
                   3356: 
                   3357:        if (revents & FDEVENT_OUT) {
                   3358:                if (hctx->state == FCGI_STATE_CONNECT_DELAYED ||
                   3359:                    hctx->state == FCGI_STATE_WRITE) {
                   3360:                        /* we are allowed to send something out
                   3361:                         *
                   3362:                         * 1. in an unfinished connect() call
                   3363:                         * 2. in an unfinished write() call (long POST request)
                   3364:                         */
                   3365:                        return mod_fastcgi_handle_subrequest(srv, con, p);
                   3366:                } else {
                   3367:                        log_error_write(srv, __FILE__, __LINE__, "sd",
                   3368:                                        "got a FDEVENT_OUT and didn't know why:",
                   3369:                                        hctx->state);
                   3370:                }
                   3371:        }
                   3372: 
                   3373:        /* perhaps this issue is already handled */
                   3374:        if (revents & FDEVENT_HUP) {
                   3375:                if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
                   3376:                        /* getoptsock will catch this one (right ?)
                   3377:                         *
                   3378:                         * if we are in connect we might get an EINPROGRESS
                   3379:                         * in the first call and an FDEVENT_HUP in the
                   3380:                         * second round
                   3381:                         *
                   3382:                         * FIXME: as it is a bit ugly.
                   3383:                         *
                   3384:                         */
                   3385:                        return mod_fastcgi_handle_subrequest(srv, con, p);
                   3386:                } else if (hctx->state == FCGI_STATE_READ &&
                   3387:                           hctx->proc->port == 0) {
                   3388:                        /* FIXME:
                   3389:                         *
                   3390:                         * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
                   3391:                         * even if the FCGI_FIN packet is not received yet
                   3392:                         */
                   3393:                } else {
                   3394:                        log_error_write(srv, __FILE__, __LINE__, "sBSbsbsd",
                   3395:                                        "error: unexpected close of fastcgi connection for",
                   3396:                                        con->uri.path, "?", con->uri.query,
                   3397:                                        "(no fastcgi process on socket:", proc->connection_name, "?)",
                   3398:                                        hctx->state);
                   3399: 
                   3400:                        connection_set_state(srv, con, CON_STATE_ERROR);
                   3401:                        fcgi_connection_close(srv, hctx);
                   3402:                        joblist_append(srv, con);
                   3403:                }
                   3404:        } else if (revents & FDEVENT_ERR) {
                   3405:                log_error_write(srv, __FILE__, __LINE__, "s",
                   3406:                                "fcgi: got a FDEVENT_ERR. Don't know why.");
                   3407:                /* kill all connections to the fastcgi process */
                   3408: 
                   3409: 
                   3410:                connection_set_state(srv, con, CON_STATE_ERROR);
                   3411:                fcgi_connection_close(srv, hctx);
                   3412:                joblist_append(srv, con);
                   3413:        }
                   3414: 
                   3415:        return HANDLER_FINISHED;
                   3416: }
                   3417: #define PATCH(x) \
                   3418:        p->conf.x = s->x;
                   3419: static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {
                   3420:        size_t i, j;
                   3421:        plugin_config *s = p->config_storage[0];
                   3422: 
                   3423:        PATCH(exts);
                   3424:        PATCH(debug);
                   3425:        PATCH(ext_mapping);
                   3426: 
                   3427:        /* skip the first, the global context */
                   3428:        for (i = 1; i < srv->config_context->used; i++) {
                   3429:                data_config *dc = (data_config *)srv->config_context->data[i];
                   3430:                s = p->config_storage[i];
                   3431: 
                   3432:                /* condition didn't match */
                   3433:                if (!config_check_cond(srv, con, dc)) continue;
                   3434: 
                   3435:                /* merge config */
                   3436:                for (j = 0; j < dc->value->used; j++) {
                   3437:                        data_unset *du = dc->value->data[j];
                   3438: 
                   3439:                        if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.server"))) {
                   3440:                                PATCH(exts);
                   3441:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.debug"))) {
                   3442:                                PATCH(debug);
                   3443:                        } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.map-extensions"))) {
                   3444:                                PATCH(ext_mapping);
                   3445:                        }
                   3446:                }
                   3447:        }
                   3448: 
                   3449:        return 0;
                   3450: }
                   3451: #undef PATCH
                   3452: 
                   3453: 
                   3454: static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
                   3455:        plugin_data *p = p_d;
                   3456:        size_t s_len;
                   3457:        size_t k;
                   3458:        buffer *fn;
                   3459:        fcgi_extension *extension = NULL;
                   3460:        fcgi_extension_host *host = NULL;
                   3461: 
                   3462:        if (con->mode != DIRECT) return HANDLER_GO_ON;
                   3463: 
                   3464:        /* Possibly, we processed already this request */
                   3465:        if (con->file_started == 1) return HANDLER_GO_ON;
                   3466: 
                   3467:        fn = uri_path_handler ? con->uri.path : con->physical.path;
                   3468: 
                   3469:        if (buffer_is_empty(fn)) return HANDLER_GO_ON;
                   3470: 
                   3471:        s_len = fn->used - 1;
                   3472: 
                   3473:        fcgi_patch_connection(srv, con, p);
                   3474: 
                   3475:        /* fastcgi.map-extensions maps extensions to existing fastcgi.server entries
                   3476:         *
                   3477:         * fastcgi.map-extensions = ( ".php3" => ".php" )
                   3478:         *
                   3479:         * fastcgi.server = ( ".php" => ... )
                   3480:         *
                   3481:         * */
                   3482: 
                   3483:        /* check if extension-mapping matches */
                   3484:        for (k = 0; k < p->conf.ext_mapping->used; k++) {
                   3485:                data_string *ds = (data_string *)p->conf.ext_mapping->data[k];
                   3486:                size_t ct_len; /* length of the config entry */
                   3487: 
                   3488:                if (ds->key->used == 0) continue;
                   3489: 
                   3490:                ct_len = ds->key->used - 1;
                   3491: 
                   3492:                if (s_len < ct_len) continue;
                   3493: 
                   3494:                /* found a mapping */
                   3495:                if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
                   3496:                        /* check if we know the extension */
                   3497: 
                   3498:                        /* we can reuse k here */
                   3499:                        for (k = 0; k < p->conf.exts->used; k++) {
                   3500:                                extension = p->conf.exts->exts[k];
                   3501: 
                   3502:                                if (buffer_is_equal(ds->value, extension->key)) {
                   3503:                                        break;
                   3504:                                }
                   3505:                        }
                   3506: 
                   3507:                        if (k == p->conf.exts->used) {
                   3508:                                /* found nothign */
                   3509:                                extension = NULL;
                   3510:                        }
                   3511:                        break;
                   3512:                }
                   3513:        }
                   3514: 
                   3515:        if (extension == NULL) {
                   3516:                /* check if extension matches */
                   3517:                for (k = 0; k < p->conf.exts->used; k++) {
                   3518:                        size_t ct_len; /* length of the config entry */
                   3519:                        fcgi_extension *ext = p->conf.exts->exts[k];
                   3520: 
                   3521:                        if (ext->key->used == 0) continue;
                   3522: 
                   3523:                        ct_len = ext->key->used - 1;
                   3524: 
                   3525:                        /* check _url_ in the form "/fcgi_pattern" */
                   3526:                        if (ext->key->ptr[0] == '/') {
                   3527:                                if ((ct_len <= con->uri.path->used -1) &&
                   3528:                                    (strncmp(con->uri.path->ptr, ext->key->ptr, ct_len) == 0)) {
                   3529:                                        extension = ext;
                   3530:                                        break;
                   3531:                                }
                   3532:                        } else if ((ct_len <= s_len) && (0 == strncmp(fn->ptr + s_len - ct_len, ext->key->ptr, ct_len))) {
                   3533:                                /* check extension in the form ".fcg" */
                   3534:                                extension = ext;
                   3535:                                break;
                   3536:                        }
                   3537:                }
                   3538:                /* extension doesn't match */
                   3539:                if (NULL == extension) {
                   3540:                        return HANDLER_GO_ON;
                   3541:                }
                   3542:        }
                   3543: 
                   3544:        /* check if we have at least one server for this extension up and running */
                   3545:        for (k = 0; k < extension->used; k++) {
                   3546:                fcgi_extension_host *h = extension->hosts[k];
                   3547: 
                   3548:                /* we should have at least one proc that can do something */
                   3549:                if (h->active_procs == 0) {
                   3550:                        continue;
                   3551:                }
                   3552: 
                   3553:                /* we found one host that is alive */
                   3554:                host = h;
                   3555:                break;
                   3556:        }
                   3557: 
                   3558:        if (!host) {
                   3559:                /* sorry, we don't have a server alive for this ext */
                   3560:                buffer_reset(con->physical.path);
                   3561:                con->http_status = 500;
                   3562: 
                   3563:                /* only send the 'no handler' once */
                   3564:                if (!extension->note_is_sent) {
                   3565:                        extension->note_is_sent = 1;
                   3566: 
                   3567:                        log_error_write(srv, __FILE__, __LINE__, "sBSbsbs",
                   3568:                                        "all handlers for", con->uri.path, "?", con->uri.query,
                   3569:                                        "on", extension->key,
                   3570:                                        "are down.");
                   3571:                }
                   3572: 
                   3573:                return HANDLER_FINISHED;
                   3574:        }
                   3575: 
                   3576:        /* a note about no handler is not sent yet */
                   3577:        extension->note_is_sent = 0;
                   3578: 
                   3579:        /*
                   3580:         * if check-local is disabled, use the uri.path handler
                   3581:         *
                   3582:         */
                   3583: 
                   3584:        /* init handler-context */
                   3585:        if (uri_path_handler) {
                   3586:                if (host->check_local == 0) {
                   3587:                        handler_ctx *hctx;
                   3588:                        char *pathinfo;
                   3589: 
                   3590:                        hctx = handler_ctx_init();
                   3591: 
                   3592:                        hctx->remote_conn      = con;
                   3593:                        hctx->plugin_data      = p;
                   3594:                        hctx->proc             = NULL;
                   3595:                        hctx->ext              = extension;
                   3596: 
                   3597: 
                   3598:                        hctx->conf.exts        = p->conf.exts;
                   3599:                        hctx->conf.debug       = p->conf.debug;
                   3600: 
                   3601:                        con->plugin_ctx[p->id] = hctx;
                   3602: 
                   3603:                        con->mode = p->id;
                   3604: 
                   3605:                        if (con->conf.log_request_handling) {
                   3606:                                log_error_write(srv, __FILE__, __LINE__, "s",
                   3607:                                "handling it in mod_fastcgi");
                   3608:                        }
                   3609: 
                   3610:                        /* do not split path info for authorizer */
                   3611:                        if (host->mode != FCGI_AUTHORIZER) {
                   3612:                                /* the prefix is the SCRIPT_NAME,
                   3613:                                * everything from start to the next slash
                   3614:                                * this is important for check-local = "disable"
                   3615:                                *
                   3616:                                * if prefix = /admin.fcgi
                   3617:                                *
                   3618:                                * /admin.fcgi/foo/bar
                   3619:                                *
                   3620:                                * SCRIPT_NAME = /admin.fcgi
                   3621:                                * PATH_INFO   = /foo/bar
                   3622:                                *
                   3623:                                * if prefix = /fcgi-bin/
                   3624:                                *
                   3625:                                * /fcgi-bin/foo/bar
                   3626:                                *
                   3627:                                * SCRIPT_NAME = /fcgi-bin/foo
                   3628:                                * PATH_INFO   = /bar
                   3629:                                *
                   3630:                                * if prefix = /, and fix-root-path-name is enable
                   3631:                                *
                   3632:                                * /fcgi-bin/foo/bar
                   3633:                                *
                   3634:                                * SCRIPT_NAME = /fcgi-bin/foo
                   3635:                                * PATH_INFO   = /bar
                   3636:                                *
                   3637:                                */
                   3638: 
                   3639:                                /* the rewrite is only done for /prefix/? matches */
                   3640:                                if (host->fix_root_path_name && extension->key->ptr[0] == '/' && extension->key->ptr[1] == '\0') {
                   3641:                                        buffer_copy_string(con->request.pathinfo, con->uri.path->ptr);
                   3642:                                        con->uri.path->used = 1;
                   3643:                                        con->uri.path->ptr[con->uri.path->used - 1] = '\0';
                   3644:                                } else if (extension->key->ptr[0] == '/' &&
                   3645:                                        con->uri.path->used > extension->key->used &&
                   3646:                                        NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
                   3647:                                        /* rewrite uri.path and pathinfo */
                   3648: 
                   3649:                                        buffer_copy_string(con->request.pathinfo, pathinfo);
                   3650: 
                   3651:                                        con->uri.path->used -= con->request.pathinfo->used - 1;
                   3652:                                        con->uri.path->ptr[con->uri.path->used - 1] = '\0';
                   3653:                                }
                   3654:                        }
                   3655:                }
                   3656:        } else {
                   3657:                handler_ctx *hctx;
                   3658:                hctx = handler_ctx_init();
                   3659: 
                   3660:                hctx->remote_conn      = con;
                   3661:                hctx->plugin_data      = p;
                   3662:                hctx->proc             = NULL;
                   3663:                hctx->ext              = extension;
                   3664: 
                   3665:                hctx->conf.exts        = p->conf.exts;
                   3666:                hctx->conf.debug       = p->conf.debug;
                   3667: 
                   3668:                con->plugin_ctx[p->id] = hctx;
                   3669: 
                   3670:                con->mode = p->id;
                   3671: 
                   3672:                if (con->conf.log_request_handling) {
                   3673:                        log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
                   3674:                }
                   3675:        }
                   3676: 
                   3677:        return HANDLER_GO_ON;
                   3678: }
                   3679: 
                   3680: /* uri-path handler */
                   3681: static handler_t fcgi_check_extension_1(server *srv, connection *con, void *p_d) {
                   3682:        return fcgi_check_extension(srv, con, p_d, 1);
                   3683: }
                   3684: 
                   3685: /* start request handler */
                   3686: static handler_t fcgi_check_extension_2(server *srv, connection *con, void *p_d) {
                   3687:        return fcgi_check_extension(srv, con, p_d, 0);
                   3688: }
                   3689: 
                   3690: JOBLIST_FUNC(mod_fastcgi_handle_joblist) {
                   3691:        plugin_data *p = p_d;
                   3692:        handler_ctx *hctx = con->plugin_ctx[p->id];
                   3693: 
                   3694:        if (hctx == NULL) return HANDLER_GO_ON;
                   3695: 
                   3696:        if (hctx->fd != -1) {
                   3697:                switch (hctx->state) {
                   3698:                case FCGI_STATE_READ:
                   3699:                        fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
                   3700: 
                   3701:                        break;
                   3702:                case FCGI_STATE_CONNECT_DELAYED:
                   3703:                case FCGI_STATE_WRITE:
                   3704:                        fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
                   3705: 
                   3706:                        break;
                   3707:                case FCGI_STATE_INIT:
                   3708:                        /* at reconnect */
                   3709:                        break;
                   3710:                default:
                   3711:                        log_error_write(srv, __FILE__, __LINE__, "sd", "unhandled fcgi.state", hctx->state);
                   3712:                        break;
                   3713:                }
                   3714:        }
                   3715: 
                   3716:        return HANDLER_GO_ON;
                   3717: }
                   3718: 
                   3719: 
                   3720: static handler_t fcgi_connection_close_callback(server *srv, connection *con, void *p_d) {
                   3721:        plugin_data *p = p_d;
                   3722: 
                   3723:        fcgi_connection_close(srv, con->plugin_ctx[p->id]);
                   3724: 
                   3725:        return HANDLER_GO_ON;
                   3726: }
                   3727: 
                   3728: TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
                   3729:        plugin_data *p = p_d;
                   3730:        size_t i, j, n;
                   3731: 
                   3732: 
                   3733:        /* perhaps we should kill a connect attempt after 10-15 seconds
                   3734:         *
                   3735:         * currently we wait for the TCP timeout which is 180 seconds on Linux
                   3736:         *
                   3737:         *
                   3738:         *
                   3739:         */
                   3740: 
                   3741:        /* check all children if they are still up */
                   3742: 
                   3743:        for (i = 0; i < srv->config_context->used; i++) {
                   3744:                plugin_config *conf;
                   3745:                fcgi_exts *exts;
                   3746: 
                   3747:                conf = p->config_storage[i];
                   3748: 
                   3749:                exts = conf->exts;
                   3750: 
                   3751:                for (j = 0; j < exts->used; j++) {
                   3752:                        fcgi_extension *ex;
                   3753: 
                   3754:                        ex = exts->exts[j];
                   3755: 
                   3756:                        for (n = 0; n < ex->used; n++) {
                   3757: 
                   3758:                                fcgi_proc *proc;
                   3759:                                fcgi_extension_host *host;
                   3760: 
                   3761:                                host = ex->hosts[n];
                   3762: 
                   3763:                                fcgi_restart_dead_procs(srv, p, host);
                   3764: 
                   3765:                                for (proc = host->unused_procs; proc; proc = proc->next) {
                   3766:                                        int status;
                   3767: 
                   3768:                                        if (proc->pid == 0) continue;
                   3769: 
                   3770:                                        switch (waitpid(proc->pid, &status, WNOHANG)) {
                   3771:                                        case 0:
                   3772:                                                /* child still running after timeout, good */
                   3773:                                                break;
                   3774:                                        case -1:
                   3775:                                                if (errno != EINTR) {
                   3776:                                                        /* no PID found ? should never happen */
                   3777:                                                        log_error_write(srv, __FILE__, __LINE__, "sddss",
                   3778:                                                                        "pid ", proc->pid, proc->state,
                   3779:                                                                        "not found:", strerror(errno));
                   3780: 
                   3781: #if 0
                   3782:                                                        if (errno == ECHILD) {
                   3783:                                                                /* someone else has cleaned up for us */
                   3784:                                                                proc->pid = 0;
                   3785:                                                                proc->state = PROC_STATE_UNSET;
                   3786:                                                        }
                   3787: #endif
                   3788:                                                }
                   3789:                                                break;
                   3790:                                        default:
                   3791:                                                /* the child should not terminate at all */
                   3792:                                                if (WIFEXITED(status)) {
                   3793:                                                        if (proc->state != PROC_STATE_KILLED) {
                   3794:                                                                log_error_write(srv, __FILE__, __LINE__, "sdb",
                   3795:                                                                                "child exited:",
                   3796:                                                                                WEXITSTATUS(status), proc->connection_name);
                   3797:                                                        }
                   3798:                                                } else if (WIFSIGNALED(status)) {
                   3799:                                                        if (WTERMSIG(status) != SIGTERM) {
                   3800:                                                                log_error_write(srv, __FILE__, __LINE__, "sd",
                   3801:                                                                                "child signaled:",
                   3802:                                                                                WTERMSIG(status));
                   3803:                                                        }
                   3804:                                                } else {
                   3805:                                                        log_error_write(srv, __FILE__, __LINE__, "sd",
                   3806:                                                                        "child died somehow:",
                   3807:                                                                        status);
                   3808:                                                }
                   3809:                                                proc->pid = 0;
                   3810:                                                if (proc->state == PROC_STATE_RUNNING) host->active_procs--;
                   3811:                                                proc->state = PROC_STATE_UNSET;
                   3812:                                                host->max_id--;
                   3813:                                        }
                   3814:                                }
                   3815:                        }
                   3816:                }
                   3817:        }
                   3818: 
                   3819:        return HANDLER_GO_ON;
                   3820: }
                   3821: 
                   3822: 
                   3823: int mod_fastcgi_plugin_init(plugin *p);
                   3824: int mod_fastcgi_plugin_init(plugin *p) {
                   3825:        p->version      = LIGHTTPD_VERSION_ID;
                   3826:        p->name         = buffer_init_string("fastcgi");
                   3827: 
                   3828:        p->init         = mod_fastcgi_init;
                   3829:        p->cleanup      = mod_fastcgi_free;
                   3830:        p->set_defaults = mod_fastcgi_set_defaults;
                   3831:        p->connection_reset        = fcgi_connection_reset;
                   3832:        p->handle_connection_close = fcgi_connection_close_callback;
                   3833:        p->handle_uri_clean        = fcgi_check_extension_1;
                   3834:        p->handle_subrequest_start = fcgi_check_extension_2;
                   3835:        p->handle_subrequest       = mod_fastcgi_handle_subrequest;
                   3836:        p->handle_joblist          = mod_fastcgi_handle_joblist;
                   3837:        p->handle_trigger          = mod_fastcgi_handle_trigger;
                   3838: 
                   3839:        p->data         = NULL;
                   3840: 
                   3841:        return 0;
                   3842: }

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