Diff for /embedaddon/lighttpd/src/mod_fastcgi.c between versions 1.1.1.2 and 1.1.1.3

version 1.1.1.2, 2014/06/15 20:20:06 version 1.1.1.3, 2016/11/02 10:35:00
Line 1 Line 1
   #include "first.h"
   
 #include "buffer.h"  #include "buffer.h"
 #include "server.h"  #include "server.h"
 #include "keyvalue.h"  #include "keyvalue.h"
Line 37 Line 39
   
 #include <stdio.h>  #include <stdio.h>
   
 #ifdef HAVE_SYS_FILIO_H  
 # include <sys/filio.h>  
 #endif  
   
 #include "sys-socket.h"  #include "sys-socket.h"
   
 #ifdef HAVE_SYS_UIO_H  #ifdef HAVE_SYS_UIO_H
Line 50 Line 48
 #include <sys/wait.h>  #include <sys/wait.h>
 #endif  #endif
   
 #include "version.h"  
   
 #define FCGI_ENV_ADD_CHECK(ret, con) \  
         if (ret == -1) { \  
                 con->http_status = 400; \  
                 con->file_finished = 1; \  
                 return -1; \  
         };  
   
 /*  /*
  *   *
  * TODO:   * TODO:
Line 157  typedef struct { Line 146  typedef struct {
          */           */
         buffer *host;          buffer *host;
         unsigned short port;          unsigned short port;
           sa_family_t family;
   
         /*          /*
          * Unix Domain Socket           * Unix Domain Socket
Line 235  typedef struct { Line 225  typedef struct {
         unsigned short fix_root_path_name;          unsigned short fix_root_path_name;
   
         /*          /*
         * If the backend includes X-LIGHTTPD-send-file in the response         * If the backend includes X-Sendfile in the response
          * we use the value as filename and ignore the content.           * we use the value as filename and ignore the content.
          *           *
          */           */
        unsigned short allow_xsendfile;        unsigned short xsendfile_allow;
         array *xsendfile_docroot;
   
         ssize_t load; /* replace by host->load */          ssize_t load; /* replace by host->load */
   
Line 255  typedef struct { Line 246  typedef struct {
                                        applications prefer SIGUSR1 while the                                         applications prefer SIGUSR1 while the
                                        rest of the world would use SIGTERM                                         rest of the world would use SIGTERM
                                        *sigh* */                                         *sigh* */
   
           int listen_backlog;
           int refcount;
 } fcgi_extension_host;  } fcgi_extension_host;
   
 /*  /*
Line 318  typedef struct { Line 312  typedef struct {
         buffer *fcgi_env;          buffer *fcgi_env;
   
         buffer *path;          buffer *path;
         buffer *parse_response;  
   
         buffer *statuskey;          buffer *statuskey;
   
Line 329  typedef struct { Line 322  typedef struct {
   
 /* connection specific data */  /* connection specific data */
 typedef enum {  typedef enum {
         FCGI_STATE_UNSET,  
         FCGI_STATE_INIT,          FCGI_STATE_INIT,
         FCGI_STATE_CONNECT_DELAYED,          FCGI_STATE_CONNECT_DELAYED,
         FCGI_STATE_PREPARE_WRITE,          FCGI_STATE_PREPARE_WRITE,
Line 345  typedef struct { Line 337  typedef struct {
         fcgi_connection_state_t state;          fcgi_connection_state_t state;
         time_t   state_timestamp;          time_t   state_timestamp;
   
         int      reconnects; /* number of reconnect attempts */  
   
         chunkqueue *rb; /* read queue */          chunkqueue *rb; /* read queue */
         chunkqueue *wb; /* write queue */          chunkqueue *wb; /* write queue */
           off_t     wb_reqlen;
   
         buffer   *response_header;          buffer   *response_header;
   
         size_t    request_id;  
         int       fd;        /* fd to the fastcgi process */          int       fd;        /* fd to the fastcgi process */
         int       fde_ndx;   /* index into the fd-event buffer */          int       fde_ndx;   /* index into the fd-event buffer */
   
         pid_t     pid;          pid_t     pid;
         int       got_proc;          int       got_proc;
           int       reconnects; /* number of reconnect attempts */
   
           int       request_id;
         int       send_content_body;          int       send_content_body;
   
         plugin_config conf;          plugin_config conf;
Line 391  static void fastcgi_status_copy_procname(buffer *b, fc Line 383  static void fastcgi_status_copy_procname(buffer *b, fc
         buffer_append_string_buffer(b, host->id);          buffer_append_string_buffer(b, host->id);
         if (proc) {          if (proc) {
                 buffer_append_string_len(b, CONST_STR_LEN("."));                  buffer_append_string_len(b, CONST_STR_LEN("."));
                buffer_append_long(b, proc->id);                buffer_append_int(b, proc->id);
         }          }
 }  }
   
Line 504  static handler_ctx * handler_ctx_init(void) { Line 496  static handler_ctx * handler_ctx_init(void) {
   
         hctx->rb = chunkqueue_init();          hctx->rb = chunkqueue_init();
         hctx->wb = chunkqueue_init();          hctx->wb = chunkqueue_init();
           hctx->wb_reqlen = 0;
   
         return hctx;          return hctx;
 }  }
Line 558  static fcgi_extension_host *fastcgi_host_init(void) { Line 551  static fcgi_extension_host *fastcgi_host_init(void) {
         f->bin_env = array_init();          f->bin_env = array_init();
         f->bin_env_copy = array_init();          f->bin_env_copy = array_init();
         f->strip_request_uri = buffer_init();          f->strip_request_uri = buffer_init();
           f->xsendfile_docroot = array_init();
   
         return f;          return f;
 }  }
   
 static void fastcgi_host_free(fcgi_extension_host *h) {  static void fastcgi_host_free(fcgi_extension_host *h) {
         if (!h) return;          if (!h) return;
           if (h->refcount) {
                   --h->refcount;
                   return;
           }
   
         buffer_free(h->id);          buffer_free(h->id);
         buffer_free(h->host);          buffer_free(h->host);
Line 573  static void fastcgi_host_free(fcgi_extension_host *h)  Line 571  static void fastcgi_host_free(fcgi_extension_host *h) 
         buffer_free(h->strip_request_uri);          buffer_free(h->strip_request_uri);
         array_free(h->bin_env);          array_free(h->bin_env);
         array_free(h->bin_env_copy);          array_free(h->bin_env_copy);
           array_free(h->xsendfile_docroot);
   
         fastcgi_process_free(h->first);          fastcgi_process_free(h->first);
         fastcgi_process_free(h->unused_procs);          fastcgi_process_free(h->unused_procs);
Line 637  static int fastcgi_extension_insert(fcgi_exts *ext, bu Line 636  static int fastcgi_extension_insert(fcgi_exts *ext, bu
                 force_assert(fe);                  force_assert(fe);
                 fe->key = buffer_init();                  fe->key = buffer_init();
                 fe->last_used_ndx = -1;                  fe->last_used_ndx = -1;
                buffer_copy_string_buffer(fe->key, key);                buffer_copy_buffer(fe->key, key);
   
                 /* */                  /* */
   
Line 679  INIT_FUNC(mod_fastcgi_init) { Line 678  INIT_FUNC(mod_fastcgi_init) {
         p->fcgi_env = buffer_init();          p->fcgi_env = buffer_init();
   
         p->path = buffer_init();          p->path = buffer_init();
         p->parse_response = buffer_init();  
   
         p->statuskey = buffer_init();          p->statuskey = buffer_init();
   
Line 694  FREE_FUNC(mod_fastcgi_free) { Line 692  FREE_FUNC(mod_fastcgi_free) {
   
         buffer_free(p->fcgi_env);          buffer_free(p->fcgi_env);
         buffer_free(p->path);          buffer_free(p->path);
         buffer_free(p->parse_response);  
         buffer_free(p->statuskey);          buffer_free(p->statuskey);
   
         if (p->config_storage) {          if (p->config_storage) {
Line 703  FREE_FUNC(mod_fastcgi_free) { Line 700  FREE_FUNC(mod_fastcgi_free) {
                         plugin_config *s = p->config_storage[i];                          plugin_config *s = p->config_storage[i];
                         fcgi_exts *exts;                          fcgi_exts *exts;
   
                        if (!s) continue;                        if (NULL == s) continue;
   
                         exts = s->exts;                          exts = s->exts;
   
Line 724  FREE_FUNC(mod_fastcgi_free) { Line 721  FREE_FUNC(mod_fastcgi_free) {
                                                 }                                                  }
   
                                                 if (proc->is_local &&                                                  if (proc->is_local &&
                                                    !buffer_is_empty(proc->unixsocket)) {                                                    !buffer_string_is_empty(proc->unixsocket)) {
                                                         unlink(proc->unixsocket->ptr);                                                          unlink(proc->unixsocket->ptr);
                                                 }                                                  }
                                         }                                          }
Line 734  FREE_FUNC(mod_fastcgi_free) { Line 731  FREE_FUNC(mod_fastcgi_free) {
                                                         kill(proc->pid, host->kill_signal);                                                          kill(proc->pid, host->kill_signal);
                                                 }                                                  }
                                                 if (proc->is_local &&                                                  if (proc->is_local &&
                                                    !buffer_is_empty(proc->unixsocket)) {                                                    !buffer_string_is_empty(proc->unixsocket)) {
                                                         unlink(proc->unixsocket->ptr);                                                          unlink(proc->unixsocket->ptr);
                                                 }                                                  }
                                         }                                          }
Line 794  static int parse_binpath(char_array *env, buffer *b) { Line 791  static int parse_binpath(char_array *env, buffer *b) {
         /* search for spaces */          /* search for spaces */
   
         start = b->ptr;          start = b->ptr;
        for (i = 0; i < b->used - 1; i++) {        for (i = 0; i < buffer_string_length(b); i++) {
                 switch(b->ptr[i]) {                  switch(b->ptr[i]) {
                 case ' ':                  case ' ':
                 case '\t':                  case '\t':
Line 844  static int parse_binpath(char_array *env, buffer *b) { Line 841  static int parse_binpath(char_array *env, buffer *b) {
         return 0;          return 0;
 }  }
   
   #if !defined(HAVE_FORK)
 static int fcgi_spawn_connection(server *srv,  static int fcgi_spawn_connection(server *srv,
                                 plugin_data *p,                                 plugin_data *p,
                                 fcgi_extension_host *host,                                 fcgi_extension_host *host,
                                 fcgi_proc *proc) {                                 fcgi_proc *proc) {
         UNUSED(srv);
         UNUSED(p);
         UNUSED(host);
         UNUSED(proc);
         return -1;
 }
 
 #else /* -> defined(HAVE_FORK) */
 
 static int fcgi_spawn_connection(server *srv,
                                  plugin_data *p,
                                  fcgi_extension_host *host,
                                  fcgi_proc *proc) {
         int fcgi_fd;          int fcgi_fd;
        int socket_type, status;        int status;
         struct timeval tv = { 0, 100 * 1000 };          struct timeval tv = { 0, 100 * 1000 };
 #ifdef HAVE_SYS_UN_H  #ifdef HAVE_SYS_UN_H
         struct sockaddr_un fcgi_addr_un;          struct sockaddr_un fcgi_addr_un;
 #endif  #endif
   #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
           struct sockaddr_in6 fcgi_addr_in6;
   #endif
         struct sockaddr_in fcgi_addr_in;          struct sockaddr_in fcgi_addr_in;
         struct sockaddr *fcgi_addr;          struct sockaddr *fcgi_addr;
   
         socklen_t servlen;          socklen_t servlen;
   
 #ifndef HAVE_FORK  
         return -1;  
 #endif  
   
         if (p->conf.debug) {          if (p->conf.debug) {
                 log_error_write(srv, __FILE__, __LINE__, "sdb",                  log_error_write(srv, __FILE__, __LINE__, "sdb",
                                 "new proc, socket:", proc->port, proc->unixsocket);                                  "new proc, socket:", proc->port, proc->unixsocket);
         }          }
   
        if (!buffer_is_empty(proc->unixsocket)) {        if (!buffer_string_is_empty(proc->unixsocket)) {
                memset(&fcgi_addr, 0, sizeof(fcgi_addr)); 
 
 #ifdef HAVE_SYS_UN_H  #ifdef HAVE_SYS_UN_H
                   memset(&fcgi_addr_un, 0, sizeof(fcgi_addr_un));
                 fcgi_addr_un.sun_family = AF_UNIX;                  fcgi_addr_un.sun_family = AF_UNIX;
                if (proc->unixsocket->used > sizeof(fcgi_addr_un.sun_path)) {                if (buffer_string_length(proc->unixsocket) + 1 > sizeof(fcgi_addr_un.sun_path)) {
                         log_error_write(srv, __FILE__, __LINE__, "sB",                          log_error_write(srv, __FILE__, __LINE__, "sB",
                                         "ERROR: Unix Domain socket filename too long:",                                          "ERROR: Unix Domain socket filename too long:",
                                         proc->unixsocket);                                          proc->unixsocket);
                         return -1;                          return -1;
                 }                  }
                memcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr, proc->unixsocket->used);                memcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr, buffer_string_length(proc->unixsocket) + 1);
   
 #ifdef SUN_LEN  #ifdef SUN_LEN
                 servlen = SUN_LEN(&fcgi_addr_un);                  servlen = SUN_LEN(&fcgi_addr_un);
 #else  #else
                 /* stevens says: */                  /* stevens says: */
                servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);                servlen = buffer_string_length(proc->unixsocket) + 1 + sizeof(fcgi_addr_un.sun_family);
 #endif  #endif
                 socket_type = AF_UNIX;  
                 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;                  fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
   
                 buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("unix:"));                  buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("unix:"));
Line 898  static int fcgi_spawn_connection(server *srv, Line 906  static int fcgi_spawn_connection(server *srv,
                                 "ERROR: Unix Domain sockets are not supported.");                                  "ERROR: Unix Domain sockets are not supported.");
                 return -1;                  return -1;
 #endif  #endif
   #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
           } else if (host->family == AF_INET6 && !buffer_string_is_empty(host->host)) {
                   memset(&fcgi_addr_in6, 0, sizeof(fcgi_addr_in6));
                   fcgi_addr_in6.sin6_family = AF_INET6;
                   inet_pton(AF_INET6, host->host->ptr, (char *) &fcgi_addr_in6.sin6_addr);
                   fcgi_addr_in6.sin6_port = htons(proc->port);
                   servlen = sizeof(fcgi_addr_in6);
                   fcgi_addr = (struct sockaddr *) &fcgi_addr_in6;
   #endif
         } else {          } else {
                   memset(&fcgi_addr_in, 0, sizeof(fcgi_addr_in));
                 fcgi_addr_in.sin_family = AF_INET;                  fcgi_addr_in.sin_family = AF_INET;
   
                if (buffer_is_empty(host->host)) {                if (buffer_string_is_empty(host->host)) {
                         fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);                          fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
                 } else {                  } else {
                         struct hostent *he;                          struct hostent *he;
Line 933  static int fcgi_spawn_connection(server *srv, Line 951  static int fcgi_spawn_connection(server *srv,
                 fcgi_addr_in.sin_port = htons(proc->port);                  fcgi_addr_in.sin_port = htons(proc->port);
                 servlen = sizeof(fcgi_addr_in);                  servlen = sizeof(fcgi_addr_in);
   
                 socket_type = AF_INET;  
                 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;                  fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
           }
   
           if (buffer_string_is_empty(proc->unixsocket)) {
                 buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("tcp:"));                  buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("tcp:"));
                if (!buffer_is_empty(host->host)) {                if (!buffer_string_is_empty(host->host)) {
                         buffer_append_string_buffer(proc->connection_name, host->host);                          buffer_append_string_buffer(proc->connection_name, host->host);
                 } else {                  } else {
                         buffer_append_string_len(proc->connection_name, CONST_STR_LEN("localhost"));                          buffer_append_string_len(proc->connection_name, CONST_STR_LEN("localhost"));
                 }                  }
                 buffer_append_string_len(proc->connection_name, CONST_STR_LEN(":"));                  buffer_append_string_len(proc->connection_name, CONST_STR_LEN(":"));
                buffer_append_long(proc->connection_name, proc->port);                buffer_append_int(proc->connection_name, proc->port);
         }          }
   
        if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {        if (-1 == (fcgi_fd = socket(fcgi_addr->sa_family, SOCK_STREAM, 0))) {
                 log_error_write(srv, __FILE__, __LINE__, "ss",                  log_error_write(srv, __FILE__, __LINE__, "ss",
                                 "failed:", strerror(errno));                                  "failed:", strerror(errno));
                 return -1;                  return -1;
Line 958  static int fcgi_spawn_connection(server *srv, Line 977  static int fcgi_spawn_connection(server *srv,
                 int val;                  int val;
   
                 if (errno != ENOENT &&                  if (errno != ENOENT &&
                    !buffer_is_empty(proc->unixsocket)) {                    !buffer_string_is_empty(proc->unixsocket)) {
                         unlink(proc->unixsocket->ptr);                          unlink(proc->unixsocket->ptr);
                 }                  }
   
                 close(fcgi_fd);                  close(fcgi_fd);
   
                 /* reopen socket */                  /* reopen socket */
                if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {                if (-1 == (fcgi_fd = socket(fcgi_addr->sa_family, SOCK_STREAM, 0))) {
                         log_error_write(srv, __FILE__, __LINE__, "ss",                          log_error_write(srv, __FILE__, __LINE__, "ss",
                                 "socket failed:", strerror(errno));                                  "socket failed:", strerror(errno));
                         return -1;                          return -1;
Line 989  static int fcgi_spawn_connection(server *srv, Line 1008  static int fcgi_spawn_connection(server *srv,
                         return -1;                          return -1;
                 }                  }
   
                if (-1 == listen(fcgi_fd, 1024)) {                if (-1 == listen(fcgi_fd, host->listen_backlog)) {
                         log_error_write(srv, __FILE__, __LINE__, "ss",                          log_error_write(srv, __FILE__, __LINE__, "ss",
                                 "listen failed:", strerror(errno));                                  "listen failed:", strerror(errno));
                         close(fcgi_fd);                          close(fcgi_fd);
                         return -1;                          return -1;
                 }                  }
   
 #ifdef HAVE_FORK  
                 switch ((child = fork())) {                  switch ((child = fork())) {
                 case 0: {                  case 0: {
                         size_t i = 0;                          size_t i = 0;
Line 1035  static int fcgi_spawn_connection(server *srv, Line 1053  static int fcgi_spawn_connection(server *srv,
                                         }                                          }
                                 }                                  }
                         } else {                          } else {
                                for (i = 0; environ[i]; i++) {                                char ** const e = environ;
                                 for (i = 0; e[i]; ++i) {
                                         char *eq;                                          char *eq;
   
                                        if (NULL != (eq = strchr(environ[i], '='))) {                                        if (NULL != (eq = strchr(e[i], '='))) {
                                                env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));                                                env_add(&env, e[i], eq - e[i], eq+1, strlen(eq+1));
                                         }                                          }
                                 }                                  }
                         }                          }
Line 1086  static int fcgi_spawn_connection(server *srv, Line 1105  static int fcgi_spawn_connection(server *srv,
                         /* log_error_write(srv, __FILE__, __LINE__, "sbs",                          /* log_error_write(srv, __FILE__, __LINE__, "sbs",
                                         "execve failed for:", host->bin_path, strerror(errno)); */                                          "execve failed for:", host->bin_path, strerror(errno)); */
   
                        exit(errno);                        _exit(errno);
   
                         break;                          break;
                 }                  }
                 case -1:                  case -1:
                         /* error */                          /* error */
                           close(fcgi_fd);
                         break;                          break;
                 default:                  default:
                         /* father */                          /* father */
                           close(fcgi_fd);
   
                         /* wait */                          /* wait */
                         select(0, NULL, NULL, NULL, &tv);                          select(0, NULL, NULL, NULL, &tv);
Line 1144  static int fcgi_spawn_connection(server *srv, Line 1165  static int fcgi_spawn_connection(server *srv,
   
                         break;                          break;
                 }                  }
 #endif  
         } else {          } else {
                   close(fcgi_fd);
                 proc->is_local = 0;                  proc->is_local = 0;
                 proc->pid = 0;                  proc->pid = 0;
   
Line 1159  static int fcgi_spawn_connection(server *srv, Line 1180  static int fcgi_spawn_connection(server *srv,
         proc->state = PROC_STATE_RUNNING;          proc->state = PROC_STATE_RUNNING;
         host->active_procs++;          host->active_procs++;
   
         close(fcgi_fd);  
   
         return 0;          return 0;
 }  }
   
   #endif /* HAVE_FORK */
   
   static fcgi_extension_host * unixsocket_is_dup(plugin_data *p, size_t used, buffer *unixsocket) {
           size_t i, j, n;
           for (i = 0; i < used; ++i) {
                   fcgi_exts *exts = p->config_storage[i]->exts;
                   for (j = 0; j < exts->used; ++j) {
                           fcgi_extension *ex = exts->exts[j];
                           for (n = 0; n < ex->used; ++n) {
                                   fcgi_extension_host *host = ex->hosts[n];
                                   if (!buffer_string_is_empty(host->unixsocket)
                                       && buffer_is_equal(host->unixsocket, unixsocket)
                                       && !buffer_string_is_empty(host->bin_path))
                                           return host;
                           }
                   }
           }
   
           return NULL;
   }
   
 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
         plugin_data *p = p_d;          plugin_data *p = p_d;
         data_unset *du;          data_unset *du;
Line 1182  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { Line 1221  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
         p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));          p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
   
         for (i = 0; i < srv->config_context->used; i++) {          for (i = 0; i < srv->config_context->used; i++) {
                   data_config const* config = (data_config const*)srv->config_context->data[i];
                 plugin_config *s;                  plugin_config *s;
                 array *ca;  
   
                 s = malloc(sizeof(plugin_config));                  s = malloc(sizeof(plugin_config));
                 s->exts          = fastcgi_extensions_init();                  s->exts          = fastcgi_extensions_init();
Line 1195  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { Line 1234  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
                 cv[2].destination = s->ext_mapping;                  cv[2].destination = s->ext_mapping;
   
                 p->config_storage[i] = s;                  p->config_storage[i] = s;
                 ca = ((data_config *)srv->config_context->data[i])->value;  
   
                if (0 != config_insert_values_global(srv, ca, cv)) {                if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
                         goto error;                          goto error;
                 }                  }
   
Line 1205  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { Line 1243  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
                  * <key> = ( ... )                   * <key> = ( ... )
                  */                   */
   
                if (NULL != (du = array_get_element(ca, "fastcgi.server"))) {                if (NULL != (du = array_get_element(config->value, "fastcgi.server"))) {
                         size_t j;                          size_t j;
                         data_array *da = (data_array *)du;                          data_array *da = (data_array *)du;
   
                         if (du->type != TYPE_ARRAY) {                          if (du->type != TYPE_ARRAY) {
                                 log_error_write(srv, __FILE__, __LINE__, "sss",                                  log_error_write(srv, __FILE__, __LINE__, "sss",
                                                "unexpected type for key: ", "fastcgi.server", "array of strings");                                                "unexpected type for key: ", "fastcgi.server", "expected ( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))");
   
                                 goto error;                                  goto error;
                         }                          }
Line 1229  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { Line 1267  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
                                 if (da->value->data[j]->type != TYPE_ARRAY) {                                  if (da->value->data[j]->type != TYPE_ARRAY) {
                                         log_error_write(srv, __FILE__, __LINE__, "sssbs",                                          log_error_write(srv, __FILE__, __LINE__, "sssbs",
                                                         "unexpected type for key: ", "fastcgi.server",                                                          "unexpected type for key: ", "fastcgi.server",
                                                        "[", da->value->data[j]->key, "](string)");                                                        "[", da->value->data[j]->key, "](string); expected ( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))");
   
                                         goto error;                                          goto error;
                                 }                                  }
Line 1269  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { Line 1307  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
                                                 { "strip-request-uri",  NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 13 */                                                  { "strip-request-uri",  NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 13 */
                                                 { "kill-signal",        NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 14 */                                                  { "kill-signal",        NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 14 */
                                                 { "fix-root-scriptname",   NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },  /* 15 */                                                  { "fix-root-scriptname",   NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },  /* 15 */
                                                   { "listen-backlog",    NULL, T_CONFIG_INT,   T_CONFIG_SCOPE_CONNECTION },        /* 16 */
                                                   { "x-sendfile",        NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 17 */
                                                   { "x-sendfile-docroot",NULL, T_CONFIG_ARRAY,  T_CONFIG_SCOPE_CONNECTION },      /* 18 */
   
                                                 { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }                                                  { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
                                         };                                          };
Line 1277  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { Line 1318  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
                                                 log_error_write(srv, __FILE__, __LINE__, "ssSBS",                                                  log_error_write(srv, __FILE__, __LINE__, "ssSBS",
                                                                 "unexpected type for key:",                                                                  "unexpected type for key:",
                                                                 "fastcgi.server",                                                                  "fastcgi.server",
                                                                "[", da_host->key, "](string)");                                                                "[", da_host->key, "](string); expected ( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))");
   
                                                 goto error;                                                  goto error;
                                         }                                          }
Line 1285  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { Line 1326  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
                                         host = fastcgi_host_init();                                          host = fastcgi_host_init();
                                         buffer_reset(fcgi_mode);                                          buffer_reset(fcgi_mode);
   
                                        buffer_copy_string_buffer(host->id, da_host->key);                                        buffer_copy_buffer(host->id, da_host->key);
   
                                         host->check_local  = 1;                                          host->check_local  = 1;
                                         host->max_procs    = 4;                                          host->max_procs    = 4;
                                         host->mode = FCGI_RESPONDER;                                          host->mode = FCGI_RESPONDER;
                                         host->disable_time = 1;                                          host->disable_time = 1;
                                         host->break_scriptfilename_for_php = 0;                                          host->break_scriptfilename_for_php = 0;
                                        host->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */                                        host->xsendfile_allow = 0;
                                         host->kill_signal = SIGTERM;                                          host->kill_signal = SIGTERM;
                                         host->fix_root_path_name = 0;                                          host->fix_root_path_name = 0;
                                           host->listen_backlog = 1024;
                                           host->refcount = 0;
   
                                         fcv[0].destination = host->host;                                          fcv[0].destination = host->host;
                                         fcv[1].destination = host->docroot;                                          fcv[1].destination = host->docroot;
Line 1310  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { Line 1353  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
                                         fcv[9].destination = host->bin_env;                                          fcv[9].destination = host->bin_env;
                                         fcv[10].destination = host->bin_env_copy;                                          fcv[10].destination = host->bin_env_copy;
                                         fcv[11].destination = &(host->break_scriptfilename_for_php);                                          fcv[11].destination = &(host->break_scriptfilename_for_php);
                                        fcv[12].destination = &(host->allow_xsendfile);                                        fcv[12].destination = &(host->xsendfile_allow);
                                         fcv[13].destination = host->strip_request_uri;                                          fcv[13].destination = host->strip_request_uri;
                                         fcv[14].destination = &(host->kill_signal);                                          fcv[14].destination = &(host->kill_signal);
                                         fcv[15].destination = &(host->fix_root_path_name);                                          fcv[15].destination = &(host->fix_root_path_name);
                                           fcv[16].destination = &(host->listen_backlog);
                                           fcv[17].destination = &(host->xsendfile_allow);
                                           fcv[18].destination = host->xsendfile_docroot;
   
                                        if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {                                        if (0 != config_insert_values_internal(srv, da_host->value, fcv, T_CONFIG_SCOPE_CONNECTION)) {
                                                 goto error;                                                  goto error;
                                         }                                          }
   
                                        if ((!buffer_is_empty(host->host) || host->port) &&                                        if ((!buffer_string_is_empty(host->host) || host->port) &&
                                            !buffer_is_empty(host->unixsocket)) {                                            !buffer_string_is_empty(host->unixsocket)) {
                                                 log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",                                                  log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
                                                                 "either host/port or socket have to be set in:",                                                                  "either host/port or socket have to be set in:",
                                                                 da->key, "= (",                                                                  da->key, "= (",
Line 1330  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { Line 1376  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
                                                 goto error;                                                  goto error;
                                         }                                          }
   
                                        if (!buffer_is_empty(host->unixsocket)) {                                        if (!buffer_string_is_empty(host->unixsocket)) {
                                                 /* unix domain socket */                                                  /* unix domain socket */
                                                 struct sockaddr_un un;                                                  struct sockaddr_un un;
   
                                                if (host->unixsocket->used > sizeof(un.sun_path) - 2) {                                                if (buffer_string_length(host->unixsocket) + 1 > sizeof(un.sun_path) - 2) {
                                                         log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",                                                          log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
                                                                         "unixsocket is too long in:",                                                                          "unixsocket is too long in:",
                                                                         da->key, "= (",                                                                          da->key, "= (",
Line 1343  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { Line 1389  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
   
                                                         goto error;                                                          goto error;
                                                 }                                                  }
   
                                                   if (!buffer_string_is_empty(host->bin_path)) {
                                                           fcgi_extension_host *duplicate = unixsocket_is_dup(p, i+1, host->unixsocket);
                                                           if (NULL != duplicate) {
                                                                   if (!buffer_is_equal(host->bin_path, duplicate->bin_path)) {
                                                                           log_error_write(srv, __FILE__, __LINE__, "sb",
                                                                                   "duplicate unixsocket path:",
                                                                                   host->unixsocket);
                                                                           goto error;
                                                                   }
                                                                   fastcgi_host_free(host);
                                                                   host = duplicate;
                                                                   ++host->refcount;
                                                           }
                                                   }
   
                                                   host->family = AF_UNIX;
                                         } else {                                          } else {
                                                 /* tcp/ip */                                                  /* tcp/ip */
   
                                                if (buffer_is_empty(host->host) &&                                                if (buffer_string_is_empty(host->host) &&
                                                    buffer_is_empty(host->bin_path)) {                                                    buffer_string_is_empty(host->bin_path)) {
                                                         log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",                                                          log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
                                                                         "host or binpath have to be set in:",                                                                          "host or binpath have to be set in:",
                                                                         da->key, "= (",                                                                          da->key, "= (",
Line 1364  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { Line 1427  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
   
                                                         goto error;                                                          goto error;
                                                 }                                                  }
   
                                                   host->family = (!buffer_string_is_empty(host->host) && NULL != strchr(host->host->ptr, ':')) ? AF_INET6 : AF_INET;
                                         }                                          }
   
                                        if (!buffer_is_empty(host->bin_path)) {                                        if (host->refcount) {
                                                 /* already init'd; skip spawning */
                                         } else if (!buffer_string_is_empty(host->bin_path)) {
                                                 /* a local socket + self spawning */                                                  /* a local socket + self spawning */
                                                 size_t pno;                                                  size_t pno;
   
Line 1386  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { Line 1453  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
                                                         proc->id = host->num_procs++;                                                          proc->id = host->num_procs++;
                                                         host->max_id++;                                                          host->max_id++;
   
                                                        if (buffer_is_empty(host->unixsocket)) {                                                        if (buffer_string_is_empty(host->unixsocket)) {
                                                                 proc->port = host->port + pno;                                                                  proc->port = host->port + pno;
                                                         } else {                                                          } else {
                                                                buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);                                                                buffer_copy_buffer(proc->unixsocket, host->unixsocket);
                                                                 buffer_append_string_len(proc->unixsocket, CONST_STR_LEN("-"));                                                                  buffer_append_string_len(proc->unixsocket, CONST_STR_LEN("-"));
                                                                buffer_append_long(proc->unixsocket, pno);                                                                buffer_append_int(proc->unixsocket, pno);
                                                         }                                                          }
   
                                                         if (s->debug) {                                                          if (s->debug) {
Line 1402  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { Line 1469  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
                                                                                 "\n\tcurrent:", pno, "/", host->max_procs);                                                                                  "\n\tcurrent:", pno, "/", host->max_procs);
                                                         }                                                          }
   
                                                        if (fcgi_spawn_connection(srv, p, host, proc)) {                                                        if (!srv->srvconf.preflight_check
                                                             && fcgi_spawn_connection(srv, p, host, proc)) {
                                                                 log_error_write(srv, __FILE__, __LINE__, "s",                                                                  log_error_write(srv, __FILE__, __LINE__, "s",
                                                                                 "[ERROR]: spawning fcgi failed.");                                                                                  "[ERROR]: spawning fcgi failed.");
                                                                 fastcgi_process_free(proc);                                                                  fastcgi_process_free(proc);
Line 1425  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { Line 1493  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
                                                 host->active_procs++;                                                  host->active_procs++;
                                                 proc->state = PROC_STATE_RUNNING;                                                  proc->state = PROC_STATE_RUNNING;
   
                                                if (buffer_is_empty(host->unixsocket)) {                                                if (buffer_string_is_empty(host->unixsocket)) {
                                                         proc->port = host->port;                                                          proc->port = host->port;
                                                 } else {                                                  } else {
                                                        buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);                                                        buffer_copy_buffer(proc->unixsocket, host->unixsocket);
                                                 }                                                  }
   
                                                 fastcgi_status_init(srv, p->statuskey, host, proc);                                                  fastcgi_status_init(srv, p->statuskey, host, proc);
Line 1438  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { Line 1506  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
                                                 host->max_procs = 1;                                                  host->max_procs = 1;
                                         }                                          }
   
                                        if (!buffer_is_empty(fcgi_mode)) {                                        if (!buffer_string_is_empty(fcgi_mode)) {
                                                 if (strcmp(fcgi_mode->ptr, "responder") == 0) {                                                  if (strcmp(fcgi_mode->ptr, "responder") == 0) {
                                                         host->mode = FCGI_RESPONDER;                                                          host->mode = FCGI_RESPONDER;
                                                 } else if (strcmp(fcgi_mode->ptr, "authorizer") == 0) {                                                  } else if (strcmp(fcgi_mode->ptr, "authorizer") == 0) {
                                                         host->mode = FCGI_AUTHORIZER;                                                          host->mode = FCGI_AUTHORIZER;
                                                        if (buffer_is_empty(host->docroot)) {                                                        if (buffer_string_is_empty(host->docroot)) {
                                                                 log_error_write(srv, __FILE__, __LINE__, "s",                                                                  log_error_write(srv, __FILE__, __LINE__, "s",
                                                                                 "ERROR: docroot is required for authorizer mode.");                                                                                  "ERROR: docroot is required for authorizer mode.");
                                                                 goto error;                                                                  goto error;
Line 1455  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { Line 1523  SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
                                                 }                                                  }
                                         }                                          }
   
                                           if (host->xsendfile_docroot->used) {
                                                   size_t k;
                                                   for (k = 0; k < host->xsendfile_docroot->used; ++k) {
                                                           data_string *ds = (data_string *)host->xsendfile_docroot->data[k];
                                                           if (ds->type != TYPE_STRING) {
                                                                   log_error_write(srv, __FILE__, __LINE__, "s",
                                                                           "unexpected type for x-sendfile-docroot; expected: \"x-sendfile-docroot\" => ( \"/allowed/path\", ... )");
                                                                   goto error;
                                                           }
                                                           if (ds->value->ptr[0] != '/') {
                                                                   log_error_write(srv, __FILE__, __LINE__, "SBs",
                                                                           "x-sendfile-docroot paths must begin with '/'; invalid: \"", ds->value, "\"");
                                                                   goto error;
                                                           }
                                                           buffer_path_simplify(ds->value, ds->value);
                                                           buffer_append_slash(ds->value);
                                                   }
                                           }
   
                                         /* if extension already exists, take it */                                          /* if extension already exists, take it */
                                         fastcgi_extension_insert(s->exts, da_ext->key, host);                                          fastcgi_extension_insert(s->exts, da_ext->key, host);
                                         host = NULL;                                          host = NULL;
Line 1484  static void fcgi_connection_close(server *srv, handler Line 1571  static void fcgi_connection_close(server *srv, handler
         plugin_data *p;          plugin_data *p;
         connection  *con;          connection  *con;
   
         if (NULL == hctx) return;  
   
         p    = hctx->plugin_data;          p    = hctx->plugin_data;
         con  = hctx->remote_conn;          con  = hctx->remote_conn;
   
Line 1514  static void fcgi_connection_close(server *srv, handler Line 1599  static void fcgi_connection_close(server *srv, handler
   
         handler_ctx_free(srv, hctx);          handler_ctx_free(srv, hctx);
         con->plugin_ctx[p->id] = NULL;          con->plugin_ctx[p->id] = NULL;
   
           /* finish response (if not already con->file_started, con->file_finished) */
           if (con->mode == p->id) {
                   http_response_backend_done(srv, con);
           }
 }  }
   
 static int fcgi_reconnect(server *srv, handler_ctx *hctx) {  static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
Line 1576  static int fcgi_reconnect(server *srv, handler_ctx *hc Line 1666  static int fcgi_reconnect(server *srv, handler_ctx *hc
   
 static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d) {  static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d) {
         plugin_data *p = p_d;          plugin_data *p = p_d;
           handler_ctx *hctx = con->plugin_ctx[p->id];
           if (hctx) fcgi_connection_close(srv, hctx);
   
         fcgi_connection_close(srv, con->plugin_ctx[p->id]);  
   
         return HANDLER_GO_ON;          return HANDLER_GO_ON;
 }  }
   
   
 static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {  static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
         size_t len;          size_t len;
           char len_enc[8];
           size_t len_enc_len = 0;
   
         if (!key || !val) return -1;          if (!key || !val) return -1;
   
Line 1593  static int fcgi_env_add(buffer *env, const char *key,  Line 1685  static int fcgi_env_add(buffer *env, const char *key, 
         len += key_len > 127 ? 4 : 1;          len += key_len > 127 ? 4 : 1;
         len += val_len > 127 ? 4 : 1;          len += val_len > 127 ? 4 : 1;
   
        if (env->used + len >= FCGI_MAX_LENGTH) {        if (buffer_string_length(env) + len >= FCGI_MAX_LENGTH) {
                 /**                  /**
                  * we can't append more headers, ignore it                   * we can't append more headers, ignore it
                  */                   */
Line 1605  static int fcgi_env_add(buffer *env, const char *key,  Line 1697  static int fcgi_env_add(buffer *env, const char *key, 
          *           *
          * HINT: this can't happen as FCGI_MAX_LENGTH is only 16bit           * HINT: this can't happen as FCGI_MAX_LENGTH is only 16bit
          */           */
        if (key_len > 0x7fffffff) key_len = 0x7fffffff;        force_assert(key_len < 0x7fffffffu);
        if (val_len > 0x7fffffff) val_len = 0x7fffffff;        force_assert(val_len < 0x7fffffffu);
   
        buffer_prepare_append(env, len);        buffer_string_prepare_append(env, len);
   
         if (key_len > 127) {          if (key_len > 127) {
                env->ptr[env->used++] = ((key_len >> 24) & 0xff) | 0x80;                len_enc[len_enc_len++] = ((key_len >> 24) & 0xff) | 0x80;
                env->ptr[env->used++] = (key_len >> 16) & 0xff;                len_enc[len_enc_len++] = (key_len >> 16) & 0xff;
                env->ptr[env->used++] = (key_len >> 8) & 0xff;                len_enc[len_enc_len++] = (key_len >> 8) & 0xff;
                env->ptr[env->used++] = (key_len >> 0) & 0xff;                len_enc[len_enc_len++] = (key_len >> 0) & 0xff;
         } else {          } else {
                env->ptr[env->used++] = (key_len >> 0) & 0xff;                len_enc[len_enc_len++] = (key_len >> 0) & 0xff;
         }          }
   
         if (val_len > 127) {          if (val_len > 127) {
                env->ptr[env->used++] = ((val_len >> 24) & 0xff) | 0x80;                len_enc[len_enc_len++] = ((val_len >> 24) & 0xff) | 0x80;
                env->ptr[env->used++] = (val_len >> 16) & 0xff;                len_enc[len_enc_len++] = (val_len >> 16) & 0xff;
                env->ptr[env->used++] = (val_len >> 8) & 0xff;                len_enc[len_enc_len++] = (val_len >> 8) & 0xff;
                env->ptr[env->used++] = (val_len >> 0) & 0xff;                len_enc[len_enc_len++] = (val_len >> 0) & 0xff;
         } else {          } else {
                env->ptr[env->used++] = (val_len >> 0) & 0xff;                len_enc[len_enc_len++] = (val_len >> 0) & 0xff;
         }          }
   
        memcpy(env->ptr + env->used, key, key_len);        buffer_append_string_len(env, len_enc, len_enc_len);
        env->used += key_len;        buffer_append_string_len(env, key, key_len);
        memcpy(env->ptr + env->used, val, val_len);        buffer_append_string_len(env, val, val_len);
        env->used += val_len; 
   
         return 0;          return 0;
 }  }
   
static int fcgi_header(FCGI_Header * header, unsigned char type, size_t request_id, int contentLength, unsigned char paddingLength) {static int fcgi_header(FCGI_Header * header, unsigned char type, int request_id, int contentLength, unsigned char paddingLength) {
         force_assert(contentLength <= FCGI_MAX_LENGTH);          force_assert(contentLength <= FCGI_MAX_LENGTH);
                   
         header->version = FCGI_VERSION_1;          header->version = FCGI_VERSION_1;
Line 1661  typedef enum { Line 1752  typedef enum {
 static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *hctx) {  static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *hctx) {
         struct sockaddr *fcgi_addr;          struct sockaddr *fcgi_addr;
         struct sockaddr_in fcgi_addr_in;          struct sockaddr_in fcgi_addr_in;
   #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
           struct sockaddr_in6 fcgi_addr_in6;
   #endif
 #ifdef HAVE_SYS_UN_H  #ifdef HAVE_SYS_UN_H
         struct sockaddr_un fcgi_addr_un;          struct sockaddr_un fcgi_addr_un;
 #endif  #endif
Line 1670  static connection_result_t fcgi_establish_connection(s Line 1764  static connection_result_t fcgi_establish_connection(s
         fcgi_proc *proc   = hctx->proc;          fcgi_proc *proc   = hctx->proc;
         int fcgi_fd       = hctx->fd;          int fcgi_fd       = hctx->fd;
   
        memset(&fcgi_addr, 0, sizeof(fcgi_addr));        if (!buffer_string_is_empty(proc->unixsocket)) {
 
        if (!buffer_is_empty(proc->unixsocket)) { 
 #ifdef HAVE_SYS_UN_H  #ifdef HAVE_SYS_UN_H
                 /* use the unix domain socket */                  /* use the unix domain socket */
                   memset(&fcgi_addr_un, 0, sizeof(fcgi_addr_un));
                 fcgi_addr_un.sun_family = AF_UNIX;                  fcgi_addr_un.sun_family = AF_UNIX;
                if (proc->unixsocket->used > sizeof(fcgi_addr_un.sun_path)) {                if (buffer_string_length(proc->unixsocket) + 1 > sizeof(fcgi_addr_un.sun_path)) {
                         log_error_write(srv, __FILE__, __LINE__, "sB",                          log_error_write(srv, __FILE__, __LINE__, "sB",
                                         "ERROR: Unix Domain socket filename too long:",                                          "ERROR: Unix Domain socket filename too long:",
                                         proc->unixsocket);                                          proc->unixsocket);
                         return -1;                          return -1;
                 }                  }
                memcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr, proc->unixsocket->used);                memcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr, buffer_string_length(proc->unixsocket) + 1);
   
 #ifdef SUN_LEN  #ifdef SUN_LEN
                 servlen = SUN_LEN(&fcgi_addr_un);                  servlen = SUN_LEN(&fcgi_addr_un);
 #else  #else
                 /* stevens says: */                  /* stevens says: */
                servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);                servlen = buffer_string_length(proc->unixsocket) + 1 + sizeof(fcgi_addr_un.sun_family);
 #endif  #endif
                 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;                  fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
   
                if (buffer_is_empty(proc->connection_name)) {                if (buffer_string_is_empty(proc->connection_name)) {
                         /* on remote spawing we have to set the connection-name now */                          /* on remote spawing we have to set the connection-name now */
                         buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("unix:"));                          buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("unix:"));
                         buffer_append_string_buffer(proc->connection_name, proc->unixsocket);                          buffer_append_string_buffer(proc->connection_name, proc->unixsocket);
Line 1700  static connection_result_t fcgi_establish_connection(s Line 1793  static connection_result_t fcgi_establish_connection(s
 #else  #else
                 return CONNECTION_DEAD;                  return CONNECTION_DEAD;
 #endif  #endif
   #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
           } else if (host->family == AF_INET6 && !buffer_string_is_empty(host->host)) {
                   memset(&fcgi_addr_in6, 0, sizeof(fcgi_addr_in6));
                   fcgi_addr_in6.sin6_family = AF_INET6;
                   inet_pton(AF_INET6, host->host->ptr, (char *) &fcgi_addr_in6.sin6_addr);
                   fcgi_addr_in6.sin6_port = htons(proc->port);
                   servlen = sizeof(fcgi_addr_in6);
                   fcgi_addr = (struct sockaddr *) &fcgi_addr_in6;
   #endif
         } else {          } else {
                   memset(&fcgi_addr_in, 0, sizeof(fcgi_addr_in));
                 fcgi_addr_in.sin_family = AF_INET;                  fcgi_addr_in.sin_family = AF_INET;
                if (!buffer_is_empty(host->host)) {                if (!buffer_string_is_empty(host->host)) {
                         if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) {                          if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) {
                                 log_error_write(srv, __FILE__, __LINE__, "sbs",                                  log_error_write(srv, __FILE__, __LINE__, "sbs",
                                                 "converting IP address failed for", host->host,                                                  "converting IP address failed for", host->host,
Line 1717  static connection_result_t fcgi_establish_connection(s Line 1820  static connection_result_t fcgi_establish_connection(s
                 servlen = sizeof(fcgi_addr_in);                  servlen = sizeof(fcgi_addr_in);
   
                 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;                  fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
           }
   
                if (buffer_is_empty(proc->connection_name)) {        if (buffer_string_is_empty(proc->unixsocket)) {
                 if (buffer_string_is_empty(proc->connection_name)) {
                         /* on remote spawing we have to set the connection-name now */                          /* on remote spawing we have to set the connection-name now */
                         buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("tcp:"));                          buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("tcp:"));
                        if (!buffer_is_empty(host->host)) {                        if (!buffer_string_is_empty(host->host)) {
                                 buffer_append_string_buffer(proc->connection_name, host->host);                                  buffer_append_string_buffer(proc->connection_name, host->host);
                         } else {                          } else {
                                 buffer_append_string_len(proc->connection_name, CONST_STR_LEN("localhost"));                                  buffer_append_string_len(proc->connection_name, CONST_STR_LEN("localhost"));
                         }                          }
                         buffer_append_string_len(proc->connection_name, CONST_STR_LEN(":"));                          buffer_append_string_len(proc->connection_name, CONST_STR_LEN(":"));
                        buffer_append_long(proc->connection_name, proc->port);                        buffer_append_int(proc->connection_name, proc->port);
                 }                  }
         }          }
   
Line 1769  static connection_result_t fcgi_establish_connection(s Line 1874  static connection_result_t fcgi_establish_connection(s
         return CONNECTION_OK;          return CONNECTION_OK;
 }  }
   
   #define FCGI_ENV_ADD_CHECK(ret, con) \
           if (ret == -1) { \
                   con->http_status = 400; \
                   return -1; \
           };
 static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {  static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
         size_t i;          size_t i;
   
Line 1777  static int fcgi_env_add_request_headers(server *srv, c Line 1887  static int fcgi_env_add_request_headers(server *srv, c
   
                 ds = (data_string *)con->request.headers->data[i];                  ds = (data_string *)con->request.headers->data[i];
   
                if (ds->value->used && ds->key->used) {                if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
                        size_t j;                        /* Do not emit HTTP_PROXY in environment.
                        buffer_reset(srv->tmp_buf);                         * Some executables use HTTP_PROXY to configure
                         * outgoing proxy.  See also https://httpoxy.org/ */
                        if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {                        if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy"))) {
                                buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("HTTP_"));                                continue;
                                srv->tmp_buf->used--; 
                         }                          }
   
                        buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);                        buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 1);
                        for (j = 0; j < ds->key->used - 1; j++) { 
                                char c = '_'; 
                                if (light_isalpha(ds->key->ptr[j])) { 
                                        /* upper-case */ 
                                        c = ds->key->ptr[j] & ~32; 
                                } else if (light_isdigit(ds->key->ptr[j])) { 
                                        /* copy */ 
                                        c = ds->key->ptr[j]; 
                                } 
                                srv->tmp_buf->ptr[srv->tmp_buf->used++] = c; 
                        } 
                        srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0'; 
   
                         FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)),con);                          FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)),con);
                 }                  }
Line 1809  static int fcgi_env_add_request_headers(server *srv, c Line 1906  static int fcgi_env_add_request_headers(server *srv, c
   
                 ds = (data_string *)con->environment->data[i];                  ds = (data_string *)con->environment->data[i];
   
                if (ds->value->used && ds->key->used) {                if (!buffer_is_empty(ds->value) && !buffer_is_empty(ds->key)) {
                        size_t j;                        buffer_copy_string_encoded_cgi_varnames(srv->tmp_buf, CONST_BUF_LEN(ds->key), 0);
                        buffer_reset(srv->tmp_buf); 
   
                         buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);  
                         for (j = 0; j < ds->key->used - 1; j++) {  
                                 char c = '_';  
                                 if (light_isalpha(ds->key->ptr[j])) {  
                                         /* upper-case */  
                                         c = ds->key->ptr[j] & ~32;  
                                 } else if (light_isdigit(ds->key->ptr[j])) {  
                                         /* copy */  
                                         c = ds->key->ptr[j];  
                                 }  
                                 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;  
                         }  
                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';  
   
                         FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)), con);                          FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)), con);
                 }                  }
         }          }
Line 1834  static int fcgi_env_add_request_headers(server *srv, c Line 1916  static int fcgi_env_add_request_headers(server *srv, c
         return 0;          return 0;
 }  }
   
   static void fcgi_stdin_append(server *srv, connection *con, handler_ctx *hctx, int request_id) {
           FCGI_Header header;
           chunkqueue *req_cq = con->request_content_queue;
           plugin_data *p     = hctx->plugin_data;
           off_t offset, weWant;
           const off_t req_cqlen = req_cq->bytes_in - req_cq->bytes_out;
   
static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {        /* something to send ? */
         for (offset = 0; offset != req_cqlen; offset += weWant) {
                 weWant = req_cqlen - offset > FCGI_MAX_LENGTH ? FCGI_MAX_LENGTH : req_cqlen - offset;
 
                 /* we announce toWrite octets
                  * now take all request_content chunks available
                  * */
 
                 fcgi_header(&(header), FCGI_STDIN, request_id, weWant, 0);
                 chunkqueue_append_mem(hctx->wb, (const char *)&header, sizeof(header));
                 hctx->wb_reqlen += sizeof(header);
 
                 if (p->conf.debug > 10) {
                         log_error_write(srv, __FILE__, __LINE__, "soso", "tosend:", offset, "/", req_cqlen);
                 }
 
                 chunkqueue_steal(hctx->wb, req_cq, weWant);
                 /*(hctx->wb_reqlen already includes content_length)*/
         }
 
         if (hctx->wb->bytes_in == hctx->wb_reqlen) {
                 /* terminate STDIN */
                 fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0);
                 chunkqueue_append_mem(hctx->wb, (const char *)&header, sizeof(header));
                 hctx->wb_reqlen += (int)sizeof(header);
         }
 }
 
 static int fcgi_create_env(server *srv, handler_ctx *hctx, int request_id) {
         FCGI_BeginRequestRecord beginRecord;          FCGI_BeginRequestRecord beginRecord;
         FCGI_Header header;          FCGI_Header header;
         buffer *b;  
   
        char buf[32];        char buf[LI_ITOSTRING_LENGTH];
         const char *s;          const char *s;
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
         char b2[INET6_ADDRSTRLEN + 1];          char b2[INET6_ADDRSTRLEN + 1];
Line 1850  static int fcgi_create_env(server *srv, handler_ctx *h Line 1965  static int fcgi_create_env(server *srv, handler_ctx *h
         fcgi_extension_host *host= hctx->host;          fcgi_extension_host *host= hctx->host;
   
         connection *con   = hctx->remote_conn;          connection *con   = hctx->remote_conn;
           buffer * const req_uri = con->request.orig_uri;
         server_socket *srv_sock = con->srv_socket;          server_socket *srv_sock = con->srv_socket;
   
         sock_addr our_addr;          sock_addr our_addr;
Line 1863  static int fcgi_create_env(server *srv, handler_ctx *h Line 1979  static int fcgi_create_env(server *srv, handler_ctx *h
         beginRecord.body.flags = 0;          beginRecord.body.flags = 0;
         memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));          memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));
   
         b = chunkqueue_get_append_buffer(hctx->wb);  
   
         buffer_copy_memory(b, (const char *)&beginRecord, sizeof(beginRecord));  
   
         /* send FCGI_PARAMS */          /* send FCGI_PARAMS */
        buffer_prepare_copy(p->fcgi_env, 1024);        buffer_string_prepare_copy(p->fcgi_env, 1023);
   
           FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_BUF_LEN(con->conf.server_tag)),con)
   
        if (buffer_is_empty(con->conf.server_tag)) {        if (!buffer_is_empty(con->server_name)) {
                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_DESC)),con)                size_t len = buffer_string_length(con->server_name);
        } else { 
                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_BUF_LEN(con->conf.server_tag)),con) 
        } 
   
         if (con->server_name->used) {  
                 size_t len = con->server_name->used - 1;  
   
                 if (con->server_name->ptr[0] == '[') {                  if (con->server_name->ptr[0] == '[') {
                         const char *colon = strstr(con->server_name->ptr, "]:");                          const char *colon = strstr(con->server_name->ptr, "]:");
                         if (colon) len = (colon + 1) - con->server_name->ptr;                          if (colon) len = (colon + 1) - con->server_name->ptr;
Line 1904  static int fcgi_create_env(server *srv, handler_ctx *h Line 2011  static int fcgi_create_env(server *srv, handler_ctx *h
   
         FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1")),con)          FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1")),con)
   
        LI_ltostr(buf,        li_utostrn(buf, sizeof(buf),
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
                ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)                 ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
 #else  #else
Line 1917  static int fcgi_create_env(server *srv, handler_ctx *h Line 2024  static int fcgi_create_env(server *srv, handler_ctx *h
         /* get the server-side of the connection to the client */          /* get the server-side of the connection to the client */
         our_addr_len = sizeof(our_addr);          our_addr_len = sizeof(our_addr);
   
        if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {        if (-1 == getsockname(con->fd, (struct sockaddr *)&our_addr, &our_addr_len)
             || our_addr_len > (socklen_t)sizeof(our_addr)) {
                 s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));                  s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
         } else {          } else {
                 s = inet_ntop_cache_get_ip(srv, &(our_addr));                  s = inet_ntop_cache_get_ip(srv, &(our_addr));
         }          }
         FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s)),con)          FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s)),con)
   
        LI_ltostr(buf,        li_utostrn(buf, sizeof(buf),
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
                ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)                 ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
 #else  #else
Line 1940  static int fcgi_create_env(server *srv, handler_ctx *h Line 2048  static int fcgi_create_env(server *srv, handler_ctx *h
         if (con->request.content_length > 0 && host->mode != FCGI_AUTHORIZER) {          if (con->request.content_length > 0 && host->mode != FCGI_AUTHORIZER) {
                 /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */                  /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
   
                /* request.content_length < SSIZE_MAX, see request.c */                li_itostrn(buf, sizeof(buf), con->request.content_length);
                LI_ltostr(buf, con->request.content_length); 
                 FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf)),con)                  FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf)),con)
         }          }
   
Line 1955  static int fcgi_create_env(server *srv, handler_ctx *h Line 2062  static int fcgi_create_env(server *srv, handler_ctx *h
   
                 FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path)),con)                  FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path)),con)
   
                if (!buffer_is_empty(con->request.pathinfo)) {                if (!buffer_string_is_empty(con->request.pathinfo)) {
                         FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo)),con)                          FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo)),con)
   
                         /* PATH_TRANSLATED is only defined if PATH_INFO is set */                          /* PATH_TRANSLATED is only defined if PATH_INFO is set */
   
                        if (!buffer_is_empty(host->docroot)) {                        if (!buffer_string_is_empty(host->docroot)) {
                                buffer_copy_string_buffer(p->path, host->docroot);                                buffer_copy_buffer(p->path, host->docroot);
                         } else {                          } else {
                                buffer_copy_string_buffer(p->path, con->physical.basedir);                                buffer_copy_buffer(p->path, con->physical.basedir);
                         }                          }
                         buffer_append_string_buffer(p->path, con->request.pathinfo);                          buffer_append_string_buffer(p->path, con->request.pathinfo);
                         FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_TRANSLATED"), CONST_BUF_LEN(p->path)),con)                          FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_TRANSLATED"), CONST_BUF_LEN(p->path)),con)
Line 1980  static int fcgi_create_env(server *srv, handler_ctx *h Line 2087  static int fcgi_create_env(server *srv, handler_ctx *h
          * parameter.           * parameter.
          */           */
   
        if (!buffer_is_empty(host->docroot)) {        if (!buffer_string_is_empty(host->docroot)) {
                 /*                  /*
                  * rewrite SCRIPT_FILENAME                   * rewrite SCRIPT_FILENAME
                  *                   *
                  */                   */
   
                buffer_copy_string_buffer(p->path, host->docroot);                buffer_copy_buffer(p->path, host->docroot);
                 buffer_append_string_buffer(p->path, con->uri.path);                  buffer_append_string_buffer(p->path, con->uri.path);
   
                 FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path)),con)                  FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path)),con)
                 FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot)),con)                  FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot)),con)
         } else {          } else {
                buffer_copy_string_buffer(p->path, con->physical.path);                buffer_copy_buffer(p->path, con->physical.path);
   
                 /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself                  /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself
                  *                   *
Line 2006  static int fcgi_create_env(server *srv, handler_ctx *h Line 2113  static int fcgi_create_env(server *srv, handler_ctx *h
                 FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir)),con)                  FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir)),con)
         }          }
   
        if (host->strip_request_uri->used > 1) {        if (!buffer_string_is_empty(host->strip_request_uri)) {
                 /* we need at least one char to strip off */                  /* we need at least one char to strip off */
                 /**                  /**
                  * /app1/index/list                   * /app1/index/list
Line 2016  static int fcgi_create_env(server *srv, handler_ctx *h Line 2123  static int fcgi_create_env(server *srv, handler_ctx *h
                  * /index/list                   * /index/list
                  *                   *
                  */                   */
                if ('/' != host->strip_request_uri->ptr[host->strip_request_uri->used - 2]) {
                 if ('/' != host->strip_request_uri->ptr[buffer_string_length(host->strip_request_uri) - 1]) {
                         /* fix the user-input to have / as last char */                          /* fix the user-input to have / as last char */
                         buffer_append_string_len(host->strip_request_uri, CONST_STR_LEN("/"));                          buffer_append_string_len(host->strip_request_uri, CONST_STR_LEN("/"));
                 }                  }
   
                if (con->request.orig_uri->used >= host->strip_request_uri->used &&                if (buffer_string_length(req_uri) >= buffer_string_length(host->strip_request_uri) &&
                    0 == strncmp(con->request.orig_uri->ptr, host->strip_request_uri->ptr, host->strip_request_uri->used - 1)) {                    0 == strncmp(req_uri->ptr, host->strip_request_uri->ptr, buffer_string_length(host->strip_request_uri))) {
                         /* the left is the same */                          /* the left is the same */
   
                        fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),                        FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
                                        con->request.orig_uri->ptr + (host->strip_request_uri->used - 2),                                        req_uri->ptr + (buffer_string_length(host->strip_request_uri) - 1),
                                        con->request.orig_uri->used - (host->strip_request_uri->used - 2) - 1);                                        buffer_string_length(req_uri) - (buffer_string_length(host->strip_request_uri) - 1)), con)
                 } else {                  } else {
                        FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)),con)                        FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(req_uri)),con)
                 }                  }
         } else {          } else {
                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)),con)                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(req_uri)),con)
         }          }
         if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {          if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {
                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.uri)),con)                FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.uri)),con);
         }          }
        if (!buffer_is_empty(con->uri.query)) {        if (!buffer_string_is_empty(con->uri.query)) {
                 FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query)),con)                  FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query)),con)
         } else {          } else {
                 FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN("")),con)                  FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN("")),con)
         }          }
   
         s = get_http_method_name(con->request.http_method);          s = get_http_method_name(con->request.http_method);
           force_assert(s);
         FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s)),con)          FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s)),con)
        FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")),con) /* if php is compiled with --force-redirect */        /* set REDIRECT_STATUS for php compiled with --force-redirect
          * (if REDIRECT_STATUS has not already been set by error handler) */
         if (0 == con->error_handler_saved_status) {
                 FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")), con);
         }
         s = get_http_version_name(con->request.http_version);          s = get_http_version_name(con->request.http_version);
           force_assert(s);
         FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s)),con)          FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s)),con)
   
         if (buffer_is_equal_caseless_string(con->uri.scheme, CONST_STR_LEN("https"))) {          if (buffer_is_equal_caseless_string(con->uri.scheme, CONST_STR_LEN("https"))) {
Line 2055  static int fcgi_create_env(server *srv, handler_ctx *h Line 2169  static int fcgi_create_env(server *srv, handler_ctx *h
   
         FCGI_ENV_ADD_CHECK(fcgi_env_add_request_headers(srv, con, p), con);          FCGI_ENV_ADD_CHECK(fcgi_env_add_request_headers(srv, con, p), con);
   
        fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0);        {
        buffer_append_memory(b, (const char *)&header, sizeof(header));                buffer *b = buffer_init();
        buffer_append_memory(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used); 
   
        fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);                buffer_copy_string_len(b, (const char *)&beginRecord, sizeof(beginRecord));
        buffer_append_memory(b, (const char *)&header, sizeof(header)); 
   
        b->used++; /* add virtual \0 */                fcgi_header(&(header), FCGI_PARAMS, request_id, buffer_string_length(p->fcgi_env), 0);
        hctx->wb->bytes_in += b->used - 1;                buffer_append_string_len(b, (const char *)&header, sizeof(header));
                 buffer_append_string_buffer(b, p->fcgi_env);
   
        if (con->request.content_length) {                fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);
                chunkqueue *req_cq = con->request_content_queue;                buffer_append_string_len(b, (const char *)&header, sizeof(header));
                chunk *req_c; 
                off_t offset; 
   
                /* something to send ? */                hctx->wb_reqlen = buffer_string_length(b);
                for (offset = 0, req_c = req_cq->first; offset != req_cq->bytes_in; ) {                chunkqueue_append_buffer(hctx->wb, b);
                        off_t weWant = req_cq->bytes_in - offset > FCGI_MAX_LENGTH ? FCGI_MAX_LENGTH : req_cq->bytes_in - offset;                buffer_free(b);
                        off_t written = 0; 
                        off_t weHave = 0; 
 
                        /* we announce toWrite octets 
                         * now take all the request_content chunks that we need to fill this request 
                         * */ 
 
                        b = chunkqueue_get_append_buffer(hctx->wb); 
                        fcgi_header(&(header), FCGI_STDIN, request_id, weWant, 0); 
                        buffer_copy_memory(b, (const char *)&header, sizeof(header)); 
                        hctx->wb->bytes_in += sizeof(header); 
 
                        if (p->conf.debug > 10) { 
                                log_error_write(srv, __FILE__, __LINE__, "soso", "tosend:", offset, "/", req_cq->bytes_in); 
                        } 
 
                        for (written = 0; written != weWant; ) { 
                                if (p->conf.debug > 10) { 
                                        log_error_write(srv, __FILE__, __LINE__, "soso", "chunk:", written, "/", weWant); 
                                } 
 
                                switch (req_c->type) { 
                                case FILE_CHUNK: 
                                        weHave = req_c->file.length - req_c->offset; 
 
                                        if (weHave > weWant - written) weHave = weWant - written; 
 
                                        if (p->conf.debug > 10) { 
                                                log_error_write(srv, __FILE__, __LINE__, "soSosOsb", 
                                                        "sending", weHave, "bytes from (", 
                                                        req_c->offset, "/", req_c->file.length, ")", 
                                                        req_c->file.name); 
                                        } 
 
                                        force_assert(weHave != 0); 
 
                                        chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave); 
 
                                        req_c->offset += weHave; 
                                        req_cq->bytes_out += weHave; 
                                        written += weHave; 
 
                                        hctx->wb->bytes_in += weHave; 
 
                                        /* steal the tempfile 
                                         * 
                                         * This is tricky: 
                                         * - we reference the tempfile from the request-content-queue several times 
                                         *   if the req_c is larger than FCGI_MAX_LENGTH 
                                         * - we can't simply cleanup the request-content-queue as soon as possible 
                                         *   as it would remove the tempfiles 
                                         * - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last 
                                         *   referencing chunk of the fastcgi-write-queue 
                                         * 
                                         *  */ 
 
                                        if (req_c->offset == req_c->file.length) { 
                                                chunk *c; 
 
                                                if (p->conf.debug > 10) { 
                                                        log_error_write(srv, __FILE__, __LINE__, "s", "next chunk"); 
                                                } 
                                                c = hctx->wb->last; 
 
                                                force_assert(c->type == FILE_CHUNK); 
                                                force_assert(req_c->file.is_temp == 1); 
 
                                                c->file.is_temp = 1; 
                                                req_c->file.is_temp = 0; 
 
                                                chunkqueue_remove_finished_chunks(req_cq); 
 
                                                req_c = req_cq->first; 
                                        } 
 
                                        break; 
                                case MEM_CHUNK: 
                                        /* append to the buffer */ 
                                        weHave = req_c->mem->used - 1 - req_c->offset; 
 
                                        if (weHave > weWant - written) weHave = weWant - written; 
 
                                        buffer_append_memory(b, req_c->mem->ptr + req_c->offset, weHave); 
 
                                        req_c->offset += weHave; 
                                        req_cq->bytes_out += weHave; 
                                        written += weHave; 
 
                                        hctx->wb->bytes_in += weHave; 
 
                                        if (req_c->offset == (off_t) req_c->mem->used - 1) { 
                                                chunkqueue_remove_finished_chunks(req_cq); 
 
                                                req_c = req_cq->first; 
                                        } 
 
                                        break; 
                                default: 
                                        break; 
                                } 
                        } 
 
                        b->used++; /* add virtual \0 */ 
                        offset += weWant; 
                } 
         }          }
   
        b = chunkqueue_get_append_buffer(hctx->wb);        hctx->wb_reqlen += con->request.content_length;/* (eventual) (minimal) total request size, not necessarily including all fcgi_headers around content length yet */
        /* terminate STDIN */        fcgi_stdin_append(srv, con, hctx, request_id);
        fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0); 
        buffer_copy_memory(b, (const char *)&header, sizeof(header)); 
        b->used++; /* add virtual \0 */ 
   
         hctx->wb->bytes_in += sizeof(header);  
   
         return 0;          return 0;
 }  }
   
Line 2201  static int fcgi_response_parse(server *srv, connection Line 2202  static int fcgi_response_parse(server *srv, connection
   
         UNUSED(srv);          UNUSED(srv);
   
         buffer_copy_string_buffer(p->parse_response, in);  
   
         /* search for \n */          /* search for \n */
        for (s = p->parse_response->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) {        for (s = in->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) {
                 char *key, *value;                  char *key, *value;
                 int key_len;                  int key_len;
                 data_string *ds = NULL;  
   
                 /* a good day. Someone has read the specs and is sending a \r\n to us */                  /* a good day. Someone has read the specs and is sending a \r\n to us */
   
                if (ns > p->parse_response->ptr &&                if (ns > in->ptr &&
                     *(ns-1) == '\r') {                      *(ns-1) == '\r') {
                         *(ns-1) = '\0';                          *(ns-1) = '\0';
                 }                  }
Line 2237  static int fcgi_response_parse(server *srv, connection Line 2235  static int fcgi_response_parse(server *srv, connection
   
                         /* don't forward Status: */                          /* don't forward Status: */
                         if (0 != strncasecmp(key, "Status", key_len)) {                          if (0 != strncasecmp(key, "Status", key_len)) {
                                   data_string *ds;
                                 if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {                                  if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
                                         ds = data_response_init();                                          ds = data_response_init();
                                 }                                  }
Line 2255  static int fcgi_response_parse(server *srv, connection Line 2254  static int fcgi_response_parse(server *srv, connection
                         break;                          break;
                 case 6:                  case 6:
                         if (0 == strncasecmp(key, "Status", key_len)) {                          if (0 == strncasecmp(key, "Status", key_len)) {
                                con->http_status = strtol(value, NULL, 10);                                int status = strtol(value, NULL, 10);
                                con->parsed_response |= HTTP_STATUS;                                if (status >= 100 && status < 1000) {
                                         con->http_status = status;
                                         con->parsed_response |= HTTP_STATUS;
                                 } else {
                                         con->http_status = 502;
                                 }
                         }                          }
                         break;                          break;
                 case 8:                  case 8:
Line 2271  static int fcgi_response_parse(server *srv, connection Line 2275  static int fcgi_response_parse(server *srv, connection
                         }                          }
                         break;                          break;
                 case 11:                  case 11:
                        if (host->allow_xsendfile && 0 == strncasecmp(key, "X-Sendfile2", key_len)&& hctx->send_content_body) {                        if (host->xsendfile_allow && 0 == strncasecmp(key, "X-Sendfile2", key_len) && hctx->send_content_body) {
                                 char *pos = value;                                  char *pos = value;
                                 have_sendfile2 = 1;                                  have_sendfile2 = 1;
   
Line 2289  static int fcgi_response_parse(server *srv, connection Line 2293  static int fcgi_response_parse(server *srv, connection
                                                 if (p->conf.debug) {                                                  if (p->conf.debug) {
                                                         log_error_write(srv, __FILE__, __LINE__, "ss", "Couldn't find range after filename:", filename);                                                          log_error_write(srv, __FILE__, __LINE__, "ss", "Couldn't find range after filename:", filename);
                                                 }                                                  }
                                                return 1;                                                return 502;
                                         }                                          }
                                         buffer_copy_string_len(srv->tmp_buf, filename, range - filename);                                          buffer_copy_string_len(srv->tmp_buf, filename, range - filename);
   
Line 2297  static int fcgi_response_parse(server *srv, connection Line 2301  static int fcgi_response_parse(server *srv, connection
                                         for (pos = ++range; *pos && *pos != ' ' && *pos != ','; pos++) ;                                          for (pos = ++range; *pos && *pos != ' ' && *pos != ','; pos++) ;
   
                                         buffer_urldecode_path(srv->tmp_buf);                                          buffer_urldecode_path(srv->tmp_buf);
                                           buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
                                           if (con->conf.force_lowercase_filenames) {
                                                   buffer_to_lower(srv->tmp_buf);
                                           }
                                           if (host->xsendfile_docroot->used) {
                                                   size_t i, xlen = buffer_string_length(srv->tmp_buf);
                                                   for (i = 0; i < host->xsendfile_docroot->used; ++i) {
                                                           data_string *ds = (data_string *)host->xsendfile_docroot->data[i];
                                                           size_t dlen = buffer_string_length(ds->value);
                                                           if (dlen <= xlen
                                                               && (!con->conf.force_lowercase_filenames
                                                                   ? 0 == memcmp(srv->tmp_buf->ptr, ds->value->ptr, dlen)
                                                                   : 0 == strncasecmp(srv->tmp_buf->ptr, ds->value->ptr, dlen))) {
                                                                   break;
                                                           }
                                                   }
                                                   if (i == host->xsendfile_docroot->used) {
                                                           log_error_write(srv, __FILE__, __LINE__, "SBs",
                                                                           "X-Sendfile2 (", srv->tmp_buf,
                                                                           ") not under configured x-sendfile-docroot(s)");
                                                           return 403;
                                                   }
                                           }
   
                                         if (HANDLER_ERROR == stat_cache_get_entry(srv, con, srv->tmp_buf, &sce)) {                                          if (HANDLER_ERROR == stat_cache_get_entry(srv, con, srv->tmp_buf, &sce)) {
                                                 if (p->conf.debug) {                                                  if (p->conf.debug) {
                                                         log_error_write(srv, __FILE__, __LINE__, "sb",                                                          log_error_write(srv, __FILE__, __LINE__, "sb",
                                                                 "send-file error: couldn't get stat_cache entry for X-Sendfile2:",                                                                  "send-file error: couldn't get stat_cache entry for X-Sendfile2:",
                                                                 srv->tmp_buf);                                                                  srv->tmp_buf);
                                                 }                                                  }
                                                return 1;                                                return 404;
                                         } else if (!S_ISREG(sce->st.st_mode)) {                                          } else if (!S_ISREG(sce->st.st_mode)) {
                                                 if (p->conf.debug) {                                                  if (p->conf.debug) {
                                                         log_error_write(srv, __FILE__, __LINE__, "sb",                                                          log_error_write(srv, __FILE__, __LINE__, "sb",
                                                                 "send-file error: wrong filetype for X-Sendfile2:",                                                                  "send-file error: wrong filetype for X-Sendfile2:",
                                                                 srv->tmp_buf);                                                                  srv->tmp_buf);
                                                 }                                                  }
                                                return 1;                                                return 502;
                                         }                                          }
                                         /* found the file */                                          /* found the file */
   
Line 2335  range_failed: Line 2363  range_failed:
                                                 if (p->conf.debug) {                                                  if (p->conf.debug) {
                                                         log_error_write(srv, __FILE__, __LINE__, "ss", "Couldn't decode range after filename:", filename);                                                          log_error_write(srv, __FILE__, __LINE__, "ss", "Couldn't decode range after filename:", filename);
                                                 }                                                  }
                                                return 1;                                                return 502;
   
 range_success: ;  range_success: ;
                                         }                                          }
Line 2343  range_success: ; Line 2371  range_success: ;
                                         /* no parameters accepted */                                          /* no parameters accepted */
   
                                         while (*pos == ' ') pos++;                                          while (*pos == ' ') pos++;
                                        if (*pos != '\0' && *pos != ',') return 1;                                        if (*pos != '\0' && *pos != ',') return 502;
   
                                         range_len = end_range - begin_range + 1;                                          range_len = end_range - begin_range + 1;
                                        if (range_len < 0) return 1;                                        if (range_len < 0) return 502;
                                         if (range_len != 0) {                                          if (range_len != 0) {
                                                http_chunk_append_file(srv, con, srv->tmp_buf, begin_range, range_len);                                                if (0 != http_chunk_append_file_range(srv, con, srv->tmp_buf, begin_range, range_len)) {
                                                         return 502;
                                                 }
                                         }                                          }
                                         sendfile2_content_length += range_len;                                          sendfile2_content_length += range_len;
   
Line 2358  range_success: ; Line 2388  range_success: ;
                         break;                          break;
                 case 14:                  case 14:
                         if (0 == strncasecmp(key, "Content-Length", key_len)) {                          if (0 == strncasecmp(key, "Content-Length", key_len)) {
                                con->response.content_length = strtol(value, NULL, 10);                                con->response.content_length = strtoul(value, NULL, 10);
                                 con->parsed_response |= HTTP_CONTENT_LENGTH;                                  con->parsed_response |= HTTP_CONTENT_LENGTH;
   
                                 if (con->response.content_length < 0) con->response.content_length = 0;                                  if (con->response.content_length < 0) con->response.content_length = 0;
Line 2372  range_success: ; Line 2402  range_success: ;
         if (have_sendfile2) {          if (have_sendfile2) {
                 data_string *dcls;                  data_string *dcls;
   
                 hctx->send_content_body = 0;  
                 joblist_append(srv, con);  
   
                 /* fix content-length */                  /* fix content-length */
                 if (NULL == (dcls = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {                  if (NULL == (dcls = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
                         dcls = data_response_init();                          dcls = data_response_init();
                 }                  }
   
                 buffer_copy_string_len(dcls->key, "Content-Length", sizeof("Content-Length")-1);                  buffer_copy_string_len(dcls->key, "Content-Length", sizeof("Content-Length")-1);
                buffer_copy_off_t(dcls->value, sendfile2_content_length);                buffer_copy_int(dcls->value, sendfile2_content_length);
                dcls = (data_string*) array_replace(con->response.headers, (data_unset *)dcls);                array_replace(con->response.headers, (data_unset *)dcls);
                if (dcls) dcls->free((data_unset*)dcls); 
   
                 con->parsed_response |= HTTP_CONTENT_LENGTH;                  con->parsed_response |= HTTP_CONTENT_LENGTH;
                 con->response.content_length = sendfile2_content_length;                  con->response.content_length = sendfile2_content_length;
                   return 200;
         }          }
   
         /* CGI/1.1 rev 03 - 7.2.1.2 */          /* CGI/1.1 rev 03 - 7.2.1.2 */
Line 2400  range_success: ; Line 2427  range_success: ;
   
 typedef struct {  typedef struct {
         buffer  *b;          buffer  *b;
        size_t   len;        unsigned int len;
         int      type;          int      type;
         int      padding;          int      padding;
        size_t   request_id;        int      request_id;
 } fastcgi_response_packet;  } fastcgi_response_packet;
   
 static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_packet *packet) {  static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_packet *packet) {
        chunk * c;        chunk *c;
         size_t offset;          size_t offset;
         size_t toread;          size_t toread;
         FCGI_Header *header;          FCGI_Header *header;
Line 2423  static int fastcgi_get_packet(server *srv, handler_ctx Line 2450  static int fastcgi_get_packet(server *srv, handler_ctx
         offset = 0; toread = 8;          offset = 0; toread = 8;
         /* get at least the FastCGI header */          /* get at least the FastCGI header */
         for (c = hctx->rb->first; c; c = c->next) {          for (c = hctx->rb->first; c; c = c->next) {
                size_t weHave = c->mem->used - c->offset - 1;                size_t weHave = buffer_string_length(c->mem) - c->offset;
   
                 if (weHave > toread) weHave = toread;                  if (weHave > toread) weHave = toread;
   
                if (packet->b->used == 0) {                buffer_append_string_len(packet->b, c->mem->ptr + c->offset, weHave);
                        buffer_copy_string_len(packet->b, c->mem->ptr + c->offset, weHave); 
                } else { 
                        buffer_append_string_len(packet->b, c->mem->ptr + c->offset, weHave); 
                } 
                 toread -= weHave;                  toread -= weHave;
                 offset = weHave; /* skip offset bytes in chunk for "real" data */                  offset = weHave; /* skip offset bytes in chunk for "real" data */
   
                 if (0 == toread) break;                  if (0 == toread) break;
         }          }
   
        if ((packet->b->used == 0) ||        if (buffer_string_length(packet->b) < sizeof(FCGI_Header)) {
            (packet->b->used - 1 < sizeof(FCGI_Header))) { 
                 /* no header */                  /* no header */
                 if (hctx->plugin_data->conf.debug) {                  if (hctx->plugin_data->conf.debug) {
                        log_error_write(srv, __FILE__, __LINE__, "sdsds", "FastCGI: header too small:", packet->b->used, "bytes <", sizeof(FCGI_Header), "bytes, waiting for more data");                        log_error_write(srv, __FILE__, __LINE__, "sdsds", "FastCGI: header too small:", buffer_string_length(packet->b), "bytes <", sizeof(FCGI_Header), "bytes, waiting for more data");
                 }                  }
   
                 buffer_free(packet->b);                  buffer_free(packet->b);
Line 2459  static int fastcgi_get_packet(server *srv, handler_ctx Line 2481  static int fastcgi_get_packet(server *srv, handler_ctx
         packet->padding = header->paddingLength;          packet->padding = header->paddingLength;
   
         /* ->b should only be the content */          /* ->b should only be the content */
        buffer_copy_string_len(packet->b, CONST_STR_LEN("")); /* used == 1 */        buffer_string_set_length(packet->b, 0);
   
         if (packet->len) {          if (packet->len) {
                 /* copy the content */                  /* copy the content */
                for (; c && (packet->b->used < packet->len + 1); c = c->next) {                for (; c && (buffer_string_length(packet->b) < packet->len); c = c->next) {
                        size_t weWant = packet->len - (packet->b->used - 1);                        size_t weWant = packet->len - buffer_string_length(packet->b);
                        size_t weHave = c->mem->used - c->offset - offset - 1;                        size_t weHave = buffer_string_length(c->mem) - c->offset - offset;
   
                         if (weHave > weWant) weHave = weWant;                          if (weHave > weWant) weHave = weWant;
   
Line 2475  static int fastcgi_get_packet(server *srv, handler_ctx Line 2497  static int fastcgi_get_packet(server *srv, handler_ctx
                         offset = 0;                          offset = 0;
                 }                  }
   
                if (packet->b->used < packet->len + 1) {                if (buffer_string_length(packet->b) < packet->len) {
                         /* we didn't get the full packet */                          /* we didn't get the full packet */
   
                         buffer_free(packet->b);                          buffer_free(packet->b);
                         return -1;                          return -1;
                 }                  }
   
                packet->b->used -= packet->padding;                buffer_string_set_length(packet->b, buffer_string_length(packet->b) - packet->padding);
                packet->b->ptr[packet->b->used - 1] = '\0'; 
         }          }
   
        /* tag the chunks as read */        chunkqueue_mark_written(hctx->rb, packet->len + sizeof(FCGI_Header));
        toread = packet->len + sizeof(FCGI_Header); 
        for (c = hctx->rb->first; c && toread; c = c->next) { 
                if (c->mem->used - c->offset - 1 <= toread) { 
                        /* we read this whole buffer, move it to unused */ 
                        toread -= c->mem->used - c->offset - 1; 
                        c->offset = c->mem->used - 1; /* everthing has been written */ 
                } else { 
                        c->offset += toread; 
                        toread = 0; 
                } 
        } 
   
         chunkqueue_remove_finished_chunks(hctx->rb);  
   
         return 0;          return 0;
 }  }
   
 static int fcgi_demux_response(server *srv, handler_ctx *hctx) {  static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
         int fin = 0;          int fin = 0;
        int toread;        int toread, ret;
        ssize_t r;        ssize_t r = 0;
   
         plugin_data *p    = hctx->plugin_data;          plugin_data *p    = hctx->plugin_data;
         connection *con   = hctx->remote_conn;          connection *con   = hctx->remote_conn;
Line 2518  static int fcgi_demux_response(server *srv, handler_ct Line 2526  static int fcgi_demux_response(server *srv, handler_ct
         /*          /*
          * check how much we have to read           * check how much we have to read
          */           */
         #if !defined(_WIN32) && !defined(__CYGWIN__)
         if (ioctl(hctx->fd, FIONREAD, &toread)) {          if (ioctl(hctx->fd, FIONREAD, &toread)) {
                if (errno == EAGAIN) return 0;                if (errno == EAGAIN) {
                         fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
                         return 0;
                 }
                 log_error_write(srv, __FILE__, __LINE__, "sd",                  log_error_write(srv, __FILE__, __LINE__, "sd",
                                 "unexpected end-of-file (perhaps the fastcgi process died):",                                  "unexpected end-of-file (perhaps the fastcgi process died):",
                                 fcgi_fd);                                  fcgi_fd);
                 return -1;                  return -1;
         }          }
         #else
           toread = 4096;
         #endif
   
         /* init read-buffer */  
   
         if (toread > 0) {          if (toread > 0) {
                buffer *b;                char *mem;
                chunk *cq_first = hctx->rb->first;                size_t mem_len;
                chunk *cq_last = hctx->rb->last; 
   
                b = chunkqueue_get_append_buffer(hctx->rb);                if ((con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN)) {
                buffer_prepare_copy(b, toread + 1);                        off_t cqlen = chunkqueue_length(hctx->rb);
                         if (cqlen + toread > 65536 + (int)sizeof(FCGI_Header)) { /*(max size of FastCGI packet + 1)*/
                                 if (cqlen < 65536 + (int)sizeof(FCGI_Header)) {
                                         toread = 65536 + (int)sizeof(FCGI_Header) - cqlen;
                                 } else { /* should not happen */
                                         toread = toread < 1024 ? toread : 1024;
                                 }
                         }
                 }
   
                /* append to read-buffer */                chunkqueue_get_memory(hctx->rb, &mem, &mem_len, 0, toread);
                if (-1 == (r = read(hctx->fd, b->ptr, toread))) {                r = read(hctx->fd, mem, mem_len);
                 chunkqueue_use_memory(hctx->rb, r > 0 ? r : 0);
 
                 if (-1 == r) {
                         if (errno == EAGAIN) {                          if (errno == EAGAIN) {
                                /* roll back the last chunk allocation,                                fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
                                   and continue on next iteration        */ 
                                buffer_free(hctx->rb->last->mem); 
                                free(hctx->rb->last); 
                                hctx->rb->first = cq_first; 
                                hctx->rb->last = cq_last; 
                                 return 0;                                  return 0;
                         }                          }
                         log_error_write(srv, __FILE__, __LINE__, "sds",                          log_error_write(srv, __FILE__, __LINE__, "sds",
Line 2552  static int fcgi_demux_response(server *srv, handler_ct Line 2570  static int fcgi_demux_response(server *srv, handler_ct
                                         fcgi_fd, strerror(errno));                                          fcgi_fd, strerror(errno));
                         return -1;                          return -1;
                 }                  }
        }
                /* this should be catched by the b > 0 above */        if (0 == r) {
                force_assert(r); 
 
                b->used = r + 1; /* one extra for the fake \0 */ 
                b->ptr[b->used - 1] = '\0'; 
        } else { 
                 log_error_write(srv, __FILE__, __LINE__, "ssdsb",                  log_error_write(srv, __FILE__, __LINE__, "ssdsb",
                                 "unexpected end-of-file (perhaps the fastcgi process died):",                                  "unexpected end-of-file (perhaps the fastcgi process died):",
                                 "pid:", proc->pid,                                  "pid:", proc->pid,
Line 2587  static int fcgi_demux_response(server *srv, handler_ct Line 2600  static int fcgi_demux_response(server *srv, handler_ct
                         /* is the header already finished */                          /* is the header already finished */
                         if (0 == con->file_started) {                          if (0 == con->file_started) {
                                 char *c;                                  char *c;
                                 size_t blen;  
                                 data_string *ds;                                  data_string *ds;
   
                                 /* search for header terminator                                  /* search for header terminator
Line 2598  static int fcgi_demux_response(server *srv, handler_ct Line 2610  static int fcgi_demux_response(server *srv, handler_ct
                                  * search for \n\n                                   * search for \n\n
                                  */                                   */
   
                                if (hctx->response_header->used == 0) {                                buffer_append_string_buffer(hctx->response_header, packet.b);
                                        buffer_copy_string_buffer(hctx->response_header, packet.b); 
                                } else { 
                                        buffer_append_string_buffer(hctx->response_header, packet.b); 
                                } 
   
                                 if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\r\n\r\n")))) {                                  if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\r\n\r\n")))) {
                                        blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 4;                                        char *hend = c + 4; /* header end == body start */
                                        hctx->response_header->used = (c - hctx->response_header->ptr) + 3;                                        size_t hlen = hend - hctx->response_header->ptr;
                                        c += 4; /* point the the start of the response */                                        buffer_copy_string_len(packet.b, hend, buffer_string_length(hctx->response_header) - hlen);
                                         buffer_string_set_length(hctx->response_header, hlen);
                                 } else if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\n\n")))) {                                  } else if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\n\n")))) {
                                        blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 2;                                        char *hend = c + 2; /* header end == body start */
                                        hctx->response_header->used = c - hctx->response_header->ptr + 2;                                        size_t hlen = hend - hctx->response_header->ptr;
                                        c += 2; /* point the the start of the response */                                        buffer_copy_string_len(packet.b, hend, buffer_string_length(hctx->response_header) - hlen);
                                         buffer_string_set_length(hctx->response_header, hlen);
                                 } else {                                  } else {
                                         /* no luck, no header found */                                          /* no luck, no header found */
                                           /*(reuse MAX_HTTP_REQUEST_HEADER as max size for response headers from backends)*/
                                           if (buffer_string_length(hctx->response_header) > MAX_HTTP_REQUEST_HEADER) {
                                                   log_error_write(srv, __FILE__, __LINE__, "sb", "response headers too large for", con->uri.path);
                                                   con->http_status = 502; /* Bad Gateway */
                                                   con->mode = DIRECT;
                                                   fin = 1;
                                           }
                                         break;                                          break;
                                 }                                  }
   
                                 /* parse the response header */                                  /* parse the response header */
                                if (fcgi_response_parse(srv, con, p, hctx->response_header)) {                                if ((ret = fcgi_response_parse(srv, con, p, hctx->response_header))) {
                                        con->http_status = 502;                                        if (200 != ret) { /*(200 returned for X-Sendfile2 handled)*/
                                        hctx->send_content_body = 0;                                                con->http_status = ret;
                                                 con->mode = DIRECT;
                                         }
                                         con->file_started = 1;                                          con->file_started = 1;
                                           hctx->send_content_body = 0;
                                           fin = 1;
                                         break;                                          break;
                                 }                                  }
   
Line 2634  static int fcgi_demux_response(server *srv, handler_ct Line 2655  static int fcgi_demux_response(server *srv, handler_ct
                                         hctx->send_content_body = 0;                                          hctx->send_content_body = 0;
                                 }                                  }
   
                                if (host->allow_xsendfile && hctx->send_content_body &&                                if (host->xsendfile_allow && hctx->send_content_body &&
                                     (NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file"))                                      (NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file"))
                                           || NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-Sendfile")))) {                                            || NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-Sendfile")))) {
                                        stat_cache_entry *sce;                                        http_response_xsendfile(srv, con, ds->value, host->xsendfile_docroot);
                                        if (con->mode == DIRECT) {
                                        if (HANDLER_ERROR != stat_cache_get_entry(srv, con, ds->value, &sce)) {                                                fin = 1;
                                                data_string *dcls; 
                                                if (NULL == (dcls = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) { 
                                                        dcls = data_response_init(); 
                                                } 
                                                /* found */ 
                                                http_chunk_append_file(srv, con, ds->value, 0, sce->st.st_size); 
                                                hctx->send_content_body = 0; /* ignore the content */ 
                                                joblist_append(srv, con); 
 
                                                buffer_copy_string_len(dcls->key, "Content-Length", sizeof("Content-Length")-1); 
                                                buffer_copy_off_t(dcls->value, sce->st.st_size); 
                                                dcls = (data_string*) array_replace(con->response.headers, (data_unset *)dcls); 
                                                if (dcls) dcls->free((data_unset*)dcls); 
 
                                                con->parsed_response |= HTTP_CONTENT_LENGTH; 
                                                con->response.content_length = sce->st.st_size; 
                                        } else { 
                                                log_error_write(srv, __FILE__, __LINE__, "sb", 
                                                        "send-file error: couldn't get stat_cache entry for:", 
                                                        ds->value); 
                                                con->http_status = 502; 
                                                hctx->send_content_body = 0; 
                                                con->file_started = 1; 
                                                break; 
                                         }                                          }
   
                                           hctx->send_content_body = 0; /* ignore the content */
                                           break;
                                 }                                  }
                           }
   
                        if (hctx->send_content_body && !buffer_string_is_empty(packet.b)) {
                                if (hctx->send_content_body && blen > 1) {                                if (0 != http_chunk_append_buffer(srv, con, packet.b)) {
                                        /* enable chunked-transfer-encoding */                                        /* error writing to tempfile;
                                        if (con->request.http_version == HTTP_VERSION_1_1 &&                                         * truncate response or send 500 if nothing sent yet */
                                            !(con->parsed_response & HTTP_CONTENT_LENGTH)) {                                        fin = 1;
                                                con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;                                        break;
                                 }
                                 if ((con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN)
                                     && chunkqueue_length(con->write_queue) > 65536 - 4096) {
                                         if (!con->is_writable) {
                                                 /*(defer removal of FDEVENT_IN interest since
                                                  * connection_state_machine() might be able to send data
                                                  * immediately, unless !con->is_writable, where
                                                  * connection_state_machine() might not loop back to call
                                                  * mod_fastcgi_handle_subrequest())*/
                                                 fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
                                         }                                          }
   
                                         http_chunk_append_mem(srv, con, c, blen);  
                                         joblist_append(srv, con);  
                                 }                                  }
                         } else if (hctx->send_content_body && packet.b->used > 1) {  
                                 if (con->request.http_version == HTTP_VERSION_1_1 &&  
                                     !(con->parsed_response & HTTP_CONTENT_LENGTH)) {  
                                         /* enable chunked-transfer-encoding */  
                                         con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;  
                                 }  
   
                                 http_chunk_append_mem(srv, con, packet.b->ptr, packet.b->used);  
                                 joblist_append(srv, con);  
                         }                          }
                         break;                          break;
                 case FCGI_STDERR:                  case FCGI_STDERR:
Line 2697  static int fcgi_demux_response(server *srv, handler_ct Line 2696  static int fcgi_demux_response(server *srv, handler_ct
   
                         break;                          break;
                 case FCGI_END_REQUEST:                  case FCGI_END_REQUEST:
                         con->file_finished = 1;  
   
                         if (host->mode != FCGI_AUTHORIZER ||  
                             !(con->http_status == 0 ||  
                               con->http_status == 200)) {  
                                 /* send chunk-end if necessary */  
                                 http_chunk_append_mem(srv, con, NULL, 0);  
                                 joblist_append(srv, con);  
                         }  
   
                         fin = 1;                          fin = 1;
                         break;                          break;
                 default:                  default:
Line 2820  static int fcgi_restart_dead_procs(server *srv, plugin Line 2809  static int fcgi_restart_dead_procs(server *srv, plugin
                         /* local procs get restarted by us,                          /* local procs get restarted by us,
                          * remote ones hopefully by the admin */                           * remote ones hopefully by the admin */
   
                        if (!buffer_is_empty(host->bin_path)) {                        if (!buffer_string_is_empty(host->bin_path)) {
                                 /* we still have connections bound to this proc,                                  /* we still have connections bound to this proc,
                                  * let them terminate first */                                   * let them terminate first */
                                 if (proc->load != 0) break;                                  if (proc->load != 0) break;
Line 2874  static handler_t fcgi_write_request(server *srv, handl Line 2863  static handler_t fcgi_write_request(server *srv, handl
                 log_error_write(srv, __FILE__, __LINE__, "s", "fatal error: host = NULL");                  log_error_write(srv, __FILE__, __LINE__, "s", "fatal error: host = NULL");
                 return HANDLER_ERROR;                  return HANDLER_ERROR;
         }          }
        if ((!host->port && !host->unixsocket->used)) {        if ((!host->port && buffer_string_is_empty(host->unixsocket))) {
                 log_error_write(srv, __FILE__, __LINE__, "s", "fatal error: neither host->port nor host->unixsocket is set");                  log_error_write(srv, __FILE__, __LINE__, "s", "fatal error: neither host->port nor host->unixsocket is set");
                 return HANDLER_ERROR;                  return HANDLER_ERROR;
         }          }
Line 2923  static handler_t fcgi_write_request(server *srv, handl Line 2912  static handler_t fcgi_write_request(server *srv, handl
         switch(hctx->state) {          switch(hctx->state) {
         case FCGI_STATE_CONNECT_DELAYED:          case FCGI_STATE_CONNECT_DELAYED:
                 /* should never happen */                  /* should never happen */
                break;                return HANDLER_WAIT_FOR_EVENT;
         case FCGI_STATE_INIT:          case FCGI_STATE_INIT:
                 /* do we have a running process for this host (max-procs) ? */                  /* do we have a running process for this host (max-procs) ? */
                 hctx->proc = NULL;                  hctx->proc = NULL;
Line 2947  static handler_t fcgi_write_request(server *srv, handl Line 2936  static handler_t fcgi_write_request(server *srv, handl
                         if (proc->load < hctx->proc->load) hctx->proc = proc;                          if (proc->load < hctx->proc->load) hctx->proc = proc;
                 }                  }
   
                ret = host->unixsocket->used ? AF_UNIX : AF_INET;                if (-1 == (hctx->fd = socket(host->family, SOCK_STREAM, 0))) {
 
                if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) { 
                         if (errno == EMFILE ||                          if (errno == EMFILE ||
                             errno == EINTR) {                              errno == EINTR) {
                                 log_error_write(srv, __FILE__, __LINE__, "sd",                                  log_error_write(srv, __FILE__, __LINE__, "sd",
Line 3066  static handler_t fcgi_write_request(server *srv, handl Line 3053  static handler_t fcgi_write_request(server *srv, handl
                                         "fcgi-request is already in use:", hctx->request_id);                                          "fcgi-request is already in use:", hctx->request_id);
                 }                  }
   
                 /* fall through */  
                 if (-1 == fcgi_create_env(srv, hctx, hctx->request_id)) return HANDLER_ERROR;                  if (-1 == fcgi_create_env(srv, hctx, hctx->request_id)) return HANDLER_ERROR;
   
                   fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
                 fcgi_set_state(srv, hctx, FCGI_STATE_WRITE);                  fcgi_set_state(srv, hctx, FCGI_STATE_WRITE);
                 /* fall through */                  /* fall through */
         case FCGI_STATE_WRITE:          case FCGI_STATE_WRITE:
Line 3098  static handler_t fcgi_write_request(server *srv, handl Line 3086  static handler_t fcgi_write_request(server *srv, handl
                         }                          }
                 }                  }
   
                if (hctx->wb->bytes_out == hctx->wb->bytes_in) {                if (hctx->wb->bytes_out == hctx->wb_reqlen) {
                        /* we don't need the out event anymore */                        fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
                        fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd); 
                        fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); 
                         fcgi_set_state(srv, hctx, FCGI_STATE_READ);                          fcgi_set_state(srv, hctx, FCGI_STATE_READ);
                 } else {                  } else {
                        fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);                        off_t wblen = hctx->wb->bytes_in - hctx->wb->bytes_out;
                        if (hctx->wb->bytes_in < hctx->wb_reqlen && wblen < 65536 - 16384) {
                        return HANDLER_WAIT_FOR_EVENT;                                /*(con->conf.stream_request_body & FDEVENT_STREAM_REQUEST)*/
                                 if (!(con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_POLLIN)) {
                                         con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLIN;
                                         con->is_readable = 1; /* trigger optimistic read from client */
                                 }
                         }
                         if (0 == wblen) {
                                 fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
                         } else {
                                 fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
                         }
                 }                  }
   
                break;                return HANDLER_WAIT_FOR_EVENT;
         case FCGI_STATE_READ:          case FCGI_STATE_READ:
                 /* waiting for a response */                  /* waiting for a response */
                break;                return HANDLER_WAIT_FOR_EVENT;
         default:          default:
                 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");                  log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
                 return HANDLER_ERROR;                  return HANDLER_ERROR;
         }          }
   
         return HANDLER_WAIT_FOR_EVENT;  
 }  }
   
   
 /* might be called on fdevent after a connect() is delay too  /* might be called on fdevent after a connect() is delay too
  * */   * */
SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {static handler_t fcgi_send_request(server *srv, handler_ctx *hctx) {
        plugin_data *p = p_d; 
 
        handler_ctx *hctx = con->plugin_ctx[p->id]; 
         fcgi_extension_host *host;          fcgi_extension_host *host;
           handler_t rc;
   
         if (NULL == hctx) return HANDLER_GO_ON;  
   
         /* not my job */  
         if (con->mode != p->id) return HANDLER_GO_ON;  
   
         /* we don't have a host yet, choose one          /* we don't have a host yet, choose one
          * -> this happens in the first round           * -> this happens in the first round
          *    and when the host died and we have to select a new one */           *    and when the host died and we have to select a new one */
Line 3168  SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) { Line 3155  SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
   
                         fcgi_connection_close(srv, hctx);                          fcgi_connection_close(srv, hctx);
   
                         con->http_status = 500;  
                         con->mode = DIRECT;  
   
                         return HANDLER_FINISHED;                          return HANDLER_FINISHED;
                 }                  }
   
Line 3194  SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) { Line 3178  SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
         }          }
   
         /* ok, create the request */          /* ok, create the request */
        switch(fcgi_write_request(srv, hctx)) {        rc = fcgi_write_request(srv, hctx);
        case HANDLER_ERROR:        if (HANDLER_ERROR != rc) {
                 return rc;
         } else {
                 plugin_data *p  = hctx->plugin_data;
                 connection *con = hctx->remote_conn;
 
                 if (hctx->state == FCGI_STATE_INIT ||                  if (hctx->state == FCGI_STATE_INIT ||
                     hctx->state == FCGI_STATE_CONNECT_DELAYED) {                      hctx->state == FCGI_STATE_CONNECT_DELAYED) {
                         fcgi_restart_dead_procs(srv, p, host);                          fcgi_restart_dead_procs(srv, p, host);
Line 3203  SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) { Line 3192  SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
                         /* cleanup this request and let the request handler start this request again */                          /* cleanup this request and let the request handler start this request again */
                         if (hctx->reconnects < 5) {                          if (hctx->reconnects < 5) {
                                 fcgi_reconnect(srv, hctx);                                  fcgi_reconnect(srv, hctx);
                                 joblist_append(srv, con); /* in case we come from the event-handler */  
   
                                return HANDLER_WAIT_FOR_FD;                                return HANDLER_COMEBACK;
                         } else {                          } else {
                                 fcgi_connection_close(srv, hctx);                                  fcgi_connection_close(srv, hctx);
   
                                 buffer_reset(con->physical.path);  
                                 con->mode = DIRECT;  
                                 con->http_status = 503;                                  con->http_status = 503;
                                 joblist_append(srv, con); /* in case we come from the event-handler */  
   
                                 return HANDLER_FINISHED;                                  return HANDLER_FINISHED;
                         }                          }
                 } else {                  } else {
                           int status = con->http_status;
                         fcgi_connection_close(srv, hctx);                          fcgi_connection_close(srv, hctx);
                           con->http_status = (status == 400) ? 400 : 503; /* see FCGI_ENV_ADD_CHECK() for 400 error */
   
                         buffer_reset(con->physical.path);  
                         con->mode = DIRECT;  
                         if (con->http_status != 400) con->http_status = 503;  
                         joblist_append(srv, con); /* really ? */  
   
                         return HANDLER_FINISHED;                          return HANDLER_FINISHED;
                 }                  }
        case HANDLER_WAIT_FOR_EVENT:        }
                if (con->file_started == 1) {}
                        return HANDLER_FINISHED;
 
 static handler_t fcgi_recv_response(server *srv, handler_ctx *hctx);
 
 
 SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
         plugin_data *p = p_d;
 
         handler_ctx *hctx = con->plugin_ctx[p->id];
 
         if (NULL == hctx) return HANDLER_GO_ON;
 
         /* not my job */
         if (con->mode != p->id) return HANDLER_GO_ON;
 
         if ((con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN)
             && con->file_started) {
                 if (chunkqueue_length(con->write_queue) > 65536 - 4096) {
                         fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
                 } else if (!(fdevent_event_get_interest(srv->ev, hctx->fd) & FDEVENT_IN)) {
                         /* optimistic read from backend, which might re-enable FDEVENT_IN */
                         handler_t rc = fcgi_recv_response(srv, hctx); /*(might invalidate hctx)*/
                         if (rc != HANDLER_GO_ON) return rc;           /*(unless HANDLER_GO_ON)*/
                 }
         }
 
         if (0 == hctx->wb->bytes_in
             ? con->state == CON_STATE_READ_POST
             : hctx->wb->bytes_in < hctx->wb_reqlen) {
                 /*(64k - 4k to attempt to avoid temporary files
                  * in conjunction with FDEVENT_STREAM_REQUEST_BUFMIN)*/
                 if (hctx->wb->bytes_in - hctx->wb->bytes_out > 65536 - 4096
                     && (con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_BUFMIN)){
                         con->conf.stream_request_body &= ~FDEVENT_STREAM_REQUEST_POLLIN;
                         if (0 != hctx->wb->bytes_in) return HANDLER_WAIT_FOR_EVENT;
                 } else {                  } else {
                        return HANDLER_WAIT_FOR_EVENT;                        handler_t r = connection_handle_read_post_state(srv, con);
                         chunkqueue *req_cq = con->request_content_queue;
                         if (0 != hctx->wb->bytes_in && !chunkqueue_is_empty(req_cq)) {
                                 fcgi_stdin_append(srv, con, hctx, hctx->request_id);
                                 if (fdevent_event_get_interest(srv->ev, hctx->fd) & FDEVENT_OUT) {
                                         return (r == HANDLER_GO_ON) ? HANDLER_WAIT_FOR_EVENT : r;
                                 }
                         }
                         if (r != HANDLER_GO_ON) return r;
                 }                  }
         case HANDLER_WAIT_FOR_FD:  
                 return HANDLER_WAIT_FOR_FD;  
         default:  
                 log_error_write(srv, __FILE__, __LINE__, "s", "subrequest write-req default");  
                 return HANDLER_ERROR;  
         }          }
   
           return ((0 == hctx->wb->bytes_in || !chunkqueue_is_empty(hctx->wb))
                   && hctx->state != FCGI_STATE_CONNECT_DELAYED)
             ? fcgi_send_request(srv, hctx)
             : HANDLER_WAIT_FOR_EVENT;
 }  }
   
static handler_t fcgi_handle_fdevent(server *srv, void *ctx, int revents) {
        handler_ctx *hctx = ctx;static handler_t fcgi_recv_response(server *srv, handler_ctx *hctx) {
         connection  *con  = hctx->remote_conn;          connection  *con  = hctx->remote_conn;
         plugin_data *p    = hctx->plugin_data;          plugin_data *p    = hctx->plugin_data;
   
         fcgi_proc *proc   = hctx->proc;          fcgi_proc *proc   = hctx->proc;
         fcgi_extension_host *host= hctx->host;          fcgi_extension_host *host= hctx->host;
   
         if ((revents & FDEVENT_IN) &&  
             hctx->state == FCGI_STATE_READ) {  
                 switch (fcgi_demux_response(srv, hctx)) {                  switch (fcgi_demux_response(srv, hctx)) {
                 case 0:                  case 0:
                         break;                          break;
Line 3264  static handler_t fcgi_handle_fdevent(server *srv, void Line 3285  static handler_t fcgi_handle_fdevent(server *srv, void
                                  * now to handle authorized request.                                   * now to handle authorized request.
                                  */                                   */
   
                                buffer_copy_string_buffer(con->physical.doc_root, host->docroot);                                buffer_copy_buffer(con->physical.doc_root, host->docroot);
                                buffer_copy_string_buffer(con->physical.basedir, host->docroot);                                buffer_copy_buffer(con->physical.basedir, host->docroot);
   
                                buffer_copy_string_buffer(con->physical.path, host->docroot);                                buffer_copy_buffer(con->physical.path, host->docroot);
                                 buffer_append_string_buffer(con->physical.path, con->uri.path);                                  buffer_append_string_buffer(con->physical.path, con->uri.path);
                                 fcgi_connection_close(srv, hctx);  
   
                                con->mode = DIRECT;                                con->mode = DIRECT;/*(avoid changing con->state, con->http_status)*/
                                 fcgi_connection_close(srv, hctx);
                                 con->http_status = 0;                                  con->http_status = 0;
                                 con->file_started = 1; /* fcgi_extension won't touch the request afterwards */                                  con->file_started = 1; /* fcgi_extension won't touch the request afterwards */
                         } else {                          } else {
Line 3279  static handler_t fcgi_handle_fdevent(server *srv, void Line 3300  static handler_t fcgi_handle_fdevent(server *srv, void
                                 fcgi_connection_close(srv, hctx);                                  fcgi_connection_close(srv, hctx);
                         }                          }
   
                         joblist_append(srv, con);  
                         return HANDLER_FINISHED;                          return HANDLER_FINISHED;
                 case -1:                  case -1:
                         if (proc->pid && proc->state != PROC_STATE_DIED) {                          if (proc->pid && proc->state != PROC_STATE_DIED) {
Line 3333  static handler_t fcgi_handle_fdevent(server *srv, void Line 3353  static handler_t fcgi_handle_fdevent(server *srv, void
   
                                 if (hctx->wb->bytes_out == 0 &&                                  if (hctx->wb->bytes_out == 0 &&
                                     hctx->reconnects < 5) {                                      hctx->reconnects < 5) {
                                         fcgi_reconnect(srv, hctx);  
   
                                         log_error_write(srv, __FILE__, __LINE__, "ssbsBSBs",                                          log_error_write(srv, __FILE__, __LINE__, "ssbsBSBs",
                                                 "response not received, request not sent",                                                  "response not received, request not sent",
                                                 "on socket:", proc->connection_name,                                                  "on socket:", proc->connection_name,
                                                 "for", con->uri.path, "?", con->uri.query, ", reconnecting");                                                  "for", con->uri.path, "?", con->uri.query, ", reconnecting");
   
                                        return HANDLER_WAIT_FOR_FD;                                        fcgi_reconnect(srv, hctx);
 
                                         return HANDLER_COMEBACK;
                                 }                                  }
   
                                 log_error_write(srv, __FILE__, __LINE__, "sosbsBSBs",                                  log_error_write(srv, __FILE__, __LINE__, "sosbsBSBs",
                                                 "response not received, request sent:", hctx->wb->bytes_out,                                                  "response not received, request sent:", hctx->wb->bytes_out,
                                                 "on socket:", proc->connection_name,                                                  "on socket:", proc->connection_name,
                                                 "for", con->uri.path, "?", con->uri.query, ", closing connection");                                                  "for", con->uri.path, "?", con->uri.query, ", closing connection");
   
                                 fcgi_connection_close(srv, hctx);  
   
                                 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);  
                                 buffer_reset(con->physical.path);  
                                 con->http_status = 500;  
                                 con->mode = DIRECT;  
                         } else {                          } else {
                                 /* response might have been already started, kill the connection */  
                                 fcgi_connection_close(srv, hctx);  
   
                                 log_error_write(srv, __FILE__, __LINE__, "ssbsBSBs",                                  log_error_write(srv, __FILE__, __LINE__, "ssbsBSBs",
                                                 "response already sent out, but backend returned error",                                                  "response already sent out, but backend returned error",
                                                 "on socket:", proc->connection_name,                                                  "on socket:", proc->connection_name,
                                                 "for", con->uri.path, "?", con->uri.query, ", terminating connection");                                                  "for", con->uri.path, "?", con->uri.query, ", terminating connection");
   
                                 connection_set_state(srv, con, CON_STATE_ERROR);  
                         }                          }
   
                        /* */                        http_response_backend_error(srv, con);
                        fcgi_connection_close(srv, hctx);
 
                        joblist_append(srv, con); 
                         return HANDLER_FINISHED;                          return HANDLER_FINISHED;
                 }                  }
   
                   return HANDLER_GO_ON;
   }
   
   
   static handler_t fcgi_handle_fdevent(server *srv, void *ctx, int revents) {
           handler_ctx *hctx = ctx;
           connection  *con  = hctx->remote_conn;
   
           joblist_append(srv, con);
   
           if (revents & FDEVENT_IN) {
                   handler_t rc = fcgi_recv_response(srv, hctx);/*(might invalidate hctx)*/
                   if (rc != HANDLER_GO_ON) return rc;          /*(unless HANDLER_GO_ON)*/
         }          }
   
         if (revents & FDEVENT_OUT) {          if (revents & FDEVENT_OUT) {
                if (hctx->state == FCGI_STATE_CONNECT_DELAYED ||                return fcgi_send_request(srv, hctx); /*(might invalidate hctx)*/
                    hctx->state == FCGI_STATE_WRITE) { 
                        /* we are allowed to send something out 
                         * 
                         * 1. in an unfinished connect() call 
                         * 2. in an unfinished write() call (long POST request) 
                         */ 
                        return mod_fastcgi_handle_subrequest(srv, con, p); 
                } else { 
                        log_error_write(srv, __FILE__, __LINE__, "sd", 
                                        "got a FDEVENT_OUT and didn't know why:", 
                                        hctx->state); 
                } 
         }          }
   
         /* perhaps this issue is already handled */          /* perhaps this issue is already handled */
Line 3402  static handler_t fcgi_handle_fdevent(server *srv, void Line 3411  static handler_t fcgi_handle_fdevent(server *srv, void
                          * FIXME: as it is a bit ugly.                           * FIXME: as it is a bit ugly.
                          *                           *
                          */                           */
                        return mod_fastcgi_handle_subrequest(srv, con, p);                        fcgi_send_request(srv, hctx);
                } else if (hctx->state == FCGI_STATE_READ &&                } else if (con->file_started) {
                           hctx->proc->port == 0) {                        /* drain any remaining data from kernel pipe buffers
                        /* FIXME:                         * even if (con->conf.stream_response_body
                         *                         *          & FDEVENT_STREAM_RESPONSE_BUFMIN)
                         * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket                         * since event loop will spin on fd FDEVENT_HUP event
                         * even if the FCGI_FIN packet is not received yet                         * until unregistered. */
                         */                        handler_t rc;
                         do {
                                 rc = fcgi_recv_response(srv,hctx);/*(might invalidate hctx)*/
                         } while (rc == HANDLER_GO_ON);            /*(unless HANDLER_GO_ON)*/
                         return rc; /* HANDLER_FINISHED or HANDLER_ERROR */
                 } else {                  } else {
                           fcgi_proc *proc = hctx->proc;
                         log_error_write(srv, __FILE__, __LINE__, "sBSbsbsd",                          log_error_write(srv, __FILE__, __LINE__, "sBSbsbsd",
                                         "error: unexpected close of fastcgi connection for",                                          "error: unexpected close of fastcgi connection for",
                                         con->uri.path, "?", con->uri.query,                                          con->uri.path, "?", con->uri.query,
                                         "(no fastcgi process on socket:", proc->connection_name, "?)",                                          "(no fastcgi process on socket:", proc->connection_name, "?)",
                                         hctx->state);                                          hctx->state);
   
                         connection_set_state(srv, con, CON_STATE_ERROR);  
                         fcgi_connection_close(srv, hctx);                          fcgi_connection_close(srv, hctx);
                         joblist_append(srv, con);  
                 }                  }
         } else if (revents & FDEVENT_ERR) {          } else if (revents & FDEVENT_ERR) {
                 log_error_write(srv, __FILE__, __LINE__, "s",                  log_error_write(srv, __FILE__, __LINE__, "s",
                                 "fcgi: got a FDEVENT_ERR. Don't know why.");                                  "fcgi: got a FDEVENT_ERR. Don't know why.");
                 /* kill all connections to the fastcgi process */  
   
                http_response_backend_error(srv, con);
                connection_set_state(srv, con, CON_STATE_ERROR); 
                 fcgi_connection_close(srv, hctx);                  fcgi_connection_close(srv, hctx);
                 joblist_append(srv, con);  
         }          }
   
         return HANDLER_FINISHED;          return HANDLER_FINISHED;
 }  }
   
 #define PATCH(x) \  #define PATCH(x) \
         p->conf.x = s->x;          p->conf.x = s->x;
 static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {  static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {
Line 3486  static handler_t fcgi_check_extension(server *srv, con Line 3496  static handler_t fcgi_check_extension(server *srv, con
   
         fn = uri_path_handler ? con->uri.path : con->physical.path;          fn = uri_path_handler ? con->uri.path : con->physical.path;
   
        if (buffer_is_empty(fn)) return HANDLER_GO_ON;        if (buffer_string_is_empty(fn)) return HANDLER_GO_ON;
   
        s_len = fn->used - 1;        s_len = buffer_string_length(fn);
   
         fcgi_patch_connection(srv, con, p);          fcgi_patch_connection(srv, con, p);
   
Line 3505  static handler_t fcgi_check_extension(server *srv, con Line 3515  static handler_t fcgi_check_extension(server *srv, con
                 data_string *ds = (data_string *)p->conf.ext_mapping->data[k];                  data_string *ds = (data_string *)p->conf.ext_mapping->data[k];
                 size_t ct_len; /* length of the config entry */                  size_t ct_len; /* length of the config entry */
   
                if (ds->key->used == 0) continue;                if (buffer_is_empty(ds->key)) continue;
   
                ct_len = ds->key->used - 1;                ct_len = buffer_string_length(ds->key);
   
                 if (s_len < ct_len) continue;                  if (s_len < ct_len) continue;
   
Line 3533  static handler_t fcgi_check_extension(server *srv, con Line 3543  static handler_t fcgi_check_extension(server *srv, con
         }          }
   
         if (extension == NULL) {          if (extension == NULL) {
                   size_t uri_path_len = buffer_string_length(con->uri.path);
   
                 /* check if extension matches */                  /* check if extension matches */
                 for (k = 0; k < p->conf.exts->used; k++) {                  for (k = 0; k < p->conf.exts->used; k++) {
                         size_t ct_len; /* length of the config entry */                          size_t ct_len; /* length of the config entry */
                         fcgi_extension *ext = p->conf.exts->exts[k];                          fcgi_extension *ext = p->conf.exts->exts[k];
   
                        if (ext->key->used == 0) continue;                        if (buffer_is_empty(ext->key)) continue;
   
                        ct_len = ext->key->used - 1;                        ct_len = buffer_string_length(ext->key);
   
                         /* check _url_ in the form "/fcgi_pattern" */                          /* check _url_ in the form "/fcgi_pattern" */
                         if (ext->key->ptr[0] == '/') {                          if (ext->key->ptr[0] == '/') {
                                if ((ct_len <= con->uri.path->used -1) &&                                if ((ct_len <= uri_path_len) &&
                                     (strncmp(con->uri.path->ptr, ext->key->ptr, ct_len) == 0)) {                                      (strncmp(con->uri.path->ptr, ext->key->ptr, ct_len) == 0)) {
                                         extension = ext;                                          extension = ext;
                                         break;                                          break;
Line 3577  static handler_t fcgi_check_extension(server *srv, con Line 3589  static handler_t fcgi_check_extension(server *srv, con
   
         if (!host) {          if (!host) {
                 /* sorry, we don't have a server alive for this ext */                  /* sorry, we don't have a server alive for this ext */
                 buffer_reset(con->physical.path);  
                 con->http_status = 500;                  con->http_status = 500;
                   con->mode = DIRECT;
   
                 /* only send the 'no handler' once */                  /* only send the 'no handler' once */
                 if (!extension->note_is_sent) {                  if (!extension->note_is_sent) {
Line 3659  static handler_t fcgi_check_extension(server *srv, con Line 3671  static handler_t fcgi_check_extension(server *srv, con
                                 /* the rewrite is only done for /prefix/? matches */                                  /* the rewrite is only done for /prefix/? matches */
                                 if (host->fix_root_path_name && extension->key->ptr[0] == '/' && extension->key->ptr[1] == '\0') {                                  if (host->fix_root_path_name && extension->key->ptr[0] == '/' && extension->key->ptr[1] == '\0') {
                                         buffer_copy_string(con->request.pathinfo, con->uri.path->ptr);                                          buffer_copy_string(con->request.pathinfo, con->uri.path->ptr);
                                        con->uri.path->used = 1;                                        buffer_string_set_length(con->uri.path, 0);
                                        con->uri.path->ptr[con->uri.path->used - 1] = '\0'; 
                                 } else if (extension->key->ptr[0] == '/' &&                                  } else if (extension->key->ptr[0] == '/' &&
                                        con->uri.path->used > extension->key->used &&                                        buffer_string_length(con->uri.path) > buffer_string_length(extension->key) &&
                                        NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {                                        NULL != (pathinfo = strchr(con->uri.path->ptr + buffer_string_length(extension->key), '/'))) {
                                         /* rewrite uri.path and pathinfo */                                          /* rewrite uri.path and pathinfo */
   
                                         buffer_copy_string(con->request.pathinfo, pathinfo);                                          buffer_copy_string(con->request.pathinfo, pathinfo);
                                        buffer_string_set_length(con->uri.path, buffer_string_length(con->uri.path) - buffer_string_length(con->request.pathinfo));
                                        con->uri.path->used -= con->request.pathinfo->used - 1; 
                                        con->uri.path->ptr[con->uri.path->used - 1] = '\0'; 
                                 }                                  }
                         }                          }
                 }                  }
Line 3707  static handler_t fcgi_check_extension_2(server *srv, c Line 3716  static handler_t fcgi_check_extension_2(server *srv, c
         return fcgi_check_extension(srv, con, p_d, 0);          return fcgi_check_extension(srv, con, p_d, 0);
 }  }
   
 JOBLIST_FUNC(mod_fastcgi_handle_joblist) {  
         plugin_data *p = p_d;  
         handler_ctx *hctx = con->plugin_ctx[p->id];  
   
         if (hctx == NULL) return HANDLER_GO_ON;  
   
         if (hctx->fd != -1) {  
                 switch (hctx->state) {  
                 case FCGI_STATE_READ:  
                         fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);  
   
                         break;  
                 case FCGI_STATE_CONNECT_DELAYED:  
                 case FCGI_STATE_WRITE:  
                         fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);  
   
                         break;  
                 case FCGI_STATE_INIT:  
                         /* at reconnect */  
                         break;  
                 default:  
                         log_error_write(srv, __FILE__, __LINE__, "sd", "unhandled fcgi.state", hctx->state);  
                         break;  
                 }  
         }  
   
         return HANDLER_GO_ON;  
 }  
   
   
 static handler_t fcgi_connection_close_callback(server *srv, connection *con, void *p_d) {  
         plugin_data *p = p_d;  
   
         fcgi_connection_close(srv, con->plugin_ctx[p->id]);  
   
         return HANDLER_GO_ON;  
 }  
   
 TRIGGER_FUNC(mod_fastcgi_handle_trigger) {  TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
         plugin_data *p = p_d;          plugin_data *p = p_d;
         size_t i, j, n;          size_t i, j, n;
Line 3849  int mod_fastcgi_plugin_init(plugin *p) { Line 3821  int mod_fastcgi_plugin_init(plugin *p) {
         p->cleanup      = mod_fastcgi_free;          p->cleanup      = mod_fastcgi_free;
         p->set_defaults = mod_fastcgi_set_defaults;          p->set_defaults = mod_fastcgi_set_defaults;
         p->connection_reset        = fcgi_connection_reset;          p->connection_reset        = fcgi_connection_reset;
        p->handle_connection_close = fcgi_connection_close_callback;        p->handle_connection_close = fcgi_connection_reset;
         p->handle_uri_clean        = fcgi_check_extension_1;          p->handle_uri_clean        = fcgi_check_extension_1;
         p->handle_subrequest_start = fcgi_check_extension_2;          p->handle_subrequest_start = fcgi_check_extension_2;
         p->handle_subrequest       = mod_fastcgi_handle_subrequest;          p->handle_subrequest       = mod_fastcgi_handle_subrequest;
         p->handle_joblist          = mod_fastcgi_handle_joblist;  
         p->handle_trigger          = mod_fastcgi_handle_trigger;          p->handle_trigger          = mod_fastcgi_handle_trigger;
   
         p->data         = NULL;          p->data         = NULL;

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.3


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>