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

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

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