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

version 1.1, 2013/10/14 10:32:48 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 26 Line 28
   
 #include <stdio.h>  #include <stdio.h>
   
 #ifdef HAVE_SYS_FILIO_H  
 # include <sys/filio.h>  
 #endif  
   
 #include "sys-socket.h"  #include "sys-socket.h"
   
 #define data_proxy data_fastcgi  #define data_proxy data_fastcgi
Line 84  typedef enum { Line 82  typedef enum {
         PROXY_STATE_CONNECT,          PROXY_STATE_CONNECT,
         PROXY_STATE_PREPARE_WRITE,          PROXY_STATE_PREPARE_WRITE,
         PROXY_STATE_WRITE,          PROXY_STATE_WRITE,
        PROXY_STATE_READ,        PROXY_STATE_READ
        PROXY_STATE_ERROR 
 } proxy_connection_state_t;  } proxy_connection_state_t;
   
 enum { PROXY_STDOUT, PROXY_END_REQUEST };  enum { PROXY_STDOUT, PROXY_END_REQUEST };
Line 100  typedef struct { Line 97  typedef struct {
         buffer *response_header;          buffer *response_header;
   
         chunkqueue *wb;          chunkqueue *wb;
           off_t wb_reqlen;
   
         int fd; /* fd to the proxy process */          int fd; /* fd to the proxy process */
         int fde_ndx; /* index into the fd-event buffer */          int fde_ndx; /* index into the fd-event buffer */
Line 127  static handler_ctx * handler_ctx_init(void) { Line 125  static handler_ctx * handler_ctx_init(void) {
         hctx->response_header = buffer_init();          hctx->response_header = buffer_init();
   
         hctx->wb = chunkqueue_init();          hctx->wb = chunkqueue_init();
           hctx->wb_reqlen = 0;
   
         hctx->fd = -1;          hctx->fd = -1;
         hctx->fde_ndx = -1;          hctx->fde_ndx = -1;
Line 167  FREE_FUNC(mod_proxy_free) { Line 166  FREE_FUNC(mod_proxy_free) {
                 for (i = 0; i < srv->config_context->used; i++) {                  for (i = 0; i < srv->config_context->used; i++) {
                         plugin_config *s = p->config_storage[i];                          plugin_config *s = p->config_storage[i];
   
                        if (s) {                        if (NULL == s) continue;
   
                                array_free(s->extensions);                        array_free(s->extensions);
   
                                free(s);                        free(s);
                        } 
                 }                  }
                 free(p->config_storage);                  free(p->config_storage);
         }          }
Line 194  SETDEFAULTS_FUNC(mod_proxy_set_defaults) { Line 192  SETDEFAULTS_FUNC(mod_proxy_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 *));
   
         for (i = 0; i < srv->config_context->used; i++) {          for (i = 0; i < srv->config_context->used; i++) {
                   data_config const* config = (data_config const*)srv->config_context->data[i];
                 plugin_config *s;                  plugin_config *s;
                 array *ca;  
   
                 s = malloc(sizeof(plugin_config));                  s = malloc(sizeof(plugin_config));
                 s->extensions    = array_init();                  s->extensions    = array_init();
Line 211  SETDEFAULTS_FUNC(mod_proxy_set_defaults) { Line 209  SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
                 buffer_reset(p->balance_buf);                  buffer_reset(p->balance_buf);
   
                 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;                          return HANDLER_ERROR;
                 }                  }
   
                if (buffer_is_empty(p->balance_buf)) {                if (buffer_string_is_empty(p->balance_buf)) {
                         s->balance = PROXY_BALANCE_FAIR;                          s->balance = PROXY_BALANCE_FAIR;
                 } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("fair"))) {                  } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("fair"))) {
                         s->balance = PROXY_BALANCE_FAIR;                          s->balance = PROXY_BALANCE_FAIR;
Line 231  SETDEFAULTS_FUNC(mod_proxy_set_defaults) { Line 228  SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
                         return HANDLER_ERROR;                          return HANDLER_ERROR;
                 }                  }
   
                if (NULL != (du = array_get_element(ca, "proxy.server"))) {                if (NULL != (du = array_get_element(config->value, "proxy.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: ", "proxy.server", "array of strings");                                                "unexpected type for key: ", "proxy.server", "expected ( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))");
   
                                 return HANDLER_ERROR;                                  return HANDLER_ERROR;
                         }                          }
Line 254  SETDEFAULTS_FUNC(mod_proxy_set_defaults) { Line 251  SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
                                 if (da_ext->type != TYPE_ARRAY) {                                  if (da_ext->type != TYPE_ARRAY) {
                                         log_error_write(srv, __FILE__, __LINE__, "sssbs",                                          log_error_write(srv, __FILE__, __LINE__, "sssbs",
                                                         "unexpected type for key: ", "proxy.server",                                                          "unexpected type for key: ", "proxy.server",
                                                        "[", da->value->data[j]->key, "](string)");                                                        "[", da->value->data[j]->key, "](string); expected ( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))");
   
                                         return HANDLER_ERROR;                                          return HANDLER_ERROR;
                                 }                                  }
Line 283  SETDEFAULTS_FUNC(mod_proxy_set_defaults) { Line 280  SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
                                                 log_error_write(srv, __FILE__, __LINE__, "ssSBS",                                                  log_error_write(srv, __FILE__, __LINE__, "ssSBS",
                                                                 "unexpected type for key:",                                                                  "unexpected type for key:",
                                                                 "proxy.server",                                                                  "proxy.server",
                                                                "[", da_ext->value->data[n]->key, "](string)");                                                                "[", da_ext->value->data[n]->key, "](string); expected ( \"ext\" => ( \"backend-label\" => ( \"key\" => \"value\" )))");
   
                                                 return HANDLER_ERROR;                                                  return HANDLER_ERROR;
                                         }                                          }
Line 292  SETDEFAULTS_FUNC(mod_proxy_set_defaults) { Line 289  SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
   
                                         df->port = 80;                                          df->port = 80;
   
                                        buffer_copy_string_buffer(df->key, da_host->key);                                        buffer_copy_buffer(df->key, da_host->key);
   
                                         pcv[0].destination = df->host;                                          pcv[0].destination = df->host;
                                         pcv[1].destination = &(df->port);                                          pcv[1].destination = &(df->port);
   
                                        if (0 != config_insert_values_internal(srv, da_host->value, pcv)) {                                        if (0 != config_insert_values_internal(srv, da_host->value, pcv, T_CONFIG_SCOPE_CONNECTION)) {
                                                 df->free((data_unset*) df);
                                                 return HANDLER_ERROR;                                                  return HANDLER_ERROR;
                                         }                                          }
   
                                        if (buffer_is_empty(df->host)) {                                        if (buffer_string_is_empty(df->host)) {
                                                 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 309  SETDEFAULTS_FUNC(mod_proxy_set_defaults) { Line 307  SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
                                                                 da_host->key,                                                                  da_host->key,
                                                                 "host");                                                                  "host");
   
                                                   df->free((data_unset*) df);
                                                 return HANDLER_ERROR;                                                  return HANDLER_ERROR;
                                         }                                          }
   
Line 317  SETDEFAULTS_FUNC(mod_proxy_set_defaults) { Line 316  SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
                                         if (NULL == (dfa = (data_array *)array_get_element(s->extensions, da_ext->key->ptr))) {                                          if (NULL == (dfa = (data_array *)array_get_element(s->extensions, da_ext->key->ptr))) {
                                                 dfa = data_array_init();                                                  dfa = data_array_init();
   
                                                buffer_copy_string_buffer(dfa->key, da_ext->key);                                                buffer_copy_buffer(dfa->key, da_ext->key);
   
                                                 array_insert_unique(dfa->value, (data_unset *)df);                                                  array_insert_unique(dfa->value, (data_unset *)df);
                                                 array_insert_unique(s->extensions, (data_unset *)dfa);                                                  array_insert_unique(s->extensions, (data_unset *)dfa);
Line 336  static void proxy_connection_close(server *srv, handle Line 335  static void proxy_connection_close(server *srv, handle
         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 355  static void proxy_connection_close(server *srv, handle Line 352  static void proxy_connection_close(server *srv, handle
   
         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 proxy_establish_connection(server *srv, handler_ctx *hctx) {  static int proxy_establish_connection(server *srv, handler_ctx *hctx) {
         struct sockaddr *proxy_addr;          struct sockaddr *proxy_addr;
         struct sockaddr_in proxy_addr_in;          struct sockaddr_in proxy_addr_in;
   #if defined(HAVE_SYS_UN_H)
           struct sockaddr_un proxy_addr_un;
   #endif
 #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)  #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
         struct sockaddr_in6 proxy_addr_in6;          struct sockaddr_in6 proxy_addr_in6;
 #endif  #endif
Line 370  static int proxy_establish_connection(server *srv, han Line 375  static int proxy_establish_connection(server *srv, han
         int proxy_fd       = hctx->fd;          int proxy_fd       = hctx->fd;
   
   
   #if defined(HAVE_SYS_UN_H)
           if (strstr(host->host->ptr, "/")) {
                   if (buffer_string_length(host->host) + 1 > sizeof(proxy_addr_un.sun_path)) {
                           log_error_write(srv, __FILE__, __LINE__, "sB",
                                   "ERROR: Unix Domain socket filename too long:",
                                   host->host);
                           return -1;
                   }
   
                   memset(&proxy_addr_un, 0, sizeof(proxy_addr_un));
                   proxy_addr_un.sun_family = AF_UNIX;
                   memcpy(proxy_addr_un.sun_path, host->host->ptr, buffer_string_length(host->host) + 1);
                   servlen = sizeof(proxy_addr_un);
                   proxy_addr = (struct sockaddr *) &proxy_addr_un;
           } else
   #endif
 #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)  #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
         if (strstr(host->host->ptr, ":")) {          if (strstr(host->host->ptr, ":")) {
                 memset(&proxy_addr_in6, 0, sizeof(proxy_addr_in6));                  memset(&proxy_addr_in6, 0, sizeof(proxy_addr_in6));
Line 415  static int proxy_establish_connection(server *srv, han Line 436  static int proxy_establish_connection(server *srv, han
 }  }
   
 static void proxy_set_header(connection *con, const char *key, const char *value) {  static void proxy_set_header(connection *con, const char *key, const char *value) {
    data_string *ds_dst;        data_string *ds_dst;
   
    if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {        if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
          ds_dst = data_string_init();                ds_dst = data_string_init();
    }        }
   
    buffer_copy_string(ds_dst->key, key);        buffer_copy_string(ds_dst->key, key);
    buffer_copy_string(ds_dst->value, value);        buffer_copy_string(ds_dst->value, value);
    array_insert_unique(con->request.headers, (data_unset *)ds_dst);        array_insert_unique(con->request.headers, (data_unset *)ds_dst);
 }  }
   
 static void proxy_append_header(connection *con, const char *key, const char *value) {  static void proxy_append_header(connection *con, const char *key, const char *value) {
    data_string *ds_dst;        data_string *ds_dst;
   
    if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {        if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
          ds_dst = data_string_init();                ds_dst = data_string_init();
    }        }
   
    buffer_copy_string(ds_dst->key, key);        buffer_copy_string(ds_dst->key, key);
    buffer_append_string(ds_dst->value, value);        buffer_append_string(ds_dst->value, value);
    array_insert_unique(con->request.headers, (data_unset *)ds_dst);        array_insert_unique(con->request.headers, (data_unset *)ds_dst);
 }  }
   
   
Line 447  static int proxy_create_env(server *srv, handler_ctx * Line 468  static int proxy_create_env(server *srv, handler_ctx *
   
         /* build header */          /* build header */
   
        b = chunkqueue_get_append_buffer(hctx->wb);        b = buffer_init();
   
         /* request line */          /* request line */
         buffer_copy_string(b, get_http_method_name(con->request.http_method));          buffer_copy_string(b, get_http_method_name(con->request.http_method));
Line 459  static int proxy_create_env(server *srv, handler_ctx * Line 480  static int proxy_create_env(server *srv, handler_ctx *
         proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr)));          proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
         /* http_host is NOT is just a pointer to a buffer          /* http_host is NOT is just a pointer to a buffer
          * which is NULL if it is not set */           * which is NULL if it is not set */
        if (con->request.http_host &&        if (!buffer_string_is_empty(con->request.http_host)) {
            !buffer_is_empty(con->request.http_host)) { 
                 proxy_set_header(con, "X-Host", con->request.http_host->ptr);                  proxy_set_header(con, "X-Host", con->request.http_host->ptr);
         }          }
         proxy_set_header(con, "X-Forwarded-Proto", con->uri.scheme->ptr);          proxy_set_header(con, "X-Forwarded-Proto", con->uri.scheme->ptr);
Line 471  static int proxy_create_env(server *srv, handler_ctx * Line 491  static int proxy_create_env(server *srv, handler_ctx *
   
                 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)) {
                        if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;                        if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Connection"))) continue;
                        if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Proxy-Connection"))) continue;                        if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy-Connection"))) continue;
                         /* Do not emit HTTP_PROXY in environment.
                          * Some executables use HTTP_PROXY to configure
                          * outgoing proxy.  See also https://httpoxy.org/ */
                         if (buffer_is_equal_caseless_string(ds->key, CONST_STR_LEN("Proxy"))) continue;
   
                         buffer_append_string_buffer(b, ds->key);                          buffer_append_string_buffer(b, ds->key);
                         buffer_append_string_len(b, CONST_STR_LEN(": "));                          buffer_append_string_len(b, CONST_STR_LEN(": "));
Line 482  static int proxy_create_env(server *srv, handler_ctx * Line 506  static int proxy_create_env(server *srv, handler_ctx *
                 }                  }
         }          }
   
        buffer_append_string_len(b, CONST_STR_LEN("\r\n"));        buffer_append_string_len(b, CONST_STR_LEN("Connection: close\r\n\r\n"));
   
        hctx->wb->bytes_in += b->used - 1;        hctx->wb_reqlen = buffer_string_length(b);
         chunkqueue_append_buffer(hctx->wb, b);
         buffer_free(b);
 
         /* body */          /* body */
   
         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 557  static int proxy_response_parse(server *srv, connectio Line 536  static int proxy_response_parse(server *srv, connectio
   
         UNUSED(srv);          UNUSED(srv);
   
        /* \r\n -> \0\0 */        /* [\r]\n -> [\0]\0 */
   
        buffer_copy_string_buffer(p->parse_response, in);        buffer_copy_buffer(p->parse_response, in);
   
        for (s = p->parse_response->ptr; NULL != (ns = strstr(s, "\r\n")); s = ns + 2) {        for (s = p->parse_response->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) {
                 char *key, *value;                  char *key, *value;
                 int key_len;                  int key_len;
                 data_string *ds;                  data_string *ds;
                 int copy_header;                  int copy_header;
   
                 ns[0] = '\0';                  ns[0] = '\0';
                ns[1] = '\0';                if (s != ns && ns[-1] == '\r') ns[-1] = '\0';
   
                 if (-1 == http_response_status) {                  if (-1 == http_response_status) {
                         /* The first line of a Response message is the Status-Line */                          /* The first line of a Response message is the Status-Line */
Line 577  static int proxy_response_parse(server *srv, connectio Line 556  static int proxy_response_parse(server *srv, connectio
   
                         if (*key) {                          if (*key) {
                                 http_response_status = (int) strtol(key, NULL, 10);                                  http_response_status = (int) strtol(key, NULL, 10);
                                if (http_response_status <= 0) http_response_status = 502;                                if (http_response_status < 100 || http_response_status >= 1000) http_response_status = 502;
                         } else {                          } else {
                                 http_response_status = 502;                                  http_response_status = 502;
                         }                          }
Line 620  static int proxy_response_parse(server *srv, connectio Line 599  static int proxy_response_parse(server *srv, connectio
                         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 653  static int proxy_demux_response(server *srv, handler_c Line 632  static int proxy_demux_response(server *srv, handler_c
         int proxy_fd       = hctx->fd;          int proxy_fd       = hctx->fd;
   
         /* check how much we have to read */          /* check how much we have to read */
         #if !defined(_WIN32) && !defined(__CYGWIN__)
         if (ioctl(hctx->fd, FIONREAD, &b)) {          if (ioctl(hctx->fd, FIONREAD, &b)) {
                   if (errno == EAGAIN) {
                           fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
                           return 0;
                   }
                 log_error_write(srv, __FILE__, __LINE__, "sd",                  log_error_write(srv, __FILE__, __LINE__, "sd",
                                 "ioctl failed: ",                                  "ioctl failed: ",
                                 proxy_fd);                                  proxy_fd);
                 return -1;                  return -1;
         }          }
         #else
           b = 4096;
         #endif
   
   
         if (p->conf.debug) {          if (p->conf.debug) {
                 log_error_write(srv, __FILE__, __LINE__, "sd",                  log_error_write(srv, __FILE__, __LINE__, "sd",
                               "proxy - have to read:", b);                                "proxy - have to read:", b);
         }          }
   
         if (b > 0) {          if (b > 0) {
                if (hctx->response->used == 0) {                if ((con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN)) {
                        /* avoid too small buffer */                        off_t cqlen = chunkqueue_length(con->write_queue);
                        buffer_prepare_append(hctx->response, b + 1);                        if (cqlen + b > 65536 - 4096) {
                        hctx->response->used = 1;                                if (!con->is_writable) {
                } else {                                        /*(defer removal of FDEVENT_IN interest since
                        buffer_prepare_append(hctx->response, b);                                         * 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_proxy_handle_subrequest())*/
                                         fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
                                 }
                                 if (cqlen >= 65536-1) return 0;
                                 b = 65536 - 1 - (int)cqlen;
                         }
                 }                  }
   
                if (-1 == (r = read(hctx->fd, hctx->response->ptr + hctx->response->used - 1, b))) {                buffer_string_prepare_append(hctx->response, b);
                        if (errno == EAGAIN) return 0;
                 if (-1 == (r = read(hctx->fd, hctx->response->ptr + buffer_string_length(hctx->response), buffer_string_space(hctx->response)))) {
                         if (errno == EAGAIN) {
                                 fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
                                 return 0;
                         }
                         log_error_write(srv, __FILE__, __LINE__, "sds",                          log_error_write(srv, __FILE__, __LINE__, "sds",
                                         "unexpected end-of-file (perhaps the proxy process died):",                                          "unexpected end-of-file (perhaps the proxy process died):",
                                         proxy_fd, strerror(errno));                                          proxy_fd, strerror(errno));
                         return -1;                          return -1;
                 }                  }
   
                 #if defined(_WIN32) || defined(__CYGWIN__)
                   if (0 == r) return 1; /* fin */
                 #endif
   
                 /* this should be catched by the b > 0 above */                  /* this should be catched by the b > 0 above */
                assert(r);                force_assert(r);
   
                hctx->response->used += r;                buffer_commit(hctx->response, r);
                hctx->response->ptr[hctx->response->used - 1] = '\0'; 
   
 #if 0  #if 0
                 log_error_write(srv, __FILE__, __LINE__, "sdsbs",                  log_error_write(srv, __FILE__, __LINE__, "sdsbs",
Line 696  static int proxy_demux_response(server *srv, handler_c Line 699  static int proxy_demux_response(server *srv, handler_c
   
                 if (0 == con->got_response) {                  if (0 == con->got_response) {
                         con->got_response = 1;                          con->got_response = 1;
                        buffer_prepare_copy(hctx->response_header, 128);                        buffer_string_prepare_copy(hctx->response_header, 1023);
                 }                  }
   
                 if (0 == con->file_started) {                  if (0 == con->file_started) {
                         char *c;                          char *c;
   
                         /* search for the \r\n\r\n in the string */                          /* search for the \r\n\r\n in the string */
                        if (NULL != (c = buffer_search_string_len(hctx->response, "\r\n\r\n", 4))) {                        if (NULL != (c = buffer_search_string_len(hctx->response, CONST_STR_LEN("\r\n\r\n")))) {
                                 size_t hlen = c - hctx->response->ptr + 4;                                  size_t hlen = c - hctx->response->ptr + 4;
                                size_t blen = hctx->response->used - hlen - 1;                                size_t blen = buffer_string_length(hctx->response) - hlen;
                                 /* found */                                  /* found */
   
                                buffer_append_string_len(hctx->response_header, hctx->response->ptr, c - hctx->response->ptr + 4);                                buffer_append_string_len(hctx->response_header, hctx->response->ptr, hlen);
 #if 0  #if 0
                                 log_error_write(srv, __FILE__, __LINE__, "sb", "Header:", hctx->response_header);                                  log_error_write(srv, __FILE__, __LINE__, "sb", "Header:", hctx->response_header);
 #endif  #endif
                                 /* parse the response header */                                  /* parse the response header */
                                 proxy_response_parse(srv, con, p, hctx->response_header);                                  proxy_response_parse(srv, con, p, hctx->response_header);
   
                                 /* enable chunked-transfer-encoding */  
                                 if (con->request.http_version == HTTP_VERSION_1_1 &&  
                                     !(con->parsed_response & HTTP_CONTENT_LENGTH)) {  
                                         con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;  
                                 }  
   
                                 con->file_started = 1;                                  con->file_started = 1;
                                if (blen) {                                if (blen > 0) {
                                        http_chunk_append_mem(srv, con, c + 4, blen + 1);                                        if (0 != http_chunk_append_mem(srv, con, c + 4, blen)) {
                                                 /* error writing to tempfile;
                                                  * truncate response or send 500 if nothing sent yet */
                                                 fin = 1;
                                                 con->file_started = 0;
                                         }
                                 }                                  }
                                hctx->response->used = 0;                                buffer_reset(hctx->response);
                                joblist_append(srv, con);                        } else {
                                 /* no luck, no header found */
                                 /*(reuse MAX_HTTP_REQUEST_HEADER as max size for response headers from backends)*/
                                 if (buffer_string_length(hctx->response) > MAX_HTTP_REQUEST_HEADER) {
                                         log_error_write(srv, __FILE__, __LINE__, "sb", "response headers too large for", con->uri.path);
                                         con->http_status = 502; /* Bad Gateway */
                                         con->mode = DIRECT;
                                         fin = 1;
                                 }
                         }                          }
                 } 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;
                        hctx->response->used = 0;                                 * truncate response or send 500 if nothing sent yet */
                                 fin = 1;
                         }
                         buffer_reset(hctx->response);
                 }                  }
   
         } else {          } else {
                 /* reading from upstream done */                  /* reading from upstream done */
                 con->file_finished = 1;  
   
                 http_chunk_append_mem(srv, con, NULL, 0);  
                 joblist_append(srv, con);  
   
                 fin = 1;                  fin = 1;
         }          }
   
Line 754  static handler_t proxy_write_request(server *srv, hand Line 761  static handler_t proxy_write_request(server *srv, hand
   
         int ret;          int ret;
   
        if (!host ||        if (!host || buffer_string_is_empty(host->host) || !host->port) return HANDLER_ERROR;
            (!host->host->used || !host->port)) return -1; 
   
         switch(hctx->state) {          switch(hctx->state) {
         case PROXY_STATE_CONNECT:          case PROXY_STATE_CONNECT:
Line 767  static handler_t proxy_write_request(server *srv, hand Line 773  static handler_t proxy_write_request(server *srv, hand
                 /* wait */                  /* wait */
                 return HANDLER_WAIT_FOR_EVENT;                  return HANDLER_WAIT_FOR_EVENT;
   
                 break;  
   
         case PROXY_STATE_INIT:          case PROXY_STATE_INIT:
   #if defined(HAVE_SYS_UN_H)
                   if (strstr(host->host->ptr,"/")) {
                           if (-1 == (hctx->fd = socket(AF_UNIX, SOCK_STREAM, 0))) {
                                   log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
                                   return HANDLER_ERROR;
                           }
                   } else
   #endif
 #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)  #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
                 if (strstr(host->host->ptr,":")) {                  if (strstr(host->host->ptr,":")) {
                    if (-1 == (hctx->fd = socket(AF_INET6, SOCK_STREAM, 0))) {                        if (-1 == (hctx->fd = socket(AF_INET6, SOCK_STREAM, 0))) {
                        log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));                                log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
                        return HANDLER_ERROR;                                return HANDLER_ERROR;
                    }                        }
                 } else                  } else
 #endif  #endif
                 {                  {
                    if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {                        if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
                        log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));                                log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
                        return HANDLER_ERROR;                                return HANDLER_ERROR;
                    }                        }
                 }                  }
                 hctx->fde_ndx = -1;                  hctx->fde_ndx = -1;
   
Line 821  static handler_t proxy_write_request(server *srv, hand Line 833  static handler_t proxy_write_request(server *srv, hand
         case PROXY_STATE_PREPARE_WRITE:          case PROXY_STATE_PREPARE_WRITE:
                 proxy_create_env(srv, hctx);                  proxy_create_env(srv, hctx);
   
                   fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
                 proxy_set_state(srv, hctx, PROXY_STATE_WRITE);                  proxy_set_state(srv, hctx, PROXY_STATE_WRITE);
   
                 /* fall through */                  /* fall through */
Line 839  static handler_t proxy_write_request(server *srv, hand Line 852  static handler_t proxy_write_request(server *srv, hand
                         return HANDLER_ERROR;                          return HANDLER_ERROR;
                 }                  }
   
                if (hctx->wb->bytes_out == hctx->wb->bytes_in) {                if (hctx->wb->bytes_out == hctx->wb_reqlen) {
                         fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
                       #if (defined(__APPLE__) && defined(__MACH__)) \
                         || 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);/* future: remove if HTTP/1.1 request */
                         }
                       #endif
                         proxy_set_state(srv, hctx, PROXY_STATE_READ);                          proxy_set_state(srv, hctx, PROXY_STATE_READ);
   
                         fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);  
                         fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);  
                 } 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);
                         }
                 }                  }
   
                 return HANDLER_WAIT_FOR_EVENT;                  return HANDLER_WAIT_FOR_EVENT;
Line 858  static handler_t proxy_write_request(server *srv, hand Line 893  static handler_t proxy_write_request(server *srv, hand
                 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_GO_ON;  
 }  }
   
 #define PATCH(x) \  #define PATCH(x) \
Line 898  static int mod_proxy_patch_connection(server *srv, con Line 931  static int mod_proxy_patch_connection(server *srv, con
 }  }
 #undef PATCH  #undef PATCH
   
SUBREQUEST_FUNC(mod_proxy_handle_subrequest) {static handler_t proxy_send_request(server *srv, handler_ctx *hctx) {
        plugin_data *p = p_d; 
 
        handler_ctx *hctx = con->plugin_ctx[p->id]; 
        data_proxy *host; 
 
        if (NULL == hctx) return HANDLER_GO_ON; 
 
        mod_proxy_patch_connection(srv, con, p); 
 
        host = hctx->host; 
 
        /* not my job */ 
        if (con->mode != p->id) return HANDLER_GO_ON; 
 
         /* ok, create the request */          /* ok, create the request */
        switch(proxy_write_request(srv, hctx)) {        handler_t rc = proxy_write_request(srv, hctx);
        case HANDLER_ERROR:        if (HANDLER_ERROR != rc) {
                 return rc;
         } else {
                 data_proxy *host = hctx->host;
                 connection *con  = hctx->remote_conn;
                 plugin_data *p   = hctx->plugin_data;
                 log_error_write(srv, __FILE__, __LINE__,  "sbdd", "proxy-server disabled:",                  log_error_write(srv, __FILE__, __LINE__,  "sbdd", "proxy-server disabled:",
                                 host->host,                                  host->host,
                                 host->port,                                  host->port,
Line 925  SUBREQUEST_FUNC(mod_proxy_handle_subrequest) { Line 949  SUBREQUEST_FUNC(mod_proxy_handle_subrequest) {
                 host->is_disabled = 1;                  host->is_disabled = 1;
                 host->disable_ts = srv->cur_ts;                  host->disable_ts = srv->cur_ts;
   
                   /* reset the enviroment and restart the sub-request */
                   con->mode = DIRECT;/*(avoid changing con->state, con->http_status)*/
                 proxy_connection_close(srv, hctx);                  proxy_connection_close(srv, hctx);
                   con->mode = p->id;
   
                /* reset the enviroment and restart the sub-request */                return HANDLER_COMEBACK;
                buffer_reset(con->physical.path);        }
                con->mode = DIRECT;}
   
                 joblist_append(srv, con);  
   
                /* mis-using HANDLER_WAIT_FOR_FD to break out of the loopstatic handler_t proxy_recv_response(server *srv, handler_ctx *hctx);
                 * and hope that the childs will be restarted 
                 * 
                 */ 
   
                return HANDLER_WAIT_FOR_FD;
        case HANDLER_WAIT_FOR_EVENT:SUBREQUEST_FUNC(mod_proxy_handle_subrequest) {
                break;        plugin_data *p = p_d;
        case HANDLER_WAIT_FOR_FD:
                return HANDLER_WAIT_FOR_FD;        handler_ctx *hctx = con->plugin_ctx[p->id];
        default:
                break;        if (NULL == hctx) return HANDLER_GO_ON;
 
         /* not my job */
         if (con->mode != p->id) return HANDLER_GO_ON;
 
         if ((con->conf.stream_response_body & FDEVENT_STREAM_RESPONSE_BUFMIN)
             && con->file_started) {
                 if (chunkqueue_length(con->write_queue) > 65536 - 4096) {
                         fdevent_event_clr(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
                 } else if (!(fdevent_event_get_interest(srv->ev, hctx->fd) & FDEVENT_IN)) {
                         /* optimistic read from backend, which might re-enable FDEVENT_IN */
                         handler_t rc = proxy_recv_response(srv, hctx); /*(might invalidate hctx)*/
                         if (rc != HANDLER_GO_ON) return rc;            /*(unless HANDLER_GO_ON)*/
                 }
         }          }
   
        if (con->file_started == 1) {        if (0 == hctx->wb->bytes_in
                return HANDLER_FINISHED;            ? con->state == CON_STATE_READ_POST
        } else {            : hctx->wb->bytes_in < hctx->wb_reqlen) {
                return HANDLER_WAIT_FOR_EVENT;                /*(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 ((0 == hctx->wb->bytes_in || !chunkqueue_is_empty(hctx->wb))
                   && hctx->state != PROXY_STATE_CONNECT)
             ? proxy_send_request(srv, hctx)
             : HANDLER_WAIT_FOR_EVENT;
 }  }
   
   
   static handler_t proxy_recv_response(server *srv, handler_ctx *hctx) {
   
                   switch (proxy_demux_response(srv, hctx)) {
                   case 0:
                           break;
                   case -1:
                           http_response_backend_error(srv, hctx->remote_conn);
                           /* fall through */
                   case 1:
                           /* we are done */
                           proxy_connection_close(srv, hctx);
   
                           return HANDLER_FINISHED;
                   }
   
                   return HANDLER_GO_ON;
   }
   
   
 static handler_t proxy_handle_fdevent(server *srv, void *ctx, int revents) {  static handler_t proxy_handle_fdevent(server *srv, void *ctx, int revents) {
         handler_ctx *hctx = ctx;          handler_ctx *hctx = ctx;
         connection  *con  = hctx->remote_conn;          connection  *con  = hctx->remote_conn;
         plugin_data *p    = hctx->plugin_data;          plugin_data *p    = hctx->plugin_data;
   
           joblist_append(srv, con);
   
        if ((revents & FDEVENT_IN) &&        if (revents & FDEVENT_IN) {
            hctx->state == PROXY_STATE_READ) { 
   
                 if (p->conf.debug) {                  if (p->conf.debug) {
                         log_error_write(srv, __FILE__, __LINE__, "sd",                          log_error_write(srv, __FILE__, __LINE__, "sd",
                                         "proxy: fdevent-in", hctx->state);                                          "proxy: fdevent-in", hctx->state);
                 }                  }
   
                switch (proxy_demux_response(srv, hctx)) {                {
                case 0:                handler_t rc = proxy_recv_response(srv,hctx);/*(might invalidate hctx)*/
                        break;                if (rc != HANDLER_GO_ON) return rc;          /*(unless HANDLER_GO_ON)*/
                case 1: 
                        /* we are done */ 
                        proxy_connection_close(srv, hctx); 
 
                        joblist_append(srv, con); 
                        return HANDLER_FINISHED; 
                case -1: 
                        if (con->file_started == 0) { 
                                /* nothing has been send out yet, send a 500 */ 
                                connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); 
                                con->http_status = 500; 
                                con->mode = DIRECT; 
                        } else { 
                                /* response might have been already started, kill the connection */ 
                                connection_set_state(srv, con, CON_STATE_ERROR); 
                        } 
 
                        joblist_append(srv, con); 
                        return HANDLER_FINISHED; 
                 }                  }
         }          }
   
Line 1003  static handler_t proxy_handle_fdevent(server *srv, voi Line 1061  static handler_t proxy_handle_fdevent(server *srv, voi
                         int socket_error;                          int socket_error;
                         socklen_t socket_error_len = sizeof(socket_error);                          socklen_t socket_error_len = sizeof(socket_error);
   
                         /* we don't need it anymore */  
                         fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);  
                         hctx->fde_ndx = -1;  
   
                         /* try to finish the connect() */                          /* try to finish the connect() */
                         if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {                          if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
                                 log_error_write(srv, __FILE__, __LINE__, "ss",                                  log_error_write(srv, __FILE__, __LINE__, "ss",
                                         "getsockopt failed:", strerror(errno));                                          "getsockopt failed:", strerror(errno));
   
                                 joblist_append(srv, con);  
                                 return HANDLER_FINISHED;                                  return HANDLER_FINISHED;
                         }                          }
                         if (socket_error != 0) {                          if (socket_error != 0) {
Line 1020  static handler_t proxy_handle_fdevent(server *srv, voi Line 1073  static handler_t proxy_handle_fdevent(server *srv, voi
                                         "establishing connection failed:", strerror(socket_error),                                          "establishing connection failed:", strerror(socket_error),
                                         "port:", hctx->host->port);                                          "port:", hctx->host->port);
   
                                 joblist_append(srv, con);  
                                 return HANDLER_FINISHED;                                  return HANDLER_FINISHED;
                         }                          }
                         if (p->conf.debug) {                          if (p->conf.debug) {
Line 1030  static handler_t proxy_handle_fdevent(server *srv, voi Line 1082  static handler_t proxy_handle_fdevent(server *srv, voi
                         proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE);                          proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE);
                 }                  }
   
                if (hctx->state == PROXY_STATE_PREPARE_WRITE ||                return proxy_send_request(srv, hctx); /*(might invalidate hctx)*/
                    hctx->state == PROXY_STATE_WRITE) { 
                        /* we are allowed to send something out 
                         * 
                         * 1. after a just finished connect() call 
                         * 2. in a unfinished write() call (long POST request) 
                         */ 
                        return mod_proxy_handle_subrequest(srv, con, p); 
                } else { 
                        log_error_write(srv, __FILE__, __LINE__, "sd", 
                                        "proxy: out", hctx->state); 
                } 
         }          }
   
         /* perhaps this issue is already handled */          /* perhaps this issue is already handled */
Line 1071  static handler_t proxy_handle_fdevent(server *srv, voi Line 1112  static handler_t proxy_handle_fdevent(server *srv, voi
                                 hctx->host->is_disabled = 1;                                  hctx->host->is_disabled = 1;
                                 hctx->host->disable_ts = srv->cur_ts;                                  hctx->host->disable_ts = srv->cur_ts;
   
                                   /* reset the environment and restart the sub-request */
                                   con->mode = DIRECT;/*(avoid changing con->state, con->http_status)*/
                                 proxy_connection_close(srv, hctx);                                  proxy_connection_close(srv, hctx);
                                con->mode = p->id;
                                /* reset the enviroment and restart the sub-request */ 
                                buffer_reset(con->physical.path); 
                                con->mode = DIRECT; 
 
                                joblist_append(srv, con); 
                         } else {                          } else {
                                 proxy_connection_close(srv, hctx);                                  proxy_connection_close(srv, hctx);
                                 joblist_append(srv, con);  
   
                                 con->mode = DIRECT;  
                                 con->http_status = 503;                                  con->http_status = 503;
                         }                          }
                } else if (con->file_started) {
                        return HANDLER_FINISHED;                        /* drain any remaining data from kernel pipe buffers
                          * even if (con->conf.stream_response_body
                          *          & FDEVENT_STREAM_RESPONSE_BUFMIN)
                          * since event loop will spin on fd FDEVENT_HUP event
                          * until unregistered. */
                         handler_t rc;
                         do {
                                 rc = proxy_recv_response(srv,hctx);/*(might invalidate hctx)*/
                         } while (rc == HANDLER_GO_ON);             /*(unless HANDLER_GO_ON)*/
                         return rc; /* HANDLER_FINISHED or HANDLER_ERROR */
                 } else {
                         proxy_connection_close(srv, hctx);
                 }                  }
   
                 if (!con->file_finished) {  
                         http_chunk_append_mem(srv, con, NULL, 0);  
                 }  
   
                 con->file_finished = 1;  
                 proxy_connection_close(srv, hctx);  
                 joblist_append(srv, con);  
         } else if (revents & FDEVENT_ERR) {          } else if (revents & FDEVENT_ERR) {
                 /* kill all connections to the proxy process */  
   
                 log_error_write(srv, __FILE__, __LINE__, "sd", "proxy-FDEVENT_ERR, but no HUP", revents);                  log_error_write(srv, __FILE__, __LINE__, "sd", "proxy-FDEVENT_ERR, but no HUP", revents);
   
                con->file_finished = 1;                http_response_backend_error(srv, con);
                joblist_append(srv, con); 
                 proxy_connection_close(srv, hctx);                  proxy_connection_close(srv, hctx);
         }          }
   
Line 1128  static handler_t mod_proxy_check_extension(server *srv Line 1163  static handler_t mod_proxy_check_extension(server *srv
         mod_proxy_patch_connection(srv, con, p);          mod_proxy_patch_connection(srv, con, p);
   
         fn = con->uri.path;          fn = con->uri.path;
           if (buffer_string_is_empty(fn)) return HANDLER_ERROR;
           s_len = buffer_string_length(fn);
   
         if (fn->used == 0) {  
                 return HANDLER_ERROR;  
         }  
   
         s_len = fn->used - 1;  
   
   
         path_info_offset = 0;          path_info_offset = 0;
   
         if (p->conf.debug) {          if (p->conf.debug) {
Line 1149  static handler_t mod_proxy_check_extension(server *srv Line 1179  static handler_t mod_proxy_check_extension(server *srv
   
                 ext = (data_array *)p->conf.extensions->data[k];                  ext = (data_array *)p->conf.extensions->data[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 1256  static handler_t mod_proxy_check_extension(server *srv Line 1286  static handler_t mod_proxy_check_extension(server *srv
                 }                  }
   
                 /* just to be sure */                  /* just to be sure */
                assert(extension->value->used < INT_MAX);                force_assert(extension->value->used < INT_MAX);
   
                 host = (data_proxy *)extension->value->data[0];                  host = (data_proxy *)extension->value->data[0];
   
Line 1333  static handler_t mod_proxy_check_extension(server *srv Line 1363  static handler_t mod_proxy_check_extension(server *srv
         return HANDLER_GO_ON;          return HANDLER_GO_ON;
 }  }
   
static handler_t mod_proxy_connection_close_callback(server *srv, connection *con, void *p_d) {static handler_t mod_proxy_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) proxy_connection_close(srv, hctx);
   
         proxy_connection_close(srv, con->plugin_ctx[p->id]);  
   
         return HANDLER_GO_ON;          return HANDLER_GO_ON;
 }  }
   
Line 1391  int mod_proxy_plugin_init(plugin *p) { Line 1421  int mod_proxy_plugin_init(plugin *p) {
         p->init         = mod_proxy_init;          p->init         = mod_proxy_init;
         p->cleanup      = mod_proxy_free;          p->cleanup      = mod_proxy_free;
         p->set_defaults = mod_proxy_set_defaults;          p->set_defaults = mod_proxy_set_defaults;
        p->connection_reset        = mod_proxy_connection_close_callback; /* end of req-resp cycle */        p->connection_reset        = mod_proxy_connection_reset; /* end of req-resp cycle */
        p->handle_connection_close = mod_proxy_connection_close_callback; /* end of client connection */        p->handle_connection_close = mod_proxy_connection_reset; /* end of client connection */
         p->handle_uri_clean        = mod_proxy_check_extension;          p->handle_uri_clean        = mod_proxy_check_extension;
         p->handle_subrequest       = mod_proxy_handle_subrequest;          p->handle_subrequest       = mod_proxy_handle_subrequest;
         p->handle_trigger          = mod_proxy_trigger;          p->handle_trigger          = mod_proxy_trigger;

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


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