1 /* This program is free software; you can redistribute it and/or modify
2  * it under the terms of the GNU General Public License as published by
3  * the Free Software Foundation; version 2 of the License. For a copy,
4  * see http://www.gnu.org/licenses/gpl-2.0.html.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU General Public License for more details.
10  */
11 
12 #include "config.h"
13 #include <sys/types.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <string.h>
17 #include <fcntl.h>
18 #include <errno.h>
19 #include <pthread.h>
20 #include <poll.h>
21 #include <sys/socket.h>
22 #include <sys/time.h>
23 #include "global.h"
24 #include "alternative.h"
25 #include "libstr.h"
26 #include "send.h"
27 #include "cgi.h"
28 #include "client.h"
29 #include "serverconfig.h"
30 #include "envir.h"
31 #include "ip.h"
32 #include "log.h"
33 #include "memdbg.h"
34 
35 #define MAX_CGI_DELAY_TIMER (int)MINUTE / TASK_RUNNER_INTERVAL
36 #define DUMMY_BUFFER_SIZE           64 * KILOBYTE
37 #define UPLOADED_FILE_BUFFER_SIZE 4096
38 
39 static int delay_timer = 0;
40 
fix_crappy_cgi_headers(t_cgi_info * cgi_info)41 int fix_crappy_cgi_headers(t_cgi_info *cgi_info) {
42 	char *header_end, *new_buffer, *src, *dst;
43 	int count = 0, header_len, new_size;
44 
45 	if ((header_end = strstr(cgi_info->input_buffer, "\n\n")) == NULL) {
46 		return 1;
47 	}
48 	header_end += 2;
49 
50 	/* Count EOL
51 	 */
52 	src = cgi_info->input_buffer;
53 	while (src < header_end) {
54 		if (*src == '\n') {
55 			count++;
56 		}
57 		src++;
58 	}
59 
60 	/* Allocate new buffer
61 	 */
62 	new_size = cgi_info->input_len + count;
63 	if ((new_buffer = (char*)malloc(new_size + 1)) == NULL) {
64 		return -1;
65 	}
66 
67 	/* Fix EOL
68 	 */
69 	src = cgi_info->input_buffer;
70 	dst = new_buffer;
71 	while (src < header_end) {
72 		if (*src == '\n') {
73 			*(dst++) = '\r';
74 		}
75 		*(dst++) = *(src++);
76 	}
77 
78 	/* Copy request body
79 	 */
80 	header_len = header_end - cgi_info->input_buffer;
81 	memcpy(new_buffer + header_len + count, header_end, cgi_info->input_len - header_len + 1);
82 
83 	free(cgi_info->input_buffer);
84 	cgi_info->input_buffer = new_buffer;
85 	cgi_info->input_len += count;
86 	cgi_info->input_buffer_size = new_size;
87 
88 	return 0;
89 }
90 
find_cgi_header(char * buffer,int size,char * header)91 char *find_cgi_header(char *buffer, int size, char *header) {
92 	char *start, *pos;
93 
94 	if ((header == NULL) || (buffer == NULL)) {
95 		return NULL;
96 	}
97 
98 	start = buffer;
99 	while ((pos = strncasestr(buffer, header, size)) != NULL) {
100 		if (pos == start) {
101 			return start;
102 		} else if (*(pos - 1) == '\n') {
103 			return pos;
104 		}
105 
106 		size -= pos + 1 - buffer;
107 		buffer = pos + 1;
108 	}
109 
110 	return NULL;
111 }
112 
113 /*
114  * Load balancer
115  * ==============
116  */
init_load_balancer(t_fcgi_server * fcgi_server)117 int init_load_balancer(t_fcgi_server *fcgi_server) {
118 	int i;
119 
120 	while (fcgi_server != NULL) {
121 		for (i = 0; i < 256; i++) {
122 			fcgi_server->cgi_session_list[i] = NULL;
123 			if (pthread_mutex_init(&fcgi_server->cgi_session_mutex[i], NULL) != 0) {
124 				return -1;
125 			}
126 		}
127 		fcgi_server = fcgi_server->next;
128 	}
129 
130 	return 0;
131 }
132 
select_connect_to(t_fcgi_server * fcgi_server,t_ip_addr * client_ip)133 t_connect_to *select_connect_to(t_fcgi_server *fcgi_server, t_ip_addr *client_ip) {
134 	t_connect_to  *connect_to = NULL;
135 	t_cgi_session *cgi_session;
136 	bool search_new_fcgi_server = true;
137 	unsigned char i;
138 	time_t now;
139 
140 
141 	if ((fcgi_server == NULL) || (client_ip == NULL)) {
142 		return NULL;
143 	}
144 
145 	/* Only one connect_to?
146 	 */
147 	if (fcgi_server->connect_to->next == fcgi_server->connect_to) {
148 		return fcgi_server->connect_to;
149 	}
150 
151 	now = time(NULL);
152 
153 	i = index_by_ip(client_ip);
154 	pthread_mutex_lock(&fcgi_server->cgi_session_mutex[i]);
155 
156 	/* Search in cgi_session_list
157 	 */
158 	cgi_session = fcgi_server->cgi_session_list[i];
159 	while (cgi_session != NULL) {
160 		if (same_ip(&(cgi_session->client_ip), client_ip)) {
161 			if (now < cgi_session->session_timeout) {
162 				if (cgi_session->connect_to->available) {
163 					cgi_session->session_timeout = now + fcgi_server->session_timeout;
164 					connect_to = cgi_session->connect_to;
165 				} else {
166 					/* Make sure it won't match the next round */
167 					cgi_session->client_ip.family = AF_UNSPEC;
168 				}
169 				search_new_fcgi_server = false;
170 			}
171 			break;
172 		}
173 		cgi_session = cgi_session->next;
174 	}
175 
176 	if (search_new_fcgi_server) {
177 		connect_to = fcgi_server->connect_to;
178 		while (connect_to->available == false) {
179 			if ((connect_to = connect_to->next) == fcgi_server->connect_to) {
180 				break;
181 			}
182 		}
183 		fcgi_server->connect_to = connect_to->next;
184 
185 		/* Add to cgi_session_list
186 		 */
187 		if (fcgi_server->session_timeout > 0) {
188 			if ((cgi_session = (t_cgi_session*)malloc(sizeof(t_cgi_session))) != NULL) {
189 				copy_ip(&(cgi_session->client_ip), client_ip);
190 				cgi_session->connect_to = connect_to;
191 				cgi_session->session_timeout = now + fcgi_server->session_timeout;
192 
193 				cgi_session->next = fcgi_server->cgi_session_list[i];
194 				fcgi_server->cgi_session_list[i] = cgi_session;
195 			}
196 		}
197 	}
198 
199 	pthread_mutex_unlock(&fcgi_server->cgi_session_mutex[i]);
200 
201 	return connect_to;
202 }
203 
manage_load_balancer(t_config * config,time_t now)204 void manage_load_balancer(t_config *config, time_t now) {
205 	t_fcgi_server *fcgi_server;
206 	t_cgi_session *cgi_session, *last, *next = NULL;
207 	t_connect_to  *connect_to = NULL;
208 	int i, sock;
209 
210 	if (++delay_timer < MAX_CGI_DELAY_TIMER) {
211 		return;
212 	}
213 
214 	fcgi_server = config->fcgi_server;
215 	while (fcgi_server != NULL) {
216 		/* Check session timeouts
217 		 */
218 		for (i = 0; i < 256; i++) {
219 			pthread_mutex_lock(&fcgi_server->cgi_session_mutex[i]);
220 
221 			last = NULL;
222 			cgi_session = fcgi_server->cgi_session_list[i];
223 			while (cgi_session != NULL) {
224 				next = cgi_session->next;
225 
226 				if ((now > cgi_session->session_timeout) || (cgi_session->connect_to->available == false)) {
227 					if (last == NULL) {
228 						fcgi_server->cgi_session_list[i] = next;
229 					} else {
230 						last->next = next;
231 					}
232 					free(cgi_session);
233 				} else {
234 					last = cgi_session;
235 				}
236 				cgi_session = next;
237 			}
238 
239 			pthread_mutex_unlock(&fcgi_server->cgi_session_mutex[i]);
240 		}
241 
242 		/* Check if offline FastCGI servers are available again
243 		 */
244 		connect_to = fcgi_server->connect_to;
245 		do {
246 			if (connect_to->available == false) {
247 				if ((sock = connect_to_fcgi_server(connect_to)) != -1) {
248 					close(sock);
249 					connect_to->available = true;
250 				} else {
251 					log_system(config, "FastCGI server %s is still (partially) unavailable", fcgi_server->fcgi_id);
252 				}
253 			}
254 			connect_to = connect_to->next;
255 		} while (connect_to != fcgi_server->connect_to);
256 
257 		fcgi_server = fcgi_server->next;
258 	}
259 
260 	delay_timer = 0;
261 }
262 
263 /*
264  * Search FastCGI server
265  * ======================
266  */
267 
fcgi_server_match(t_fcgi_server ** fcgi_server,char * extension)268 t_fcgi_server *fcgi_server_match(t_fcgi_server **fcgi_server, char *extension) {
269 	int i;
270 
271 	if ((fcgi_server == NULL) || (extension == NULL)) {
272 		return NULL;
273 	}
274 
275 	i = 0;
276 	while (fcgi_server[i] != NULL) {
277 		if (fcgi_server[i]->extension.size == 0) {
278 			return fcgi_server[i];
279 		} else if (in_charlist(extension, &(fcgi_server[i]->extension))) {
280 			return fcgi_server[i];
281 		}
282 
283 		i++;
284 	}
285 
286 	return NULL;
287 }
288 
find_fcgi_server(t_fcgi_server * fcgi_server,char * fcgi_id)289 t_fcgi_server *find_fcgi_server(t_fcgi_server *fcgi_server, char *fcgi_id) {
290 	if (fcgi_id == NULL) {
291 		return NULL;
292 	}
293 
294 	while (fcgi_server != NULL) {
295 		if (strcasecmp(fcgi_server->fcgi_id, fcgi_id) == 0) {
296 			return fcgi_server;
297 		}
298 
299 		fcgi_server = fcgi_server->next;
300 	}
301 
302 	return NULL;
303 }
304 
305 /*
306  * Normal CGI processes
307  * =====================
308  */
309 
fork_cgi_process(t_session * session,t_cgi_info * cgi_info)310 pid_t fork_cgi_process(t_session *session, t_cgi_info *cgi_info) {
311 	int post_pipe[2], html_pipe[2], error_pipe[2], i, handle, bytes_read;
312 	char *pos, slash = '/', *run[10], cgi_time[16], buffer[UPLOADED_FILE_BUFFER_SIZE];
313 	pid_t cgi_pid;
314 
315 	if (pipe(post_pipe) == -1) {
316 		return -1;
317 	} else if (pipe(html_pipe) == -1) {
318 		close(post_pipe[0]);
319 		close(post_pipe[1]);
320 		return -1;
321 	} else if (pipe(error_pipe) == -1) {
322 		close(html_pipe[0]);
323 		close(html_pipe[1]);
324 		close(post_pipe[0]);
325 		close(post_pipe[1]);
326 		return -1;
327 	}
328 
329 	switch (cgi_pid = fork()) {
330 		case -1:
331 			break;
332 		case 0:
333 			/* Child. Executes CGI program.
334 			 */
335 			dup2(post_pipe[0], STDIN_FILENO);
336 			dup2(html_pipe[1], STDOUT_FILENO);
337 			dup2(error_pipe[1], STDERR_FILENO);
338 
339 			close(post_pipe[0]);
340 			close(post_pipe[1]);
341 			close(html_pipe[0]);
342 			close(html_pipe[1]);
343 			close(error_pipe[0]);
344 			close(error_pipe[1]);
345 
346 			fcntl(STDIN_FILENO, F_SETFD, 0);
347 			fcntl(STDOUT_FILENO, F_SETFD, 0);
348 			fcntl(STDERR_FILENO, F_SETFD, 0);
349 
350 			/* Close all other open filedescriptors.
351 			 */
352 			close_bindings(session->config->binding);
353 			close_client_sockets_for_cgi_run();
354 			close_logfiles_for_cgi_run(session->config->first_host);
355 
356 			set_environment(session, NULL);
357 
358 			pos = strrchr(session->file_on_disk, slash);
359 #ifdef CYGWIN
360 			if ((pos == NULL) && (session->config->platform == windows)) {
361 				slash = '\\';
362 				pos = strrchr(session->file_on_disk, slash);
363 			}
364 #endif
365 			if (pos != NULL) {
366 				*pos = '\0';
367 				if (chdir(session->file_on_disk) == -1) {
368 					log_error_file(session, session->file_on_disk, "couldn't change to CGI directory");
369 				}
370 				*pos = slash;
371 			}
372 
373 			i = 0;
374 			if (cgi_info->wrap_cgi) {
375 				run[i++] = session->config->cgi_wrapper;
376 				if (session->host->wrap_cgi != NULL) {
377 					setenv("CGIWRAP_ID", session->host->wrap_cgi, 1);
378 				} else {
379 					setenv("CGIWRAP_ID", session->local_user, 1);
380 				}
381 				if (session->host->follow_symlinks) {
382 					setenv("CGIWRAP_FOLLOWSYMLINKS", "true", 1);
383 				} else {
384 					setenv("CGIWRAP_FOLLOWSYMLINKS", "false", 1);
385 				}
386 				cgi_time[15] = '\0';
387 				snprintf(cgi_time, 15, "%d", session->host->time_for_cgi);
388 				setenv("CGIWRAP_TIMEFORCGI", cgi_time, 1);
389 				if (session->config->user_directory_set) {
390 					setenv("CGIWRAP_USERDIRECTORY", session->config->user_directory, 1);
391 				}
392 			} else if (setsid() == -1) {
393 				exit(EXIT_FAILURE);
394 			}
395 			if (session->cgi_handler != NULL) {
396 				run[i++] = session->cgi_handler;
397 				run[i++] = session->cgi_handler;
398 			} else {
399 				if (cgi_info->wrap_cgi) {
400 					run[i++] = "-";
401 				}
402 				run[i++] = session->file_on_disk;
403 			}
404 			run[i++] = session->file_on_disk;
405 			run[i] = NULL;
406 
407 			execvp(run[0], run + 1);
408 			perror("execute CGI");
409 			exit(EXIT_FAILURE);
410 		default:
411 			/* Parent. Reads CGI output.
412 			 */
413 			close(post_pipe[0]);
414 			close(error_pipe[1]);
415 			close(html_pipe[1]);
416 
417 			cgi_info->to_cgi = post_pipe[1];
418 			cgi_info->from_cgi = html_pipe[0];
419 			cgi_info->cgi_error = error_pipe[0];
420 
421 			if (session->body != NULL) {
422 				/* Send POST data to CGI program.
423 				 */
424 				if (write_buffer(cgi_info->to_cgi, session->body, session->content_length) == -1) {
425 					close(cgi_info->to_cgi);
426 					close(cgi_info->from_cgi);
427 					close(cgi_info->cgi_error);
428 					return -1;
429 				}
430 			} else if (session->uploaded_file != NULL) {
431 				/* Send uploaded file to CGI program.
432 				 */
433 				if ((handle = open(session->uploaded_file, O_RDONLY)) == -1) {
434 					bytes_read = -1;
435 				} else {
436 					while ((bytes_read = read(handle, buffer, UPLOADED_FILE_BUFFER_SIZE)) > 0) {
437 						if (write_buffer(cgi_info->to_cgi, buffer, bytes_read) == -1) {
438 							bytes_read = -1;
439 							break;
440 						}
441 					}
442 					close(handle);
443 				}
444 
445 				if (bytes_read == -1) {
446 					close(cgi_info->to_cgi);
447 					close(cgi_info->from_cgi);
448 					close(cgi_info->cgi_error);
449 					return -1;
450 				}
451 			}
452 	}
453 
454 	return cgi_pid;
455 }
456 
read_from_cgi_process(t_session * session,t_cgi_info * cgi_info)457 t_cgi_result read_from_cgi_process(t_session *session, t_cgi_info *cgi_info) {
458 	int bytes_read, result = cgi_OKE;
459 	bool read_again;
460 	struct pollfd poll_data[2];
461 	int poll_size;
462 	size_t can_read;
463 
464 	poll_size = 0;
465 	if (cgi_info->from_cgi != -1) {
466 		poll_data[poll_size].fd = cgi_info->from_cgi;
467 		poll_data[poll_size].events = POLL_EVENT_BITS;
468 		poll_size++;
469 	}
470 	if (cgi_info->cgi_error != -1) {
471 		poll_data[poll_size].fd = cgi_info->cgi_error;
472 		poll_data[poll_size].events = POLL_EVENT_BITS;
473 		poll_size++;
474 	}
475 
476 	do {
477 		read_again = false;
478 		switch (poll((struct pollfd*)&poll_data, poll_size, 1000)) {
479 			case -1:
480 				if (errno != EINTR) {
481 					return cgi_ERROR;
482 				}
483 				read_again = true;
484 				break;
485 			case 0:
486 				if (session->force_quit) {
487 					return cgi_FORCE_QUIT;
488 				} else if (time(NULL) > cgi_info->deadline) {
489 					return cgi_TIMEOUT;
490 				}
491 				read_again = true;
492 				break;
493 		}
494 	} while (read_again);
495 
496 	/* Read CGI output
497 	 */
498 	if (cgi_info->from_cgi != -1) {
499 		if (poll_data[0].revents != 0) do {
500 			read_again = false;
501 
502 			if ((can_read = cgi_info->input_buffer_size - cgi_info->input_len) <= 0) {
503 				break;
504 			}
505 
506 			bytes_read = read(cgi_info->from_cgi, cgi_info->input_buffer + cgi_info->input_len, can_read);
507 			switch (bytes_read) {
508 				case -1:
509 					if (errno != EINTR) {
510 						return cgi_ERROR;
511 					}
512 					read_again = true;
513 					break;
514 				case 0:
515 					close(cgi_info->from_cgi);
516 					cgi_info->from_cgi = -1;
517 					break;
518 				default:
519 					cgi_info->input_len += bytes_read;
520 			}
521 		} while (read_again);
522 	}
523 
524 	/* Read CGI error output
525 	 */
526 	if (cgi_info->cgi_error != -1) {
527 		if (poll_data[1].revents != 0) {
528 			do {
529 				read_again = false;
530 
531 				bytes_read = read(cgi_info->cgi_error, cgi_info->error_buffer + cgi_info->error_len, cgi_info->error_buffer_size - cgi_info->error_len);
532 				switch (bytes_read) {
533 					case -1:
534 						if (errno != EINTR) {
535 							return cgi_ERROR;
536 						}
537 						read_again = true;
538 						break;
539 					case 0:
540 						close(cgi_info->cgi_error);
541 						cgi_info->cgi_error = -1;
542 						break;
543 					default:
544 						cgi_info->error_len += bytes_read;
545 				}
546 			} while (read_again);
547 		} else if (recv(cgi_info->cgi_error, cgi_info->error_buffer + cgi_info->error_len, cgi_info->error_buffer_size - cgi_info->error_len, MSG_PEEK | MSG_DONTWAIT) <= 0) {
548 			close(cgi_info->cgi_error);
549 			cgi_info->cgi_error = -1;
550 		}
551 	}
552 
553 	if ((cgi_info->from_cgi == -1) && (cgi_info->cgi_error == -1)) {
554 		result = cgi_END_OF_DATA;
555 	}
556 
557 	return result;
558 }
559 
560 /*
561  *  FastCGI servers
562  *  ================
563  */
connect_to_fcgi_server(t_connect_to * connect_to)564 int connect_to_fcgi_server(t_connect_to *connect_to) {
565 	if (connect_to == NULL) {
566 		return -1;
567 	}
568 
569 	if (connect_to->unix_socket != NULL) {
570 		return connect_to_unix_socket(connect_to->unix_socket);
571 	} else {
572 		return connect_to_server(&(connect_to->ip_addr), connect_to->port);
573 	}
574 }
575 
send_fcgi_request(t_session * session,int sock)576 int send_fcgi_request(t_session *session, int sock) {
577 	t_fcgi_buffer fcgi_buffer;
578 	char buffer[UPLOADED_FILE_BUFFER_SIZE];
579 	int handle, bytes_read;
580 
581 	fcgi_buffer.sock = sock;
582 	fcgi_buffer.size = 0;
583 
584 	if (write_buffer(sock, "\x01\x01\x00\x01" "\x00\x08\x00\x00" "\x00\x01\x00\x00" "\x00\x00\x00\x00", 16) == -1) {
585 		return -1;
586 	}
587 
588 	fcgi_buffer.type = FCGI_PARAMS;
589 	set_environment(session, &fcgi_buffer);
590 	if (send_fcgi_buffer(&fcgi_buffer, NULL, 0) == -1) {
591 		return -1;
592 	}
593 
594 	fcgi_buffer.type = FCGI_STDIN;
595 	if (session->body != NULL) {
596 		/* Send POST data to FastCGI program.
597 		 */
598 		if (send_fcgi_buffer(&fcgi_buffer, session->body, session->content_length) == -1) {
599 			return -1;
600 		}
601 	} else if (session->uploaded_file != NULL) {
602 		/* Send uploaded file to FastCGI program
603 		 */
604 		if ((handle = open(session->uploaded_file, O_RDONLY)) == -1) {
605 			return -1;
606 		}
607 		while ((bytes_read = read(handle, buffer, UPLOADED_FILE_BUFFER_SIZE)) > 0) {
608 			if (send_fcgi_buffer(&fcgi_buffer, buffer, bytes_read) == -1) {
609 				bytes_read = -1;
610 				break;
611 			}
612 		}
613 		close(handle);
614 
615 		if (bytes_read == -1) {
616 			return -1;
617 		}
618 
619 	}
620 
621 	if (send_fcgi_buffer(&fcgi_buffer, NULL, 0) == -1) {
622 		return -1;
623 	}
624 
625 	return 0;
626 }
627 
read_fcgi_socket(t_session * session,t_cgi_info * cgi_info,char * buffer,int size)628 static t_cgi_result read_fcgi_socket(t_session *session, t_cgi_info *cgi_info, char *buffer, int size) {
629 	int bytes_read;
630 	bool read_again;
631 	struct pollfd poll_data;
632 
633 	poll_data.fd = cgi_info->from_cgi;
634 	poll_data.events = POLL_EVENT_BITS;
635 
636 	do {
637 		read_again = false;
638 		switch (poll(&poll_data, 1, 1000)) {
639 			case -1:
640 				if (errno == EINTR) {
641 					read_again = true;
642 				}
643 				break;
644 			case 0:
645 				if (session->force_quit) {
646 					return cgi_FORCE_QUIT;
647 				} else if (time(NULL) > cgi_info->deadline) {
648 					return cgi_TIMEOUT;
649 				}
650 				read_again = true;
651 				break;
652 			default:
653 				do {
654 					read_again = false;
655 					if ((bytes_read = read(cgi_info->from_cgi, buffer, size)) == -1) {
656 						if (errno != EINTR) {
657 							break;
658 						}
659 						read_again = true;
660 					}
661 				} while (read_again);
662 				return bytes_read;
663 		}
664 	} while (read_again);
665 
666 	return cgi_ERROR;
667 }
668 
read_from_fcgi_server(t_session * session,t_cgi_info * cgi_info)669 t_cgi_result read_from_fcgi_server(t_session *session, t_cgi_info *cgi_info) {
670 	char *buffer, *dummy = NULL;
671 	bool read_again;
672 	int bytes_read, bytes_left;
673 	unsigned int content, padding, data_length;
674 	t_cgi_result result = cgi_OKE;
675 
676 	/* Read header
677 	 */
678 	if (cgi_info->read_header) {
679 		bytes_left = FCGI_HEADER_LENGTH;
680 		do {
681 			read_again = false;
682 
683 			switch (bytes_read = read_fcgi_socket(session, cgi_info, cgi_info->header + FCGI_HEADER_LENGTH - bytes_left, bytes_left)) {
684 				case cgi_TIMEOUT:
685 					return cgi_TIMEOUT;
686 				case cgi_FORCE_QUIT:
687 					return cgi_FORCE_QUIT;
688 				case cgi_ERROR:
689 					return cgi_ERROR;
690 				case 0:
691 					return cgi_END_OF_DATA;
692 				default:
693 					if ((bytes_left -= bytes_read) > 0) {
694 						read_again = true;
695 					}
696 			}
697 		} while (read_again);
698 
699 		cgi_info->read_header = false;
700 		cgi_info->fcgi_data_len = 0;
701 	}
702 
703 	if (((unsigned char)cgi_info->header[1]) == FCGI_END_REQUEST) {
704 		return cgi_END_OF_DATA;
705 	}
706 
707 	/* Determine the size of the data
708 	 */
709 	content = 256 * (unsigned char)cgi_info->header[4] + (unsigned char)cgi_info->header[5];
710 	padding = (unsigned char)cgi_info->header[6];
711 	if ((data_length = content + padding) <= 0) {
712 		cgi_info->read_header = true;
713 		return cgi_OKE;
714 	}
715 
716 	switch ((unsigned char)cgi_info->header[1]) {
717 		case FCGI_STDOUT:
718 			buffer = cgi_info->input_buffer + cgi_info->input_len;
719 			bytes_left = cgi_info->input_buffer_size - cgi_info->input_len;
720 			break;
721 		case FCGI_STDERR:
722 			buffer = cgi_info->error_buffer + cgi_info->error_len;
723 			bytes_left = cgi_info->error_buffer_size - cgi_info->error_len;
724 			break;
725 		default:
726 			/* Unsupported type, so skip data
727 			 */
728 			if ((dummy = (char*)malloc(DUMMY_BUFFER_SIZE)) == NULL) {
729 				return cgi_ERROR;
730 			}
731 			buffer = dummy;
732 			bytes_left = DUMMY_BUFFER_SIZE;
733 	}
734 
735 	/* Read data
736 	 */
737 	if ((unsigned int)bytes_left > (data_length - cgi_info->fcgi_data_len)) {
738 		bytes_left = data_length - cgi_info->fcgi_data_len;
739 	}
740 
741 	switch (bytes_read = read_fcgi_socket(session, cgi_info, buffer, bytes_left)) {
742 		case cgi_TIMEOUT:
743 			result = cgi_TIMEOUT;
744 			break;
745 		case cgi_FORCE_QUIT:
746 			result = cgi_FORCE_QUIT;
747 			break;
748 		case cgi_ERROR:
749 			result = cgi_ERROR;
750 			break;
751 		case 0:
752 			result = cgi_END_OF_DATA;
753 			break;
754 		default:
755 			if ((cgi_info->fcgi_data_len += bytes_read) == data_length) {
756 				cgi_info->read_header = true;
757 			}
758 			if (cgi_info->fcgi_data_len > content) {
759 				/* Read more then content (padding)
760 				 */
761 				if (cgi_info->fcgi_data_len - bytes_read < content) {
762 					bytes_read = content - (cgi_info->fcgi_data_len - bytes_read);
763 				} else {
764 					bytes_read = 0;
765 				}
766 			}
767 			switch ((unsigned char)cgi_info->header[1]) {
768 				case FCGI_STDOUT:
769 					cgi_info->input_len += bytes_read;
770 					break;
771 				case FCGI_STDERR:
772 					cgi_info->error_len += bytes_read;
773 					break;
774 				default:
775 					break;
776 			}
777 	}
778 
779 	check_clear_free(dummy, DUMMY_BUFFER_SIZE);
780 
781 	return result;
782 }
783