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