Diff for /embedaddon/lighttpd/src/mod_scgi.c between versions 1.1 and 1.1.1.3

version 1.1, 2013/10/14 10:32:47 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 25 Line 27
   
 #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 39 Line 37
 # include <sys/wait.h>  # include <sys/wait.h>
 #endif  #endif
   
 #include "version.h"  
   
 enum {EOL_UNSET, EOL_N, EOL_RN};  enum {EOL_UNSET, EOL_N, EOL_RN};
   
 /*  /*
Line 148  typedef struct { Line 144  typedef struct {
          */           */
         buffer *host;          buffer *host;
         unsigned short port;          unsigned short port;
           sa_family_t family;
   
         /*          /*
          * Unix Domain Socket           * Unix Domain Socket
Line 214  typedef struct { Line 211  typedef struct {
          */           */
   
         unsigned short fix_root_path_name;          unsigned short fix_root_path_name;
   
           /*
            * If the backend includes X-Sendfile in the response
            * we use the value as filename and ignore the content.
            *
            */
           unsigned short xsendfile_allow;
           array *xsendfile_docroot;
   
         ssize_t load; /* replace by host->load */          ssize_t load; /* replace by host->load */
   
         size_t max_id; /* corresponds most of the time to          size_t max_id; /* corresponds most of the time to
Line 221  typedef struct { Line 227  typedef struct {
   
         only if a process is killed max_id waits for the process itself          only if a process is killed max_id waits for the process itself
         to die and decrements its afterwards */          to die and decrements its afterwards */
   
           int listen_backlog;
           int refcount;
 } scgi_extension_host;  } scgi_extension_host;
   
 /*  /*
Line 294  typedef enum { FCGI_STATE_INIT, FCGI_STATE_CONNECT, FC Line 303  typedef enum { FCGI_STATE_INIT, FCGI_STATE_CONNECT, FC
   
 typedef struct {  typedef struct {
         buffer  *response;          buffer  *response;
         size_t   response_len;  
         int      response_type;  
         int      response_padding;  
   
         scgi_proc *proc;          scgi_proc *proc;
         scgi_extension_host *host;          scgi_extension_host *host;
Line 304  typedef struct { Line 310  typedef struct {
         scgi_connection_state_t state;          scgi_connection_state_t state;
         time_t   state_timestamp;          time_t   state_timestamp;
   
         int      reconnects; /* number of reconnect attempts */  
   
         read_buffer *rb;  
         chunkqueue *wb;          chunkqueue *wb;
           off_t     wb_reqlen;
   
         buffer   *response_header;          buffer   *response_header;
   
         int       delayed;   /* flag to mark that the connect() is delayed */  
   
         size_t    request_id;  
         int       fd;        /* fd to the scgi process */          int       fd;        /* fd to the scgi 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 */
   
         plugin_config conf;          plugin_config conf;
   
Line 351  static handler_ctx * handler_ctx_init(void) { Line 353  static handler_ctx * handler_ctx_init(void) {
         handler_ctx * hctx;          handler_ctx * hctx;
   
         hctx = calloc(1, sizeof(*hctx));          hctx = calloc(1, sizeof(*hctx));
        assert(hctx);        force_assert(hctx);
   
         hctx->fde_ndx = -1;          hctx->fde_ndx = -1;
   
         hctx->response = buffer_init();          hctx->response = buffer_init();
         hctx->response_header = buffer_init();          hctx->response_header = buffer_init();
   
         hctx->request_id = 0;  
         hctx->state = FCGI_STATE_INIT;          hctx->state = FCGI_STATE_INIT;
         hctx->proc = NULL;          hctx->proc = NULL;
   
         hctx->response_len = 0;  
         hctx->response_type = 0;  
         hctx->response_padding = 0;  
         hctx->fd = -1;          hctx->fd = -1;
   
         hctx->reconnects = 0;          hctx->reconnects = 0;
   
         hctx->wb = chunkqueue_init();          hctx->wb = chunkqueue_init();
           hctx->wb_reqlen = 0;
   
         return hctx;          return hctx;
 }  }
Line 380  static void handler_ctx_free(handler_ctx *hctx) { Line 379  static void handler_ctx_free(handler_ctx *hctx) {
   
         chunkqueue_free(hctx->wb);          chunkqueue_free(hctx->wb);
   
         if (hctx->rb) {  
                 if (hctx->rb->ptr) free(hctx->rb->ptr);  
                 free(hctx->rb);  
         }  
   
         free(hctx);          free(hctx);
 }  }
   
Line 392  static scgi_proc *scgi_process_init(void) { Line 386  static scgi_proc *scgi_process_init(void) {
         scgi_proc *f;          scgi_proc *f;
   
         f = calloc(1, sizeof(*f));          f = calloc(1, sizeof(*f));
           force_assert(f);
         f->socket = buffer_init();          f->socket = buffer_init();
   
         f->prev = NULL;          f->prev = NULL;
Line 421  static scgi_extension_host *scgi_host_init(void) { Line 416  static scgi_extension_host *scgi_host_init(void) {
         f->bin_path = buffer_init();          f->bin_path = buffer_init();
         f->bin_env = array_init();          f->bin_env = array_init();
         f->bin_env_copy = array_init();          f->bin_env_copy = array_init();
           f->xsendfile_docroot = array_init();
   
         return f;          return f;
 }  }
   
 static void scgi_host_free(scgi_extension_host *h) {  static void scgi_host_free(scgi_extension_host *h) {
         if (!h) return;          if (!h) return;
           if (h->refcount) {
                   --h->refcount;
                   return;
           }
   
         buffer_free(h->host);          buffer_free(h->host);
         buffer_free(h->unixsocket);          buffer_free(h->unixsocket);
Line 434  static void scgi_host_free(scgi_extension_host *h) { Line 434  static void scgi_host_free(scgi_extension_host *h) {
         buffer_free(h->bin_path);          buffer_free(h->bin_path);
         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);
   
         scgi_process_free(h->first);          scgi_process_free(h->first);
         scgi_process_free(h->unused_procs);          scgi_process_free(h->unused_procs);
Line 446  static scgi_exts *scgi_extensions_init(void) { Line 447  static scgi_exts *scgi_extensions_init(void) {
         scgi_exts *f;          scgi_exts *f;
   
         f = calloc(1, sizeof(*f));          f = calloc(1, sizeof(*f));
           force_assert(f);
   
         return f;          return f;
 }  }
Line 495  static int scgi_extension_insert(scgi_exts *ext, buffe Line 497  static int scgi_extension_insert(scgi_exts *ext, buffe
         if (i == ext->used) {          if (i == ext->used) {
                 /* filextension is new */                  /* filextension is new */
                 fe = calloc(1, sizeof(*fe));                  fe = calloc(1, sizeof(*fe));
                assert(fe);                force_assert(fe);
                 fe->key = buffer_init();                  fe->key = buffer_init();
                buffer_copy_string_buffer(fe->key, key);                buffer_copy_buffer(fe->key, key);
   
                 /* */                  /* */
   
                 if (ext->size == 0) {                  if (ext->size == 0) {
                         ext->size = 8;                          ext->size = 8;
                         ext->exts = malloc(ext->size * sizeof(*(ext->exts)));                          ext->exts = malloc(ext->size * sizeof(*(ext->exts)));
                        assert(ext->exts);                        force_assert(ext->exts);
                 } else if (ext->used == ext->size) {                  } else if (ext->used == ext->size) {
                         ext->size += 8;                          ext->size += 8;
                         ext->exts = realloc(ext->exts, ext->size * sizeof(*(ext->exts)));                          ext->exts = realloc(ext->exts, ext->size * sizeof(*(ext->exts)));
                        assert(ext->exts);                        force_assert(ext->exts);
                 }                  }
                 ext->exts[ext->used++] = fe;                  ext->exts[ext->used++] = fe;
         } else {          } else {
Line 518  static int scgi_extension_insert(scgi_exts *ext, buffe Line 520  static int scgi_extension_insert(scgi_exts *ext, buffe
         if (fe->size == 0) {          if (fe->size == 0) {
                 fe->size = 4;                  fe->size = 4;
                 fe->hosts = malloc(fe->size * sizeof(*(fe->hosts)));                  fe->hosts = malloc(fe->size * sizeof(*(fe->hosts)));
                assert(fe->hosts);                force_assert(fe->hosts);
         } else if (fe->size == fe->used) {          } else if (fe->size == fe->used) {
                 fe->size += 4;                  fe->size += 4;
                 fe->hosts = realloc(fe->hosts, fe->size * sizeof(*(fe->hosts)));                  fe->hosts = realloc(fe->hosts, fe->size * sizeof(*(fe->hosts)));
                assert(fe->hosts);                force_assert(fe->hosts);
         }          }
   
         fe->hosts[fe->used++] = fh;          fe->hosts[fe->used++] = fh;
Line 535  INIT_FUNC(mod_scgi_init) { Line 537  INIT_FUNC(mod_scgi_init) {
         plugin_data *p;          plugin_data *p;
   
         p = calloc(1, sizeof(*p));          p = calloc(1, sizeof(*p));
           force_assert(p);
   
         p->scgi_env = buffer_init();          p->scgi_env = buffer_init();
   
Line 560  FREE_FUNC(mod_scgi_free) { Line 563  FREE_FUNC(mod_scgi_free) {
                         plugin_config *s = p->config_storage[i];                          plugin_config *s = p->config_storage[i];
                         scgi_exts *exts;                          scgi_exts *exts;
   
                        if (!s) continue;                        if (NULL == s) continue;
   
                         exts = s->exts;                          exts = s->exts;
   
Line 579  FREE_FUNC(mod_scgi_free) { Line 582  FREE_FUNC(mod_scgi_free) {
                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);                                                  if (proc->pid != 0) kill(proc->pid, SIGTERM);
   
                                                 if (proc->is_local &&                                                  if (proc->is_local &&
                                                    !buffer_is_empty(proc->socket)) {                                                    !buffer_string_is_empty(proc->socket)) {
                                                         unlink(proc->socket->ptr);                                                          unlink(proc->socket->ptr);
                                                 }                                                  }
                                         }                                          }
Line 588  FREE_FUNC(mod_scgi_free) { Line 591  FREE_FUNC(mod_scgi_free) {
                                                 if (proc->pid != 0) kill(proc->pid, SIGTERM);                                                  if (proc->pid != 0) kill(proc->pid, SIGTERM);
   
                                                 if (proc->is_local &&                                                  if (proc->is_local &&
                                                    !buffer_is_empty(proc->socket)) {                                                    !buffer_string_is_empty(proc->socket)) {
                                                         unlink(proc->socket->ptr);                                                          unlink(proc->socket->ptr);
                                                 }                                                  }
                                         }                                          }
Line 614  static int env_add(char_array *env, const char *key, s Line 617  static int env_add(char_array *env, const char *key, s
         if (!key || !val) return -1;          if (!key || !val) return -1;
   
         dst = malloc(key_len + val_len + 3);          dst = malloc(key_len + val_len + 3);
           force_assert(dst);
         memcpy(dst, key, key_len);          memcpy(dst, key, key_len);
         dst[key_len] = '=';          dst[key_len] = '=';
         /* add the \0 from the value */          /* add the \0 from the value */
Line 631  static int env_add(char_array *env, const char *key, s Line 635  static int env_add(char_array *env, const char *key, s
         if (env->size == 0) {          if (env->size == 0) {
                 env->size = 16;                  env->size = 16;
                 env->ptr = malloc(env->size * sizeof(*env->ptr));                  env->ptr = malloc(env->size * sizeof(*env->ptr));
                   force_assert(env->ptr);
         } else if (env->size == env->used) {          } else if (env->size == env->used) {
                 env->size += 16;                  env->size += 16;
                 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));                  env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
                   force_assert(env->ptr);
         }          }
   
         env->ptr[env->used++] = dst;          env->ptr[env->used++] = dst;
Line 641  static int env_add(char_array *env, const char *key, s Line 647  static int env_add(char_array *env, const char *key, s
         return 0;          return 0;
 }  }
   
   #if !defined(HAVE_FORK)
 static int scgi_spawn_connection(server *srv,  static int scgi_spawn_connection(server *srv,
                                 plugin_data *p,                                 plugin_data *p,
                                 scgi_extension_host *host,                                 scgi_extension_host *host,
                                 scgi_proc *proc) {                                 scgi_proc *proc) {
         UNUSED(srv);
         UNUSED(p);
         UNUSED(host);
         UNUSED(proc);
         return -1;
 }
 
 #else /* -> defined(HAVE_FORK) */
 
 static int scgi_spawn_connection(server *srv,
                                  plugin_data *p,
                                  scgi_extension_host *host,
                                  scgi_proc *proc) {
         int scgi_fd;          int scgi_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 scgi_addr_un;          struct sockaddr_un scgi_addr_un;
 #endif  #endif
   #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
           struct sockaddr_in6 scgi_addr_in6;
   #endif
         struct sockaddr_in scgi_addr_in;          struct sockaddr_in scgi_addr_in;
         struct sockaddr *scgi_addr;          struct sockaddr *scgi_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->socket);                                  "new proc, socket:", proc->port, proc->socket);
         }          }
   
         if (!buffer_is_empty(proc->socket)) {  
                 memset(&scgi_addr, 0, sizeof(scgi_addr));  
   
           if (!buffer_string_is_empty(proc->socket)) {
 #ifdef HAVE_SYS_UN_H  #ifdef HAVE_SYS_UN_H
                   memset(&scgi_addr_un, 0, sizeof(scgi_addr_un));
                 scgi_addr_un.sun_family = AF_UNIX;                  scgi_addr_un.sun_family = AF_UNIX;
                strcpy(scgi_addr_un.sun_path, proc->socket->ptr);                if (buffer_string_length(proc->socket) + 1 > sizeof(scgi_addr_un.sun_path)) {
                         log_error_write(srv, __FILE__, __LINE__, "sB",
                                         "ERROR: Unix Domain socket filename too long:",
                                         proc->socket);
                         return -1;
                 }
                 memcpy(scgi_addr_un.sun_path, proc->socket->ptr, buffer_string_length(proc->socket) + 1);
   
 #ifdef SUN_LEN  #ifdef SUN_LEN
                 servlen = SUN_LEN(&scgi_addr_un);                  servlen = SUN_LEN(&scgi_addr_un);
 #else  #else
                 /* stevens says: */                  /* stevens says: */
                servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);                servlen = buffer_string_length(proc->socket) + 1 + sizeof(scgi_addr_un.sun_family);
 #endif  #endif
                 socket_type = AF_UNIX;  
                 scgi_addr = (struct sockaddr *) &scgi_addr_un;                  scgi_addr = (struct sockaddr *) &scgi_addr_un;
 #else  #else
                 log_error_write(srv, __FILE__, __LINE__, "s",                  log_error_write(srv, __FILE__, __LINE__, "s",
                                 "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(&scgi_addr_in6, 0, sizeof(scgi_addr_in6));
                   scgi_addr_in6.sin6_family = AF_INET6;
                   inet_pton(AF_INET6, host->host->ptr, (char *) &scgi_addr_in6.sin6_addr);
                   scgi_addr_in6.sin6_port = htons(proc->port);
                   servlen = sizeof(scgi_addr_in6);
                   scgi_addr = (struct sockaddr *) &scgi_addr_in6;
   #endif
         } else {          } else {
                   memset(&scgi_addr_in, 0, sizeof(scgi_addr_in));
                 scgi_addr_in.sin_family = AF_INET;                  scgi_addr_in.sin_family = AF_INET;
   
                if (buffer_is_empty(host->host)) {                if (buffer_string_is_empty(host->host)) {
                         scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);                          scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
                 } else {                  } else {
                         struct hostent *he;                          struct hostent *he;
Line 720  static int scgi_spawn_connection(server *srv, Line 754  static int scgi_spawn_connection(server *srv,
                 scgi_addr_in.sin_port = htons(proc->port);                  scgi_addr_in.sin_port = htons(proc->port);
                 servlen = sizeof(scgi_addr_in);                  servlen = sizeof(scgi_addr_in);
   
                 socket_type = AF_INET;  
                 scgi_addr = (struct sockaddr *) &scgi_addr_in;                  scgi_addr = (struct sockaddr *) &scgi_addr_in;
         }          }
   
        if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {        if (-1 == (scgi_fd = socket(scgi_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 735  static int scgi_spawn_connection(server *srv, Line 768  static int scgi_spawn_connection(server *srv,
                 pid_t child;                  pid_t child;
                 int val;                  int val;
   
                if (!buffer_is_empty(proc->socket)) {                if (!buffer_string_is_empty(proc->socket)) {
                         unlink(proc->socket->ptr);                          unlink(proc->socket->ptr);
                 }                  }
   
                 close(scgi_fd);                  close(scgi_fd);
   
                 /* reopen socket */                  /* reopen socket */
                if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {                if (-1 == (scgi_fd = socket(scgi_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 752  static int scgi_spawn_connection(server *srv, Line 785  static int scgi_spawn_connection(server *srv,
                 if (setsockopt(scgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {                  if (setsockopt(scgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
                         log_error_write(srv, __FILE__, __LINE__, "ss",                          log_error_write(srv, __FILE__, __LINE__, "ss",
                                         "socketsockopt failed:", strerror(errno));                                          "socketsockopt failed:", strerror(errno));
                           close(scgi_fd);
                         return -1;                          return -1;
                 }                  }
   
Line 762  static int scgi_spawn_connection(server *srv, Line 796  static int scgi_spawn_connection(server *srv,
                                 proc->socket,                                  proc->socket,
                                 proc->port,                                  proc->port,
                                 strerror(errno));                                  strerror(errno));
                           close(scgi_fd);
                         return -1;                          return -1;
                 }                  }
   
                if (-1 == listen(scgi_fd, 1024)) {                if (-1 == listen(scgi_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(scgi_fd);
                         return -1;                          return -1;
                 }                  }
   
 #ifdef HAVE_FORK  
                 switch ((child = fork())) {                  switch ((child = fork())) {
                 case 0: {                  case 0: {
                         buffer *b;                          buffer *b;
Line 806  static int scgi_spawn_connection(server *srv, Line 841  static int scgi_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 846  static int scgi_spawn_connection(server *srv, Line 882  static int scgi_spawn_connection(server *srv,
                         log_error_write(srv, __FILE__, __LINE__, "sbs",                          log_error_write(srv, __FILE__, __LINE__, "sbs",
                                         "execl failed for:", host->bin_path, strerror(errno));                                          "execl failed for:", host->bin_path, strerror(errno));
   
                        exit(errno);                        _exit(errno);
   
                         break;                          break;
                 }                  }
                 case -1:                  case -1:
                         /* error */                          /* error */
                           close(scgi_fd);
                         break;                          break;
                 default:                  default:
                         /* father */                          /* father */
                           close(scgi_fd);
   
                         /* wait */                          /* wait */
                         select(0, NULL, NULL, NULL, &tv);                          select(0, NULL, NULL, NULL, &tv);
Line 893  static int scgi_spawn_connection(server *srv, Line 931  static int scgi_spawn_connection(server *srv,
   
                         break;                          break;
                 }                  }
 #endif  
         } else {          } else {
                   close(scgi_fd);
   
                 proc->is_local = 0;                  proc->is_local = 0;
                 proc->pid = 0;                  proc->pid = 0;
   
Line 908  static int scgi_spawn_connection(server *srv, Line 947  static int scgi_spawn_connection(server *srv,
         proc->state = PROC_STATE_RUNNING;          proc->state = PROC_STATE_RUNNING;
         host->active_procs++;          host->active_procs++;
   
         close(scgi_fd);  
   
         return 0;          return 0;
 }  }
   
   #endif /* HAVE_FORK */
   
   static scgi_extension_host * unixsocket_is_dup(plugin_data *p, size_t used, buffer *unixsocket) {
           size_t i, j, n;
           for (i = 0; i < used; ++i) {
                   scgi_exts *exts = p->config_storage[i]->exts;
                   for (j = 0; j < exts->used; ++j) {
                           scgi_extension *ex = exts->exts[j];
                           for (n = 0; n < ex->used; ++n) {
                                   scgi_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_scgi_set_defaults) {  SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
         plugin_data *p = p_d;          plugin_data *p = p_d;
         data_unset *du;          data_unset *du;
         size_t i = 0;          size_t i = 0;
           scgi_extension_host *df = NULL;
   
         config_values_t cv[] = {          config_values_t cv[] = {
                 { "scgi.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */                  { "scgi.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
Line 925  SETDEFAULTS_FUNC(mod_scgi_set_defaults) { Line 983  SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
                 { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }                  { NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
         };          };
   
        p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));        p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
         force_assert(p->config_storage);
   
         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));
                   force_assert(s);
                 s->exts          = scgi_extensions_init();                  s->exts          = scgi_extensions_init();
                 s->debug         = 0;                  s->debug         = 0;
   
Line 939  SETDEFAULTS_FUNC(mod_scgi_set_defaults) { Line 999  SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
                 cv[1].destination = &(s->debug);                  cv[1].destination = &(s->debug);
   
                 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)) {
                        return HANDLER_ERROR;                        goto error;
                 }                  }
   
                 /*                  /*
                  * <key> = ( ... )                   * <key> = ( ... )
                  */                   */
   
                if (NULL != (du = array_get_element(ca, "scgi.server"))) {                if (NULL != (du = array_get_element(config->value, "scgi.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: ", "scgi.server", "array of strings");                                                "unexpected type for key: ", "scgi.server", "expected ( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))");
   
                                return HANDLER_ERROR;                                goto error;
                         }                          }
   
   
Line 973  SETDEFAULTS_FUNC(mod_scgi_set_defaults) { Line 1032  SETDEFAULTS_FUNC(mod_scgi_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: ", "scgi.server",                                                          "unexpected type for key: ", "scgi.server",
                                                        "[", da->value->data[j]->key, "](string)");                                                        "[", da->value->data[j]->key, "](string); expected ( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))");
   
                                        return HANDLER_ERROR;                                        goto error;
                                 }                                  }
   
                                 /*                                  /*
Line 993  SETDEFAULTS_FUNC(mod_scgi_set_defaults) { Line 1052  SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
                                 for (n = 0; n < da_ext->value->used; n++) {                                  for (n = 0; n < da_ext->value->used; n++) {
                                         data_array *da_host = (data_array *)da_ext->value->data[n];                                          data_array *da_host = (data_array *)da_ext->value->data[n];
   
                                         scgi_extension_host *df;  
   
                                         config_values_t fcv[] = {                                          config_values_t fcv[] = {
                                                 { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */                                                  { "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
                                                 { "docroot",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */                                                  { "docroot",           NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
Line 1012  SETDEFAULTS_FUNC(mod_scgi_set_defaults) { Line 1069  SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
                                                 { "bin-environment",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 11 */                                                  { "bin-environment",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },        /* 11 */
                                                 { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },     /* 12 */                                                  { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },     /* 12 */
                                                 { "fix-root-scriptname",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },   /* 13 */                                                  { "fix-root-scriptname",  NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },   /* 13 */
                                                   { "listen-backlog",    NULL, T_CONFIG_INT,   T_CONFIG_SCOPE_CONNECTION },        /* 14 */
                                                   { "x-sendfile",        NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },      /* 15 */
                                                   { "x-sendfile-docroot",NULL, T_CONFIG_ARRAY,   T_CONFIG_SCOPE_CONNECTION },      /* 16 */
   
   
                                                 { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }                                                  { NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
Line 1021  SETDEFAULTS_FUNC(mod_scgi_set_defaults) { Line 1081  SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
                                                 log_error_write(srv, __FILE__, __LINE__, "ssSBS",                                                  log_error_write(srv, __FILE__, __LINE__, "ssSBS",
                                                                 "unexpected type for key:",                                                                  "unexpected type for key:",
                                                                 "scgi.server",                                                                  "scgi.server",
                                                                "[", da_host->key, "](string)");                                                                "[", da_host->key, "](string); expected ( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))");
   
                                                return HANDLER_ERROR;                                                goto error;
                                         }                                          }
   
                                         df = scgi_host_init();                                          df = scgi_host_init();
Line 1035  SETDEFAULTS_FUNC(mod_scgi_set_defaults) { Line 1095  SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
                                         df->idle_timeout = 60;                                          df->idle_timeout = 60;
                                         df->disable_time = 60;                                          df->disable_time = 60;
                                         df->fix_root_path_name = 0;                                          df->fix_root_path_name = 0;
                                           df->listen_backlog = 1024;
                                           df->xsendfile_allow = 0;
                                           df->refcount = 0;
   
                                         fcv[0].destination = df->host;                                          fcv[0].destination = df->host;
                                         fcv[1].destination = df->docroot;                                          fcv[1].destination = df->docroot;
Line 1052  SETDEFAULTS_FUNC(mod_scgi_set_defaults) { Line 1115  SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
                                         fcv[11].destination = df->bin_env;                                          fcv[11].destination = df->bin_env;
                                         fcv[12].destination = df->bin_env_copy;                                          fcv[12].destination = df->bin_env_copy;
                                         fcv[13].destination = &(df->fix_root_path_name);                                          fcv[13].destination = &(df->fix_root_path_name);
                                           fcv[14].destination = &(df->listen_backlog);
                                           fcv[15].destination = &(df->xsendfile_allow);
                                           fcv[16].destination = df->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)) {
                                                return HANDLER_ERROR;                                                goto error;
                                         }                                          }
   
                                        if ((!buffer_is_empty(df->host) || df->port) &&                                        if ((!buffer_string_is_empty(df->host) || df->port) &&
                                            !buffer_is_empty(df->unixsocket)) {                                            !buffer_string_is_empty(df->unixsocket)) {
                                                 log_error_write(srv, __FILE__, __LINE__, "s",                                                  log_error_write(srv, __FILE__, __LINE__, "s",
                                                                 "either host+port or socket");                                                                  "either host+port or socket");
   
                                                return HANDLER_ERROR;                                                goto error;
                                         }                                          }
   
                                        if (!buffer_is_empty(df->unixsocket)) {                                        if (!buffer_string_is_empty(df->unixsocket)) {
                                                 /* unix domain socket */                                                  /* unix domain socket */
                                                 struct sockaddr_un un;                                                  struct sockaddr_un un;
   
                                                if (df->unixsocket->used > sizeof(un.sun_path) - 2) {                                                if (buffer_string_length(df->unixsocket) + 1 > sizeof(un.sun_path) - 2) {
                                                         log_error_write(srv, __FILE__, __LINE__, "s",                                                          log_error_write(srv, __FILE__, __LINE__, "s",
                                                                         "path of the unixdomain socket is too large");                                                                          "path of the unixdomain socket is too large");
                                                        return HANDLER_ERROR;                                                        goto error;
                                                 }                                                  }
   
                                                   if (!buffer_string_is_empty(df->bin_path)) {
                                                           scgi_extension_host *duplicate = unixsocket_is_dup(p, i+1, df->unixsocket);
                                                           if (NULL != duplicate) {
                                                                   if (!buffer_is_equal(df->bin_path, duplicate->bin_path)) {
                                                                           log_error_write(srv, __FILE__, __LINE__, "sb",
                                                                                   "duplicate unixsocket path:",
                                                                                   df->unixsocket);
                                                                           goto error;
                                                                   }
                                                                   scgi_host_free(df);
                                                                   df = duplicate;
                                                                   ++df->refcount;
                                                           }
                                                   }
   
                                                   df->family = AF_UNIX;
                                         } else {                                          } else {
                                                 /* tcp/ip */                                                  /* tcp/ip */
   
                                                if (buffer_is_empty(df->host) &&                                                if (buffer_string_is_empty(df->host) &&
                                                    buffer_is_empty(df->bin_path)) {                                                    buffer_string_is_empty(df->bin_path)) {
                                                         log_error_write(srv, __FILE__, __LINE__, "sbbbs",                                                          log_error_write(srv, __FILE__, __LINE__, "sbbbs",
                                                                         "missing key (string):",                                                                          "missing key (string):",
                                                                         da->key,                                                                          da->key,
Line 1087  SETDEFAULTS_FUNC(mod_scgi_set_defaults) { Line 1170  SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
                                                                         da_host->key,                                                                          da_host->key,
                                                                         "host");                                                                          "host");
   
                                                        return HANDLER_ERROR;                                                        goto error;
                                                 } else if (df->port == 0) {                                                  } else if (df->port == 0) {
                                                         log_error_write(srv, __FILE__, __LINE__, "sbbbs",                                                          log_error_write(srv, __FILE__, __LINE__, "sbbbs",
                                                                         "missing key (short):",                                                                          "missing key (short):",
Line 1095  SETDEFAULTS_FUNC(mod_scgi_set_defaults) { Line 1178  SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
                                                                         da_ext->key,                                                                          da_ext->key,
                                                                         da_host->key,                                                                          da_host->key,
                                                                         "port");                                                                          "port");
                                                        return HANDLER_ERROR;                                                        goto error;
                                                 }                                                  }
   
                                                   df->family = (!buffer_string_is_empty(df->host) && NULL != strchr(df->host->ptr, ':')) ? AF_INET6 : AF_INET;
                                         }                                          }
   
                                        if (!buffer_is_empty(df->bin_path)) {                                        if (df->refcount) {
                                                 /* already init'd; skip spawning */
                                         } else if (!buffer_string_is_empty(df->bin_path)) {
                                                 /* a local socket + self spawning */                                                  /* a local socket + self spawning */
                                                 size_t pno;                                                  size_t pno;
   
Line 1126  SETDEFAULTS_FUNC(mod_scgi_set_defaults) { Line 1213  SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
                                                         proc->id = df->num_procs++;                                                          proc->id = df->num_procs++;
                                                         df->max_id++;                                                          df->max_id++;
   
                                                        if (buffer_is_empty(df->unixsocket)) {                                                        if (buffer_string_is_empty(df->unixsocket)) {
                                                                 proc->port = df->port + pno;                                                                  proc->port = df->port + pno;
                                                         } else {                                                          } else {
                                                                buffer_copy_string_buffer(proc->socket, df->unixsocket);                                                                buffer_copy_buffer(proc->socket, df->unixsocket);
                                                                 buffer_append_string_len(proc->socket, CONST_STR_LEN("-"));                                                                  buffer_append_string_len(proc->socket, CONST_STR_LEN("-"));
                                                                buffer_append_long(proc->socket, pno);                                                                buffer_append_int(proc->socket, pno);
                                                         }                                                          }
   
                                                         if (s->debug) {                                                          if (s->debug) {
Line 1142  SETDEFAULTS_FUNC(mod_scgi_set_defaults) { Line 1229  SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
                                                                                 "\n\tcurrent:", pno, "/", df->min_procs);                                                                                  "\n\tcurrent:", pno, "/", df->min_procs);
                                                         }                                                          }
   
                                                        if (scgi_spawn_connection(srv, p, df, proc)) {                                                        if (!srv->srvconf.preflight_check
                                                             && scgi_spawn_connection(srv, p, df, proc)) {
                                                                 log_error_write(srv, __FILE__, __LINE__, "s",                                                                  log_error_write(srv, __FILE__, __LINE__, "s",
                                                                                 "[ERROR]: spawning fcgi failed.");                                                                                  "[ERROR]: spawning fcgi failed.");
                                                                return HANDLER_ERROR;                                                                scgi_process_free(proc);
                                                                 goto error;
                                                         }                                                          }
   
                                                         proc->next = df->first;                                                          proc->next = df->first;
Line 1162  SETDEFAULTS_FUNC(mod_scgi_set_defaults) { Line 1251  SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
                                                 df->active_procs++;                                                  df->active_procs++;
                                                 fp->state = PROC_STATE_RUNNING;                                                  fp->state = PROC_STATE_RUNNING;
   
                                                if (buffer_is_empty(df->unixsocket)) {                                                if (buffer_string_is_empty(df->unixsocket)) {
                                                         fp->port = df->port;                                                          fp->port = df->port;
                                                 } else {                                                  } else {
                                                        buffer_copy_string_buffer(fp->socket, df->unixsocket);                                                        buffer_copy_buffer(fp->socket, df->unixsocket);
                                                 }                                                  }
   
                                                 df->first = fp;                                                  df->first = fp;
Line 1174  SETDEFAULTS_FUNC(mod_scgi_set_defaults) { Line 1263  SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
                                                 df->max_procs = 1;                                                  df->max_procs = 1;
                                         }                                          }
   
                                           if (df->xsendfile_docroot->used) {
                                                   size_t k;
                                                   for (k = 0; k < df->xsendfile_docroot->used; ++k) {
                                                           data_string *ds = (data_string *)df->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 */
                                         scgi_extension_insert(s->exts, da_ext->key, df);                                          scgi_extension_insert(s->exts, da_ext->key, df);
                                           df = NULL;
                                 }                                  }
                         }                          }
                 }                  }
         }          }
   
         return HANDLER_GO_ON;          return HANDLER_GO_ON;
   
   error:
           if (NULL != df) scgi_host_free(df);
           return HANDLER_ERROR;
 }  }
   
 static int scgi_set_state(server *srv, handler_ctx *hctx, scgi_connection_state_t state) {  static int scgi_set_state(server *srv, handler_ctx *hctx, scgi_connection_state_t state) {
Line 1192  static int scgi_set_state(server *srv, handler_ctx *hc Line 1305  static int scgi_set_state(server *srv, handler_ctx *hc
 }  }
   
   
static void scgi_connection_cleanup(server *srv, handler_ctx *hctx) {static void scgi_connection_close(server *srv, handler_ctx *hctx) {
         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 1229  static void scgi_connection_cleanup(server *srv, handl Line 1340  static void scgi_connection_cleanup(server *srv, handl
   
         handler_ctx_free(hctx);          handler_ctx_free(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 scgi_reconnect(server *srv, handler_ctx *hctx) {  static int scgi_reconnect(server *srv, handler_ctx *hctx) {
Line 1260  static int scgi_reconnect(server *srv, handler_ctx *hc Line 1376  static int scgi_reconnect(server *srv, handler_ctx *hc
   
         scgi_set_state(srv, hctx, FCGI_STATE_INIT);          scgi_set_state(srv, hctx, FCGI_STATE_INIT);
   
         hctx->request_id = 0;  
         hctx->reconnects++;          hctx->reconnects++;
   
         if (p->conf.debug) {          if (p->conf.debug) {
Line 1279  static int scgi_reconnect(server *srv, handler_ctx *hc Line 1394  static int scgi_reconnect(server *srv, handler_ctx *hc
   
 static handler_t scgi_connection_reset(server *srv, connection *con, void *p_d) {  static handler_t scgi_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) scgi_connection_close(srv, hctx);
   
         scgi_connection_cleanup(srv, con->plugin_ctx[p->id]);  
   
         return HANDLER_GO_ON;          return HANDLER_GO_ON;
 }  }
   
Line 1293  static int scgi_env_add(buffer *env, const char *key,  Line 1408  static int scgi_env_add(buffer *env, const char *key, 
   
         len = key_len + val_len + 2;          len = key_len + val_len + 2;
   
        buffer_prepare_append(env, len);        buffer_string_prepare_append(env, len);
   
        memcpy(env->ptr + env->used, key, key_len);        buffer_append_string_len(env, key, key_len);
        env->ptr[env->used + key_len] = '\0';        buffer_append_string_len(env, "", 1);
        env->used += key_len + 1;        buffer_append_string_len(env, val, val_len);
        memcpy(env->ptr + env->used, val, val_len);        buffer_append_string_len(env, "", 1);
        env->ptr[env->used + val_len] = '\0'; 
        env->used += val_len + 1; 
   
         return 0;          return 0;
 }  }
Line 1317  static int scgi_env_add(buffer *env, const char *key,  Line 1430  static int scgi_env_add(buffer *env, const char *key, 
 static int scgi_establish_connection(server *srv, handler_ctx *hctx) {  static int scgi_establish_connection(server *srv, handler_ctx *hctx) {
         struct sockaddr *scgi_addr;          struct sockaddr *scgi_addr;
         struct sockaddr_in scgi_addr_in;          struct sockaddr_in scgi_addr_in;
   #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
           struct sockaddr_in6 scgi_addr_in6;
   #endif
 #ifdef HAVE_SYS_UN_H  #ifdef HAVE_SYS_UN_H
         struct sockaddr_un scgi_addr_un;          struct sockaddr_un scgi_addr_un;
 #endif  #endif
Line 1326  static int scgi_establish_connection(server *srv, hand Line 1442  static int scgi_establish_connection(server *srv, hand
         scgi_proc *proc   = hctx->proc;          scgi_proc *proc   = hctx->proc;
         int scgi_fd       = hctx->fd;          int scgi_fd       = hctx->fd;
   
        memset(&scgi_addr, 0, sizeof(scgi_addr));        if (!buffer_string_is_empty(proc->socket)) {
 
        if (!buffer_is_empty(proc->socket)) { 
 #ifdef HAVE_SYS_UN_H  #ifdef HAVE_SYS_UN_H
                 /* use the unix domain socket */                  /* use the unix domain socket */
                   memset(&scgi_addr_un, 0, sizeof(scgi_addr_un));
                 scgi_addr_un.sun_family = AF_UNIX;                  scgi_addr_un.sun_family = AF_UNIX;
                strcpy(scgi_addr_un.sun_path, proc->socket->ptr);                if (buffer_string_length(proc->socket) + 1 > sizeof(scgi_addr_un.sun_path)) {
                         log_error_write(srv, __FILE__, __LINE__, "sB",
                                         "ERROR: Unix Domain socket filename too long:",
                                         proc->socket);
                         return -1;
                 }
                 memcpy(scgi_addr_un.sun_path, proc->socket->ptr, buffer_string_length(proc->socket) + 1);
 
 #ifdef SUN_LEN  #ifdef SUN_LEN
                 servlen = SUN_LEN(&scgi_addr_un);                  servlen = SUN_LEN(&scgi_addr_un);
 #else  #else
                 /* stevens says: */                  /* stevens says: */
                servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);                servlen = buffer_string_length(proc->socket) + 1 + sizeof(scgi_addr_un.sun_family);
 #endif  #endif
                 scgi_addr = (struct sockaddr *) &scgi_addr_un;                  scgi_addr = (struct sockaddr *) &scgi_addr_un;
 #else  #else
                 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(&scgi_addr_in6, 0, sizeof(scgi_addr_in6));
                   scgi_addr_in6.sin6_family = AF_INET6;
                   inet_pton(AF_INET6, host->host->ptr, (char *) &scgi_addr_in6.sin6_addr);
                   scgi_addr_in6.sin6_port = htons(proc->port);
                   servlen = sizeof(scgi_addr_in6);
                   scgi_addr = (struct sockaddr *) &scgi_addr_in6;
   #endif
         } else {          } else {
                   memset(&scgi_addr_in, 0, sizeof(scgi_addr_in));
                 scgi_addr_in.sin_family = AF_INET;                  scgi_addr_in.sin_family = AF_INET;
                 if (0 == inet_aton(host->host->ptr, &(scgi_addr_in.sin_addr))) {                  if (0 == inet_aton(host->host->ptr, &(scgi_addr_in.sin_addr))) {
                         log_error_write(srv, __FILE__, __LINE__, "sbs",                          log_error_write(srv, __FILE__, __LINE__, "sbs",
Line 1403  static int scgi_env_add_request_headers(server *srv, c Line 1535  static int scgi_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++) { 
                                srv->tmp_buf->ptr[srv->tmp_buf->used++] = 
                                        light_isalpha(ds->key->ptr[j]) ? 
                                        ds->key->ptr[j] & ~32 : '_'; 
                        } 
                        srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0'; 
   
                         scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));                          scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
                 }                  }
Line 1429  static int scgi_env_add_request_headers(server *srv, c Line 1554  static int scgi_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++) {  
                                 srv->tmp_buf->ptr[srv->tmp_buf->used++] =  
                                         light_isalnum((unsigned char)ds->key->ptr[j]) ?  
                                         toupper((unsigned char)ds->key->ptr[j]) : '_';  
                         }  
                         srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';  
   
                         scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));                          scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
                 }                  }
         }          }
Line 1450  static int scgi_env_add_request_headers(server *srv, c Line 1566  static int scgi_env_add_request_headers(server *srv, c
   
   
 static int scgi_create_env(server *srv, handler_ctx *hctx) {  static int scgi_create_env(server *srv, handler_ctx *hctx) {
        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 1466  static int scgi_create_env(server *srv, handler_ctx *h Line 1582  static int scgi_create_env(server *srv, handler_ctx *h
         sock_addr our_addr;          sock_addr our_addr;
         socklen_t our_addr_len;          socklen_t our_addr_len;
   
        buffer_prepare_copy(p->scgi_env, 1024);        buffer_string_prepare_copy(p->scgi_env, 1023);
   
         /* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */          /* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */
   
        /* request.content_length < SSIZE_MAX, see request.c */        li_itostrn(buf, sizeof(buf), con->request.content_length);
        LI_ltostr(buf, con->request.content_length); 
         scgi_env_add(p->scgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));          scgi_env_add(p->scgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
         scgi_env_add(p->scgi_env, CONST_STR_LEN("SCGI"), CONST_STR_LEN("1"));          scgi_env_add(p->scgi_env, CONST_STR_LEN("SCGI"), CONST_STR_LEN("1"));
   
           scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_BUF_LEN(con->conf.server_tag));
   
        if (buffer_is_empty(con->conf.server_tag)) {        if (!buffer_is_empty(con->server_name)) {
                scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_DESC));                size_t len = buffer_string_length(con->server_name);
        } else { 
                scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_BUF_LEN(con->conf.server_tag)); 
        } 
   
         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 1504  static int scgi_create_env(server *srv, handler_ctx *h Line 1614  static int scgi_create_env(server *srv, handler_ctx *h
 #else  #else
                 s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);                  s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
 #endif  #endif
                   force_assert(s);
                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));                  scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
         }          }
   
         scgi_env_add(p->scgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));          scgi_env_add(p->scgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
   
        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 1522  static int scgi_create_env(server *srv, handler_ctx *h Line 1633  static int scgi_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));
         }          }
         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));          scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
   
        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 1540  static int scgi_create_env(server *srv, handler_ctx *h Line 1652  static int scgi_create_env(server *srv, handler_ctx *h
         scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));          scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
   
         s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));          s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
           force_assert(s);
         scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));          scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
   
         /*          /*
Line 1550  static int scgi_create_env(server *srv, handler_ctx *h Line 1663  static int scgi_create_env(server *srv, handler_ctx *h
   
         scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));          scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
   
        if (!buffer_is_empty(con->request.pathinfo)) {        if (!buffer_string_is_empty(con->request.pathinfo)) {
                 scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));                  scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
   
                 /* 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);
                 scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_TRANSLATED"), CONST_BUF_LEN(p->path));                  scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_TRANSLATED"), CONST_BUF_LEN(p->path));
Line 1574  static int scgi_create_env(server *srv, handler_ctx *h Line 1687  static int scgi_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);
   
                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));                  scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
                 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));                  scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
         } else {          } else {
                buffer_copy_string_buffer(p->path, con->physical.path);                buffer_copy_buffer(p->path, con->physical.path);
   
                 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));                  scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
                 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir));                  scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir));
Line 1595  static int scgi_create_env(server *srv, handler_ctx *h Line 1708  static int scgi_create_env(server *srv, handler_ctx *h
         if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {          if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {
                 scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.uri));                  scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.uri));
         }          }
        if (!buffer_is_empty(con->uri.query)) {        if (!buffer_string_is_empty(con->uri.query)) {
                 scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));                  scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
         } else {          } else {
                 scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));                  scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
         }          }
   
         s = get_http_method_name(con->request.http_method);          s = get_http_method_name(con->request.http_method);
           force_assert(s);
         scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));          scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
        scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* 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) {
                 scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200"));
         }
         s = get_http_version_name(con->request.http_version);          s = get_http_version_name(con->request.http_version);
           force_assert(s);
         scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));          scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
   
 #ifdef USE_OPENSSL  #ifdef USE_OPENSSL
Line 1615  static int scgi_create_env(server *srv, handler_ctx *h Line 1734  static int scgi_create_env(server *srv, handler_ctx *h
   
         scgi_env_add_request_headers(srv, con, p);          scgi_env_add_request_headers(srv, con, p);
   
        b = chunkqueue_get_append_buffer(hctx->wb);        b = buffer_init();
   
        buffer_append_long(b, p->scgi_env->used);        buffer_append_int(b, buffer_string_length(p->scgi_env));
         buffer_append_string_len(b, CONST_STR_LEN(":"));          buffer_append_string_len(b, CONST_STR_LEN(":"));
        buffer_append_string_len(b, (const char *)p->scgi_env->ptr, p->scgi_env->used);        buffer_append_string_buffer(b, p->scgi_env);
         buffer_append_string_len(b, CONST_STR_LEN(","));          buffer_append_string_len(b, CONST_STR_LEN(","));
   
        hctx->wb->bytes_in += b->used - 1;        hctx->wb_reqlen = buffer_string_length(b);
         chunkqueue_append_buffer(hctx->wb, b);
         buffer_free(b);
   
         if (con->request.content_length) {          if (con->request.content_length) {
                chunkqueue *req_cq = con->request_content_queue;                chunkqueue_append_chunkqueue(hctx->wb, con->request_content_queue);
                chunk *req_c;                hctx->wb_reqlen += con->request.content_length;/* (eventual) total request size */
                off_t offset; 
 
                /* something to send ? */ 
                for (offset = 0, req_c = req_cq->first; offset != req_cq->bytes_in; req_c = req_c->next) { 
                        off_t weWant = req_cq->bytes_in - offset; 
                        off_t weHave = 0; 
 
                        /* we announce toWrite octects 
                         * now take all the request_content chunk that we need to fill this request 
                         * */ 
 
                        switch (req_c->type) { 
                        case FILE_CHUNK: 
                                weHave = req_c->file.length - req_c->offset; 
 
                                if (weHave > weWant) weHave = weWant; 
 
                                chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave); 
 
                                req_c->offset += weHave; 
                                req_cq->bytes_out += weHave; 
 
                                hctx->wb->bytes_in += weHave; 
 
                                break; 
                        case MEM_CHUNK: 
                                /* append to the buffer */ 
                                weHave = req_c->mem->used - 1 - req_c->offset; 
 
                                if (weHave > weWant) weHave = weWant; 
 
                                b = chunkqueue_get_append_buffer(hctx->wb); 
                                buffer_append_memory(b, req_c->mem->ptr + req_c->offset, weHave); 
                                b->used++; /* add virtual \0 */ 
 
                                req_c->offset += weHave; 
                                req_cq->bytes_out += weHave; 
 
                                hctx->wb->bytes_in += weHave; 
 
                                break; 
                        default: 
                                break; 
                        } 
 
                        offset += weHave; 
                } 
         }          }
   
         return 0;          return 0;
Line 1686  static int scgi_response_parse(server *srv, connection Line 1760  static int scgi_response_parse(server *srv, connection
   
         UNUSED(srv);          UNUSED(srv);
   
        buffer_copy_string_buffer(p->parse_response, in);        buffer_copy_buffer(p->parse_response, in);
   
         for (s = p->parse_response->ptr;          for (s = p->parse_response->ptr;
              NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n')));               NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n')));
Line 1745  static int scgi_response_parse(server *srv, connection Line 1819  static int scgi_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 1762  static int scgi_response_parse(server *srv, connection Line 1841  static int scgi_response_parse(server *srv, connection
                                 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;
                                 }                                  }
                                 break;                                  break;
Line 1789  static int scgi_demux_response(server *srv, handler_ct Line 1868  static int scgi_demux_response(server *srv, handler_ct
         while(1) {          while(1) {
                 int n;                  int n;
   
                buffer_prepare_copy(hctx->response, 1024);                buffer_string_prepare_copy(hctx->response, 1023);
                 if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {                  if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
                         if (errno == EAGAIN || errno == EINTR) {                          if (errno == EAGAIN || errno == EINTR) {
                                 /* would block, wait for signal */                                  /* would block, wait for signal */
                                   fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
                                 return 0;                                  return 0;
                         }                          }
                         /* error */                          /* error */
Line 1802  static int scgi_demux_response(server *srv, handler_ct Line 1882  static int scgi_demux_response(server *srv, handler_ct
   
                 if (n == 0) {                  if (n == 0) {
                         /* read finished */                          /* read finished */
   
                         con->file_finished = 1;  
   
                         /* send final chunk */  
                         http_chunk_append_mem(srv, con, NULL, 0);  
                         joblist_append(srv, con);  
   
                         return 1;                          return 1;
                 }                  }
   
                hctx->response->ptr[n] = '\0';                buffer_commit(hctx->response, n);
                hctx->response->used = n+1; 
   
                 /* split header from body */                  /* split header from body */
   
Line 1831  static int scgi_demux_response(server *srv, handler_ct Line 1903  static int scgi_demux_response(server *srv, handler_ct
                         if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;                          if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
   
                         /* search for the \r\n\r\n or \n\n in the string */                          /* search for the \r\n\r\n or \n\n in the string */
                        for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {                        for (c = hctx->response_header->ptr, cp = 0, used = buffer_string_length(hctx->response_header); used; c++, cp++, used--) {
                                 if (*c == ':') in_header = 1;                                  if (*c == ':') in_header = 1;
                                 else if (*c == '\n') {                                  else if (*c == '\n') {
                                         if (in_header == 0) {                                          if (in_header == 0) {
Line 1879  static int scgi_demux_response(server *srv, handler_ct Line 1951  static int scgi_demux_response(server *srv, handler_ct
                         if (header_end) {                          if (header_end) {
                                 if (c == NULL) {                                  if (c == NULL) {
                                         /* no header, but a body */                                          /* no header, but a body */
                                        if (0 != http_chunk_append_buffer(srv, con, hctx->response_header)) {
                                        if (con->request.http_version == HTTP_VERSION_1_1) {                                                /* error writing to tempfile;
                                                con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;                                                 * truncate response or send 500 if nothing sent yet */
                                                 return 1;
                                         }                                          }
   
                                         http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);  
                                         joblist_append(srv, con);  
                                 } else {                                  } else {
                                        size_t blen = hctx->response_header->used - hlen - 1;                                        size_t blen = buffer_string_length(hctx->response_header) - hlen;
   
                                         /* a small hack: terminate after at the second \r */                                          /* a small hack: terminate after at the second \r */
                                        hctx->response_header->used = hlen;                                        buffer_string_set_length(hctx->response_header, hlen - 1);
                                        hctx->response_header->ptr[hlen - 1] = '\0'; 
   
                                         /* parse the response header */                                          /* parse the response header */
                                         scgi_response_parse(srv, con, p, hctx->response_header, eol);                                          scgi_response_parse(srv, con, p, hctx->response_header, eol);
   
                                        /* enable chunked-transfer-encoding */                                        if (hctx->host->xsendfile_allow) {
                                        if (con->request.http_version == HTTP_VERSION_1_1 &&                                                data_string *ds;
                                            !(con->parsed_response & HTTP_CONTENT_LENGTH)) {                                                if (NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-Sendfile"))) {
                                                con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;                                                        http_response_xsendfile(srv, con, ds->value, hctx->host->xsendfile_docroot);
                                                         return 1;
                                                 }
                                         }                                          }
   
                                        if ((hctx->response->used != hlen) && blen > 0) {                                        if (blen > 0) {
                                                http_chunk_append_mem(srv, con, hctx->response_header->ptr + hlen, blen + 1);                                                if (0 != http_chunk_append_mem(srv, con, hctx->response_header->ptr + hlen, blen)) {
                                                joblist_append(srv, con);                                                        /* error writing to tempfile;
                                                          * truncate response or send 500 if nothing sent yet */
                                                         return 1;
                                                 }
                                         }                                          }
                                 }                                  }
   
                                 con->file_started = 1;                                  con->file_started = 1;
                           } else {
                                   /*(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;
                                           return 1;
                                   }
                         }                          }
                 } else {                  } else {
                        http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);                        if (0 != http_chunk_append_buffer(srv, con, hctx->response)) {
                        joblist_append(srv, con);                                /* error writing to tempfile;
                                  * truncate response or send 500 if nothing sent yet */
                                 return 1;
                         }
                         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_scgi_handle_subrequest())*/
                                         fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
                                 }
                                 break;
                         }
                 }                  }
   
 #if 0  #if 0
Line 2165  static handler_t scgi_write_request(server *srv, handl Line 2262  static handler_t scgi_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->host->used || !host->port) && !host->unixsocket->used)) {        if (((buffer_string_is_empty(host->host) || !host->port) && buffer_string_is_empty(host->unixsocket))) {
                 log_error_write(srv, __FILE__, __LINE__, "sxddd",                  log_error_write(srv, __FILE__, __LINE__, "sxddd",
                                 "write-req: error",                                  "write-req: error",
                                 host,                                  host,
                                host->host->used,                                buffer_string_length(host->host),
                                 host->port,                                  host->port,
                                host->unixsocket->used);                                buffer_string_length(host->unixsocket));
                 return HANDLER_ERROR;                  return HANDLER_ERROR;
         }          }
   
   
         switch(hctx->state) {          switch(hctx->state) {
         case FCGI_STATE_INIT:          case FCGI_STATE_INIT:
                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 2292  static handler_t scgi_write_request(server *srv, handl Line 2387  static handler_t scgi_write_request(server *srv, handl
         case FCGI_STATE_PREPARE_WRITE:          case FCGI_STATE_PREPARE_WRITE:
                 scgi_create_env(srv, hctx);                  scgi_create_env(srv, hctx);
   
                   fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
                 scgi_set_state(srv, hctx, FCGI_STATE_WRITE);                  scgi_set_state(srv, hctx, FCGI_STATE_WRITE);
   
                 /* fall through */                  /* fall through */
Line 2316  static handler_t scgi_write_request(server *srv, handl Line 2412  static handler_t scgi_write_request(server *srv, handl
   
                                         scgi_reconnect(srv, hctx);                                          scgi_reconnect(srv, hctx);
   
                                        return HANDLER_WAIT_FOR_FD;                                        return HANDLER_COMEBACK;
                                 }                                  }
   
                                 /* not reconnected ... why                                  /* not reconnected ... why
Line 2340  static handler_t scgi_write_request(server *srv, handl Line 2436  static handler_t scgi_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);                      #if (defined(__APPLE__) && defined(__MACH__)) \
                        fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);                        || defined(__FreeBSD__) || defined(__NetBSD__) \
                         || defined(__OpenBSD__) || defined(__DragonflyBSD__)
                         /*(*BSD stack on remote might signal POLLHUP and remote
                          * might treat as socket error instead of half-close)*/
                       #else
                         /*(remote could be different machine running affected OS,
                          * so only issue shutdown for known local sockets)*/
                         if ( '/' == host->host->ptr[0]
                             || buffer_is_equal_string(host->host, CONST_STR_LEN("127.0.0.1"))
                             || buffer_is_equal_string(host->host, CONST_STR_LEN("::1"))) {
                                 shutdown(hctx->fd, SHUT_WR);
                         }
                       #endif
                         scgi_set_state(srv, hctx, FCGI_STATE_READ);                          scgi_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;  
 }  }
   
SUBREQUEST_FUNC(mod_scgi_handle_subrequest) {static handler_t scgi_send_request(server *srv, handler_ctx *hctx) {
        plugin_data *p = p_d; 
 
        handler_ctx *hctx = con->plugin_ctx[p->id]; 
        scgi_proc *proc; 
        scgi_extension_host *host; 
 
        if (NULL == hctx) return HANDLER_GO_ON; 
 
        /* not my job */ 
        if (con->mode != p->id) return HANDLER_GO_ON; 
 
         /* ok, create the request */          /* ok, create the request */
        switch(scgi_write_request(srv, hctx)) {        handler_t rc = scgi_write_request(srv, hctx);
        case HANDLER_ERROR:        if (HANDLER_ERROR != rc) {
                proc = hctx->proc;                return rc;
                host = hctx->host;        } else {
                 scgi_proc *proc = hctx->proc;
                 scgi_extension_host *host = hctx->host;
                 plugin_data *p  = hctx->plugin_data;
                 connection *con = hctx->remote_conn;
   
                 if (proc &&                  if (proc &&
                     0 == proc->is_local &&                      0 == proc->is_local &&
Line 2428  SUBREQUEST_FUNC(mod_scgi_handle_subrequest) { Line 2537  SUBREQUEST_FUNC(mod_scgi_handle_subrequest) {
                         }                          }
                         scgi_restart_dead_procs(srv, p, host);                          scgi_restart_dead_procs(srv, p, host);
   
                        scgi_connection_cleanup(srv, hctx);                        con->mode = DIRECT;/*(avoid changing con->state, con->http_status)*/
                         scgi_connection_close(srv, hctx);
                         con->mode = p->id;
   
                        buffer_reset(con->physical.path);                        return HANDLER_COMEBACK;
                        con->mode = DIRECT; 
                        joblist_append(srv, con); 
 
                        /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop 
                         * and hope that the childs will be restarted 
                         * 
                         */ 
                        return HANDLER_WAIT_FOR_FD; 
                 } else {                  } else {
                        scgi_connection_cleanup(srv, hctx);                        scgi_connection_close(srv, hctx);
 
                        buffer_reset(con->physical.path); 
                        con->mode = DIRECT; 
                         con->http_status = 503;                          con->http_status = 503;
   
                         return HANDLER_FINISHED;                          return HANDLER_FINISHED;
                 }                  }
         case HANDLER_WAIT_FOR_EVENT:  
                 if (con->file_started == 1) {  
                         return HANDLER_FINISHED;  
                 } else {  
                         return HANDLER_WAIT_FOR_EVENT;  
                 }  
         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;  
         }          }
 }  }
   
 static handler_t scgi_connection_close(server *srv, handler_ctx *hctx) {  
         connection  *con;  
   
   static handler_t scgi_recv_response(server *srv, handler_ctx *hctx);
   
   
   SUBREQUEST_FUNC(mod_scgi_handle_subrequest) {
           plugin_data *p = p_d;
   
           handler_ctx *hctx = con->plugin_ctx[p->id];
   
         if (NULL == hctx) return HANDLER_GO_ON;          if (NULL == hctx) return HANDLER_GO_ON;
   
        con  = hctx->remote_conn;        /* not my job */
         if (con->mode != p->id) return HANDLER_GO_ON;
   
        log_error_write(srv, __FILE__, __LINE__, "ssdsd",        if ((con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN)
                        "emergency exit: scgi:",            && con->file_started) {
                        "connection-fd:", con->fd,                if (chunkqueue_length(con->write_queue) > 65536 - 4096) {
                        "fcgi-fd:", hctx->fd);                        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 = scgi_recv_response(srv, hctx); /*(might invalidate hctx)*/
                         if (rc != HANDLER_GO_ON) return rc;           /*(unless HANDLER_GO_ON)*/
                 }
         }
   
        scgi_connection_cleanup(srv, hctx);        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 {
                         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)) {
                                 chunkqueue_append_chunkqueue(hctx->wb, req_cq);
                                 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;
                 }
         }
   
        return HANDLER_FINISHED;        return ((0 == hctx->wb->bytes_in || !chunkqueue_is_empty(hctx->wb))
                 && hctx->state != FCGI_STATE_CONNECT)
           ? scgi_send_request(srv, hctx)
           : HANDLER_WAIT_FOR_EVENT;
 }  }
   
   
static handler_t scgi_handle_fdevent(server *srv, void *ctx, int revents) {static handler_t scgi_recv_response(server *srv, handler_ctx *hctx) {
        handler_ctx *hctx = ctx; 
        connection  *con  = hctx->remote_conn; 
        plugin_data *p    = hctx->plugin_data; 
   
         scgi_proc *proc   = hctx->proc;  
         scgi_extension_host *host= hctx->host;  
   
         if ((revents & FDEVENT_IN) &&  
             hctx->state == FCGI_STATE_READ) {  
                 switch (scgi_demux_response(srv, hctx)) {                  switch (scgi_demux_response(srv, hctx)) {
                 case 0:                  case 0:
                         break;                          break;
                 case 1:                  case 1:
                         /* we are done */                          /* we are done */
                        scgi_connection_cleanup(srv, hctx);                        scgi_connection_close(srv, hctx);
   
                         joblist_append(srv, con);  
                         return HANDLER_FINISHED;                          return HANDLER_FINISHED;
                case -1:                case -1: {
                         connection  *con  = hctx->remote_conn;
                         plugin_data *p    = hctx->plugin_data;
 
                         scgi_proc *proc   = hctx->proc;
                         scgi_extension_host *host= hctx->host;
 
                         if (proc->pid && proc->state != PROC_STATE_DIED) {                          if (proc->pid && proc->state != PROC_STATE_DIED) {
                                 int status;                                  int status;
   
Line 2551  static handler_t scgi_handle_fdevent(server *srv, void Line 2673  static handler_t scgi_handle_fdevent(server *srv, void
   
                                 if (hctx->wb->bytes_out == 0 &&                                  if (hctx->wb->bytes_out == 0 &&
                                     hctx->reconnects < 5) {                                      hctx->reconnects < 5) {
                                         scgi_reconnect(srv, hctx);  
   
                                         log_error_write(srv, __FILE__, __LINE__, "ssdsd",                                          log_error_write(srv, __FILE__, __LINE__, "ssdsd",
                                                 "response not sent, request not sent, reconnection.",                                                  "response not sent, request not sent, reconnection.",
                                                 "connection-fd:", con->fd,                                                  "connection-fd:", con->fd,
                                                 "fcgi-fd:", hctx->fd);                                                  "fcgi-fd:", hctx->fd);
   
                                        return HANDLER_WAIT_FOR_FD;                                        scgi_reconnect(srv, hctx);
 
                                         return HANDLER_COMEBACK;
                                 }                                  }
   
                                 log_error_write(srv, __FILE__, __LINE__, "sosdsd",                                  log_error_write(srv, __FILE__, __LINE__, "sosdsd",
                                                 "response not sent, request sent:", hctx->wb->bytes_out,                                                  "response not sent, request sent:", hctx->wb->bytes_out,
                                                 "connection-fd:", con->fd,                                                  "connection-fd:", con->fd,
                                                 "fcgi-fd:", hctx->fd);                                                  "fcgi-fd:", hctx->fd);
   
                                 scgi_connection_cleanup(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 */  
                                 log_error_write(srv, __FILE__, __LINE__, "ssdsd",                                  log_error_write(srv, __FILE__, __LINE__, "ssdsd",
                                                 "response already sent out, termination connection",                                                  "response already sent out, termination connection",
                                                 "connection-fd:", con->fd,                                                  "connection-fd:", con->fd,
                                                 "fcgi-fd:", hctx->fd);                                                  "fcgi-fd:", hctx->fd);
                           }
   
                                scgi_connection_cleanup(srv, hctx);                        http_response_backend_error(srv, con);
                         scgi_connection_close(srv, hctx);
                         return HANDLER_FINISHED;
                 }
                 }
   
                                connection_set_state(srv, con, CON_STATE_ERROR);                return HANDLER_GO_ON;
                        }}
   
                         /* */  
   
   static handler_t scgi_handle_fdevent(server *srv, void *ctx, int revents) {
           handler_ctx *hctx = ctx;
           connection  *con  = hctx->remote_conn;
   
                        joblist_append(srv, con);        joblist_append(srv, con);
                        return HANDLER_FINISHED;
                }        if (revents & FDEVENT_IN) {
                 handler_t rc = scgi_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 ||                return scgi_send_request(srv, hctx); /*(might invalidate hctx)*/
                    hctx->state == FCGI_STATE_WRITE) { 
                        /* we are allowed to send something out 
                         * 
                         * 1. in a unfinished connect() call 
                         * 2. in a unfinished write() call (long POST request) 
                         */ 
                        return mod_scgi_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 2620  static handler_t scgi_handle_fdevent(server *srv, void Line 2732  static handler_t scgi_handle_fdevent(server *srv, void
                          * FIXME: as it is a bit ugly.                           * FIXME: as it is a bit ugly.
                          *                           *
                          */                           */
                        return mod_scgi_handle_subrequest(srv, con, p);                        scgi_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 = scgi_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 {
                           scgi_extension_host *host= hctx->host;
                         log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",                          log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
                                         "error: unexpected close of scgi connection for",                                          "error: unexpected close of scgi connection for",
                                         con->uri.path,                                          con->uri.path,
Line 2639  static handler_t scgi_handle_fdevent(server *srv, void Line 2756  static handler_t scgi_handle_fdevent(server *srv, void
                                         " ?)",                                          " ?)",
                                         hctx->state);                                          hctx->state);
   
                         connection_set_state(srv, con, CON_STATE_ERROR);  
                         scgi_connection_close(srv, hctx);                          scgi_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 scgi process */  
   
                http_response_backend_error(srv, con);
                connection_set_state(srv, con, CON_STATE_ERROR); 
                 scgi_connection_close(srv, hctx);                  scgi_connection_close(srv, hctx);
                 joblist_append(srv, con);  
         }          }
   
         return HANDLER_FINISHED;          return HANDLER_FINISHED;
Line 2706  static handler_t scgi_check_extension(server *srv, con Line 2818  static handler_t scgi_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);
   
         scgi_patch_connection(srv, con, p);          scgi_patch_connection(srv, con, p);
   
Line 2717  static handler_t scgi_check_extension(server *srv, con Line 2829  static handler_t scgi_check_extension(server *srv, con
                 size_t ct_len;                  size_t ct_len;
                 scgi_extension *ext = p->conf.exts->exts[k];                  scgi_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);
   
                 if (s_len < ct_len) continue;                  if (s_len < ct_len) continue;
   
Line 2759  static handler_t scgi_check_extension(server *srv, con Line 2871  static handler_t scgi_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 2778  static handler_t scgi_check_extension(server *srv, con Line 2890  static handler_t scgi_check_extension(server *srv, con
         /* a note about no handler is not sent yet */          /* a note about no handler is not sent yet */
         extension->note_is_sent = 0;          extension->note_is_sent = 0;
   
           /* SCGI requires that Content-Length be set.
            * Send 411 Length Required if Content-Length missing.
            * (Alternatively, collect full request body before proceeding
            *  in mod_scgi_handle_subrequest()) */
           if (0 == con->request.content_length
               && array_get_element(con->request.headers, "Transfer-Encoding")) {
                   con->keep_alive = 0;
                   con->http_status = 411; /* Length Required */
                   con->mode = DIRECT;
                   return HANDLER_FINISHED;
           }
   
         /*          /*
          * if check-local is disabled, use the uri.path handler           * if check-local is disabled, use the uri.path handler
          *           *
Line 2833  static handler_t scgi_check_extension(server *srv, con Line 2957  static handler_t scgi_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'; 
                         }                          }
                 }                  }
         } else {          } else {
Line 2882  static handler_t scgi_check_extension_2(server *srv, c Line 3003  static handler_t scgi_check_extension_2(server *srv, c
         return scgi_check_extension(srv, con, p_d, 0);          return scgi_check_extension(srv, con, p_d, 0);
 }  }
   
 JOBLIST_FUNC(mod_scgi_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:  
                 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 scgi_connection_close_callback(server *srv, connection *con, void *p_d) {  
         plugin_data *p = p_d;  
   
         return scgi_connection_close(srv, con->plugin_ctx[p->id]);  
 }  
   
 TRIGGER_FUNC(mod_scgi_handle_trigger) {  TRIGGER_FUNC(mod_scgi_handle_trigger) {
         plugin_data *p = p_d;          plugin_data *p = p_d;
         size_t i, j, n;          size_t i, j, n;
Line 2986  TRIGGER_FUNC(mod_scgi_handle_trigger) { Line 3072  TRIGGER_FUNC(mod_scgi_handle_trigger) {
   
                                         host->num_procs++;                                          host->num_procs++;
   
                                        if (buffer_is_empty(host->unixsocket)) {                                        if (buffer_string_is_empty(host->unixsocket)) {
                                                 fp->port = host->port + fp->id;                                                  fp->port = host->port + fp->id;
                                         } else {                                          } else {
                                                buffer_copy_string_buffer(fp->socket, host->unixsocket);                                                buffer_copy_buffer(fp->socket, host->unixsocket);
                                                 buffer_append_string_len(fp->socket, CONST_STR_LEN("-"));                                                  buffer_append_string_len(fp->socket, CONST_STR_LEN("-"));
                                                buffer_append_long(fp->socket, fp->id);                                                buffer_append_int(fp->socket, fp->id);
                                         }                                          }
   
                                         if (scgi_spawn_connection(srv, p, host, fp)) {                                          if (scgi_spawn_connection(srv, p, host, fp)) {
                                                 log_error_write(srv, __FILE__, __LINE__, "s",                                                  log_error_write(srv, __FILE__, __LINE__, "s",
                                                                 "ERROR: spawning fcgi failed.");                                                                  "ERROR: spawning fcgi failed.");
                                                   scgi_process_free(fp);
                                                 return HANDLER_ERROR;                                                  return HANDLER_ERROR;
                                         }                                          }
   
Line 3118  int mod_scgi_plugin_init(plugin *p) { Line 3205  int mod_scgi_plugin_init(plugin *p) {
         p->cleanup      = mod_scgi_free;          p->cleanup      = mod_scgi_free;
         p->set_defaults = mod_scgi_set_defaults;          p->set_defaults = mod_scgi_set_defaults;
         p->connection_reset        = scgi_connection_reset;          p->connection_reset        = scgi_connection_reset;
        p->handle_connection_close = scgi_connection_close_callback;        p->handle_connection_close = scgi_connection_reset;
         p->handle_uri_clean        = scgi_check_extension_1;          p->handle_uri_clean        = scgi_check_extension_1;
         p->handle_subrequest_start = scgi_check_extension_2;          p->handle_subrequest_start = scgi_check_extension_2;
         p->handle_subrequest       = mod_scgi_handle_subrequest;          p->handle_subrequest       = mod_scgi_handle_subrequest;
         p->handle_joblist          = mod_scgi_handle_joblist;  
         p->handle_trigger          = mod_scgi_handle_trigger;          p->handle_trigger          = mod_scgi_handle_trigger;
   
         p->data         = NULL;          p->data         = NULL;

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


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