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

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

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