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

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

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