1 /* 2 * gw_backend - gateway backend code shared by dynamic socket backends 3 * 4 * Copyright(c) 2017 Glenn Strauss gstrauss()gluelogic.com All rights reserved 5 * License: BSD 3-clause (same as lighttpd) 6 */ 7 #include "first.h" 8 9 #include "gw_backend.h" 10 11 #include <sys/types.h> 12 #include <sys/stat.h> 13 #include "sys-socket.h" 14 #ifdef HAVE_SYS_UIO_H 15 #include <sys/uio.h> 16 #endif 17 #ifdef HAVE_SYS_WAIT_H 18 #include <sys/wait.h> 19 #endif 20 21 #include <errno.h> 22 #include <fcntl.h> 23 #include <limits.h> 24 #include <stdint.h> 25 #include <stdlib.h> 26 #include <signal.h> 27 #include <string.h> 28 #include <unistd.h> 29 30 #include "base.h" 31 #include "algo_md.h" 32 #include "array.h" 33 #include "buffer.h" 34 #include "chunk.h" 35 #include "fdevent.h" 36 #include "http_header.h" 37 #include "log.h" 38 #include "sock_addr.h" 39 40 41 42 43 __attribute_noinline__ 44 static int * gw_status_get_counter(gw_host *host, gw_proc *proc, const char *tag, size_t tlen) { 45 /*(At the cost of some memory, could prepare strings for host and for proc 46 * so that here we would copy ready made string for proc (or if NULL, 47 * for host), and then append tag to produce key)*/ 48 char label[288]; 49 size_t llen = sizeof("gw.backend.")-1, len; 50 memcpy(label, "gw.backend.", llen); 51 52 len = buffer_clen(host->id); 53 if (len) { 54 force_assert(len < sizeof(label) - llen); 55 memcpy(label+llen, host->id->ptr, len); 56 llen += len; 57 } 58 59 if (proc) { 60 force_assert(llen < sizeof(label) - (LI_ITOSTRING_LENGTH + 1)); 61 label[llen++] = '.'; 62 len = li_utostrn(label+llen, LI_ITOSTRING_LENGTH, proc->id); 63 llen += len; 64 } 65 66 force_assert(tlen < sizeof(label) - llen); 67 memcpy(label+llen, tag, tlen); 68 llen += tlen; 69 label[llen] = '\0'; 70 71 return plugin_stats_get_ptr(label, llen); 72 } 73 74 static void gw_proc_tag_inc(gw_host *host, gw_proc *proc, const char *tag, size_t len) { 75 ++(*gw_status_get_counter(host, proc, tag, len)); 76 } 77 78 static void gw_proc_connected_inc(gw_host *host, gw_proc *proc) { 79 UNUSED(host); 80 ++(*proc->stats_connected); /* "gw.backend...connected" */ 81 } 82 83 static void gw_proc_load_inc(gw_host *host, gw_proc *proc) { 84 *proc->stats_load = ++proc->load; /* "gw.backend...load" */ 85 ++(*host->stats_global_active); /* "gw.active-requests" */ 86 } 87 88 static void gw_proc_load_dec(gw_host *host, gw_proc *proc) { 89 *proc->stats_load = --proc->load; /* "gw.backend...load" */ 90 --(*host->stats_global_active); /* "gw.active-requests" */ 91 } 92 93 static void gw_host_assign(gw_host *host) { 94 *host->stats_load = ++host->load; /* "gw.backend...load" */ 95 } 96 97 static void gw_host_reset(gw_host *host) { 98 *host->stats_load = --host->load; /* "gw.backend...load" */ 99 } 100 101 static void gw_status_init_proc(gw_host *host, gw_proc *proc) { 102 *gw_status_get_counter(host, proc, CONST_STR_LEN(".disabled")) = 0; 103 *gw_status_get_counter(host, proc, CONST_STR_LEN(".died")) = 0; 104 *gw_status_get_counter(host, proc, CONST_STR_LEN(".overloaded")) = 0; 105 proc->stats_connected = 106 gw_status_get_counter(host, proc, CONST_STR_LEN(".connected")); 107 *proc->stats_connected = 0; 108 proc->stats_load = 109 gw_status_get_counter(host, proc, CONST_STR_LEN(".load")); 110 *proc->stats_load = 0; 111 } 112 113 static void gw_status_init_host(gw_host *host) { 114 host->stats_load = 115 gw_status_get_counter(host, NULL, CONST_STR_LEN(".load")); 116 *host->stats_load = 0; 117 host->stats_global_active = 118 plugin_stats_get_ptr("gw.active-requests",sizeof("gw.active-requests")-1); 119 } 120 121 122 123 124 __attribute_cold__ 125 static void gw_proc_set_state(gw_host *host, gw_proc *proc, int state) { 126 if ((int)proc->state == state) return; 127 if (proc->state == PROC_STATE_RUNNING) { 128 --host->active_procs; 129 } else if (state == PROC_STATE_RUNNING) { 130 ++host->active_procs; 131 } 132 proc->state = state; 133 } 134 135 136 __attribute_cold__ 137 __attribute_noinline__ 138 static void gw_proc_init_portpath(gw_host *host, gw_proc *proc) { 139 if (!host->unixsocket) { 140 proc->port = host->port + proc->id; 141 return; 142 } 143 144 if (!proc->unixsocket) 145 proc->unixsocket = buffer_init(); 146 147 if (!host->bin_path) 148 buffer_copy_buffer(proc->unixsocket, host->unixsocket); 149 else { 150 buffer_clear(proc->unixsocket); 151 buffer_append_str2(proc->unixsocket, BUF_PTR_LEN(host->unixsocket), 152 CONST_STR_LEN("-")); 153 buffer_append_int(proc->unixsocket, proc->id); 154 } 155 } 156 157 __attribute_cold__ 158 __attribute_noinline__ 159 __attribute_returns_nonnull__ 160 static gw_proc *gw_proc_init(gw_host *host) { 161 gw_proc *proc = calloc(1, sizeof(*proc)); 162 force_assert(proc); 163 164 /*proc->unixsocket = buffer_init();*//*(init on demand)*/ 165 proc->connection_name = buffer_init(); 166 167 proc->prev = NULL; 168 proc->next = NULL; 169 proc->state = PROC_STATE_DIED; 170 171 proc->id = host->max_id++; 172 gw_status_init_proc(host, proc); /*(proc->id must be set)*/ 173 gw_proc_init_portpath(host, proc); 174 175 return proc; 176 } 177 178 static void gw_proc_free(gw_proc *proc) { 179 if (!proc) return; 180 181 gw_proc_free(proc->next); 182 183 buffer_free(proc->unixsocket); 184 buffer_free(proc->connection_name); 185 free(proc->saddr); 186 187 free(proc); 188 } 189 190 __attribute_malloc__ 191 __attribute_returns_nonnull__ 192 static gw_host *gw_host_init(void) { 193 gw_host *f = calloc(1, sizeof(*f)); 194 force_assert(f); 195 return f; 196 } 197 198 static void gw_host_free(gw_host *h) { 199 if (!h) return; 200 if (h->refcount) { 201 --h->refcount; 202 return; 203 } 204 205 gw_proc_free(h->first); 206 gw_proc_free(h->unused_procs); 207 208 for (uint32_t i = 0; i < h->args.used; ++i) free(h->args.ptr[i]); 209 free(h->args.ptr); 210 free(h); 211 } 212 213 __attribute_malloc__ 214 __attribute_returns_nonnull__ 215 static gw_exts *gw_extensions_init(void) { 216 gw_exts *f = calloc(1, sizeof(*f)); 217 force_assert(f); 218 return f; 219 } 220 221 static void gw_extensions_free(gw_exts *f) { 222 if (!f) return; 223 for (uint32_t i = 0; i < f->used; ++i) { 224 gw_extension *fe = f->exts+i; 225 for (uint32_t j = 0; j < fe->used; ++j) { 226 gw_host_free(fe->hosts[j]); 227 } 228 free(fe->hosts); 229 } 230 free(f->exts); 231 free(f); 232 } 233 234 static int gw_extension_insert(gw_exts *ext, const buffer *key, gw_host *fh) { 235 gw_extension *fe = NULL; 236 for (uint32_t i = 0; i < ext->used; ++i) { 237 if (buffer_is_equal(key, &ext->exts[i].key)) { 238 fe = ext->exts+i; 239 break; 240 } 241 } 242 243 if (NULL == fe) { 244 if (ext->used == ext->size) { 245 ext->size += 8; 246 ext->exts = realloc(ext->exts, ext->size * sizeof(gw_extension)); 247 force_assert(ext->exts); 248 memset(ext->exts + ext->used, 0, 8 * sizeof(gw_extension)); 249 } 250 fe = ext->exts + ext->used++; 251 fe->last_used_ndx = -1; 252 buffer *b; 253 *(const buffer **)&b = &fe->key; 254 memcpy(b, key, sizeof(buffer)); /*(copy; not later free'd)*/ 255 } 256 257 if (fe->size == fe->used) { 258 fe->size += 4; 259 fe->hosts = realloc(fe->hosts, fe->size * sizeof(*(fe->hosts))); 260 force_assert(fe->hosts); 261 } 262 263 fe->hosts[fe->used++] = fh; 264 return 0; 265 } 266 267 static void gw_proc_connect_success(gw_host *host, gw_proc *proc, int debug, request_st * const r) { 268 gw_proc_connected_inc(host, proc); /*(".connected")*/ 269 proc->last_used = log_monotonic_secs; 270 271 if (debug) { 272 log_error(r->conf.errh, __FILE__, __LINE__, 273 "got proc: pid: %d socket: %s load: %d", 274 proc->pid, proc->connection_name->ptr, proc->load); 275 } 276 } 277 278 __attribute_cold__ 279 static void gw_proc_connect_error(request_st * const r, gw_host *host, gw_proc *proc, pid_t pid, int errnum, int debug) { 280 const unix_time64_t cur_ts = log_monotonic_secs; 281 log_error_st * const errh = r->conf.errh; 282 errno = errnum; /*(for log_perror())*/ 283 log_perror(errh, __FILE__, __LINE__, 284 "establishing connection failed: socket: %s", proc->connection_name->ptr); 285 286 if (!proc->is_local) { 287 proc->disabled_until = cur_ts + host->disable_time; 288 gw_proc_set_state(host, proc, PROC_STATE_OVERLOADED); 289 } 290 else if (proc->pid == pid && proc->state == PROC_STATE_RUNNING) { 291 /* several requests from lighttpd might reference the same proc 292 * 293 * Only one of them should mark the proc 294 * and all other ones should just take a new one. 295 * 296 * If a new proc was started with the old struct, this might 297 * otherwise lead to marking a perfectly good proc as dead 298 */ 299 log_error(errh, __FILE__, __LINE__, 300 "backend error; we'll disable for %d" 301 "secs and send the request to another backend instead:" 302 "load: %d", host->disable_time, host->load); 303 if (EAGAIN == errnum) { 304 /* - EAGAIN: cool down the backend; it is overloaded */ 305 #ifdef __linux__ 306 log_error(errh, __FILE__, __LINE__, 307 "If this happened on Linux: You have run out of local ports. " 308 "Check the manual, section Performance how to handle this."); 309 #endif 310 if (debug) { 311 log_error(errh, __FILE__, __LINE__, 312 "This means that you have more incoming requests than your " 313 "FastCGI backend can handle in parallel. It might help to " 314 "spawn more FastCGI backends or PHP children; if not, " 315 "decrease server.max-connections. The load for this FastCGI " 316 "backend %s is %d", proc->connection_name->ptr, proc->load); 317 } 318 proc->disabled_until = cur_ts + host->disable_time; 319 gw_proc_set_state(host, proc, PROC_STATE_OVERLOADED); 320 } 321 else { 322 /* we got a hard error from the backend like 323 * - ECONNREFUSED for tcp-ip sockets 324 * - ENOENT for unix-domain-sockets 325 */ 326 #if 0 327 gw_proc_set_state(host, proc, PROC_STATE_DIED_WAIT_FOR_PID); 328 #else /* treat as overloaded (future: unless we send kill() signal)*/ 329 proc->disabled_until = cur_ts + host->disable_time; 330 gw_proc_set_state(host, proc, PROC_STATE_OVERLOADED); 331 #endif 332 } 333 } 334 335 if (EAGAIN == errnum) { 336 gw_proc_tag_inc(host, proc, CONST_STR_LEN(".overloaded")); 337 } 338 else { 339 gw_proc_tag_inc(host, proc, CONST_STR_LEN(".died")); 340 } 341 } 342 343 static void gw_proc_release(gw_host *host, gw_proc *proc, int debug, log_error_st *errh) { 344 gw_proc_load_dec(host, proc); 345 346 if (debug) { 347 log_error(errh, __FILE__, __LINE__, 348 "released proc: pid: %d socket: %s load: %u", 349 proc->pid, proc->connection_name->ptr, proc->load); 350 } 351 } 352 353 __attribute_cold__ 354 static void gw_proc_check_enable(gw_host * const host, gw_proc * const proc, log_error_st * const errh) { 355 if (log_monotonic_secs <= proc->disabled_until) return; 356 if (proc->state != PROC_STATE_OVERLOADED) return; 357 358 gw_proc_set_state(host, proc, PROC_STATE_RUNNING); 359 360 log_error(errh, __FILE__, __LINE__, 361 "gw-server re-enabled: %s %s %hu %s", 362 proc->connection_name->ptr, 363 host->host ? host->host->ptr : "", host->port, 364 host->unixsocket ? host->unixsocket->ptr : ""); 365 } 366 367 __attribute_cold__ 368 static void gw_proc_waitpid_log(const gw_host * const host, const gw_proc * const proc, log_error_st * const errh, const int status) { 369 if (WIFEXITED(status)) { 370 if (proc->state != PROC_STATE_KILLED) { 371 log_error(errh, __FILE__, __LINE__, 372 "child exited: %d %s", 373 WEXITSTATUS(status), proc->connection_name->ptr); 374 } 375 } else if (WIFSIGNALED(status)) { 376 if (WTERMSIG(status) != SIGTERM && WTERMSIG(status) != SIGINT 377 && WTERMSIG(status) != host->kill_signal) { 378 log_error(errh, __FILE__, __LINE__, 379 "child signalled: %d", WTERMSIG(status)); 380 } 381 } else { 382 log_error(errh, __FILE__, __LINE__, 383 "child died somehow: %d", status); 384 } 385 } 386 387 static int gw_proc_waitpid(gw_host *host, gw_proc *proc, log_error_st *errh) { 388 int rc, status; 389 390 if (!proc->is_local) return 0; 391 if (proc->pid <= 0) return 0; 392 393 rc = fdevent_waitpid(proc->pid, &status, 1); 394 if (0 == rc) return 0; /* child still running */ 395 396 /* child terminated */ 397 if (-1 == rc) { 398 /* EINVAL or ECHILD no child processes */ 399 /* should not happen; someone else has cleaned up for us */ 400 log_perror(errh, __FILE__, __LINE__, 401 "pid %d %d not found", proc->pid, proc->state); 402 } 403 else { 404 gw_proc_waitpid_log(host, proc, errh, status); 405 } 406 407 proc->pid = 0; 408 if (proc->state != PROC_STATE_KILLED) 409 proc->disabled_until = log_monotonic_secs; 410 gw_proc_set_state(host, proc, PROC_STATE_DIED); 411 return 1; 412 } 413 414 __attribute_cold__ 415 static int gw_proc_sockaddr_init(gw_host * const host, gw_proc * const proc, log_error_st * const errh) { 416 sock_addr addr; 417 socklen_t addrlen; 418 419 if (proc->unixsocket) { 420 if (1 != sock_addr_from_str_hints(&addr,&addrlen,proc->unixsocket->ptr, 421 AF_UNIX, 0, errh)) { 422 errno = EINVAL; 423 return -1; 424 } 425 buffer_clear(proc->connection_name); 426 buffer_append_str2(proc->connection_name, 427 CONST_STR_LEN("unix:"), 428 BUF_PTR_LEN(proc->unixsocket)); 429 } 430 else { 431 #ifdef __COVERITY__ 432 force_assert(host->host); /*(not NULL if !host->unixsocket)*/ 433 #endif 434 /*(note: name resolution here is *blocking* if IP string not supplied)*/ 435 if (1 != sock_addr_from_str_hints(&addr, &addrlen, host->host->ptr, 436 0, proc->port, errh)) { 437 errno = EINVAL; 438 return -1; 439 } 440 else if (host->host->size) { 441 /*(skip if constant string set in gw_set_defaults_backend())*/ 442 /* overwrite host->host buffer with IP addr string so that 443 * any further use of gw_host does not block on DNS lookup */ 444 buffer *h; 445 *(const buffer **)&h = host->host; 446 sock_addr_inet_ntop_copy_buffer(h, &addr); 447 host->family = sock_addr_get_family(&addr); 448 } 449 buffer_clear(proc->connection_name); 450 buffer_append_str3(proc->connection_name, 451 CONST_STR_LEN("tcp:"), 452 BUF_PTR_LEN(host->host), 453 CONST_STR_LEN(":")); 454 buffer_append_int(proc->connection_name, proc->port); 455 } 456 457 if (NULL != proc->saddr && proc->saddrlen < addrlen) { 458 free(proc->saddr); 459 proc->saddr = NULL; 460 } 461 if (NULL == proc->saddr) { 462 proc->saddr = (struct sockaddr *)malloc(addrlen); 463 force_assert(proc->saddr); 464 } 465 proc->saddrlen = addrlen; 466 memcpy(proc->saddr, &addr, addrlen); 467 return 0; 468 } 469 470 static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) { 471 char *dst; 472 473 if (!key || !val) return -1; 474 475 dst = malloc(key_len + val_len + 3); 476 force_assert(dst); 477 memcpy(dst, key, key_len); 478 dst[key_len] = '='; 479 memcpy(dst + key_len + 1, val, val_len + 1); /* add the \0 from the value */ 480 481 for (uint32_t i = 0; i < env->used; ++i) { 482 #ifdef __COVERITY__ 483 force_assert(env->ptr); /*(non-NULL if env->used != 0)*/ 484 #endif 485 if (0 == strncmp(dst, env->ptr[i], key_len + 1)) { 486 free(env->ptr[i]); 487 env->ptr[i] = dst; 488 return 0; 489 } 490 } 491 492 if (env->size <= env->used + 1) { 493 env->size += 16; 494 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr)); 495 force_assert(env->ptr); 496 } 497 498 #ifdef __COVERITY__ 499 force_assert(env->ptr); /*(non-NULL if env->used != 0; guaranteed above)*/ 500 #endif 501 env->ptr[env->used++] = dst; 502 503 return 0; 504 } 505 506 __attribute_cold__ 507 static int gw_spawn_connection(gw_host * const host, gw_proc * const proc, log_error_st * const errh, int debug) { 508 int gw_fd; 509 int status; 510 511 if (debug) { 512 log_error(errh, __FILE__, __LINE__, 513 "new proc, socket: %hu %s", 514 proc->port, proc->unixsocket ? proc->unixsocket->ptr : ""); 515 } 516 517 gw_fd = fdevent_socket_cloexec(proc->saddr->sa_family, SOCK_STREAM, 0); 518 if (-1 == gw_fd) { 519 log_perror(errh, __FILE__, __LINE__, "socket()"); 520 return -1; 521 } 522 523 do { 524 status = connect(gw_fd, proc->saddr, proc->saddrlen); 525 } while (-1 == status && errno == EINTR); 526 527 if (-1 == status && errno != ENOENT && proc->unixsocket) { 528 log_perror(errh, __FILE__, __LINE__, 529 "connect %s", proc->unixsocket->ptr); 530 unlink(proc->unixsocket->ptr); 531 } 532 533 close(gw_fd); 534 535 if (-1 == status) { 536 /* server is not up, spawn it */ 537 char_array env; 538 uint32_t i; 539 540 /* reopen socket */ 541 gw_fd = fdevent_socket_cloexec(proc->saddr->sa_family, SOCK_STREAM, 0); 542 if (-1 == gw_fd) { 543 log_perror(errh, __FILE__, __LINE__, "socket()"); 544 return -1; 545 } 546 547 if (fdevent_set_so_reuseaddr(gw_fd, 1) < 0) { 548 log_perror(errh, __FILE__, __LINE__, "socketsockopt()"); 549 close(gw_fd); 550 return -1; 551 } 552 553 /* create socket */ 554 if (-1 == bind(gw_fd, proc->saddr, proc->saddrlen)) { 555 log_perror(errh, __FILE__, __LINE__, 556 "bind failed for: %s", proc->connection_name->ptr); 557 close(gw_fd); 558 return -1; 559 } 560 561 if (-1 == listen(gw_fd, host->listen_backlog)) { 562 log_perror(errh, __FILE__, __LINE__, "listen()"); 563 close(gw_fd); 564 return -1; 565 } 566 567 { 568 /* create environment */ 569 env.ptr = NULL; 570 env.size = 0; 571 env.used = 0; 572 573 /* build clean environment */ 574 if (host->bin_env_copy && host->bin_env_copy->used) { 575 for (i = 0; i < host->bin_env_copy->used; ++i) { 576 data_string *ds=(data_string *)host->bin_env_copy->data[i]; 577 char *ge; 578 579 if (NULL != (ge = getenv(ds->value.ptr))) { 580 env_add(&env, BUF_PTR_LEN(&ds->value), ge, strlen(ge)); 581 } 582 } 583 } else { 584 char ** const e = fdevent_environ(); 585 for (i = 0; e[i]; ++i) { 586 char *eq; 587 588 if (NULL != (eq = strchr(e[i], '='))) { 589 env_add(&env, e[i], eq - e[i], eq+1, strlen(eq+1)); 590 } 591 } 592 } 593 594 /* create environment */ 595 if (host->bin_env) { 596 for (i = 0; i < host->bin_env->used; ++i) { 597 data_string *ds = (data_string *)host->bin_env->data[i]; 598 env_add(&env, BUF_PTR_LEN(&ds->key), 599 BUF_PTR_LEN(&ds->value)); 600 } 601 } 602 603 for (i = 0; i < env.used; ++i) { 604 /* search for PHP_FCGI_CHILDREN */ 605 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", 606 sizeof("PHP_FCGI_CHILDREN=")-1)) { 607 break; 608 } 609 } 610 611 /* not found, add a default */ 612 if (i == env.used) { 613 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), 614 CONST_STR_LEN("1")); 615 } 616 617 env.ptr[env.used] = NULL; 618 } 619 620 int dfd = fdevent_open_dirname(host->args.ptr[0], 1);/*permit symlinks*/ 621 if (-1 == dfd) { 622 log_perror(errh, __FILE__, __LINE__, 623 "open dirname failed: %s", host->args.ptr[0]); 624 } 625 626 /*(FCGI_LISTENSOCK_FILENO == STDIN_FILENO == 0)*/ 627 proc->pid = (dfd >= 0) 628 ? fdevent_fork_execve(host->args.ptr[0], host->args.ptr, 629 env.ptr, gw_fd, -1, -1, dfd) 630 : -1; 631 632 for (i = 0; i < env.used; ++i) free(env.ptr[i]); 633 free(env.ptr); 634 if (-1 != dfd) close(dfd); 635 close(gw_fd); 636 637 if (-1 == proc->pid) { 638 log_error(errh, __FILE__, __LINE__, 639 "gw-backend failed to start: %s", host->bin_path->ptr); 640 proc->pid = 0; 641 proc->disabled_until = log_monotonic_secs; 642 return -1; 643 } 644 645 /* register process */ 646 proc->last_used = log_monotonic_secs; 647 proc->is_local = 1; 648 649 /* wait */ 650 struct timeval tv = { 0, 1000 }; 651 select(0, NULL, NULL, NULL, &tv); 652 653 if (0 != gw_proc_waitpid(host, proc, errh)) { 654 log_error(errh, __FILE__, __LINE__, 655 "gw-backend failed to start: %s", host->bin_path->ptr); 656 log_error(errh, __FILE__, __LINE__, 657 "If you're trying to run your app as a FastCGI backend, make " 658 "sure you're using the FastCGI-enabled version. If this is PHP " 659 "on Gentoo, add 'fastcgi' to the USE flags. If this is PHP, try " 660 "removing the bytecode caches for now and try again."); 661 return -1; 662 } 663 } else { 664 proc->is_local = 0; 665 proc->pid = 0; 666 667 if (debug) { 668 log_error(errh, __FILE__, __LINE__, 669 "(debug) socket is already used; won't spawn: %s", 670 proc->connection_name->ptr); 671 } 672 } 673 674 gw_proc_set_state(host, proc, PROC_STATE_RUNNING); 675 return 0; 676 } 677 678 __attribute_cold__ 679 static void gw_proc_spawn(gw_host * const host, log_error_st * const errh, const int debug) { 680 gw_proc *proc; 681 for (proc = host->unused_procs; proc; proc = proc->next) { 682 /* (proc->pid <= 0 indicates PROC_STATE_DIED, not PROC_STATE_KILLED) */ 683 if (proc->pid > 0) continue; 684 /* (do not attempt to spawn another proc if a proc just exited) */ 685 if (proc->disabled_until >= log_monotonic_secs) return; 686 break; 687 } 688 if (proc) { 689 if (proc == host->unused_procs) 690 host->unused_procs = proc->next; 691 else 692 proc->prev->next = proc->next; 693 694 if (proc->next) { 695 proc->next->prev = proc->prev; 696 proc->next = NULL; 697 } 698 699 proc->prev = NULL; 700 gw_proc_init_portpath(host, proc); 701 } else { 702 proc = gw_proc_init(host); 703 } 704 705 if (0 != gw_proc_sockaddr_init(host, proc, errh)) { 706 /*(should not happen if host->host validated at startup, 707 * and translated from name to IP address at startup)*/ 708 log_error(errh, __FILE__, __LINE__, 709 "ERROR: spawning backend failed."); 710 if (proc->id == host->max_id-1) --host->max_id; 711 gw_proc_free(proc); 712 } else if (gw_spawn_connection(host, proc, errh, debug)) { 713 log_error(errh, __FILE__, __LINE__, 714 "ERROR: spawning backend failed."); 715 proc->next = host->unused_procs; 716 if (host->unused_procs) 717 host->unused_procs->prev = proc; 718 host->unused_procs = proc; 719 } else { 720 proc->next = host->first; 721 if (host->first) 722 host->first->prev = proc; 723 host->first = proc; 724 ++host->num_procs; 725 } 726 } 727 728 __attribute_cold__ 729 static void gw_proc_kill(gw_host *host, gw_proc *proc) { 730 if (proc->next) proc->next->prev = proc->prev; 731 if (proc->prev) proc->prev->next = proc->next; 732 else host->first = proc->next; 733 --host->num_procs; 734 735 proc->prev = NULL; 736 proc->next = host->unused_procs; 737 proc->disabled_until = 0; 738 739 if (host->unused_procs) 740 host->unused_procs->prev = proc; 741 host->unused_procs = proc; 742 743 kill(proc->pid, host->kill_signal); 744 745 gw_proc_set_state(host, proc, PROC_STATE_KILLED); 746 } 747 748 __attribute_pure__ 749 static gw_host * unixsocket_is_dup(gw_plugin_data *p, const buffer *unixsocket) { 750 if (NULL == p->cvlist) return NULL; 751 /* (init i to 0 if global context; to 1 to skip empty global context) */ 752 for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) { 753 config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0]; 754 gw_plugin_config *conf = NULL; 755 for (; -1 != cpv->k_id; ++cpv) { 756 switch (cpv->k_id) { 757 case 0: /* xxxxx.server */ 758 if (cpv->vtype == T_CONFIG_LOCAL) conf = cpv->v.v; 759 break; 760 default: 761 break; 762 } 763 } 764 765 if (NULL == conf || NULL == conf->exts) continue; 766 767 gw_exts *exts = conf->exts; 768 for (uint32_t j = 0; j < exts->used; ++j) { 769 gw_extension *ex = exts->exts+j; 770 for (uint32_t n = 0; n < ex->used; ++n) { 771 gw_host *host = ex->hosts[n]; 772 if (host->unixsocket 773 && buffer_is_equal(host->unixsocket, unixsocket) 774 && host->bin_path) 775 return host; 776 } 777 } 778 } 779 780 return NULL; 781 } 782 783 static int parse_binpath(char_array *env, const buffer *b) { 784 char *start = b->ptr; 785 char c; 786 /* search for spaces */ 787 for (size_t i = 0, used = buffer_clen(b); i < used; ++i) { 788 switch(b->ptr[i]) { 789 case ' ': 790 case '\t': 791 /* a WS, stop here and copy the argument */ 792 793 if (env->size == env->used) { 794 env->size += 16; 795 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr)); 796 force_assert(env->ptr); 797 } 798 799 c = b->ptr[i]; 800 b->ptr[i] = '\0'; 801 env->ptr[env->used++] = strdup(start); 802 b->ptr[i] = c; 803 804 start = b->ptr + i + 1; 805 break; 806 default: 807 break; 808 } 809 } 810 811 if (env->size == env->used) { /*need one extra for terminating NULL*/ 812 env->size += 16; 813 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr)); 814 } 815 816 /* the rest */ 817 env->ptr[env->used++] = strdup(start); 818 819 if (env->size == env->used) { /*need one extra for terminating NULL*/ 820 env->size += 16; 821 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr)); 822 } 823 824 /* terminate */ 825 env->ptr[env->used++] = NULL; 826 827 return 0; 828 } 829 830 enum { 831 GW_BALANCE_LEAST_CONNECTION, 832 GW_BALANCE_RR, 833 GW_BALANCE_HASH, 834 GW_BALANCE_STICKY 835 }; 836 837 __attribute_noinline__ 838 __attribute_pure__ 839 static uint32_t 840 gw_hash(const char *str, const uint32_t len, uint32_t hash) 841 { 842 return djbhash(str, len, hash); 843 } 844 845 static gw_host * gw_host_get(request_st * const r, gw_extension *extension, int balance, int debug) { 846 int ndx = -1; 847 const int ext_used = (int)extension->used; 848 849 if (ext_used <= 1) { 850 if (1 == ext_used && extension->hosts[0]->active_procs > 0) 851 ndx = 0; 852 } 853 else { 854 /*const char *balancing = "";*/ 855 switch(balance) { 856 case GW_BALANCE_HASH: 857 { /* hash balancing */ 858 const uint32_t base_hash = 859 gw_hash(BUF_PTR_LEN(&r->uri.authority), 860 gw_hash(BUF_PTR_LEN(&r->uri.path), DJBHASH_INIT)); 861 uint32_t last_max = UINT32_MAX; 862 for (int k = 0; k < ext_used; ++k) { 863 const gw_host * const host = extension->hosts[k]; 864 if (0 == host->active_procs) continue; 865 const uint32_t cur_max = base_hash ^ host->gw_hash; 866 #if 0 867 if (debug) { 868 log_error(r->conf.errh, __FILE__, __LINE__, 869 "proxy - election: %s %s %s %u", r->uri.path.ptr, 870 host->host ? host->host->ptr : "", 871 r->uri.authority.ptr, cur_max); 872 } 873 #endif 874 if (last_max < cur_max || last_max == UINT32_MAX) { 875 last_max = cur_max; 876 ndx = k; 877 } 878 } 879 /*balancing = "hash";*/ 880 break; 881 } 882 case GW_BALANCE_LEAST_CONNECTION: 883 { /* fair balancing */ 884 for (int k = 0, max_usage = INT_MAX; k < ext_used; ++k) { 885 const gw_host * const host = extension->hosts[k]; 886 if (0 == host->active_procs) continue; 887 if (host->load < max_usage) { 888 max_usage = host->load; 889 ndx = k; 890 } 891 } 892 /*balancing = "least connection";*/ 893 break; 894 } 895 case GW_BALANCE_RR: 896 { /* round robin */ 897 const gw_host *host = extension->hosts[0]; 898 899 /* Use last_used_ndx from first host in list */ 900 int k = extension->last_used_ndx; 901 ndx = k + 1; /* use next host after the last one */ 902 if (ndx < 0) ndx = 0; 903 904 /* Search first active host after last_used_ndx */ 905 while (ndx < ext_used 906 && 0 == (host = extension->hosts[ndx])->active_procs) ++ndx; 907 908 if (ndx >= ext_used) { 909 /* didn't find a higher id, wrap to the start */ 910 for (ndx = 0; ndx <= (int) k; ++ndx) { 911 host = extension->hosts[ndx]; 912 if (0 != host->active_procs) break; 913 } 914 915 /* No active host found */ 916 if (0 == host->active_procs) ndx = -1; 917 } 918 919 /* Save new index for next round */ 920 extension->last_used_ndx = ndx; 921 922 /*balancing = "round-robin";*/ 923 break; 924 } 925 case GW_BALANCE_STICKY: 926 { /* source sticky balancing */ 927 const buffer * const dst_addr_buf = &r->con->dst_addr_buf; 928 const uint32_t base_hash = 929 gw_hash(BUF_PTR_LEN(dst_addr_buf), DJBHASH_INIT); 930 uint32_t last_max = UINT32_MAX; 931 for (int k = 0; k < ext_used; ++k) { 932 const gw_host * const host = extension->hosts[k]; 933 if (0 == host->active_procs) continue; 934 const uint32_t cur_max = base_hash ^ host->gw_hash ^ host->port; 935 #if 0 936 if (debug) { 937 log_error(r->conf.errh, __FILE__, __LINE__, 938 "proxy - election: %s %s %hu %u", dst_addr_buf->ptr, 939 host->host ? host->host->ptr : "", 940 host->port, cur_max); 941 } 942 #endif 943 if (last_max < cur_max || last_max == UINT32_MAX) { 944 last_max = cur_max; 945 ndx = k; 946 } 947 } 948 /*balancing = "sticky";*/ 949 break; 950 } 951 default: 952 break; 953 } 954 #if 0 955 if (debug) { 956 log_error(r->conf.errh, __FILE__, __LINE__, 957 "gw - balancing: %s, hosts: %d", balancing, ext_used); 958 } 959 #endif 960 } 961 962 if (__builtin_expect( (-1 != ndx), 1)) { 963 /* found a server */ 964 965 if (debug) { 966 gw_host * const host = extension->hosts[ndx]; 967 log_error(r->conf.errh, __FILE__, __LINE__, 968 "gw - found a host %s %hu", 969 host->host ? host->host->ptr : "", host->port); 970 return host; 971 } 972 973 return extension->hosts[ndx]; 974 } else if (0 == r->con->srv->srvconf.max_worker) { 975 /* special-case adaptive spawning and 0 == host->min_procs */ 976 for (int k = 0; k < ext_used; ++k) { 977 gw_host * const host = extension->hosts[k]; 978 if (0 == host->min_procs && 0 == host->num_procs && host->bin_path){ 979 gw_proc_spawn(host, r->con->srv->errh, debug); 980 if (host->num_procs) return host; 981 } 982 } 983 } 984 985 /* all hosts are down */ 986 /* sorry, we don't have a server alive for this ext */ 987 r->http_status = 503; /* Service Unavailable */ 988 r->handler_module = NULL; 989 990 /* only send the 'no handler' once */ 991 if (!extension->note_is_sent) { 992 extension->note_is_sent = 1; 993 log_error(r->conf.errh, __FILE__, __LINE__, 994 "all handlers for %s?%.*s on %s are down.", 995 r->uri.path.ptr, BUFFER_INTLEN_PTR(&r->uri.query), 996 extension->key.ptr); 997 } 998 999 return NULL; 1000 } 1001 1002 static int gw_establish_connection(request_st * const r, gw_host *host, gw_proc *proc, pid_t pid, int gw_fd, int debug) { 1003 if (-1 == connect(gw_fd, proc->saddr, proc->saddrlen)) { 1004 int errnum = errno; 1005 if (errnum == EINPROGRESS || errnum == EALREADY || errnum == EINTR 1006 || (errnum == EAGAIN && host->unixsocket)) { 1007 if (debug > 2) { 1008 log_error(r->conf.errh, __FILE__, __LINE__, 1009 "connect delayed; will continue later: %s", 1010 proc->connection_name->ptr); 1011 } 1012 1013 return 1; 1014 } else { 1015 gw_proc_connect_error(r, host, proc, pid, errnum, debug); 1016 return -1; 1017 } 1018 } 1019 1020 if (debug > 1) { 1021 log_error(r->conf.errh, __FILE__, __LINE__, 1022 "connect succeeded: %d", gw_fd); 1023 } 1024 1025 return 0; 1026 } 1027 1028 __attribute_cold__ 1029 __attribute_noinline__ 1030 static void gw_restart_dead_proc(gw_host * const host, log_error_st * const errh, const int debug, const int trigger, gw_proc * const proc) { 1031 switch (proc->state) { 1032 case PROC_STATE_RUNNING: 1033 break; 1034 case PROC_STATE_OVERLOADED: 1035 gw_proc_check_enable(host, proc, errh); 1036 break; 1037 case PROC_STATE_KILLED: 1038 if (trigger && ++proc->disabled_until > 4) { 1039 int sig = (proc->disabled_until <= 8) 1040 ? host->kill_signal 1041 : proc->disabled_until <= 16 ? SIGTERM : SIGKILL; 1042 kill(proc->pid, sig); 1043 } 1044 break; 1045 case PROC_STATE_DIED_WAIT_FOR_PID: 1046 /*(state should not happen in workers if server.max-worker > 0)*/ 1047 /*(if PROC_STATE_DIED_WAIT_FOR_PID is used in future, might want 1048 * to save proc->disabled_until before gw_proc_waitpid() since 1049 * gw_proc_waitpid will set proc->disabled_until=log_monotonic_secs, 1050 * and so process will not be restarted below until one sec later)*/ 1051 if (0 == gw_proc_waitpid(host, proc, errh)) { 1052 gw_proc_check_enable(host, proc, errh); 1053 } 1054 1055 if (proc->state != PROC_STATE_DIED) break; 1056 __attribute_fallthrough__/*(we have a dead proc now)*/ 1057 1058 case PROC_STATE_DIED: 1059 /* local procs get restarted by us, 1060 * remote ones hopefully by the admin */ 1061 1062 if (host->bin_path) { 1063 /* we still have connections bound to this proc, 1064 * let them terminate first */ 1065 if (proc->load != 0) break; 1066 1067 /* avoid spinning if child exits too quickly */ 1068 if (proc->disabled_until >= log_monotonic_secs) break; 1069 1070 /* restart the child */ 1071 1072 if (debug) { 1073 log_error(errh, __FILE__, __LINE__, 1074 "--- gw spawning" 1075 "\n\tsocket %s" 1076 "\n\tcurrent: 1 / %u", 1077 proc->connection_name->ptr, host->max_procs); 1078 } 1079 1080 if (gw_spawn_connection(host, proc, errh, debug)) { 1081 log_error(errh, __FILE__, __LINE__, 1082 "ERROR: spawning gw failed."); 1083 } 1084 } else { 1085 gw_proc_check_enable(host, proc, errh); 1086 } 1087 break; 1088 } 1089 } 1090 1091 static void gw_restart_dead_procs(gw_host * const host, log_error_st * const errh, const int debug, const int trigger) { 1092 for (gw_proc *proc = host->first; proc; proc = proc->next) { 1093 if (debug > 2) { 1094 log_error(errh, __FILE__, __LINE__, 1095 "proc: %s %d %d %d %d", proc->connection_name->ptr, 1096 proc->state, proc->is_local, proc->load, proc->pid); 1097 } 1098 if (proc->state != PROC_STATE_RUNNING) 1099 gw_restart_dead_proc(host, errh, debug, trigger, proc); 1100 } 1101 } 1102 1103 1104 1105 1106 #include "base.h" 1107 #include "response.h" 1108 1109 1110 /* ok, we need a prototype */ 1111 static handler_t gw_handle_fdevent(void *ctx, int revents); 1112 static handler_t gw_process_fdevent(gw_handler_ctx *hctx, request_st *r, int revents); 1113 1114 1115 __attribute_returns_nonnull__ 1116 static gw_handler_ctx * handler_ctx_init(size_t sz) { 1117 gw_handler_ctx *hctx = calloc(1, 0 == sz ? sizeof(*hctx) : sz); 1118 force_assert(hctx); 1119 1120 /*hctx->response = chunk_buffer_acquire();*//*(allocated when needed)*/ 1121 1122 hctx->request_id = 0; 1123 hctx->gw_mode = GW_RESPONDER; 1124 hctx->state = GW_STATE_INIT; 1125 hctx->proc = NULL; 1126 1127 hctx->fd = -1; 1128 1129 hctx->reconnects = 0; 1130 hctx->send_content_body = 1; 1131 1132 /*hctx->rb = chunkqueue_init();*//*(allocated when needed)*/ 1133 chunkqueue_init(&hctx->wb); 1134 hctx->wb_reqlen = 0; 1135 1136 return hctx; 1137 } 1138 1139 static void handler_ctx_free(gw_handler_ctx *hctx) { 1140 /* caller MUST have called gw_backend_close(hctx, r) if necessary */ 1141 if (hctx->handler_ctx_free) hctx->handler_ctx_free(hctx); 1142 chunk_buffer_release(hctx->response); 1143 1144 if (hctx->rb) chunkqueue_free(hctx->rb); 1145 chunkqueue_reset(&hctx->wb); 1146 1147 free(hctx); 1148 } 1149 1150 static void handler_ctx_clear(gw_handler_ctx *hctx) { 1151 /* caller MUST have called gw_backend_close(hctx, r) if necessary */ 1152 1153 hctx->proc = NULL; 1154 hctx->host = NULL; 1155 hctx->ext = NULL; 1156 /*hctx->ext_auth is intentionally preserved to flag prior authorizer*/ 1157 1158 hctx->gw_mode = GW_RESPONDER; 1159 hctx->state = GW_STATE_INIT; 1160 /*hctx->state_timestamp = 0;*//*(unused; left as-is)*/ 1161 1162 if (hctx->rb) chunkqueue_reset(hctx->rb); 1163 chunkqueue_reset(&hctx->wb); 1164 hctx->wb_reqlen = 0; 1165 1166 if (hctx->response) buffer_clear(hctx->response); 1167 1168 hctx->fd = -1; 1169 hctx->reconnects = 0; 1170 hctx->request_id = 0; 1171 hctx->send_content_body = 1; 1172 1173 /*plugin_config conf;*//*(no need to reset for same request)*/ 1174 1175 /*hctx->r = NULL;*//*(no need to reset for same request)*/ 1176 /*hctx->plugin_data = NULL;*//*(no need to reset for same request)*/ 1177 } 1178 1179 1180 void * gw_init(void) { 1181 return calloc(1, sizeof(gw_plugin_data)); 1182 } 1183 1184 1185 void gw_plugin_config_free(gw_plugin_config *s) { 1186 gw_exts *exts = s->exts; 1187 if (exts) { 1188 for (uint32_t j = 0; j < exts->used; ++j) { 1189 gw_extension *ex = exts->exts+j; 1190 for (uint32_t n = 0; n < ex->used; ++n) { 1191 gw_proc *proc; 1192 gw_host *host = ex->hosts[n]; 1193 1194 for (proc = host->first; proc; proc = proc->next) { 1195 if (proc->pid > 0) { 1196 kill(proc->pid, host->kill_signal); 1197 } 1198 1199 if (proc->is_local && proc->unixsocket) { 1200 unlink(proc->unixsocket->ptr); 1201 } 1202 } 1203 1204 for (proc = host->unused_procs; proc; proc = proc->next) { 1205 if (proc->pid > 0) { 1206 kill(proc->pid, host->kill_signal); 1207 } 1208 if (proc->is_local && proc->unixsocket) { 1209 unlink(proc->unixsocket->ptr); 1210 } 1211 } 1212 } 1213 } 1214 1215 gw_extensions_free(s->exts); 1216 gw_extensions_free(s->exts_auth); 1217 gw_extensions_free(s->exts_resp); 1218 } 1219 free(s); 1220 } 1221 1222 void gw_free(void *p_d) { 1223 gw_plugin_data * const p = p_d; 1224 if (NULL == p->cvlist) return; 1225 /* (init i to 0 if global context; to 1 to skip empty global context) */ 1226 for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) { 1227 config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0]; 1228 for (; -1 != cpv->k_id; ++cpv) { 1229 switch (cpv->k_id) { 1230 case 0: /* xxxxx.server */ 1231 if (cpv->vtype == T_CONFIG_LOCAL) 1232 gw_plugin_config_free(cpv->v.v); 1233 break; 1234 default: 1235 break; 1236 } 1237 } 1238 } 1239 } 1240 1241 void gw_exts_clear_check_local(gw_exts *exts) { 1242 for (uint32_t j = 0; j < exts->used; ++j) { 1243 gw_extension *ex = exts->exts+j; 1244 for (uint32_t n = 0; n < ex->used; ++n) { 1245 ex->hosts[n]->check_local = 0; 1246 } 1247 } 1248 } 1249 1250 int gw_set_defaults_backend(server *srv, gw_plugin_data *p, const array *a, gw_plugin_config *s, int sh_exec, const char *cpkkey) { 1251 /* per-module plugin_config MUST have common "base class" gw_plugin_config*/ 1252 /* per-module plugin_data MUST have pointer-compatible common "base class" 1253 * with gw_plugin_data (stemming from gw_plugin_config compatibility) */ 1254 1255 static const config_plugin_keys_t cpk[] = { 1256 { CONST_STR_LEN("host"), 1257 T_CONFIG_STRING, 1258 T_CONFIG_SCOPE_CONNECTION } 1259 ,{ CONST_STR_LEN("port"), 1260 T_CONFIG_SHORT, 1261 T_CONFIG_SCOPE_CONNECTION } 1262 ,{ CONST_STR_LEN("socket"), 1263 T_CONFIG_STRING, 1264 T_CONFIG_SCOPE_CONNECTION } 1265 ,{ CONST_STR_LEN("listen-backlog"), 1266 T_CONFIG_INT, 1267 T_CONFIG_SCOPE_CONNECTION } 1268 ,{ CONST_STR_LEN("bin-path"), 1269 T_CONFIG_STRING, 1270 T_CONFIG_SCOPE_CONNECTION } 1271 ,{ CONST_STR_LEN("kill-signal"), 1272 T_CONFIG_SHORT, 1273 T_CONFIG_SCOPE_CONNECTION } 1274 ,{ CONST_STR_LEN("check-local"), 1275 T_CONFIG_BOOL, 1276 T_CONFIG_SCOPE_CONNECTION } 1277 ,{ CONST_STR_LEN("mode"), 1278 T_CONFIG_STRING, 1279 T_CONFIG_SCOPE_CONNECTION } 1280 ,{ CONST_STR_LEN("docroot"), 1281 T_CONFIG_STRING, 1282 T_CONFIG_SCOPE_CONNECTION } 1283 ,{ CONST_STR_LEN("min-procs"), 1284 T_CONFIG_SHORT, 1285 T_CONFIG_SCOPE_CONNECTION } 1286 ,{ CONST_STR_LEN("max-procs"), 1287 T_CONFIG_SHORT, 1288 T_CONFIG_SCOPE_CONNECTION } 1289 ,{ CONST_STR_LEN("max-load-per-proc"), 1290 T_CONFIG_SHORT, 1291 T_CONFIG_SCOPE_CONNECTION } 1292 ,{ CONST_STR_LEN("idle-timeout"), 1293 T_CONFIG_SHORT, 1294 T_CONFIG_SCOPE_CONNECTION } 1295 ,{ CONST_STR_LEN("disable-time"), 1296 T_CONFIG_SHORT, 1297 T_CONFIG_SCOPE_CONNECTION } 1298 ,{ CONST_STR_LEN("bin-environment"), 1299 T_CONFIG_ARRAY_KVSTRING, 1300 T_CONFIG_SCOPE_CONNECTION } 1301 ,{ CONST_STR_LEN("bin-copy-environment"), 1302 T_CONFIG_ARRAY_VLIST, 1303 T_CONFIG_SCOPE_CONNECTION } 1304 ,{ CONST_STR_LEN("broken-scriptfilename"), 1305 T_CONFIG_BOOL, 1306 T_CONFIG_SCOPE_CONNECTION } 1307 ,{ CONST_STR_LEN("strip-request-uri"), 1308 T_CONFIG_STRING, 1309 T_CONFIG_SCOPE_CONNECTION } 1310 ,{ CONST_STR_LEN("fix-root-scriptname"), 1311 T_CONFIG_BOOL, 1312 T_CONFIG_SCOPE_CONNECTION } 1313 ,{ CONST_STR_LEN("allow-x-send-file"), 1314 T_CONFIG_BOOL, 1315 T_CONFIG_SCOPE_CONNECTION } 1316 ,{ CONST_STR_LEN("x-sendfile"), 1317 T_CONFIG_BOOL, 1318 T_CONFIG_SCOPE_CONNECTION } 1319 ,{ CONST_STR_LEN("x-sendfile-docroot"), 1320 T_CONFIG_ARRAY_VLIST, 1321 T_CONFIG_SCOPE_CONNECTION } 1322 ,{ CONST_STR_LEN("tcp-fin-propagate"), 1323 T_CONFIG_BOOL, 1324 T_CONFIG_SCOPE_CONNECTION } 1325 ,{ CONST_STR_LEN("connect-timeout"), 1326 T_CONFIG_INT, 1327 T_CONFIG_SCOPE_CONNECTION } 1328 ,{ CONST_STR_LEN("write-timeout"), 1329 T_CONFIG_INT, 1330 T_CONFIG_SCOPE_CONNECTION } 1331 ,{ CONST_STR_LEN("read-timeout"), 1332 T_CONFIG_INT, 1333 T_CONFIG_SCOPE_CONNECTION } 1334 ,{ NULL, 0, 1335 T_CONFIG_UNSET, 1336 T_CONFIG_SCOPE_UNSET } 1337 }; 1338 1339 gw_host *host = NULL; 1340 1341 int graceful_restart_bg = 1342 config_feature_bool(srv, "server.graceful-restart-bg", 0); 1343 1344 p->srv_pid = srv->pid; 1345 1346 s->exts = gw_extensions_init(); 1347 s->exts_auth = gw_extensions_init(); 1348 s->exts_resp = gw_extensions_init(); 1349 /*s->balance = GW_BALANCE_LEAST_CONNECTION;*//*(default)*/ 1350 1351 /* 1352 * gw.server = ( "<ext>" => ( ... ), 1353 * "<ext>" => ( ... ) ) 1354 */ 1355 1356 for (uint32_t j = 0; j < a->used; ++j) { 1357 data_array *da_ext = (data_array *)a->data[j]; 1358 1359 /* 1360 * da_ext->key == name of the extension 1361 */ 1362 1363 /* 1364 * gw.server = ( "<ext>" => 1365 * ( "<host>" => ( ... ), 1366 * "<host>" => ( ... ) 1367 * ), 1368 * "<ext>" => ... ) 1369 */ 1370 1371 for (uint32_t n = 0; n < da_ext->value.used; ++n) { 1372 data_array * const da_host = (data_array *)da_ext->value.data[n]; 1373 1374 if (da_host->type != TYPE_ARRAY 1375 || !array_is_kvany(&da_host->value)){ 1376 log_error(srv->errh, __FILE__, __LINE__, 1377 "unexpected value for gw.server near [%s](string); " 1378 "expected ( \"ext\" => " 1379 "( \"backend-label\" => ( \"key\" => \"value\" )))", 1380 da_host->key.ptr ? da_host->key.ptr : ""); 1381 goto error; 1382 } 1383 1384 config_plugin_value_t cvlist[sizeof(cpk)/sizeof(cpk[0])+1]; 1385 memset(cvlist, 0, sizeof(cvlist)); 1386 1387 array *ca = &da_host->value; 1388 if (!config_plugin_values_init_block(srv, ca, cpk, cpkkey, cvlist)) 1389 goto error; 1390 1391 unsigned short host_mode = GW_RESPONDER; 1392 1393 host = gw_host_init(); 1394 host->id = &da_host->key; 1395 host->check_local = 1; 1396 host->min_procs = 4; 1397 host->max_procs = 4; 1398 host->max_load_per_proc = 1; 1399 host->idle_timeout = 60; 1400 host->connect_timeout = 8; 1401 host->disable_time = 1; 1402 host->break_scriptfilename_for_php = 0; 1403 host->kill_signal = SIGTERM; 1404 host->fix_root_path_name = 0; 1405 host->listen_backlog = 1024; 1406 host->xsendfile_allow = 0; 1407 host->refcount = 0; 1408 1409 config_plugin_value_t *cpv = cvlist; 1410 for (; -1 != cpv->k_id; ++cpv) { 1411 switch (cpv->k_id) { 1412 case 0: /* host */ 1413 if (!buffer_is_blank(cpv->v.b)) 1414 host->host = cpv->v.b; 1415 break; 1416 case 1: /* port */ 1417 host->port = cpv->v.shrt; 1418 break; 1419 case 2: /* socket */ 1420 if (!buffer_is_blank(cpv->v.b)) 1421 host->unixsocket = cpv->v.b; 1422 break; 1423 case 3: /* listen-backlog */ 1424 host->listen_backlog = cpv->v.u; 1425 break; 1426 case 4: /* bin-path */ 1427 if (!buffer_is_blank(cpv->v.b)) 1428 host->bin_path = cpv->v.b; 1429 break; 1430 case 5: /* kill-signal */ 1431 host->kill_signal = cpv->v.shrt; 1432 break; 1433 case 6: /* check-local */ 1434 host->check_local = (0 != cpv->v.u); 1435 break; 1436 case 7: /* mode */ 1437 if (!buffer_is_blank(cpv->v.b)) { 1438 const buffer *b = cpv->v.b; 1439 if (buffer_eq_slen(b, CONST_STR_LEN("responder"))) 1440 host_mode = GW_RESPONDER; 1441 else if (buffer_eq_slen(b, CONST_STR_LEN("authorizer"))) 1442 host_mode = GW_AUTHORIZER; 1443 else 1444 log_error(srv->errh, __FILE__, __LINE__, 1445 "WARNING: unknown gw mode: %s " 1446 "(ignored, mode set to responder)", b->ptr); 1447 } 1448 break; 1449 case 8: /* docroot */ 1450 if (!buffer_is_blank(cpv->v.b)) 1451 host->docroot = cpv->v.b; 1452 break; 1453 case 9: /* min-procs */ 1454 host->min_procs = cpv->v.shrt; 1455 break; 1456 case 10:/* max-procs */ 1457 host->max_procs = cpv->v.shrt; 1458 break; 1459 case 11:/* max-load-per-proc */ 1460 host->max_load_per_proc = cpv->v.shrt; 1461 break; 1462 case 12:/* idle-timeout */ 1463 host->idle_timeout = cpv->v.shrt; 1464 break; 1465 case 13:/* disable-time */ 1466 host->disable_time = cpv->v.shrt; 1467 break; 1468 case 14:/* bin-environment */ 1469 host->bin_env = cpv->v.a; 1470 break; 1471 case 15:/* bin-copy-environment */ 1472 host->bin_env_copy = cpv->v.a; 1473 break; 1474 case 16:/* broken-scriptfilename */ 1475 host->break_scriptfilename_for_php = (0 != cpv->v.u); 1476 break; 1477 case 17:/* strip-request-uri */ 1478 host->strip_request_uri = cpv->v.b; 1479 if (buffer_has_slash_suffix(host->strip_request_uri)) { 1480 buffer *b; /*(remove trailing slash; see http_cgi.c)*/ 1481 *(const buffer **)&b = host->strip_request_uri; 1482 buffer_truncate(b, buffer_clen(b)-1); 1483 } 1484 break; 1485 case 18:/* fix-root-scriptname */ 1486 host->fix_root_path_name = (0 != cpv->v.u); 1487 break; 1488 case 19:/* allow-x-send-file */ 1489 host->xsendfile_allow = (0 != cpv->v.u); 1490 break; 1491 case 20:/* x-sendfile */ 1492 host->xsendfile_allow = (0 != cpv->v.u); 1493 break; 1494 case 21:/* x-sendfile-docroot */ 1495 host->xsendfile_docroot = cpv->v.a; 1496 if (cpv->v.a->used) { 1497 for (uint32_t k = 0; k < cpv->v.a->used; ++k) { 1498 data_string *ds = (data_string *)cpv->v.a->data[k]; 1499 if (ds->type != TYPE_STRING) { 1500 log_error(srv->errh, __FILE__, __LINE__, 1501 "unexpected type for x-sendfile-docroot; " 1502 "expected: \"x-sendfile-docroot\" => " 1503 "( \"/allowed/path\", ... )"); 1504 goto error; 1505 } 1506 if (ds->value.ptr[0] != '/') { 1507 log_error(srv->errh, __FILE__, __LINE__, 1508 "x-sendfile-docroot paths must begin with " 1509 "'/'; invalid: \"%s\"", ds->value.ptr); 1510 goto error; 1511 } 1512 buffer_path_simplify(&ds->value); 1513 buffer_append_slash(&ds->value); 1514 } 1515 } 1516 break; 1517 case 22:/* tcp-fin-propagate */ 1518 host->tcp_fin_propagate = (0 != cpv->v.u); 1519 break; 1520 case 23:/* connect-timeout */ 1521 host->connect_timeout = cpv->v.u; 1522 break; 1523 case 24:/* write-timeout */ 1524 host->write_timeout = cpv->v.u; 1525 break; 1526 case 25:/* read-timeout */ 1527 host->read_timeout = cpv->v.u; 1528 break; 1529 default: 1530 break; 1531 } 1532 } 1533 1534 for (uint32_t m = 0; m < da_host->value.used; ++m) { 1535 if (NULL != strchr(da_host->value.data[m]->key.ptr, '_')) { 1536 log_error(srv->errh, __FILE__, __LINE__, 1537 "incorrect directive contains underscore ('_') instead of dash ('-'): %s", 1538 da_host->value.data[m]->key.ptr); 1539 } 1540 } 1541 1542 if ((host->host || host->port) && host->unixsocket) { 1543 log_error(srv->errh, __FILE__, __LINE__, 1544 "either host/port or socket have to be set in: " 1545 "%s = (%s => (%s ( ...", cpkkey, da_ext->key.ptr, 1546 da_host->key.ptr); 1547 1548 goto error; 1549 } 1550 1551 if (host->host && *host->host->ptr == '/' && !host->unixsocket) { 1552 host->unixsocket = host->host; 1553 } 1554 1555 if (host->unixsocket) { 1556 /* unix domain socket */ 1557 struct sockaddr_un un; 1558 1559 if (buffer_clen(host->unixsocket) + 1 > sizeof(un.sun_path) - 2) { 1560 log_error(srv->errh, __FILE__, __LINE__, 1561 "unixsocket is too long in: %s = (%s => (%s ( ...", 1562 cpkkey, da_ext->key.ptr, da_host->key.ptr); 1563 1564 goto error; 1565 } 1566 1567 if (host->bin_path) { 1568 gw_host *duplicate = unixsocket_is_dup(p, host->unixsocket); 1569 if (NULL != duplicate) { 1570 if (!buffer_is_equal(host->bin_path, duplicate->bin_path)) { 1571 log_error(srv->errh, __FILE__, __LINE__, 1572 "duplicate unixsocket path: %s", 1573 host->unixsocket->ptr); 1574 goto error; 1575 } 1576 gw_host_free(host); 1577 host = duplicate; 1578 ++host->refcount; 1579 } 1580 } 1581 1582 host->family = AF_UNIX; 1583 } else { 1584 /* tcp/ip */ 1585 1586 if (!host->host && !host->bin_path) { 1587 log_error(srv->errh, __FILE__, __LINE__, 1588 "host or bin-path have to be set in: " 1589 "%s = (%s => (%s ( ...", cpkkey, da_ext->key.ptr, 1590 da_host->key.ptr); 1591 1592 goto error; 1593 } else if (0 == host->port) { 1594 host->port = 80; 1595 } 1596 1597 if (!host->host) { 1598 static const buffer lhost ={CONST_STR_LEN("127.0.0.1")+1,0}; 1599 host->host = &lhost; 1600 } 1601 1602 host->family = (NULL != strchr(host->host->ptr, ':')) 1603 ? AF_INET6 1604 : AF_INET; 1605 } 1606 if (!host->refcount) 1607 gw_status_init_host(host); 1608 1609 if (host->refcount) { 1610 /* already init'd; skip spawning */ 1611 } else if (host->bin_path) { 1612 /* a local socket + self spawning */ 1613 struct stat st; 1614 parse_binpath(&host->args, host->bin_path); 1615 if (0 != stat(host->args.ptr[0], &st) || !S_ISREG(st.st_mode) 1616 || !(st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) { 1617 log_error(srv->errh, __FILE__, __LINE__, 1618 "invalid \"bin-path\" => \"%s\" " 1619 "(check that file exists, is regular file, " 1620 "and is executable by lighttpd)", host->bin_path->ptr); 1621 } 1622 1623 if (sh_exec) { 1624 /*(preserve prior behavior for SCGI exec of command)*/ 1625 /*(admin should really prefer to put 1626 * any complex command into a script)*/ 1627 for (uint32_t m = 0; m < host->args.used; ++m) 1628 free(host->args.ptr[m]); 1629 free(host->args.ptr); 1630 1631 host->args.ptr = calloc(4, sizeof(char *)); 1632 force_assert(host->args.ptr); 1633 host->args.used = 3; 1634 host->args.size = 4; 1635 host->args.ptr[0] = malloc(sizeof("/bin/sh")); 1636 force_assert(host->args.ptr[0]); 1637 memcpy(host->args.ptr[0], "/bin/sh", sizeof("/bin/sh")); 1638 host->args.ptr[1] = malloc(sizeof("-c")); 1639 force_assert(host->args.ptr[1]); 1640 memcpy(host->args.ptr[1], "-c", sizeof("-c")); 1641 host->args.ptr[2] = 1642 malloc(sizeof("exec ")-1+buffer_clen(host->bin_path)+1); 1643 force_assert(host->args.ptr[2]); 1644 memcpy(host->args.ptr[2], "exec ", sizeof("exec ")-1); 1645 memcpy(host->args.ptr[2]+sizeof("exec ")-1, 1646 host->bin_path->ptr, buffer_clen(host->bin_path)+1); 1647 host->args.ptr[3] = NULL; 1648 } 1649 1650 if (host->min_procs > host->max_procs) 1651 host->min_procs = host->max_procs; 1652 if (host->min_procs!= host->max_procs 1653 && 0 != srv->srvconf.max_worker) { 1654 host->min_procs = host->max_procs; 1655 log_error(srv->errh, __FILE__, __LINE__, 1656 "adaptive backend spawning disabled " 1657 "(server.max_worker is non-zero)"); 1658 } 1659 if (host->max_load_per_proc < 1) 1660 host->max_load_per_proc = 0; 1661 1662 if (s->debug) { 1663 log_error(srv->errh, __FILE__, __LINE__, 1664 "--- gw spawning local" 1665 "\n\tproc: %s" 1666 "\n\tport: %hu" 1667 "\n\tsocket %s" 1668 "\n\tmin-procs: %d" 1669 "\n\tmax-procs: %d", 1670 host->bin_path->ptr, 1671 host->port, 1672 host->unixsocket ? host->unixsocket->ptr : "", 1673 host->min_procs, 1674 host->max_procs); 1675 } 1676 1677 for (uint32_t pno = 0; pno < host->min_procs; ++pno) { 1678 gw_proc * const proc = gw_proc_init(host); 1679 1680 if (s->debug) { 1681 log_error(srv->errh, __FILE__, __LINE__, 1682 "--- gw spawning" 1683 "\n\tport: %hu" 1684 "\n\tsocket %s" 1685 "\n\tcurrent: %u / %u", 1686 host->port, 1687 host->unixsocket ? host->unixsocket->ptr : "", 1688 pno, host->max_procs); 1689 } 1690 1691 if (0 != gw_proc_sockaddr_init(host, proc, srv->errh)) { 1692 gw_proc_free(proc); 1693 goto error; 1694 } 1695 1696 if (!srv->srvconf.preflight_check 1697 && gw_spawn_connection(host, proc, srv->errh, s->debug)) { 1698 log_error(srv->errh, __FILE__, __LINE__, 1699 "[ERROR]: spawning gw failed."); 1700 gw_proc_free(proc); 1701 goto error; 1702 } 1703 1704 proc->next = host->first; 1705 if (host->first) host->first->prev = proc; 1706 host->first = proc; 1707 ++host->num_procs; 1708 } 1709 1710 if (graceful_restart_bg) { 1711 /*(set flag to false to avoid repeating)*/ 1712 graceful_restart_bg = 0; 1713 log_error(srv->errh, __FILE__, __LINE__, 1714 "server.graceful-restart-bg disabled " 1715 "(incompatible with %s.server \"bin-path\")", 1716 p->self->name); 1717 data_unset * const du = 1718 array_get_data_unset(srv->srvconf.feature_flags, 1719 CONST_STR_LEN("server.graceful-restart-bg")); 1720 if (du->type == TYPE_STRING) 1721 buffer_copy_string_len(&((data_string *)du)->value, 1722 CONST_STR_LEN("false")); 1723 else /* (du->type == TYPE_INTEGER) */ 1724 ((data_integer *)du)->value = 0; 1725 } 1726 } else { 1727 gw_proc * const proc = gw_proc_init(host); 1728 host->first = proc; 1729 ++host->num_procs; 1730 host->min_procs = 1; 1731 host->max_procs = 1; 1732 if (0 != gw_proc_sockaddr_init(host, proc, srv->errh)) goto error; 1733 gw_proc_set_state(host, proc, PROC_STATE_RUNNING); 1734 } 1735 1736 const buffer * const h = host->host ? host->host : host->unixsocket; 1737 host->gw_hash = gw_hash(BUF_PTR_LEN(h), DJBHASH_INIT); 1738 1739 /* s->exts is list of exts -> hosts 1740 * s->exts now used as combined list 1741 * of authorizer and responder hosts (for backend maintenance) 1742 * s->exts_auth is list of exts -> authorizer hosts 1743 * s->exts_resp is list of exts -> responder hosts 1744 * For each path/extension: 1745 * there may be an independent GW_AUTHORIZER and GW_RESPONDER 1746 * (The GW_AUTHORIZER and GW_RESPONDER could be handled by the same 1747 * host, and an admin might want to do that for large uploads, 1748 * since GW_AUTHORIZER runs prior to receiving (potentially large) 1749 * request body from client and can authorizer or deny request 1750 * prior to receiving the full upload) 1751 */ 1752 gw_extension_insert(s->exts, &da_ext->key, host); 1753 1754 if (host_mode == GW_AUTHORIZER) { 1755 ++host->refcount; 1756 gw_extension_insert(s->exts_auth, &da_ext->key, host); 1757 } else if (host_mode == GW_RESPONDER) { 1758 ++host->refcount; 1759 gw_extension_insert(s->exts_resp, &da_ext->key, host); 1760 } /*(else should have been rejected above)*/ 1761 1762 host = NULL; 1763 } 1764 } 1765 1766 return 1; 1767 1768 error: 1769 if (NULL != host) gw_host_free(host); 1770 return 0; 1771 } 1772 1773 int gw_get_defaults_balance(server *srv, const buffer *b) { 1774 if (!b || buffer_is_blank(b)) 1775 return GW_BALANCE_LEAST_CONNECTION; 1776 if (buffer_eq_slen(b, CONST_STR_LEN("fair"))) 1777 return GW_BALANCE_LEAST_CONNECTION; 1778 if (buffer_eq_slen(b, CONST_STR_LEN("least-connection"))) 1779 return GW_BALANCE_LEAST_CONNECTION; 1780 if (buffer_eq_slen(b, CONST_STR_LEN("round-robin"))) 1781 return GW_BALANCE_RR; 1782 if (buffer_eq_slen(b, CONST_STR_LEN("hash"))) 1783 return GW_BALANCE_HASH; 1784 if (buffer_eq_slen(b, CONST_STR_LEN("sticky"))) 1785 return GW_BALANCE_STICKY; 1786 1787 log_error(srv->errh, __FILE__, __LINE__, 1788 "xxxxx.balance has to be one of: " 1789 "least-connection, round-robin, hash, sticky, but not: %s", b->ptr); 1790 return GW_BALANCE_LEAST_CONNECTION; 1791 } 1792 1793 1794 static void gw_set_state(gw_handler_ctx *hctx, gw_connection_state_t state) { 1795 hctx->state = state; 1796 /*hctx->state_timestamp = log_monotonic_secs;*/ 1797 } 1798 1799 1800 void gw_set_transparent(gw_handler_ctx *hctx) { 1801 if (AF_UNIX != hctx->host->family) { 1802 if (-1 == fdevent_set_tcp_nodelay(hctx->fd, 1)) { 1803 /*(error, but not critical)*/ 1804 } 1805 } 1806 hctx->wb_reqlen = -1; 1807 gw_set_state(hctx, GW_STATE_WRITE); 1808 } 1809 1810 1811 static void gw_host_hctx_enq(gw_handler_ctx * const hctx) { 1812 gw_host * const host = hctx->host; 1813 /*if (__builtin_expect( (host == NULL), 0)) return;*/ 1814 1815 hctx->prev = NULL; 1816 hctx->next = host->hctxs; 1817 if (hctx->next) 1818 hctx->next->prev = hctx; 1819 host->hctxs = hctx; 1820 } 1821 1822 1823 static void gw_host_hctx_deq(gw_handler_ctx * const hctx) { 1824 /*if (__builtin_expect( (hctx->host == NULL), 0)) return;*/ 1825 1826 if (hctx->prev) 1827 hctx->prev->next = hctx->next; 1828 else 1829 hctx->host->hctxs= hctx->next; 1830 1831 if (hctx->next) 1832 hctx->next->prev = hctx->prev; 1833 1834 hctx->next = NULL; 1835 hctx->prev = NULL; 1836 } 1837 1838 1839 static void gw_backend_close(gw_handler_ctx * const hctx, request_st * const r) { 1840 if (hctx->fd >= 0) { 1841 fdevent_fdnode_event_del(hctx->ev, hctx->fdn); 1842 /*fdevent_unregister(ev, hctx->fd);*//*(handled below)*/ 1843 fdevent_sched_close(hctx->ev, hctx->fd, 1); 1844 hctx->fdn = NULL; 1845 hctx->fd = -1; 1846 gw_host_hctx_deq(hctx); 1847 } 1848 1849 if (hctx->host) { 1850 if (hctx->proc) { 1851 gw_proc_release(hctx->host, hctx->proc, hctx->conf.debug, 1852 r->conf.errh); 1853 hctx->proc = NULL; 1854 } 1855 1856 gw_host_reset(hctx->host); 1857 hctx->host = NULL; 1858 } 1859 } 1860 1861 static void gw_connection_close(gw_handler_ctx * const hctx, request_st * const r) { 1862 gw_plugin_data *p = hctx->plugin_data; 1863 1864 gw_backend_close(hctx, r); 1865 handler_ctx_free(hctx); 1866 r->plugin_ctx[p->id] = NULL; 1867 1868 if (r->handler_module == p->self) { 1869 http_response_backend_done(r); 1870 } 1871 } 1872 1873 static handler_t gw_reconnect(gw_handler_ctx * const hctx, request_st * const r) { 1874 gw_backend_close(hctx, r); 1875 1876 hctx->host = gw_host_get(r,hctx->ext,hctx->conf.balance,hctx->conf.debug); 1877 if (NULL == hctx->host) return HANDLER_FINISHED; 1878 1879 gw_host_assign(hctx->host); 1880 hctx->request_id = 0; 1881 hctx->opts.xsendfile_allow = hctx->host->xsendfile_allow; 1882 hctx->opts.xsendfile_docroot = hctx->host->xsendfile_docroot; 1883 gw_set_state(hctx, GW_STATE_INIT); 1884 return HANDLER_COMEBACK; 1885 } 1886 1887 1888 handler_t gw_handle_request_reset(request_st * const r, void *p_d) { 1889 gw_plugin_data *p = p_d; 1890 gw_handler_ctx *hctx = r->plugin_ctx[p->id]; 1891 if (hctx) gw_connection_close(hctx, r); 1892 1893 return HANDLER_GO_ON; 1894 } 1895 1896 1897 __attribute_cold__ 1898 static void gw_conditional_tcp_fin(gw_handler_ctx * const hctx, request_st * const r) { 1899 /*assert(r->conf.stream_request_body & FDEVENT_STREAM_REQUEST_TCP_FIN);*/ 1900 if (!chunkqueue_is_empty(&hctx->wb))return; 1901 if (!hctx->host->tcp_fin_propagate) return; 1902 if (hctx->gw_mode == GW_AUTHORIZER) return; 1903 if (r->conf.stream_request_body & FDEVENT_STREAM_REQUEST_BACKEND_SHUT_WR) 1904 return; 1905 1906 /* propagate shutdown SHUT_WR to backend if TCP half-close on con->fd */ 1907 r->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_BACKEND_SHUT_WR; 1908 r->conf.stream_request_body &= ~FDEVENT_STREAM_REQUEST_POLLIN; 1909 r->con->is_readable = 0; 1910 shutdown(hctx->fd, SHUT_WR); 1911 fdevent_fdnode_event_clr(hctx->ev, hctx->fdn, FDEVENT_OUT); 1912 } 1913 1914 static handler_t gw_write_refill_wb(gw_handler_ctx * const hctx, request_st * const r) { 1915 if (chunkqueue_is_empty(&r->reqbody_queue)) 1916 return HANDLER_GO_ON; 1917 if (hctx->stdin_append) { 1918 if (chunkqueue_length(&hctx->wb) < 65536 - 16384) 1919 return hctx->stdin_append(hctx); 1920 } 1921 else { 1922 const chunk * const c = r->reqbody_queue.last; 1923 const off_t qlen = chunkqueue_length(&r->reqbody_queue); 1924 if (c->type == FILE_CHUNK) { 1925 /*(move all but last chunk if reqbody_queue using tempfiles, unless 1926 * hctx->wb is empty and only one chunk, then move last chunk)*/ 1927 if (c != r->reqbody_queue.first) 1928 chunkqueue_steal(&hctx->wb, &r->reqbody_queue, 1929 qlen - (c->file.length-c->offset)); 1930 else if (chunkqueue_is_empty(&hctx->wb)) 1931 chunkqueue_append_chunkqueue(&hctx->wb, &r->reqbody_queue); 1932 } 1933 else if (qlen + chunkqueue_length(&hctx->wb) > 65536) { 1934 if (0 != chunkqueue_steal_with_tempfiles(&hctx->wb, 1935 &r->reqbody_queue, qlen, r->conf.errh)) 1936 return HANDLER_ERROR; 1937 } 1938 else 1939 chunkqueue_append_chunkqueue(&hctx->wb, &r->reqbody_queue); 1940 } 1941 return HANDLER_GO_ON; 1942 } 1943 1944 static handler_t gw_write_request(gw_handler_ctx * const hctx, request_st * const r) { 1945 switch(hctx->state) { 1946 case GW_STATE_INIT: 1947 /* do we have a running process for this host (max-procs) ? */ 1948 hctx->proc = NULL; 1949 1950 for (gw_proc *proc = hctx->host->first; proc; proc = proc->next) { 1951 if (proc->state == PROC_STATE_RUNNING) { 1952 hctx->proc = proc; 1953 break; 1954 } 1955 } 1956 1957 /* all children are dead */ 1958 if (hctx->proc == NULL) { 1959 return HANDLER_ERROR; 1960 } 1961 1962 /* check the other procs if they have a lower load */ 1963 for (gw_proc *proc = hctx->proc->next; proc; proc = proc->next) { 1964 if (proc->state != PROC_STATE_RUNNING) continue; 1965 if (proc->load < hctx->proc->load) hctx->proc = proc; 1966 } 1967 1968 gw_proc_load_inc(hctx->host, hctx->proc); 1969 1970 hctx->fd = fdevent_socket_nb_cloexec(hctx->host->family,SOCK_STREAM,0); 1971 if (-1 == hctx->fd) { 1972 log_perror(r->conf.errh, __FILE__, __LINE__, 1973 "socket() failed (cur_fds:%d) (max_fds:%d)", 1974 r->con->srv->cur_fds, r->con->srv->max_fds); 1975 return HANDLER_ERROR; 1976 } 1977 1978 ++r->con->srv->cur_fds; 1979 1980 hctx->fdn = fdevent_register(hctx->ev,hctx->fd,gw_handle_fdevent,hctx); 1981 1982 if (hctx->proc->is_local) { 1983 hctx->pid = hctx->proc->pid; 1984 } 1985 1986 hctx->write_ts = log_monotonic_secs; 1987 gw_host_hctx_enq(hctx); 1988 switch (gw_establish_connection(r, hctx->host, hctx->proc, hctx->pid, 1989 hctx->fd, hctx->conf.debug)) { 1990 case 1: /* connection is in progress */ 1991 fdevent_fdnode_event_set(hctx->ev, hctx->fdn, FDEVENT_OUT); 1992 gw_set_state(hctx, GW_STATE_CONNECT_DELAYED); 1993 return HANDLER_WAIT_FOR_EVENT; 1994 case -1:/* connection error */ 1995 return HANDLER_ERROR; 1996 case 0: /* everything is ok, go on */ 1997 hctx->reconnects = 0; 1998 break; 1999 } 2000 __attribute_fallthrough__ 2001 case GW_STATE_CONNECT_DELAYED: 2002 if (hctx->state == GW_STATE_CONNECT_DELAYED) { /*(not GW_STATE_INIT)*/ 2003 if (!(fdevent_fdnode_interest(hctx->fdn) & FDEVENT_OUT)) 2004 return HANDLER_WAIT_FOR_EVENT; 2005 int socket_error = fdevent_connect_status(hctx->fd); 2006 if (socket_error != 0) { 2007 gw_proc_connect_error(r, hctx->host, hctx->proc, hctx->pid, 2008 socket_error, hctx->conf.debug); 2009 return HANDLER_ERROR; 2010 } 2011 /* go on with preparing the request */ 2012 hctx->write_ts = log_monotonic_secs; 2013 } 2014 2015 gw_proc_connect_success(hctx->host, hctx->proc, hctx->conf.debug, r); 2016 2017 gw_set_state(hctx, GW_STATE_PREPARE_WRITE); 2018 __attribute_fallthrough__ 2019 case GW_STATE_PREPARE_WRITE: 2020 /* ok, we have the connection */ 2021 2022 { 2023 handler_t rc = hctx->create_env(hctx); 2024 if (HANDLER_GO_ON != rc) { 2025 if (HANDLER_FINISHED != rc && HANDLER_ERROR != rc) 2026 fdevent_fdnode_event_clr(hctx->ev, hctx->fdn, FDEVENT_OUT); 2027 return rc; 2028 } 2029 } 2030 2031 /*(disable Nagle algorithm if streaming and content-length unknown)*/ 2032 if (AF_UNIX != hctx->host->family) { 2033 if (r->reqbody_length < 0) { 2034 if (-1 == fdevent_set_tcp_nodelay(hctx->fd, 1)) { 2035 /*(error, but not critical)*/ 2036 } 2037 } 2038 } 2039 2040 hctx->read_ts = log_monotonic_secs; 2041 fdevent_fdnode_event_add(hctx->ev, hctx->fdn, FDEVENT_IN|FDEVENT_RDHUP); 2042 gw_set_state(hctx, GW_STATE_WRITE); 2043 __attribute_fallthrough__ 2044 case GW_STATE_WRITE: 2045 if (!chunkqueue_is_empty(&hctx->wb)) { 2046 log_error_st * const errh = r->conf.errh; 2047 #if 0 2048 if (hctx->conf.debug > 1) { 2049 log_error(errh, __FILE__, __LINE__, "sdsx", 2050 "send data to backend (fd=%d), size=%zu", 2051 hctx->fd, chunkqueue_length(&hctx->wb)); 2052 } 2053 #endif 2054 off_t bytes_out = hctx->wb.bytes_out; 2055 if (r->con->srv->network_backend_write(hctx->fd, &hctx->wb, 2056 MAX_WRITE_LIMIT, errh) < 0) { 2057 switch(errno) { 2058 case EPIPE: 2059 case ENOTCONN: 2060 case ECONNRESET: 2061 /* the connection got dropped after accept() 2062 * we don't care about that -- 2063 * if you accept() it, you have to handle it. 2064 */ 2065 log_error(errh, __FILE__, __LINE__, 2066 "connection was dropped after accept() " 2067 "(perhaps the gw process died), " 2068 "write-offset: %lld socket: %s", 2069 (long long)hctx->wb.bytes_out, 2070 hctx->proc->connection_name->ptr); 2071 return HANDLER_ERROR; 2072 default: 2073 log_perror(errh, __FILE__, __LINE__, "write failed"); 2074 return HANDLER_ERROR; 2075 } 2076 } 2077 else if (hctx->wb.bytes_out > bytes_out) { 2078 hctx->write_ts = hctx->proc->last_used = log_monotonic_secs; 2079 handler_t rc = gw_write_refill_wb(hctx, r); 2080 if (HANDLER_GO_ON != rc) return rc; 2081 } 2082 } 2083 2084 if (hctx->wb.bytes_out == hctx->wb_reqlen) { 2085 fdevent_fdnode_event_clr(hctx->ev, hctx->fdn, FDEVENT_OUT); 2086 gw_set_state(hctx, GW_STATE_READ); 2087 } else { 2088 off_t wblen = chunkqueue_length(&hctx->wb); 2089 if ((hctx->wb.bytes_in < hctx->wb_reqlen || hctx->wb_reqlen < 0) 2090 && wblen < 65536 - 16384) { 2091 /*(r->conf.stream_request_body & FDEVENT_STREAM_REQUEST)*/ 2092 if (!(r->conf.stream_request_body 2093 & FDEVENT_STREAM_REQUEST_POLLIN)) { 2094 r->conf.stream_request_body |= 2095 FDEVENT_STREAM_REQUEST_POLLIN; 2096 r->con->is_readable = 1; /* trigger optimistic client read */ 2097 } 2098 } 2099 if (0 == wblen) { 2100 fdevent_fdnode_event_clr(hctx->ev, hctx->fdn, FDEVENT_OUT); 2101 } 2102 else if (!(fdevent_fdnode_interest(hctx->fdn) & FDEVENT_OUT)) { 2103 hctx->write_ts = log_monotonic_secs; 2104 fdevent_fdnode_event_add(hctx->ev, hctx->fdn, FDEVENT_OUT); 2105 } 2106 } 2107 2108 if (r->conf.stream_request_body 2109 & FDEVENT_STREAM_REQUEST_TCP_FIN) 2110 gw_conditional_tcp_fin(hctx, r); 2111 2112 return HANDLER_WAIT_FOR_EVENT; 2113 case GW_STATE_READ: 2114 /* waiting for a response */ 2115 return HANDLER_WAIT_FOR_EVENT; 2116 default: 2117 log_error(r->conf.errh, __FILE__, __LINE__, 2118 "(debug) unknown state"); 2119 return HANDLER_ERROR; 2120 } 2121 } 2122 2123 2124 __attribute_cold__ 2125 __attribute_noinline__ 2126 static handler_t gw_backend_error(gw_handler_ctx * const hctx, request_st * const r) 2127 { 2128 if (hctx->backend_error) hctx->backend_error(hctx); 2129 http_response_backend_error(r); 2130 gw_connection_close(hctx, r); 2131 return HANDLER_FINISHED; 2132 } 2133 2134 2135 static handler_t gw_recv_response(gw_handler_ctx *hctx, request_st *r); 2136 2137 2138 __attribute_cold__ 2139 static handler_t gw_write_error(gw_handler_ctx * const hctx, request_st * const r) { 2140 2141 if (hctx->state == GW_STATE_INIT || 2142 hctx->state == GW_STATE_CONNECT_DELAYED) { 2143 2144 /* (optimization to detect backend process exit while processing a 2145 * large number of ready events; (this block could be removed)) */ 2146 if (hctx->proc && hctx->proc->is_local) { 2147 server * const srv = r->con->srv; 2148 if (0 == srv->srvconf.max_worker) 2149 gw_restart_dead_procs(hctx->host,srv->errh,hctx->conf.debug,0); 2150 } 2151 2152 /* cleanup this request and let request handler start request again */ 2153 if (hctx->reconnects++ < 5) return gw_reconnect(hctx, r); 2154 } 2155 else { 2156 /* backend might not read request body (even though backend should) 2157 * before sending response, so it is possible to get EPIPE trying to 2158 * write request body to the backend when backend has already sent a 2159 * response. If called from gw_handle_fdevent(), response should have 2160 * been read prior to getting here. However, if reqbody arrived on 2161 * client side, and called gw_handle_subrequest() and we tried to write 2162 * in gw_send_request() in state GW_STATE_WRITE, then it is possible to 2163 * get EPIPE and error out here when response is waiting to be read from 2164 * kernel socket buffers. Since we did not actually receive FDEVENT_HUP 2165 * or FDEVENT_RDHUP, calling gw_handle_fdevent() and fabricating 2166 * FDEVENT_RDHUP would cause an infinite loop trying to read(). 2167 * Instead, try once to read (small) response in this theoretical race*/ 2168 handler_t rc = gw_recv_response(hctx, r); /*(might invalidate hctx)*/ 2169 if (rc != HANDLER_GO_ON) return rc; /*(unless HANDLER_GO_ON)*/ 2170 } 2171 2172 /*(r->status == 400 if hctx->create_env() failed)*/ 2173 if (!r->resp_body_started && r->http_status < 500 && r->http_status != 400) 2174 r->http_status = 503; /* Service Unavailable */ 2175 2176 return gw_backend_error(hctx, r); /* HANDLER_FINISHED */ 2177 } 2178 2179 static handler_t gw_send_request(gw_handler_ctx * const hctx, request_st * const r) { 2180 handler_t rc = gw_write_request(hctx, r); 2181 return (HANDLER_ERROR != rc) ? rc : gw_write_error(hctx, r); 2182 } 2183 2184 2185 handler_t gw_handle_subrequest(request_st * const r, void *p_d) { 2186 gw_plugin_data *p = p_d; 2187 gw_handler_ctx *hctx = r->plugin_ctx[p->id]; 2188 if (NULL == hctx) return HANDLER_GO_ON; 2189 2190 const int revents = hctx->revents; 2191 if (revents) { 2192 hctx->revents = 0; 2193 handler_t rc = gw_process_fdevent(hctx, r, revents); 2194 if (rc != HANDLER_GO_ON && rc != HANDLER_WAIT_FOR_EVENT) 2195 return rc; /*(might invalidate hctx)*/ 2196 } 2197 2198 if ((r->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN) 2199 && r->resp_body_started) { 2200 if (chunkqueue_length(&r->write_queue) > 65536 - 4096) { 2201 /* Note: if apps inheriting gw_handle use hctx->rb, then those apps 2202 * are responsible for limiting amount of data buffered in memory 2203 * in hctx->rb. Currently, mod_fastcgi is the only core app doing 2204 * so, and the maximum FCGI_Record size is 8 + 65535 + 255 = 65798 2205 * (FCGI_HEADER_LEN(8)+contentLength(65535)+paddingLength(255)) */ 2206 fdevent_fdnode_event_clr(hctx->ev, hctx->fdn, FDEVENT_IN); 2207 } 2208 else if (!(fdevent_fdnode_interest(hctx->fdn) & FDEVENT_IN)) { 2209 /* optimistic read from backend */ 2210 handler_t rc; 2211 rc = gw_recv_response(hctx, r); /*(might invalidate hctx)*/ 2212 if (rc != HANDLER_GO_ON) return rc; /*(unless HANDLER_GO_ON)*/ 2213 hctx->read_ts = log_monotonic_secs; 2214 fdevent_fdnode_event_add(hctx->ev, hctx->fdn, FDEVENT_IN); 2215 } 2216 } 2217 2218 /* (do not receive request body before GW_AUTHORIZER has run or else 2219 * the request body is discarded with handler_ctx_clear() after running 2220 * the FastCGI Authorizer) */ 2221 2222 if (hctx->gw_mode != GW_AUTHORIZER 2223 && (0 == hctx->wb.bytes_in 2224 ? (r->state == CON_STATE_READ_POST || -1 == hctx->wb_reqlen) 2225 : (hctx->wb.bytes_in < hctx->wb_reqlen || hctx->wb_reqlen < 0))) { 2226 /* leave excess data in r->reqbody_queue, which is 2227 * buffered to disk if too large and backend can not keep up */ 2228 /*(64k - 4k to attempt to avoid temporary files 2229 * in conjunction with FDEVENT_STREAM_REQUEST_BUFMIN)*/ 2230 if (chunkqueue_length(&hctx->wb) > 65536 - 4096 2231 && (r->conf.stream_request_body & FDEVENT_STREAM_REQUEST_BUFMIN)) { 2232 r->conf.stream_request_body &= ~FDEVENT_STREAM_REQUEST_POLLIN; 2233 return HANDLER_WAIT_FOR_EVENT; 2234 } 2235 else { 2236 handler_t rc = r->con->reqbody_read(r); 2237 2238 if (hctx->opts.backend == BACKEND_PROXY) { 2239 if (hctx->state == GW_STATE_INIT /* ??? < GW_STATE_WRITE ??? */ 2240 && rc == HANDLER_WAIT_FOR_EVENT 2241 /* streaming flags might not be set yet 2242 * if hctx->create_env() not called yet */ 2243 && ((r->conf.stream_request_body & FDEVENT_STREAM_REQUEST) 2244 || r->h2_connect_ext)) 2245 rc = HANDLER_GO_ON; 2246 /* connect() to backend proxy w/o waiting for any request body*/ 2247 } 2248 else if (-1 == r->reqbody_length) { 2249 /* XXX: create configurable flag */ 2250 /* CGI environment requires that Content-Length be set. 2251 * Send 411 Length Required if Content-Length missing. 2252 * (occurs here if client sends Transfer-Encoding: chunked 2253 * and module is flagged to stream request body to backend) */ 2254 return (r->conf.stream_request_body & FDEVENT_STREAM_REQUEST) 2255 ? http_response_reqbody_read_error(r, 411) 2256 : (rc == HANDLER_GO_ON) ? HANDLER_WAIT_FOR_EVENT : rc; 2257 } 2258 2259 if (hctx->wb_reqlen < -1 && r->reqbody_length >= 0) { 2260 /* (completed receiving Transfer-Encoding: chunked) */ 2261 hctx->wb_reqlen = -hctx->wb_reqlen; 2262 if (hctx->stdin_append) { 2263 handler_t rca = hctx->stdin_append(hctx); 2264 if (HANDLER_GO_ON != rca) return rca; 2265 } 2266 else 2267 chunkqueue_append_chunkqueue(&hctx->wb, &r->reqbody_queue); 2268 } 2269 2270 if (0 != hctx->wb.bytes_in || -1 == hctx->wb_reqlen) { 2271 handler_t rca = gw_write_refill_wb(hctx, r); 2272 if (HANDLER_GO_ON != rca) return rca; 2273 if (fdevent_fdnode_interest(hctx->fdn) & FDEVENT_OUT) { 2274 return (rc == HANDLER_GO_ON) ? HANDLER_WAIT_FOR_EVENT : rc; 2275 } 2276 } 2277 if (rc != HANDLER_GO_ON) return rc; 2278 } 2279 } 2280 2281 { 2282 handler_t rc =((0==hctx->wb.bytes_in || !chunkqueue_is_empty(&hctx->wb)) 2283 && hctx->state != GW_STATE_CONNECT_DELAYED) 2284 ? gw_send_request(hctx, r) 2285 : HANDLER_WAIT_FOR_EVENT; 2286 if (HANDLER_WAIT_FOR_EVENT != rc) return rc; 2287 } 2288 2289 if (r->conf.stream_request_body & FDEVENT_STREAM_REQUEST_TCP_FIN) 2290 gw_conditional_tcp_fin(hctx, r); 2291 2292 return HANDLER_WAIT_FOR_EVENT; 2293 } 2294 2295 2296 static handler_t gw_authorizer_ok(gw_handler_ctx * const hctx, request_st * const r) { 2297 /* 2298 * If we are here in AUTHORIZER mode then a request for authorizer 2299 * was processed already, and status 200 has been returned. We need 2300 * now to handle authorized request. 2301 */ 2302 char *physpath = NULL; 2303 2304 gw_host * const host = hctx->host; 2305 if (host->docroot) { 2306 buffer_copy_buffer(&r->physical.doc_root, host->docroot); 2307 buffer_copy_buffer(&r->physical.basedir, host->docroot); 2308 buffer_copy_path_len2(&r->physical.path, 2309 BUF_PTR_LEN(host->docroot), 2310 BUF_PTR_LEN(&r->uri.path)); 2311 physpath = r->physical.path.ptr; 2312 } 2313 2314 /*(restore streaming flags removed during authorizer processing)*/ 2315 r->conf.stream_response_body |= (hctx->opts.authorizer >> 1); 2316 2317 gw_backend_close(hctx, r); 2318 handler_ctx_clear(hctx); 2319 2320 /* don't do more than 6 loops here; normally shouldn't happen */ 2321 if (++r->loops_per_request > 5) { 2322 log_error(r->conf.errh, __FILE__, __LINE__, 2323 "too many loops while processing request: %s", 2324 r->target_orig.ptr); 2325 r->http_status = 500; /* Internal Server Error */ 2326 r->handler_module = NULL; 2327 return HANDLER_FINISHED; 2328 } 2329 2330 /* restart the request so other handlers can process it */ 2331 2332 if (physpath) r->physical.path.ptr = NULL; 2333 http_response_reset(r); /*(includes r->http_status=0)*/ 2334 /* preserve r->physical.path.ptr with modified docroot */ 2335 if (physpath) r->physical.path.ptr = physpath; 2336 2337 /*(FYI: if multiple FastCGI authorizers were to be supported, 2338 * next one could be started here instead of restarting request)*/ 2339 2340 r->handler_module = NULL; 2341 return HANDLER_COMEBACK; 2342 } 2343 2344 2345 __attribute_cold__ 2346 static handler_t gw_recv_response_error(gw_handler_ctx * const hctx, request_st * const r, gw_proc * const proc); 2347 2348 2349 static handler_t gw_recv_response(gw_handler_ctx * const hctx, request_st * const r) { 2350 /*(XXX: make this a configurable flag for other protocols)*/ 2351 buffer *b = (hctx->opts.backend == BACKEND_FASTCGI 2352 || hctx->opts.backend == BACKEND_AJP13) 2353 ? chunk_buffer_acquire() 2354 : hctx->response; 2355 const off_t bytes_in = r->write_queue.bytes_in; 2356 2357 handler_t rc = http_response_read(r, &hctx->opts, b, hctx->fdn); 2358 2359 if (b != hctx->response) chunk_buffer_release(b); 2360 2361 gw_proc * const proc = hctx->proc; 2362 2363 switch (rc) { 2364 default: 2365 /* change in r->write_queue.bytes_in used to approximate backend read, 2366 * since bytes read from backend, if any, might be consumed from b by 2367 * hctx->opts->parse callback, hampering detection here. However, this 2368 * may not be triggered for partial collection of HTTP response headers 2369 * or partial packets for backend protocol (e.g. FastCGI) */ 2370 if (r->write_queue.bytes_in > bytes_in) 2371 hctx->read_ts = proc->last_used = log_monotonic_secs; 2372 return HANDLER_GO_ON; 2373 case HANDLER_FINISHED: 2374 /*hctx->read_ts =*/ proc->last_used = log_monotonic_secs; 2375 2376 if (hctx->gw_mode == GW_AUTHORIZER 2377 && (200 == r->http_status || 0 == r->http_status)) 2378 return gw_authorizer_ok(hctx, r); 2379 2380 gw_connection_close(hctx, r); 2381 return HANDLER_FINISHED; 2382 case HANDLER_COMEBACK: /*(not expected; treat as error)*/ 2383 case HANDLER_ERROR: 2384 return gw_recv_response_error(hctx, r, proc); 2385 } 2386 } 2387 2388 2389 __attribute_cold__ 2390 static handler_t gw_recv_response_error(gw_handler_ctx * const hctx, request_st * const r, gw_proc * const proc) 2391 { 2392 /* (optimization to detect backend process exit while processing a 2393 * large number of ready events; (this block could be removed)) */ 2394 if (proc->is_local && 1 == proc->load && proc->pid == hctx->pid 2395 && proc->state != PROC_STATE_DIED 2396 && 0 == r->con->srv->srvconf.max_worker) { 2397 /* intentionally check proc->disabed_until before gw_proc_waitpid */ 2398 gw_host * const host = hctx->host; 2399 log_error_st * const errh = r->con->srv->errh; 2400 if (proc->disabled_until < log_monotonic_secs 2401 && 0 != gw_proc_waitpid(host, proc, errh)) { 2402 if (hctx->conf.debug) { 2403 log_error(errh, __FILE__, __LINE__, 2404 "--- gw spawning\n\tsocket %s\n\tcurrent: 1/%d", 2405 proc->connection_name->ptr, host->num_procs); 2406 } 2407 2408 if (gw_spawn_connection(host, proc, errh, hctx->conf.debug)) { 2409 log_error(errh, __FILE__, __LINE__, 2410 "respawning failed, will retry later"); 2411 } 2412 } 2413 } 2414 2415 if (r->resp_body_started == 0) { 2416 /* nothing has been sent out yet, try to use another child */ 2417 2418 if (hctx->wb.bytes_out == 0 && hctx->reconnects++ < 5) { 2419 log_error(r->conf.errh, __FILE__, __LINE__, 2420 "response not received, request not sent on " 2421 "socket: %s for %s?%.*s, reconnecting", 2422 proc->connection_name->ptr, 2423 r->uri.path.ptr, BUFFER_INTLEN_PTR(&r->uri.query)); 2424 2425 return gw_reconnect(hctx, r); 2426 } 2427 2428 log_error(r->conf.errh, __FILE__, __LINE__, 2429 "response not received, request sent: %lld on " 2430 "socket: %s for %s?%.*s, closing connection", 2431 (long long)hctx->wb.bytes_out, proc->connection_name->ptr, 2432 r->uri.path.ptr, BUFFER_INTLEN_PTR(&r->uri.query)); 2433 } else if (!light_btst(r->resp_htags, HTTP_HEADER_UPGRADE) 2434 && !r->h2_connect_ext) { 2435 log_error(r->conf.errh, __FILE__, __LINE__, 2436 "response already sent out, but backend returned error on " 2437 "socket: %s for %s?%.*s, terminating connection", 2438 proc->connection_name->ptr, 2439 r->uri.path.ptr, BUFFER_INTLEN_PTR(&r->uri.query)); 2440 } 2441 2442 return gw_backend_error(hctx, r); /* HANDLER_FINISHED */ 2443 } 2444 2445 2446 static handler_t gw_handle_fdevent(void *ctx, int revents) { 2447 gw_handler_ctx *hctx = ctx; 2448 hctx->revents |= revents; 2449 joblist_append(hctx->con); 2450 return HANDLER_FINISHED; 2451 } 2452 2453 static handler_t gw_process_fdevent(gw_handler_ctx * const hctx, request_st * const r, int revents) { 2454 if (revents & FDEVENT_IN) { 2455 handler_t rc = gw_recv_response(hctx, r); /*(might invalidate hctx)*/ 2456 if (rc != HANDLER_GO_ON) return rc; /*(unless HANDLER_GO_ON)*/ 2457 } 2458 2459 if (revents & FDEVENT_OUT) { 2460 return gw_send_request(hctx, r); /*(might invalidate hctx)*/ 2461 } 2462 2463 /* perhaps this issue is already handled */ 2464 if (revents & (FDEVENT_HUP|FDEVENT_RDHUP)) { 2465 if (hctx->state == GW_STATE_CONNECT_DELAYED) { 2466 return gw_send_request(hctx, r); /*(might invalidate hctx)*/ 2467 } else if (r->resp_body_started) { 2468 /* drain any remaining data from kernel pipe buffers 2469 * even if (r->conf.stream_response_body 2470 * & FDEVENT_STREAM_RESPONSE_BUFMIN) 2471 * since event loop will spin on fd FDEVENT_HUP event 2472 * until unregistered. */ 2473 handler_t rc; 2474 const unsigned short flags = r->conf.stream_response_body; 2475 r->conf.stream_response_body &= ~FDEVENT_STREAM_RESPONSE_BUFMIN; 2476 r->conf.stream_response_body |= FDEVENT_STREAM_RESPONSE_POLLRDHUP; 2477 do { 2478 rc = gw_recv_response(hctx, r); /*(might invalidate hctx)*/ 2479 } while (rc == HANDLER_GO_ON); /*(unless HANDLER_GO_ON)*/ 2480 r->conf.stream_response_body = flags; 2481 return rc; /* HANDLER_FINISHED or HANDLER_ERROR */ 2482 } else { 2483 gw_proc *proc = hctx->proc; 2484 log_error(r->conf.errh, __FILE__, __LINE__, 2485 "error: unexpected close of gw connection for %s?%.*s " 2486 "(no gw process on socket: %s ?) %d", 2487 r->uri.path.ptr, BUFFER_INTLEN_PTR(&r->uri.query), 2488 proc->connection_name->ptr, hctx->state); 2489 2490 gw_connection_close(hctx, r); 2491 return HANDLER_FINISHED; 2492 } 2493 } else if (revents & FDEVENT_ERR) { 2494 log_error(r->conf.errh, __FILE__, __LINE__, 2495 "gw: got a FDEVENT_ERR. Don't know why."); 2496 return gw_backend_error(hctx, r); /* HANDLER_FINISHED */ 2497 } 2498 2499 return HANDLER_GO_ON; 2500 } 2501 2502 handler_t gw_check_extension(request_st * const r, gw_plugin_data * const p, int uri_path_handler, size_t hctx_sz) { 2503 #if 0 /*(caller must handle)*/ 2504 if (NULL != r->handler_module) return HANDLER_GO_ON; 2505 gw_patch_connection(r, p); 2506 if (NULL == p->conf.exts) return HANDLER_GO_ON; 2507 #endif 2508 2509 buffer *fn = uri_path_handler ? &r->uri.path : &r->physical.path; 2510 const size_t s_len = buffer_clen(fn); 2511 gw_extension *extension = NULL; 2512 gw_host *host = NULL; 2513 gw_handler_ctx *hctx; 2514 unsigned short gw_mode; 2515 2516 if (0 == s_len) return HANDLER_GO_ON; /*(not expected)*/ 2517 2518 /* check p->conf.exts_auth list and then p->conf.ext_resp list 2519 * (skip p->conf.exts_auth if array is empty 2520 * or if GW_AUTHORIZER already ran in this request) */ 2521 hctx = r->plugin_ctx[p->id]; 2522 /*(hctx not NULL if GW_AUTHORIZER ran; hctx->ext_auth check is redundant)*/ 2523 gw_mode = (NULL == hctx || NULL == hctx->ext_auth) 2524 ? 0 /*GW_AUTHORIZER p->conf.exts_auth will be searched next*/ 2525 : GW_AUTHORIZER; /*GW_RESPONDER p->conf.exts_resp will be searched next*/ 2526 2527 do { 2528 2529 gw_exts *exts; 2530 if (0 == gw_mode) { 2531 gw_mode = GW_AUTHORIZER; 2532 exts = p->conf.exts_auth; 2533 } else { 2534 gw_mode = GW_RESPONDER; 2535 exts = p->conf.exts_resp; 2536 } 2537 2538 if (0 == exts->used) continue; 2539 2540 /* gw.map-extensions maps extensions to existing gw.server entries 2541 * 2542 * gw.map-extensions = ( ".php3" => ".php" ) 2543 * 2544 * gw.server = ( ".php" => ... ) 2545 * 2546 * */ 2547 2548 /* check if extension-mapping matches */ 2549 if (p->conf.ext_mapping) { 2550 data_string *ds = 2551 (data_string *)array_match_key_suffix(p->conf.ext_mapping, fn); 2552 if (NULL != ds) { 2553 /* found a mapping */ 2554 /* check if we know the extension */ 2555 uint32_t k; 2556 for (k = 0; k < exts->used; ++k) { 2557 extension = exts->exts+k; 2558 2559 if (buffer_is_equal(&ds->value, &extension->key)) { 2560 break; 2561 } 2562 } 2563 2564 if (k == exts->used) { 2565 /* found nothing */ 2566 extension = NULL; 2567 } 2568 } 2569 } 2570 2571 if (extension == NULL) { 2572 size_t uri_path_len = buffer_clen(&r->uri.path); 2573 2574 /* check if extension matches */ 2575 for (uint32_t k = 0; k < exts->used; ++k) { 2576 gw_extension *ext = exts->exts+k; 2577 #ifdef __clang_analyzer__ 2578 force_assert(ext); /*(unnecessary; quiet clang analyzer)*/ 2579 #endif 2580 size_t ct_len = buffer_clen(&ext->key); 2581 2582 /* check _url_ in the form "/gw_pattern" */ 2583 if (ext->key.ptr[0] == '/') { 2584 if (ct_len <= uri_path_len 2585 && 0 == memcmp(r->uri.path.ptr, ext->key.ptr, ct_len)) { 2586 extension = ext; 2587 break; 2588 } 2589 } else if (ct_len <= s_len 2590 && 0 == memcmp(fn->ptr + s_len - ct_len, 2591 ext->key.ptr, ct_len)) { 2592 /* check extension in the form ".fcg" */ 2593 extension = ext; 2594 break; 2595 } 2596 } 2597 } 2598 2599 } while (NULL == extension && gw_mode != GW_RESPONDER); 2600 2601 /* extension doesn't match */ 2602 if (NULL == extension) { 2603 return HANDLER_GO_ON; 2604 } 2605 2606 /* check if we have at least one server for this extension up and running */ 2607 host = gw_host_get(r, extension, p->conf.balance, p->conf.debug); 2608 if (NULL == host) { 2609 return HANDLER_FINISHED; 2610 } 2611 2612 /* a note about no handler is not sent yet */ 2613 extension->note_is_sent = 0; 2614 2615 /* 2616 * if check-local is disabled, use the uri.path handler 2617 * 2618 */ 2619 2620 /* init handler-context */ 2621 if (uri_path_handler) { 2622 if (host->check_local) 2623 return HANDLER_GO_ON; 2624 2625 /* path info rewrite is done only for /prefix/? matches */ 2626 /* do not split path info for authorizer */ 2627 if (extension->key.ptr[0] == '/' && gw_mode != GW_AUTHORIZER) { 2628 /* the prefix is the SCRIPT_NAME, 2629 * everything from start to the next slash 2630 * this is important for check-local = "disable" 2631 * 2632 * if prefix = /admin.gw 2633 * 2634 * /admin.gw/foo/bar 2635 * 2636 * SCRIPT_NAME = /admin.gw 2637 * PATH_INFO = /foo/bar 2638 * 2639 * if prefix = /cgi-bin/ 2640 * 2641 * /cgi-bin/foo/bar 2642 * 2643 * SCRIPT_NAME = /cgi-bin/foo 2644 * PATH_INFO = /bar 2645 * 2646 * if prefix = /, and fix-root-path-name is enable 2647 * 2648 * /cgi-bin/foo/bar 2649 * 2650 * SCRIPT_NAME = /cgi-bin/foo 2651 * PATH_INFO = /bar 2652 * 2653 */ 2654 /* (s_len is buffer_clen(&r->uri.path) if (uri_path_handler) */ 2655 uint32_t elen = buffer_clen(&extension->key); 2656 const char *pathinfo; 2657 if (1 == elen && host->fix_root_path_name) { 2658 buffer_copy_buffer(&r->pathinfo, &r->uri.path); 2659 buffer_truncate(&r->uri.path, 0); 2660 } 2661 else if (s_len > elen 2662 && (pathinfo = strchr(r->uri.path.ptr+elen, '/'))) { 2663 /* rewrite uri.path and pathinfo */ 2664 const uint32_t plen = r->uri.path.ptr + s_len - pathinfo; 2665 buffer_copy_string_len(&r->pathinfo, pathinfo, plen); 2666 buffer_truncate(&r->uri.path, s_len - plen); 2667 } 2668 } 2669 } 2670 2671 if (!hctx) hctx = handler_ctx_init(hctx_sz); 2672 2673 hctx->ev = r->con->srv->ev; 2674 hctx->r = r; 2675 hctx->con = r->con; 2676 hctx->plugin_data = p; 2677 hctx->host = host; 2678 hctx->proc = NULL; 2679 hctx->ext = extension; 2680 gw_host_assign(host); 2681 2682 hctx->gw_mode = gw_mode; 2683 if (gw_mode == GW_AUTHORIZER) { 2684 hctx->ext_auth = hctx->ext; 2685 } 2686 2687 /*hctx->conf.exts = p->conf.exts;*/ 2688 /*hctx->conf.exts_auth = p->conf.exts_auth;*/ 2689 /*hctx->conf.exts_resp = p->conf.exts_resp;*/ 2690 /*hctx->conf.ext_mapping = p->conf.ext_mapping;*/ 2691 hctx->conf.balance = p->conf.balance; 2692 hctx->conf.proto = p->conf.proto; 2693 hctx->conf.debug = p->conf.debug; 2694 2695 hctx->opts.max_per_read = 2696 !(r->conf.stream_response_body /*(if not streaming response body)*/ 2697 & (FDEVENT_STREAM_RESPONSE|FDEVENT_STREAM_RESPONSE_BUFMIN)) 2698 ? 262144 2699 : (r->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN) 2700 ? 16384 /* FDEVENT_STREAM_RESPONSE_BUFMIN */ 2701 : 65536; /* FDEVENT_STREAM_RESPONSE */ 2702 hctx->opts.fdfmt = S_IFSOCK; 2703 hctx->opts.authorizer = (gw_mode == GW_AUTHORIZER); 2704 hctx->opts.local_redir = 0; 2705 hctx->opts.xsendfile_allow = host->xsendfile_allow; 2706 hctx->opts.xsendfile_docroot = host->xsendfile_docroot; 2707 2708 r->plugin_ctx[p->id] = hctx; 2709 2710 r->handler_module = p->self; 2711 2712 if (r->conf.log_request_handling) { 2713 log_error(r->conf.errh, __FILE__, __LINE__, 2714 "handling the request using %s", p->self->name); 2715 } 2716 2717 return HANDLER_GO_ON; 2718 } 2719 2720 __attribute_cold__ 2721 __attribute_noinline__ 2722 static void gw_handle_trigger_hctx_timeout(gw_handler_ctx * const hctx, const char * const msg) { 2723 2724 request_st * const r = hctx->r; 2725 joblist_append(r->con); 2726 2727 if (*msg == 'c') { /* "connect" */ 2728 /* temporarily disable backend proc */ 2729 gw_proc_connect_error(r, hctx->host, hctx->proc, hctx->pid, 2730 ETIMEDOUT, hctx->conf.debug); 2731 /* cleanup this request and let request handler start request again */ 2732 /* retry only once since request already waited write_timeout secs */ 2733 if (hctx->reconnects++ < 1) { 2734 gw_reconnect(hctx, r); 2735 return; 2736 } 2737 r->http_status = 503; /* Service Unavailable */ 2738 } 2739 else { /* "read" or "write" */ 2740 /* blocked waiting to send (more) data to or to receive response 2741 * (neither are a definite indication that the proc is no longer 2742 * responsive on other socket connections; not marking proc overloaded) 2743 * (If connect() to backend succeeded, then we began sending 2744 * request and filled kernel socket buffers, so request is 2745 * in progress and it is not safe or possible to retry) */ 2746 /*if (hctx->conf.debug)*/ 2747 log_error(r->conf.errh, __FILE__, __LINE__, 2748 "%s timeout on socket: %s (fd: %d)", 2749 msg, hctx->proc->connection_name->ptr, hctx->fd); 2750 2751 if (*msg == 'w') { /* "write" */ 2752 gw_write_error(hctx, r); /*(calls gw_backend_error())*/ 2753 if (r->http_status == 503) r->http_status = 504; /*Gateway Timeout*/ 2754 return; 2755 } /* else "read" */ 2756 } 2757 gw_backend_error(hctx, r); 2758 if (r->http_status == 500 && !r->resp_body_started && !r->handler_module) 2759 r->http_status = 504; /*Gateway Timeout*/ 2760 } 2761 2762 __attribute_noinline__ 2763 static void gw_handle_trigger_host_timeouts(gw_host * const host) { 2764 2765 if (NULL == host->hctxs) return; 2766 const unix_time64_t rsecs = (unix_time64_t)host->read_timeout; 2767 const unix_time64_t wsecs = (unix_time64_t)host->write_timeout; 2768 const unix_time64_t csecs = (unix_time64_t)host->connect_timeout; 2769 if (!rsecs && !wsecs && !csecs) 2770 return; /*(no timeout policy (default))*/ 2771 2772 const unix_time64_t mono = log_monotonic_secs; /*(could have callers pass)*/ 2773 for (gw_handler_ctx *hctx = host->hctxs, *next; hctx; hctx = next) { 2774 /* if timeout occurs, hctx might be invalidated and removed from list, 2775 * so next element must be store before checking for timeout */ 2776 next = hctx->next; 2777 2778 if (hctx->state == GW_STATE_CONNECT_DELAYED) { 2779 if (mono - hctx->write_ts > csecs && csecs) /*(waiting for write)*/ 2780 gw_handle_trigger_hctx_timeout(hctx, "connect"); 2781 continue; /*(do not apply wsecs below to GW_STATE_CONNECT_DELAYED)*/ 2782 } 2783 2784 const int events = fdevent_fdnode_interest(hctx->fdn); 2785 if ((events & FDEVENT_IN) && mono - hctx->read_ts > rsecs && rsecs) { 2786 gw_handle_trigger_hctx_timeout(hctx, "read"); 2787 continue; 2788 } 2789 if ((events & FDEVENT_OUT) && mono - hctx->write_ts > wsecs && wsecs) { 2790 gw_handle_trigger_hctx_timeout(hctx, "write"); 2791 continue; 2792 } 2793 } 2794 } 2795 2796 static void gw_handle_trigger_host(gw_host * const host, log_error_st * const errh, const int debug) { 2797 2798 /* check for socket timeouts on active requests to backend host */ 2799 gw_handle_trigger_host_timeouts(host); 2800 2801 /* check each child proc to detect if proc exited */ 2802 2803 gw_proc *proc; 2804 unix_time64_t idle_timestamp; 2805 int overload = 1; 2806 2807 #if 0 /* redundant w/ handle_waitpid hook since lighttpd 1.4.46 */ 2808 for (proc = host->first; proc; proc = proc->next) { 2809 gw_proc_waitpid(host, proc, errh); 2810 } 2811 #endif 2812 2813 gw_restart_dead_procs(host, errh, debug, 1); 2814 2815 /* check if adaptive spawning enabled */ 2816 if (host->min_procs == host->max_procs) return; 2817 if (!host->bin_path) return; 2818 2819 for (proc = host->first; proc; proc = proc->next) { 2820 if (proc->load <= host->max_load_per_proc) { 2821 overload = 0; 2822 break; 2823 } 2824 } 2825 2826 if (overload && host->num_procs && host->num_procs < host->max_procs) { 2827 /* overload, spawn new child */ 2828 if (debug) { 2829 log_error(errh, __FILE__, __LINE__, 2830 "overload detected, spawning a new child"); 2831 } 2832 2833 gw_proc_spawn(host, errh, debug); 2834 } 2835 2836 idle_timestamp = log_monotonic_secs - host->idle_timeout; 2837 for (proc = host->first; proc; proc = proc->next) { 2838 if (host->num_procs <= host->min_procs) break; 2839 if (0 != proc->load) continue; 2840 if (proc->pid <= 0) continue; 2841 if (proc->last_used >= idle_timestamp) continue; 2842 2843 /* terminate proc that has been idling for a long time */ 2844 if (debug) { 2845 log_error(errh, __FILE__, __LINE__, 2846 "idle-timeout reached, terminating child: socket: %s pid %d", 2847 proc->unixsocket ? proc->unixsocket->ptr : "", proc->pid); 2848 } 2849 2850 gw_proc_kill(host, proc); 2851 2852 /* proc is now in unused, let next second handle next process */ 2853 break; 2854 } 2855 2856 #if 0 /* redundant w/ handle_waitpid hook since lighttpd 1.4.46 */ 2857 for (proc = host->unused_procs; proc; proc = proc->next) { 2858 gw_proc_waitpid(host, proc, errh); 2859 } 2860 #endif 2861 } 2862 2863 static void gw_handle_trigger_exts(gw_exts * const exts, log_error_st * const errh, const int debug) { 2864 for (uint32_t j = 0; j < exts->used; ++j) { 2865 gw_extension *ex = exts->exts+j; 2866 for (uint32_t n = 0; n < ex->used; ++n) { 2867 gw_handle_trigger_host(ex->hosts[n], errh, debug); 2868 } 2869 } 2870 } 2871 2872 static void gw_handle_trigger_exts_wkr(gw_exts *exts, log_error_st *errh) { 2873 for (uint32_t j = 0; j < exts->used; ++j) { 2874 gw_extension * const ex = exts->exts+j; 2875 for (uint32_t n = 0; n < ex->used; ++n) { 2876 gw_host * const host = ex->hosts[n]; 2877 gw_handle_trigger_host_timeouts(host); 2878 for (gw_proc *proc = host->first; proc; proc = proc->next) { 2879 if (proc->state == PROC_STATE_OVERLOADED) 2880 gw_proc_check_enable(host, proc, errh); 2881 } 2882 } 2883 } 2884 } 2885 2886 handler_t gw_handle_trigger(server *srv, void *p_d) { 2887 gw_plugin_data * const p = p_d; 2888 int wkr = (0 != srv->srvconf.max_worker && p->srv_pid != srv->pid); 2889 log_error_st * const errh = srv->errh; 2890 int global_debug = 0; 2891 2892 if (NULL == p->cvlist) return HANDLER_GO_ON; 2893 /* (init i to 0 if global context; to 1 to skip empty global context) */ 2894 for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) { 2895 config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0]; 2896 gw_plugin_config *conf = NULL; 2897 int debug = global_debug; 2898 for (; -1 != cpv->k_id; ++cpv) { 2899 switch (cpv->k_id) { 2900 case 0: /* xxxxx.server */ 2901 if (cpv->vtype == T_CONFIG_LOCAL) conf = cpv->v.v; 2902 break; 2903 case 2: /* xxxxx.debug */ 2904 debug = (int)cpv->v.u; 2905 if (0 == i) global_debug = (int)cpv->v.u; 2906 default: 2907 break; 2908 } 2909 } 2910 2911 if (NULL == conf || NULL == conf->exts) continue; 2912 2913 /* (debug flag is only active if set in same scope as xxxxx.server 2914 * or global scope (for convenience)) 2915 * (unable to use p->defaults.debug since gw_plugin_config 2916 * might be part of a larger plugin_config) */ 2917 wkr 2918 ? gw_handle_trigger_exts_wkr(conf->exts, errh) 2919 : gw_handle_trigger_exts(conf->exts, errh, debug); 2920 } 2921 2922 return HANDLER_GO_ON; 2923 } 2924 2925 handler_t gw_handle_waitpid_cb(server *srv, void *p_d, pid_t pid, int status) { 2926 gw_plugin_data * const p = p_d; 2927 if (0 != srv->srvconf.max_worker && p->srv_pid != srv->pid) 2928 return HANDLER_GO_ON; 2929 log_error_st * const errh = srv->errh; 2930 int global_debug = 0; 2931 2932 if (NULL == p->cvlist) return HANDLER_GO_ON; 2933 /* (init i to 0 if global context; to 1 to skip empty global context) */ 2934 for (int i = !p->cvlist[0].v.u2[1], used = p->nconfig; i < used; ++i) { 2935 config_plugin_value_t *cpv = p->cvlist + p->cvlist[i].v.u2[0]; 2936 gw_plugin_config *conf = NULL; 2937 int debug = global_debug; 2938 for (; -1 != cpv->k_id; ++cpv) { 2939 switch (cpv->k_id) { 2940 case 0: /* xxxxx.server */ 2941 if (cpv->vtype == T_CONFIG_LOCAL) conf = cpv->v.v; 2942 break; 2943 case 2: /* xxxxx.debug */ 2944 debug = (int)cpv->v.u; 2945 if (0 == i) global_debug = (int)cpv->v.u; 2946 default: 2947 break; 2948 } 2949 } 2950 2951 if (NULL == conf || NULL == conf->exts) continue; 2952 2953 /* (debug flag is only active if set in same scope as xxxxx.server 2954 * or global scope (for convenience)) 2955 * (unable to use p->defaults.debug since gw_plugin_config 2956 * might be part of a larger plugin_config) */ 2957 const unix_time64_t cur_ts = log_monotonic_secs; 2958 gw_exts *exts = conf->exts; 2959 for (uint32_t j = 0; j < exts->used; ++j) { 2960 gw_extension *ex = exts->exts+j; 2961 for (uint32_t n = 0; n < ex->used; ++n) { 2962 gw_host *host = ex->hosts[n]; 2963 gw_proc *proc; 2964 for (proc = host->first; proc; proc = proc->next) { 2965 if (!proc->is_local || proc->pid != pid) continue; 2966 2967 gw_proc_waitpid_log(host, proc, errh, status); 2968 gw_proc_set_state(host, proc, PROC_STATE_DIED); 2969 proc->pid = 0; 2970 2971 /* restart, but avoid spinning if child exits too quickly */ 2972 if (proc->disabled_until < cur_ts) { 2973 /*(set state PROC_STATE_DIED above, so != KILLED here)*/ 2974 /*(PROC_STATE_KILLED belongs in unused_procs, anyway)*/ 2975 if (proc->state != PROC_STATE_KILLED) 2976 proc->disabled_until = cur_ts; 2977 if (gw_spawn_connection(host, proc, errh, debug)) { 2978 log_error(errh, __FILE__, __LINE__, 2979 "ERROR: spawning gw failed."); 2980 } 2981 } 2982 2983 return HANDLER_FINISHED; 2984 } 2985 for (proc = host->unused_procs; proc; proc = proc->next) { 2986 if (!proc->is_local || proc->pid != pid) continue; 2987 2988 gw_proc_waitpid_log(host, proc, errh, status); 2989 if (proc->state != PROC_STATE_KILLED) 2990 proc->disabled_until = cur_ts; 2991 gw_proc_set_state(host, proc, PROC_STATE_DIED); 2992 proc->pid = 0; 2993 return HANDLER_FINISHED; 2994 } 2995 } 2996 } 2997 } 2998 2999 return HANDLER_GO_ON; 3000 } 3001