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