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