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