xref: /lighttpd1.4/src/mod_cgi.c (revision 4eeeb8fc)
1 #include "first.h"
2 
3 #include "server.h"
4 #include "stat_cache.h"
5 #include "keyvalue.h"
6 #include "log.h"
7 #include "connections.h"
8 #include "joblist.h"
9 #include "response.h"
10 #include "http_chunk.h"
11 #include "network_backends.h"
12 
13 #include "plugin.h"
14 
15 #include <sys/types.h>
16 #include "sys-mmap.h"
17 
18 #ifdef __WIN32
19 # include <winsock2.h>
20 #else
21 # include <sys/socket.h>
22 # include <sys/wait.h>
23 # include <netinet/in.h>
24 # include <arpa/inet.h>
25 #endif
26 
27 #include <unistd.h>
28 #include <errno.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <fdevent.h>
32 #include <signal.h>
33 #include <ctype.h>
34 #include <assert.h>
35 
36 #include <stdio.h>
37 #include <fcntl.h>
38 
39 #include "version.h"
40 
41 enum {EOL_UNSET, EOL_N, EOL_RN};
42 
43 typedef struct {
44 	char **ptr;
45 
46 	size_t size;
47 	size_t used;
48 } char_array;
49 
50 typedef struct {
51 	pid_t *ptr;
52 	size_t used;
53 	size_t size;
54 } buffer_pid_t;
55 
56 typedef struct {
57 	array *cgi;
58 	unsigned short execute_x_only;
59 	unsigned short xsendfile_allow;
60 	array *xsendfile_docroot;
61 } plugin_config;
62 
63 typedef struct {
64 	PLUGIN_DATA;
65 	buffer_pid_t cgi_pid;
66 
67 	buffer *tmp_buf;
68 	buffer *parse_response;
69 
70 	plugin_config **config_storage;
71 
72 	plugin_config conf;
73 } plugin_data;
74 
75 typedef struct {
76 	pid_t pid;
77 	int fd;
78 	int fdtocgi;
79 	int fde_ndx; /* index into the fd-event buffer */
80 	int fde_ndx_tocgi; /* index into the fd-event buffer */
81 
82 	connection *remote_conn;  /* dumb pointer */
83 	plugin_data *plugin_data; /* dumb pointer */
84 
85 	buffer *response;
86 	buffer *response_header;
87 } handler_ctx;
88 
89 static handler_ctx * cgi_handler_ctx_init(void) {
90 	handler_ctx *hctx = calloc(1, sizeof(*hctx));
91 
92 	force_assert(hctx);
93 
94 	hctx->response = buffer_init();
95 	hctx->response_header = buffer_init();
96 	hctx->fd = -1;
97 	hctx->fdtocgi = -1;
98 
99 	return hctx;
100 }
101 
102 static void cgi_handler_ctx_free(handler_ctx *hctx) {
103 	buffer_free(hctx->response);
104 	buffer_free(hctx->response_header);
105 
106 	free(hctx);
107 }
108 
109 enum {FDEVENT_HANDLED_UNSET, FDEVENT_HANDLED_FINISHED, FDEVENT_HANDLED_NOT_FINISHED, FDEVENT_HANDLED_ERROR};
110 
111 INIT_FUNC(mod_cgi_init) {
112 	plugin_data *p;
113 
114 	p = calloc(1, sizeof(*p));
115 
116 	force_assert(p);
117 
118 	p->tmp_buf = buffer_init();
119 	p->parse_response = buffer_init();
120 
121 	return p;
122 }
123 
124 
125 FREE_FUNC(mod_cgi_free) {
126 	plugin_data *p = p_d;
127 	buffer_pid_t *r = &(p->cgi_pid);
128 
129 	UNUSED(srv);
130 
131 	if (p->config_storage) {
132 		size_t i;
133 		for (i = 0; i < srv->config_context->used; i++) {
134 			plugin_config *s = p->config_storage[i];
135 
136 			if (NULL == s) continue;
137 
138 			array_free(s->cgi);
139 			array_free(s->xsendfile_docroot);
140 
141 			free(s);
142 		}
143 		free(p->config_storage);
144 	}
145 
146 
147 	if (r->ptr) free(r->ptr);
148 
149 	buffer_free(p->tmp_buf);
150 	buffer_free(p->parse_response);
151 
152 	free(p);
153 
154 	return HANDLER_GO_ON;
155 }
156 
157 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
158 	plugin_data *p = p_d;
159 	size_t i = 0;
160 
161 	config_values_t cv[] = {
162 		{ "cgi.assign",                  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
163 		{ "cgi.execute-x-only",          NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },     /* 1 */
164 		{ "cgi.x-sendfile",              NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },     /* 2 */
165 		{ "cgi.x-sendfile-docroot",      NULL, T_CONFIG_ARRAY,   T_CONFIG_SCOPE_CONNECTION },     /* 3 */
166 		{ NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET}
167 	};
168 
169 	if (!p) return HANDLER_ERROR;
170 
171 	p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
172 	force_assert(p->config_storage);
173 
174 	for (i = 0; i < srv->config_context->used; i++) {
175 		data_config const* config = (data_config const*)srv->config_context->data[i];
176 		plugin_config *s;
177 
178 		s = calloc(1, sizeof(plugin_config));
179 		force_assert(s);
180 
181 		s->cgi    = array_init();
182 		s->execute_x_only = 0;
183 		s->xsendfile_allow= 0;
184 		s->xsendfile_docroot = array_init();
185 
186 		cv[0].destination = s->cgi;
187 		cv[1].destination = &(s->execute_x_only);
188 		cv[2].destination = &(s->xsendfile_allow);
189 		cv[3].destination = s->xsendfile_docroot;
190 
191 		p->config_storage[i] = s;
192 
193 		if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
194 			return HANDLER_ERROR;
195 		}
196 
197 		if (s->xsendfile_docroot->used) {
198 			size_t j;
199 			for (j = 0; j < s->xsendfile_docroot->used; ++j) {
200 				data_string *ds = (data_string *)s->xsendfile_docroot->data[j];
201 				if (ds->type != TYPE_STRING) {
202 					log_error_write(srv, __FILE__, __LINE__, "s",
203 						"unexpected type for key cgi.x-sendfile-docroot; expected: cgi.x-sendfile-docroot = ( \"/allowed/path\", ... )");
204 					return HANDLER_ERROR;
205 				}
206 				if (ds->value->ptr[0] != '/') {
207 					log_error_write(srv, __FILE__, __LINE__, "SBs",
208 						"cgi.x-sendfile-docroot paths must begin with '/'; invalid: \"", ds->value, "\"");
209 					return HANDLER_ERROR;
210 				}
211 				buffer_path_simplify(ds->value, ds->value);
212 				buffer_append_slash(ds->value);
213 			}
214 		}
215 	}
216 
217 	return HANDLER_GO_ON;
218 }
219 
220 
221 static int cgi_pid_add(server *srv, plugin_data *p, pid_t pid) {
222 	int m = -1;
223 	size_t i;
224 	buffer_pid_t *r = &(p->cgi_pid);
225 
226 	UNUSED(srv);
227 
228 	for (i = 0; i < r->used; i++) {
229 		if (r->ptr[i] > m) m = r->ptr[i];
230 	}
231 
232 	if (r->size == 0) {
233 		r->size = 16;
234 		r->ptr = malloc(sizeof(*r->ptr) * r->size);
235 		force_assert(r->ptr);
236 	} else if (r->used == r->size) {
237 		r->size += 16;
238 		r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
239 		force_assert(r->ptr);
240 	}
241 
242 	r->ptr[r->used++] = pid;
243 
244 	return m;
245 }
246 
247 static int cgi_pid_del(server *srv, plugin_data *p, pid_t pid) {
248 	size_t i;
249 	buffer_pid_t *r = &(p->cgi_pid);
250 
251 	UNUSED(srv);
252 
253 	for (i = 0; i < r->used; i++) {
254 		if (r->ptr[i] == pid) break;
255 	}
256 
257 	if (i != r->used) {
258 		/* found */
259 
260 		if (i != r->used - 1) {
261 			r->ptr[i] = r->ptr[r->used - 1];
262 		}
263 		r->used--;
264 	}
265 
266 	return 0;
267 }
268 
269 static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
270 	char *ns;
271 	const char *s;
272 	int line = 0;
273 
274 	UNUSED(srv);
275 
276 	buffer_copy_buffer(p->parse_response, in);
277 
278 	for (s = p->parse_response->ptr;
279 	     NULL != (ns = strchr(s, '\n'));
280 	     s = ns + 1, line++) {
281 		const char *key, *value;
282 		int key_len;
283 		data_string *ds;
284 
285 		/* strip the \n */
286 		ns[0] = '\0';
287 
288 		if (ns > s && ns[-1] == '\r') ns[-1] = '\0';
289 
290 		if (line == 0 &&
291 		    0 == strncmp(s, "HTTP/1.", 7)) {
292 			/* non-parsed header ... we parse them anyway */
293 
294 			if ((s[7] == '1' ||
295 			     s[7] == '0') &&
296 			    s[8] == ' ') {
297 				int status;
298 				/* after the space should be a status code for us */
299 
300 				status = strtol(s+9, NULL, 10);
301 
302 				if (status >= 100 &&
303 				    status < 1000) {
304 					/* we expected 3 digits and didn't got them */
305 					con->parsed_response |= HTTP_STATUS;
306 					con->http_status = status;
307 				}
308 			}
309 		} else {
310 			/* parse the headers */
311 			key = s;
312 			if (NULL == (value = strchr(s, ':'))) {
313 				/* we expect: "<key>: <value>\r\n" */
314 				continue;
315 			}
316 
317 			key_len = value - key;
318 			value += 1;
319 
320 			/* skip LWS */
321 			while (*value == ' ' || *value == '\t') value++;
322 
323 			if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
324 				ds = data_response_init();
325 			}
326 			buffer_copy_string_len(ds->key, key, key_len);
327 			buffer_copy_string(ds->value, value);
328 
329 			array_insert_unique(con->response.headers, (data_unset *)ds);
330 
331 			switch(key_len) {
332 			case 4:
333 				if (0 == strncasecmp(key, "Date", key_len)) {
334 					con->parsed_response |= HTTP_DATE;
335 				}
336 				break;
337 			case 6:
338 				if (0 == strncasecmp(key, "Status", key_len)) {
339 					int status = strtol(value, NULL, 10);
340 					if (status >= 100 && status < 1000) {
341 						con->http_status = status;
342 						con->parsed_response |= HTTP_STATUS;
343 					} else {
344 						con->http_status = 502;
345 					}
346 				}
347 				break;
348 			case 8:
349 				if (0 == strncasecmp(key, "Location", key_len)) {
350 					con->parsed_response |= HTTP_LOCATION;
351 				}
352 				break;
353 			case 10:
354 				if (0 == strncasecmp(key, "Connection", key_len)) {
355 					con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
356 					con->parsed_response |= HTTP_CONNECTION;
357 				}
358 				break;
359 			case 14:
360 				if (0 == strncasecmp(key, "Content-Length", key_len)) {
361 					con->response.content_length = strtoul(value, NULL, 10);
362 					con->parsed_response |= HTTP_CONTENT_LENGTH;
363 				}
364 				break;
365 			default:
366 				break;
367 			}
368 		}
369 	}
370 
371 	/* CGI/1.1 rev 03 - 7.2.1.2 */
372 	if ((con->parsed_response & HTTP_LOCATION) &&
373 	    !(con->parsed_response & HTTP_STATUS)) {
374 		con->http_status = 302;
375 	}
376 
377 	return 0;
378 }
379 
380 
381 static int cgi_demux_response(server *srv, handler_ctx *hctx) {
382 	plugin_data *p    = hctx->plugin_data;
383 	connection  *con  = hctx->remote_conn;
384 
385 	while(1) {
386 		int n;
387 		int toread;
388 
389 #if defined(__WIN32)
390 		buffer_string_prepare_copy(hctx->response, 4 * 1024);
391 #else
392 		if (ioctl(con->fd, FIONREAD, &toread) || toread == 0 || toread <= 4*1024) {
393 			buffer_string_prepare_copy(hctx->response, 4 * 1024);
394 		} else {
395 			if (toread > MAX_READ_LIMIT) toread = MAX_READ_LIMIT;
396 			buffer_string_prepare_copy(hctx->response, toread);
397 		}
398 #endif
399 
400 		if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
401 			if (errno == EAGAIN || errno == EINTR) {
402 				/* would block, wait for signal */
403 				return FDEVENT_HANDLED_NOT_FINISHED;
404 			}
405 			/* error */
406 			log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
407 			return FDEVENT_HANDLED_ERROR;
408 		}
409 
410 		if (n == 0) {
411 			/* read finished */
412 
413 			con->file_finished = 1;
414 
415 			/* send final chunk */
416 			http_chunk_close(srv, con);
417 
418 			return FDEVENT_HANDLED_FINISHED;
419 		}
420 
421 		buffer_commit(hctx->response, n);
422 
423 		/* split header from body */
424 
425 		if (con->file_started == 0) {
426 			int is_header = 0;
427 			int is_header_end = 0;
428 			size_t last_eol = 0;
429 			size_t i, header_len;
430 
431 			buffer_append_string_buffer(hctx->response_header, hctx->response);
432 
433 			/**
434 			 * we have to handle a few cases:
435 			 *
436 			 * nph:
437 			 *
438 			 *   HTTP/1.0 200 Ok\n
439 			 *   Header: Value\n
440 			 *   \n
441 			 *
442 			 * CGI:
443 			 *   Header: Value\n
444 			 *   Status: 200\n
445 			 *   \n
446 			 *
447 			 * and different mixes of \n and \r\n combinations
448 			 *
449 			 * Some users also forget about CGI and just send a response and hope
450 			 * we handle it. No headers, no header-content seperator
451 			 *
452 			 */
453 
454 			/* nph (non-parsed headers) */
455 			if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) is_header = 1;
456 
457 			header_len = buffer_string_length(hctx->response_header);
458 			for (i = 0; !is_header_end && i < header_len; i++) {
459 				char c = hctx->response_header->ptr[i];
460 
461 				switch (c) {
462 				case ':':
463 					/* we found a colon
464 					 *
465 					 * looks like we have a normal header
466 					 */
467 					is_header = 1;
468 					break;
469 				case '\n':
470 					/* EOL */
471 					if (is_header == 0) {
472 						/* we got a EOL but we don't seem to got a HTTP header */
473 
474 						is_header_end = 1;
475 
476 						break;
477 					}
478 
479 					/**
480 					 * check if we saw a \n(\r)?\n sequence
481 					 */
482 					if (last_eol > 0 &&
483 					    ((i - last_eol == 1) ||
484 					     (i - last_eol == 2 && hctx->response_header->ptr[i - 1] == '\r'))) {
485 						is_header_end = 1;
486 						break;
487 					}
488 
489 					last_eol = i;
490 
491 					break;
492 				}
493 			}
494 
495 			if (is_header_end) {
496 				if (!is_header) {
497 					/* no header, but a body */
498 
499 					if (con->request.http_version == HTTP_VERSION_1_1) {
500 						con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
501 					}
502 
503 					http_chunk_append_buffer(srv, con, hctx->response_header);
504 				} else {
505 					const char *bstart;
506 					size_t blen;
507 
508 					/* the body starts after the EOL */
509 					bstart = hctx->response_header->ptr + i;
510 					blen = header_len - i;
511 
512 					/**
513 					 * i still points to the char after the terminating EOL EOL
514 					 *
515 					 * put it on the last \n again
516 					 */
517 					i--;
518 
519 					/* string the last \r?\n */
520 					if (i > 0 && (hctx->response_header->ptr[i - 1] == '\r')) {
521 						i--;
522 					}
523 
524 					buffer_string_set_length(hctx->response_header, i);
525 
526 					/* parse the response header */
527 					cgi_response_parse(srv, con, p, hctx->response_header);
528 
529 					if (p->conf.xsendfile_allow) {
530 						data_string *ds;
531 						if (NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-Sendfile"))) {
532 							http_response_xsendfile(srv, con, ds->value, p->conf.xsendfile_docroot);
533 							return FDEVENT_HANDLED_FINISHED;
534 						}
535 					}
536 
537 					/* enable chunked-transfer-encoding */
538 					if (con->request.http_version == HTTP_VERSION_1_1 &&
539 					    !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
540 						con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
541 					}
542 
543 					if (blen > 0) {
544 						http_chunk_append_mem(srv, con, bstart, blen);
545 					}
546 				}
547 
548 				con->file_started = 1;
549 			}
550 		} else {
551 			http_chunk_append_buffer(srv, con, hctx->response);
552 		}
553 
554 #if 0
555 		log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
556 #endif
557 	}
558 
559 	return FDEVENT_HANDLED_NOT_FINISHED;
560 }
561 
562 static void cgi_connection_close_fdtocgi(server *srv, handler_ctx *hctx) {
563 	/*(closes only hctx->fdtocgi)*/
564 	fdevent_event_del(srv->ev, &(hctx->fde_ndx_tocgi), hctx->fdtocgi);
565 	fdevent_unregister(srv->ev, hctx->fdtocgi);
566 
567 	if (close(hctx->fdtocgi)) {
568 		log_error_write(srv, __FILE__, __LINE__, "sds", "cgi stdin close failed ", hctx->fdtocgi, strerror(errno));
569 	}
570 	hctx->fdtocgi = -1;
571 }
572 
573 static void cgi_connection_close(server *srv, handler_ctx *hctx) {
574 	int status;
575 	pid_t pid;
576 	plugin_data *p = hctx->plugin_data;
577 	connection *con = hctx->remote_conn;
578 
579 #ifndef __WIN32
580 
581 	/* the connection to the browser went away, but we still have a connection
582 	 * to the CGI script
583 	 *
584 	 * close cgi-connection
585 	 */
586 
587 	if (hctx->fd != -1) {
588 		/* close connection to the cgi-script */
589 		fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
590 		fdevent_unregister(srv->ev, hctx->fd);
591 
592 		if (close(hctx->fd)) {
593 			log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
594 		}
595 	}
596 
597 	if (hctx->fdtocgi != -1) {
598 		cgi_connection_close_fdtocgi(srv, hctx); /*(closes only hctx->fdtocgi)*/
599 	}
600 
601 	pid = hctx->pid;
602 
603 	con->plugin_ctx[p->id] = NULL;
604 
605 	cgi_handler_ctx_free(hctx);
606 
607 	/* if waitpid hasn't been called by response.c yet, do it here */
608 	if (pid) {
609 		/* check if the CGI-script is already gone */
610 		switch(waitpid(pid, &status, WNOHANG)) {
611 		case 0:
612 			/* not finished yet */
613 #if 0
614 			log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) child isn't done yet, pid:", pid);
615 #endif
616 			break;
617 		case -1:
618 			/* */
619 			if (errno == EINTR) break;
620 
621 			/*
622 			 * errno == ECHILD happens if _subrequest catches the process-status before
623 			 * we have read the response of the cgi process
624 			 *
625 			 * -> catch status
626 			 * -> WAIT_FOR_EVENT
627 			 * -> read response
628 			 * -> we get here with waitpid == ECHILD
629 			 *
630 			 */
631 			if (errno != ECHILD) {
632 				log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
633 			}
634 			/* anyway: don't wait for it anymore */
635 			pid = 0;
636 			break;
637 		default:
638 			if (WIFEXITED(status)) {
639 #if 0
640 				log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", pid);
641 #endif
642 			} else {
643 				log_error_write(srv, __FILE__, __LINE__, "sd", "cgi died, pid:", pid);
644 			}
645 
646 			pid = 0;
647 			break;
648 		}
649 
650 		if (pid) {
651 			kill(pid, SIGTERM);
652 
653 			/* cgi-script is still alive, queue the PID for removal */
654 			cgi_pid_add(srv, p, pid);
655 		}
656 	}
657 #endif
658 
659 	/* finish response (if not already finished) */
660 	if (con->mode == p->id
661 	    && (con->state == CON_STATE_HANDLE_REQUEST || con->state == CON_STATE_READ_POST)) {
662 		/* (not CON_STATE_ERROR and not CON_STATE_RESPONSE_END,
663 		 * i.e. not called from cgi_connection_close_callback()) */
664 
665 		/* Send an error if we haven't sent any data yet */
666 		if (0 == con->file_started) {
667 			con->http_status = 500;
668 			con->mode = DIRECT;
669 		} else if (0 == con->file_finished) {
670 			http_chunk_close(srv, con);
671 			con->file_finished = 1;
672 		}
673 	}
674 }
675 
676 static handler_t cgi_connection_close_callback(server *srv, connection *con, void *p_d) {
677 	plugin_data *p = p_d;
678 	handler_ctx *hctx = con->plugin_ctx[p->id];
679 	if (hctx) cgi_connection_close(srv, hctx);
680 
681 	return HANDLER_GO_ON;
682 }
683 
684 
685 static int cgi_write_request(server *srv, handler_ctx *hctx, int fd);
686 
687 
688 static handler_t cgi_handle_fdevent_send (server *srv, void *ctx, int revents) {
689 	handler_ctx *hctx = ctx;
690 	connection  *con  = hctx->remote_conn;
691 
692 	/*(joblist only actually necessary here in mod_cgi fdevent send if returning HANDLER_ERROR)*/
693 	joblist_append(srv, con);
694 
695 	if (revents & FDEVENT_OUT) {
696 		if (0 != cgi_write_request(srv, hctx, hctx->fdtocgi)) {
697 			cgi_connection_close(srv, hctx);
698 			return HANDLER_ERROR;
699 		}
700 		/* more request body to be sent to CGI */
701 	}
702 
703 	if (revents & FDEVENT_HUP) {
704 		/* skip sending remaining data to CGI */
705 		chunkqueue *cq = con->request_content_queue;
706 		chunkqueue_mark_written(cq, chunkqueue_length(cq));
707 
708 		cgi_connection_close_fdtocgi(srv, hctx); /*(closes only hctx->fdtocgi)*/
709 	} else if (revents & FDEVENT_ERR) {
710 		/* kill all connections to the cgi process */
711 #if 1
712 		log_error_write(srv, __FILE__, __LINE__, "s", "cgi-FDEVENT_ERR");
713 #endif
714 		cgi_connection_close(srv, hctx);
715 		return HANDLER_ERROR;
716 	}
717 
718 	return HANDLER_FINISHED;
719 }
720 
721 
722 static handler_t cgi_handle_fdevent(server *srv, void *ctx, int revents) {
723 	handler_ctx *hctx = ctx;
724 	connection  *con  = hctx->remote_conn;
725 
726 	joblist_append(srv, con);
727 
728 	if (revents & FDEVENT_IN) {
729 		switch (cgi_demux_response(srv, hctx)) {
730 		case FDEVENT_HANDLED_NOT_FINISHED:
731 			break;
732 		case FDEVENT_HANDLED_FINISHED:
733 			/* we are done */
734 
735 #if 0
736 			log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "finished");
737 #endif
738 			cgi_connection_close(srv, hctx);
739 
740 			/* if we get a IN|HUP and have read everything don't exec the close twice */
741 			return HANDLER_FINISHED;
742 		case FDEVENT_HANDLED_ERROR:
743 			log_error_write(srv, __FILE__, __LINE__, "s", "demuxer failed: ");
744 
745 			cgi_connection_close(srv, hctx);
746 			return HANDLER_FINISHED;
747 		}
748 	}
749 
750 	if (revents & FDEVENT_OUT) {
751 		/* nothing to do */
752 	}
753 
754 	/* perhaps this issue is already handled */
755 	if (revents & FDEVENT_HUP) {
756 		/* check if we still have a unfinished header package which is a body in reality */
757 		if (con->file_started == 0 && !buffer_string_is_empty(hctx->response_header)) {
758 			con->file_started = 1;
759 			http_chunk_append_buffer(srv, con, hctx->response_header);
760 		}
761 
762 # if 0
763 		log_error_write(srv, __FILE__, __LINE__, "sddd", "got HUP from cgi", con->fd, hctx->fd, revents);
764 # endif
765 
766 		/* rtsigs didn't liked the close */
767 		cgi_connection_close(srv, hctx);
768 	} else if (revents & FDEVENT_ERR) {
769 		/* kill all connections to the cgi process */
770 		cgi_connection_close(srv, hctx);
771 #if 1
772 		log_error_write(srv, __FILE__, __LINE__, "s", "cgi-FDEVENT_ERR");
773 #endif
774 		return HANDLER_ERROR;
775 	}
776 
777 	return HANDLER_FINISHED;
778 }
779 
780 
781 static int cgi_env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
782 	char *dst;
783 
784 	if (!key || !val) return -1;
785 
786 	dst = malloc(key_len + val_len + 2);
787 	force_assert(dst);
788 	memcpy(dst, key, key_len);
789 	dst[key_len] = '=';
790 	memcpy(dst + key_len + 1, val, val_len);
791 	dst[key_len + 1 + val_len] = '\0';
792 
793 	if (env->size == 0) {
794 		env->size = 16;
795 		env->ptr = malloc(env->size * sizeof(*env->ptr));
796 		force_assert(env->ptr);
797 	} else if (env->size == env->used) {
798 		env->size += 16;
799 		env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
800 		force_assert(env->ptr);
801 	}
802 
803 	env->ptr[env->used++] = dst;
804 
805 	return 0;
806 }
807 
808 /* returns: 0: continue, -1: fatal error, -2: connection reset */
809 /* similar to network_write_file_chunk_mmap, but doesn't use send on windows (because we're on pipes),
810  * also mmaps and sends complete chunk instead of only small parts - the files
811  * are supposed to be temp files with reasonable chunk sizes.
812  *
813  * Also always use mmap; the files are "trusted", as we created them.
814  */
815 static ssize_t cgi_write_file_chunk_mmap(server *srv, connection *con, int fd, chunkqueue *cq) {
816 	chunk* const c = cq->first;
817 	off_t offset, toSend, file_end;
818 	ssize_t r;
819 	size_t mmap_offset, mmap_avail;
820 	char *data;
821 
822 	force_assert(NULL != c);
823 	force_assert(FILE_CHUNK == c->type);
824 	force_assert(c->offset >= 0 && c->offset <= c->file.length);
825 
826 	offset = c->file.start + c->offset;
827 	toSend = c->file.length - c->offset;
828 	file_end = c->file.start + c->file.length; /* offset to file end in this chunk */
829 
830 	if (0 == toSend) {
831 		chunkqueue_remove_finished_chunks(cq);
832 		return 0;
833 	}
834 
835 	if (0 != network_open_file_chunk(srv, con, cq)) return -1;
836 
837 	/* (re)mmap the buffer if range is not covered completely */
838 	if (MAP_FAILED == c->file.mmap.start
839 		|| offset < c->file.mmap.offset
840 		|| file_end > (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
841 
842 		if (MAP_FAILED != c->file.mmap.start) {
843 			munmap(c->file.mmap.start, c->file.mmap.length);
844 			c->file.mmap.start = MAP_FAILED;
845 		}
846 
847 		c->file.mmap.offset = mmap_align_offset(offset);
848 		c->file.mmap.length = file_end - c->file.mmap.offset;
849 
850 		if (MAP_FAILED == (c->file.mmap.start = mmap(NULL, c->file.mmap.length, PROT_READ, MAP_PRIVATE, c->file.fd, c->file.mmap.offset))) {
851 			if (toSend > 65536) toSend = 65536;
852 			data = malloc(toSend);
853 			force_assert(data);
854 			if (-1 == lseek(c->file.fd, offset, SEEK_SET)
855 			    || 0 >= (toSend = read(c->file.fd, data, toSend))) {
856 				if (-1 == toSend) {
857 					log_error_write(srv, __FILE__, __LINE__, "ssbdo", "lseek/read failed:",
858 						strerror(errno), c->file.name, c->file.fd, offset);
859 				} else { /*(0 == toSend)*/
860 					log_error_write(srv, __FILE__, __LINE__, "sbdo", "unexpected EOF (input truncated?):",
861 						c->file.name, c->file.fd, offset);
862 				}
863 				free(data);
864 				return -1;
865 			}
866 		}
867 	}
868 
869 	if (MAP_FAILED != c->file.mmap.start) {
870 		force_assert(offset >= c->file.mmap.offset);
871 		mmap_offset = offset - c->file.mmap.offset;
872 		force_assert(c->file.mmap.length > mmap_offset);
873 		mmap_avail = c->file.mmap.length - mmap_offset;
874 		force_assert(toSend <= (off_t) mmap_avail);
875 
876 		data = c->file.mmap.start + mmap_offset;
877 	}
878 
879 	r = write(fd, data, toSend);
880 
881 	if (MAP_FAILED == c->file.mmap.start) free(data);
882 
883 	if (r < 0) {
884 		switch (errno) {
885 		case EAGAIN:
886 		case EINTR:
887 			return 0;
888 		case EPIPE:
889 		case ECONNRESET:
890 			return -2;
891 		default:
892 			log_error_write(srv, __FILE__, __LINE__, "ssd",
893 				"write failed:", strerror(errno), fd);
894 			return -1;
895 		}
896 	}
897 
898 	if (r >= 0) {
899 		chunkqueue_mark_written(cq, r);
900 	}
901 
902 	return r;
903 }
904 
905 static int cgi_write_request(server *srv, handler_ctx *hctx, int fd) {
906 	connection *con = hctx->remote_conn;
907 	chunkqueue *cq = con->request_content_queue;
908 	chunk *c;
909 
910 	/* old comment: windows doesn't support select() on pipes - wouldn't be easy to fix for all platforms.
911 	 * solution: if this is still a problem on windows, then substitute
912 	 * socketpair() for pipe() and closesocket() for close() on windows.
913 	 */
914 
915 	for (c = cq->first; c; c = cq->first) {
916 		ssize_t r = -1;
917 
918 		switch(c->type) {
919 		case FILE_CHUNK:
920 			r = cgi_write_file_chunk_mmap(srv, con, fd, cq);
921 			break;
922 
923 		case MEM_CHUNK:
924 			if ((r = write(fd, c->mem->ptr + c->offset, buffer_string_length(c->mem) - c->offset)) < 0) {
925 				switch(errno) {
926 				case EAGAIN:
927 				case EINTR:
928 					/* ignore and try again */
929 					r = 0;
930 					break;
931 				case EPIPE:
932 				case ECONNRESET:
933 					/* connection closed */
934 					r = -2;
935 					break;
936 				default:
937 					/* fatal error */
938 					log_error_write(srv, __FILE__, __LINE__, "ss", "write failed due to: ", strerror(errno));
939 					r = -1;
940 					break;
941 				}
942 			} else if (r > 0) {
943 				chunkqueue_mark_written(cq, r);
944 			}
945 			break;
946 		}
947 
948 		if (0 == r) break; /*(might block)*/
949 
950 		switch (r) {
951 		case -1:
952 			/* fatal error */
953 			return -1;
954 		case -2:
955 			/* connection reset */
956 			log_error_write(srv, __FILE__, __LINE__, "s", "failed to send post data to cgi, connection closed by CGI");
957 			/* skip all remaining data */
958 			chunkqueue_mark_written(cq, chunkqueue_length(cq));
959 			break;
960 		default:
961 			break;
962 		}
963 	}
964 
965 	if (chunkqueue_is_empty(cq)) {
966 		/* sent all request body input */
967 		/* close connection to the cgi-script */
968 		if (-1 == hctx->fdtocgi) { /*(entire request body sent in initial send to pipe buffer)*/
969 			if (close(fd)) {
970 				log_error_write(srv, __FILE__, __LINE__, "sds", "cgi stdin close failed ", fd, strerror(errno));
971 			}
972 		} else {
973 			cgi_connection_close_fdtocgi(srv, hctx); /*(closes only hctx->fdtocgi)*/
974 		}
975 	} else {
976 		/* more request body remains to be sent to CGI so register for fdevents */
977 		if (-1 == hctx->fdtocgi) { /*(not registered yet)*/
978 			hctx->fdtocgi = fd;
979 			hctx->fde_ndx_tocgi = -1;
980 			fdevent_register(srv->ev, hctx->fdtocgi, cgi_handle_fdevent_send, hctx);
981 			fdevent_event_set(srv->ev, &(hctx->fde_ndx_tocgi), hctx->fdtocgi, FDEVENT_OUT);
982 		}
983 	}
984 
985 	return 0;
986 }
987 
988 static int cgi_create_env(server *srv, connection *con, plugin_data *p, handler_ctx *hctx, buffer *cgi_handler) {
989 	pid_t pid;
990 
991 #ifdef HAVE_IPV6
992 	char b2[INET6_ADDRSTRLEN + 1];
993 #endif
994 
995 	int to_cgi_fds[2];
996 	int from_cgi_fds[2];
997 	struct stat st;
998 
999 #ifndef __WIN32
1000 
1001 	if (!buffer_string_is_empty(cgi_handler)) {
1002 		/* stat the exec file */
1003 		if (-1 == (stat(cgi_handler->ptr, &st))) {
1004 			log_error_write(srv, __FILE__, __LINE__, "sbss",
1005 					"stat for cgi-handler", cgi_handler,
1006 					"failed:", strerror(errno));
1007 			return -1;
1008 		}
1009 	}
1010 
1011 	if (pipe(to_cgi_fds)) {
1012 		log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
1013 		return -1;
1014 	}
1015 
1016 	if (pipe(from_cgi_fds)) {
1017 		close(to_cgi_fds[0]);
1018 		close(to_cgi_fds[1]);
1019 		log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
1020 		return -1;
1021 	}
1022 
1023 	/* fork, execve */
1024 	switch (pid = fork()) {
1025 	case 0: {
1026 		/* child */
1027 		char **args;
1028 		int argc;
1029 		int i = 0;
1030 		char buf[LI_ITOSTRING_LENGTH];
1031 		size_t n;
1032 		char_array env;
1033 		char *c;
1034 		const char *s;
1035 		server_socket *srv_sock = con->srv_socket;
1036 
1037 		/* move stdout to from_cgi_fd[1] */
1038 		close(STDOUT_FILENO);
1039 		dup2(from_cgi_fds[1], STDOUT_FILENO);
1040 		close(from_cgi_fds[1]);
1041 		/* not needed */
1042 		close(from_cgi_fds[0]);
1043 
1044 		/* move the stdin to to_cgi_fd[0] */
1045 		close(STDIN_FILENO);
1046 		dup2(to_cgi_fds[0], STDIN_FILENO);
1047 		close(to_cgi_fds[0]);
1048 		/* not needed */
1049 		close(to_cgi_fds[1]);
1050 
1051 		/* create environment */
1052 		env.ptr = NULL;
1053 		env.size = 0;
1054 		env.used = 0;
1055 
1056 		if (buffer_is_empty(con->conf.server_tag)) {
1057 			cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_DESC));
1058 		} else {
1059 			cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_BUF_LEN(con->conf.server_tag));
1060 		}
1061 
1062 		if (!buffer_string_is_empty(con->server_name)) {
1063 			size_t len = buffer_string_length(con->server_name);
1064 
1065 			if (con->server_name->ptr[0] == '[') {
1066 				const char *colon = strstr(con->server_name->ptr, "]:");
1067 				if (colon) len = (colon + 1) - con->server_name->ptr;
1068 			} else {
1069 				const char *colon = strchr(con->server_name->ptr, ':');
1070 				if (colon) len = colon - con->server_name->ptr;
1071 			}
1072 
1073 			cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), con->server_name->ptr, len);
1074 		} else {
1075 #ifdef HAVE_IPV6
1076 			s = inet_ntop(
1077 				srv_sock->addr.plain.sa_family,
1078 				srv_sock->addr.plain.sa_family == AF_INET6 ?
1079 				(const void *) &(srv_sock->addr.ipv6.sin6_addr) :
1080 				(const void *) &(srv_sock->addr.ipv4.sin_addr),
1081 				b2, sizeof(b2)-1);
1082 #else
1083 			s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
1084 #endif
1085 			force_assert(s);
1086 			cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
1087 		}
1088 		cgi_env_add(&env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
1089 
1090 		s = get_http_version_name(con->request.http_version);
1091 		force_assert(s);
1092 		cgi_env_add(&env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
1093 
1094 		li_utostrn(buf, sizeof(buf),
1095 #ifdef HAVE_IPV6
1096 			ntohs(srv_sock->addr.plain.sa_family == AF_INET6 ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
1097 #else
1098 			ntohs(srv_sock->addr.ipv4.sin_port)
1099 #endif
1100 			);
1101 		cgi_env_add(&env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
1102 
1103 		switch (srv_sock->addr.plain.sa_family) {
1104 #ifdef HAVE_IPV6
1105 		case AF_INET6:
1106 			s = inet_ntop(
1107 				srv_sock->addr.plain.sa_family,
1108 				(const void *) &(srv_sock->addr.ipv6.sin6_addr),
1109 				b2, sizeof(b2)-1);
1110 			break;
1111 		case AF_INET:
1112 			s = inet_ntop(
1113 				srv_sock->addr.plain.sa_family,
1114 				(const void *) &(srv_sock->addr.ipv4.sin_addr),
1115 				b2, sizeof(b2)-1);
1116 			break;
1117 #else
1118 		case AF_INET:
1119 			s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
1120 			break;
1121 #endif
1122 		default:
1123 			s = "";
1124 			break;
1125 		}
1126 		force_assert(s);
1127 		cgi_env_add(&env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
1128 
1129 		s = get_http_method_name(con->request.http_method);
1130 		force_assert(s);
1131 		cgi_env_add(&env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
1132 
1133 		if (!buffer_string_is_empty(con->request.pathinfo)) {
1134 			cgi_env_add(&env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
1135 		}
1136 		if (!buffer_string_is_empty(con->uri.query)) {
1137 			cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
1138 		} else {
1139 			cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
1140 		}
1141 		if (con->error_handler_saved_status >= 0) {
1142 			cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.uri));
1143 		} else {
1144 			cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
1145 		}
1146 		/* set REDIRECT_STATUS for php compiled with --force-redirect
1147 		 * (if REDIRECT_STATUS has not already been set by error handler) */
1148 		if (0 == con->error_handler_saved_status) {
1149 			cgi_env_add(&env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200"));
1150 		}
1151 
1152 
1153 		switch (con->dst_addr.plain.sa_family) {
1154 #ifdef HAVE_IPV6
1155 		case AF_INET6:
1156 			s = inet_ntop(
1157 				con->dst_addr.plain.sa_family,
1158 				(const void *) &(con->dst_addr.ipv6.sin6_addr),
1159 				b2, sizeof(b2)-1);
1160 			break;
1161 		case AF_INET:
1162 			s = inet_ntop(
1163 				con->dst_addr.plain.sa_family,
1164 				(const void *) &(con->dst_addr.ipv4.sin_addr),
1165 				b2, sizeof(b2)-1);
1166 			break;
1167 #else
1168 		case AF_INET:
1169 			s = inet_ntoa(con->dst_addr.ipv4.sin_addr);
1170 			break;
1171 #endif
1172 		default:
1173 			s = "";
1174 			break;
1175 		}
1176 		force_assert(s);
1177 		cgi_env_add(&env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
1178 
1179 		li_utostrn(buf, sizeof(buf),
1180 #ifdef HAVE_IPV6
1181 			ntohs(con->dst_addr.plain.sa_family == AF_INET6 ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
1182 #else
1183 			ntohs(con->dst_addr.ipv4.sin_port)
1184 #endif
1185 			);
1186 		cgi_env_add(&env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
1187 
1188 		if (buffer_is_equal_caseless_string(con->uri.scheme, CONST_STR_LEN("https"))) {
1189 			cgi_env_add(&env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
1190 		}
1191 
1192 		li_itostrn(buf, sizeof(buf), con->request.content_length);
1193 		cgi_env_add(&env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
1194 		cgi_env_add(&env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
1195 		cgi_env_add(&env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
1196 		cgi_env_add(&env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir));
1197 
1198 		/* for valgrind */
1199 		if (NULL != (s = getenv("LD_PRELOAD"))) {
1200 			cgi_env_add(&env, CONST_STR_LEN("LD_PRELOAD"), s, strlen(s));
1201 		}
1202 
1203 		if (NULL != (s = getenv("LD_LIBRARY_PATH"))) {
1204 			cgi_env_add(&env, CONST_STR_LEN("LD_LIBRARY_PATH"), s, strlen(s));
1205 		}
1206 #ifdef __CYGWIN__
1207 		/* CYGWIN needs SYSTEMROOT */
1208 		if (NULL != (s = getenv("SYSTEMROOT"))) {
1209 			cgi_env_add(&env, CONST_STR_LEN("SYSTEMROOT"), s, strlen(s));
1210 		}
1211 #endif
1212 
1213 		for (n = 0; n < con->request.headers->used; n++) {
1214 			data_string *ds;
1215 
1216 			ds = (data_string *)con->request.headers->data[n];
1217 
1218 			if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
1219 				buffer_copy_string_encoded_cgi_varnames(p->tmp_buf, CONST_BUF_LEN(ds->key), 1);
1220 
1221 				cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
1222 			}
1223 		}
1224 
1225 		for (n = 0; n < con->environment->used; n++) {
1226 			data_string *ds;
1227 
1228 			ds = (data_string *)con->environment->data[n];
1229 
1230 			if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
1231 				buffer_copy_string_encoded_cgi_varnames(p->tmp_buf, CONST_BUF_LEN(ds->key), 0);
1232 
1233 				cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
1234 			}
1235 		}
1236 
1237 		if (env.size == env.used) {
1238 			env.size += 16;
1239 			env.ptr = realloc(env.ptr, env.size * sizeof(*env.ptr));
1240 		}
1241 
1242 		env.ptr[env.used] = NULL;
1243 
1244 		/* set up args */
1245 		argc = 3;
1246 		args = malloc(sizeof(*args) * argc);
1247 		force_assert(args);
1248 		i = 0;
1249 
1250 		if (!buffer_string_is_empty(cgi_handler)) {
1251 			args[i++] = cgi_handler->ptr;
1252 		}
1253 		args[i++] = con->physical.path->ptr;
1254 		args[i  ] = NULL;
1255 
1256 		/* search for the last / */
1257 		if (NULL != (c = strrchr(con->physical.path->ptr, '/'))) {
1258 			/* handle special case of file in root directory */
1259 			const char* physdir = (c == con->physical.path->ptr) ? "/" : con->physical.path->ptr;
1260 
1261 			/* temporarily shorten con->physical.path to directory without terminating '/' */
1262 			*c = '\0';
1263 			/* change to the physical directory */
1264 			if (-1 == chdir(physdir)) {
1265 				log_error_write(srv, __FILE__, __LINE__, "ssb", "chdir failed:", strerror(errno), con->physical.path);
1266 			}
1267 			*c = '/';
1268 		}
1269 
1270 		/* we don't need the client socket */
1271 		for (i = 3; i < 256; i++) {
1272 			if (i != srv->errorlog_fd) close(i);
1273 		}
1274 
1275 		/* exec the cgi */
1276 		execve(args[0], args, env.ptr);
1277 
1278 		/* most log files may have been closed/redirected by this point,
1279 		 * though stderr might still point to lighttpd.breakage.log */
1280 		perror(args[0]);
1281 		_exit(1);
1282 	}
1283 	case -1:
1284 		/* error */
1285 		log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno));
1286 		close(from_cgi_fds[0]);
1287 		close(from_cgi_fds[1]);
1288 		close(to_cgi_fds[0]);
1289 		close(to_cgi_fds[1]);
1290 		return -1;
1291 	default: {
1292 		/* parent process */
1293 
1294 		close(from_cgi_fds[1]);
1295 		close(to_cgi_fds[0]);
1296 
1297 		/* register PID and wait for them asynchronously */
1298 
1299 		hctx->pid = pid;
1300 		hctx->fd = from_cgi_fds[0];
1301 		hctx->fde_ndx = -1;
1302 
1303 		if (0 == con->request.content_length) {
1304 			close(to_cgi_fds[1]);
1305 		} else {
1306 			/* there is content to send */
1307 			if (-1 == fdevent_fcntl_set(srv->ev, to_cgi_fds[1])) {
1308 				log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
1309 				close(to_cgi_fds[1]);
1310 				cgi_connection_close(srv, hctx);
1311 				return -1;
1312 			}
1313 
1314 			if (0 != cgi_write_request(srv, hctx, to_cgi_fds[1])) {
1315 				close(to_cgi_fds[1]);
1316 				cgi_connection_close(srv, hctx);
1317 				return -1;
1318 			}
1319 		}
1320 
1321 		fdevent_register(srv->ev, hctx->fd, cgi_handle_fdevent, hctx);
1322 		fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
1323 
1324 		if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
1325 			log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
1326 			cgi_connection_close(srv, hctx);
1327 			return -1;
1328 		}
1329 
1330 		break;
1331 	}
1332 	}
1333 
1334 	return 0;
1335 #else
1336 	return -1;
1337 #endif
1338 }
1339 
1340 static buffer * cgi_get_handler(array *a, buffer *fn) {
1341 	size_t k, s_len = buffer_string_length(fn);
1342 	for (k = 0; k < a->used; ++k) {
1343 		data_string *ds = (data_string *)a->data[k];
1344 		size_t ct_len = buffer_string_length(ds->key);
1345 
1346 		if (buffer_is_empty(ds->key)) continue;
1347 		if (s_len < ct_len) continue;
1348 
1349 		if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
1350 			return ds->value;
1351 		}
1352 	}
1353 
1354 	return NULL;
1355 }
1356 
1357 #define PATCH(x) \
1358 	p->conf.x = s->x;
1359 static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p) {
1360 	size_t i, j;
1361 	plugin_config *s = p->config_storage[0];
1362 
1363 	PATCH(cgi);
1364 	PATCH(execute_x_only);
1365 	PATCH(xsendfile_allow);
1366 	PATCH(xsendfile_docroot);
1367 
1368 	/* skip the first, the global context */
1369 	for (i = 1; i < srv->config_context->used; i++) {
1370 		data_config *dc = (data_config *)srv->config_context->data[i];
1371 		s = p->config_storage[i];
1372 
1373 		/* condition didn't match */
1374 		if (!config_check_cond(srv, con, dc)) continue;
1375 
1376 		/* merge config */
1377 		for (j = 0; j < dc->value->used; j++) {
1378 			data_unset *du = dc->value->data[j];
1379 
1380 			if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.assign"))) {
1381 				PATCH(cgi);
1382 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.execute-x-only"))) {
1383 				PATCH(execute_x_only);
1384 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.x-sendfile"))) {
1385 				PATCH(xsendfile_allow);
1386 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.x-sendfile-docroot"))) {
1387 				PATCH(xsendfile_docroot);
1388 			}
1389 		}
1390 	}
1391 
1392 	return 0;
1393 }
1394 #undef PATCH
1395 
1396 URIHANDLER_FUNC(cgi_is_handled) {
1397 	plugin_data *p = p_d;
1398 	buffer *fn = con->physical.path;
1399 	stat_cache_entry *sce = NULL;
1400 
1401 	if (con->mode != DIRECT) return HANDLER_GO_ON;
1402 
1403 	if (buffer_is_empty(fn)) return HANDLER_GO_ON;
1404 
1405 	mod_cgi_patch_connection(srv, con, p);
1406 
1407 	if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) return HANDLER_GO_ON;
1408 	if (!S_ISREG(sce->st.st_mode)) return HANDLER_GO_ON;
1409 	if (p->conf.execute_x_only == 1 && (sce->st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) return HANDLER_GO_ON;
1410 
1411 	if (NULL != cgi_get_handler(p->conf.cgi, fn)) {
1412 		handler_ctx *hctx = cgi_handler_ctx_init();
1413 		hctx->remote_conn = con;
1414 		hctx->plugin_data = p;
1415 		con->plugin_ctx[p->id] = hctx;
1416 		con->mode = p->id;
1417 	}
1418 
1419 	return HANDLER_GO_ON;
1420 }
1421 
1422 TRIGGER_FUNC(cgi_trigger) {
1423 	plugin_data *p = p_d;
1424 	size_t ndx;
1425 	/* the trigger handle only cares about lonely PID which we have to wait for */
1426 #ifndef __WIN32
1427 
1428 	for (ndx = 0; ndx < p->cgi_pid.used; ndx++) {
1429 		int status;
1430 
1431 		switch(waitpid(p->cgi_pid.ptr[ndx], &status, WNOHANG)) {
1432 		case 0:
1433 			/* not finished yet */
1434 #if 0
1435 			log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) child isn't done yet, pid:", p->cgi_pid.ptr[ndx]);
1436 #endif
1437 			break;
1438 		case -1:
1439 			if (errno == ECHILD) {
1440 				/* someone else called waitpid... remove the pid to stop looping the error each time */
1441 				log_error_write(srv, __FILE__, __LINE__, "s", "cgi child vanished, probably someone else called waitpid");
1442 
1443 				cgi_pid_del(srv, p, p->cgi_pid.ptr[ndx]);
1444 				ndx--;
1445 				continue;
1446 			}
1447 
1448 			log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
1449 
1450 			return HANDLER_ERROR;
1451 		default:
1452 
1453 			if (WIFEXITED(status)) {
1454 #if 0
1455 				log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", p->cgi_pid.ptr[ndx]);
1456 #endif
1457 			} else if (WIFSIGNALED(status)) {
1458 				/* FIXME: what if we killed the CGI script with a kill(..., SIGTERM) ?
1459 				 */
1460 				if (WTERMSIG(status) != SIGTERM) {
1461 					log_error_write(srv, __FILE__, __LINE__, "sd", "cleaning up CGI: process died with signal", WTERMSIG(status));
1462 				}
1463 			} else {
1464 				log_error_write(srv, __FILE__, __LINE__, "s", "cleaning up CGI: ended unexpectedly");
1465 			}
1466 
1467 			cgi_pid_del(srv, p, p->cgi_pid.ptr[ndx]);
1468 			/* del modified the buffer structure
1469 			 * and copies the last entry to the current one
1470 			 * -> recheck the current index
1471 			 */
1472 			ndx--;
1473 		}
1474 	}
1475 #endif
1476 	return HANDLER_GO_ON;
1477 }
1478 
1479 /*
1480  * - HANDLER_GO_ON : not our job
1481  * - HANDLER_FINISHED: got response
1482  * - HANDLER_WAIT_FOR_EVENT: waiting for response
1483  */
1484 SUBREQUEST_FUNC(mod_cgi_handle_subrequest) {
1485 	plugin_data *p = p_d;
1486 	handler_ctx *hctx = con->plugin_ctx[p->id];
1487 
1488 	if (con->mode != p->id) return HANDLER_GO_ON;
1489 	if (NULL == hctx) return HANDLER_GO_ON;
1490 
1491 	if (con->state == CON_STATE_READ_POST) {
1492 		handler_t r = connection_handle_read_post_state(srv, con);
1493 		if (r != HANDLER_GO_ON) return r;
1494 	}
1495 
1496 	if (-1 == hctx->fd) {
1497 		buffer *handler = cgi_get_handler(p->conf.cgi, con->physical.path);
1498 		if (!handler) return HANDLER_GO_ON; /*(should not happen; checked in cgi_is_handled())*/
1499 		if (cgi_create_env(srv, con, p, hctx, handler)) {
1500 			con->http_status = 500;
1501 			con->mode = DIRECT;
1502 
1503 			return HANDLER_FINISHED;
1504 		}
1505 	}
1506 
1507 #if 0
1508 	log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", hctx, hctx->pid);
1509 #endif
1510 
1511 	/* if not done, wait for CGI to close stdout, so we read EOF on pipe */
1512 	return con->file_finished ? HANDLER_FINISHED : HANDLER_WAIT_FOR_EVENT;
1513 }
1514 
1515 
1516 int mod_cgi_plugin_init(plugin *p);
1517 int mod_cgi_plugin_init(plugin *p) {
1518 	p->version     = LIGHTTPD_VERSION_ID;
1519 	p->name        = buffer_init_string("cgi");
1520 
1521 	p->connection_reset = cgi_connection_close_callback;
1522 	p->handle_subrequest_start = cgi_is_handled;
1523 	p->handle_subrequest = mod_cgi_handle_subrequest;
1524 	p->handle_trigger = cgi_trigger;
1525 	p->init           = mod_cgi_init;
1526 	p->cleanup        = mod_cgi_free;
1527 	p->set_defaults   = mod_fastcgi_set_defaults;
1528 
1529 	p->data        = NULL;
1530 
1531 	return 0;
1532 }
1533