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