diff --git a/src/mod_cgi.c b/src/mod_cgi.c index 71fb5fd1..088de085 100644 --- a/src/mod_cgi.c +++ b/src/mod_cgi.c @@ -35,10 +35,6 @@ #include #include -#ifdef HAVE_SYS_FILIO_H -# include -#endif - #include "version.h" enum {EOL_UNSET, EOL_N, EOL_RN}; @@ -92,6 +88,7 @@ static handler_ctx * cgi_handler_ctx_init(void) { hctx->response = buffer_init(); hctx->response_header = buffer_init(); + hctx->fd = -1; return hctx; } @@ -385,7 +382,6 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) { /* send final chunk */ http_chunk_close(srv, con); - joblist_append(srv, con); return FDEVENT_HANDLED_FINISHED; } @@ -473,7 +469,6 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) { } http_chunk_append_buffer(srv, con, hctx->response_header); - joblist_append(srv, con); } else { const char *bstart; size_t blen; @@ -507,7 +502,6 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) { if (blen > 0) { http_chunk_append_mem(srv, con, bstart, blen); - joblist_append(srv, con); } } @@ -515,7 +509,6 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) { } } else { http_chunk_append_buffer(srv, con, hctx->response); - joblist_append(srv, con); } #if 0 @@ -526,7 +519,7 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) { return FDEVENT_HANDLED_NOT_FINISHED; } -static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) { +static void cgi_connection_close(server *srv, handler_ctx *hctx) { int status; pid_t pid; plugin_data *p = hctx->plugin_data; @@ -612,7 +605,8 @@ static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) { } #endif - if (con->state == CON_STATE_HANDLE_REQUEST) { + /* finish response (if not already finished) */ + if (con->mode == p->id && con->state == CON_STATE_HANDLE_REQUEST) { /* (not CON_STATE_ERROR and not CON_STATE_RESPONSE_END, * i.e. not called from cgi_connection_close_callback()) */ @@ -625,18 +619,14 @@ static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) { con->file_finished = 1; } } - - return HANDLER_GO_ON; } static handler_t cgi_connection_close_callback(server *srv, connection *con, void *p_d) { plugin_data *p = p_d; handler_ctx *hctx = con->plugin_ctx[p->id]; + if (hctx) cgi_connection_close(srv, hctx); - if (con->mode != p->id) return HANDLER_GO_ON; - if (NULL == hctx) return HANDLER_GO_ON; - - return cgi_connection_close(srv, hctx); + return HANDLER_GO_ON; } @@ -805,7 +795,7 @@ static int cgi_write_file_chunk_mmap(server *srv, connection *con, int fd, chunk return 0; } -static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *cgi_handler) { +static int cgi_create_env(server *srv, connection *con, plugin_data *p, handler_ctx *hctx, buffer *cgi_handler) { pid_t pid; #ifdef HAVE_IPV6 @@ -1103,8 +1093,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * close(to_cgi_fds[1]); return -1; default: { - handler_ctx *hctx; - /* parent proces */ + /* parent process */ close(from_cgi_fds[1]); close(to_cgi_fds[0]); @@ -1180,19 +1169,11 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * close(to_cgi_fds[1]); /* register PID and wait for them asyncronously */ - con->mode = p->id; - buffer_reset(con->physical.path); - hctx = cgi_handler_ctx_init(); - - hctx->remote_conn = con; - hctx->plugin_data = p; hctx->pid = pid; hctx->fd = from_cgi_fds[0]; hctx->fde_ndx = -1; - con->plugin_ctx[p->id] = hctx; - fdevent_register(srv->ev, hctx->fd, cgi_handle_fdevent, hctx); fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); @@ -1212,6 +1193,23 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * #endif } +static buffer * cgi_get_handler(array *a, buffer *fn) { + size_t k, s_len = buffer_string_length(fn); + for (k = 0; k < a->used; ++k) { + data_string *ds = (data_string *)a->data[k]; + size_t ct_len = buffer_string_length(ds->key); + + if (buffer_is_empty(ds->key)) continue; + if (s_len < ct_len) continue; + + if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) { + return ds->value; + } + } + + return NULL; +} + #define PATCH(x) \ p->conf.x = s->x; static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p) { @@ -1246,7 +1244,6 @@ static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p #undef PATCH URIHANDLER_FUNC(cgi_is_handled) { - size_t k, s_len; plugin_data *p = p_d; buffer *fn = con->physical.path; stat_cache_entry *sce = NULL; @@ -1261,26 +1258,12 @@ URIHANDLER_FUNC(cgi_is_handled) { if (!S_ISREG(sce->st.st_mode)) return HANDLER_GO_ON; if (p->conf.execute_x_only == 1 && (sce->st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) return HANDLER_GO_ON; - s_len = buffer_string_length(fn); - - for (k = 0; k < p->conf.cgi->used; k++) { - data_string *ds = (data_string *)p->conf.cgi->data[k]; - size_t ct_len = buffer_string_length(ds->key); - - if (buffer_is_empty(ds->key)) continue; - if (s_len < ct_len) continue; - - if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) { - if (cgi_create_env(srv, con, p, ds->value)) { - con->mode = DIRECT; - con->http_status = 500; - - buffer_reset(con->physical.path); - return HANDLER_FINISHED; - } - /* one handler is enough for the request */ - break; - } + if (NULL != cgi_get_handler(p->conf.cgi, fn)) { + handler_ctx *hctx = cgi_handler_ctx_init(); + hctx->remote_conn = con; + hctx->plugin_data = p; + con->plugin_ctx[p->id] = hctx; + con->mode = p->id; } return HANDLER_GO_ON; @@ -1351,11 +1334,21 @@ TRIGGER_FUNC(cgi_trigger) { SUBREQUEST_FUNC(mod_cgi_handle_subrequest) { plugin_data *p = p_d; handler_ctx *hctx = con->plugin_ctx[p->id]; - UNUSED(srv); if (con->mode != p->id) return HANDLER_GO_ON; if (NULL == hctx) return HANDLER_GO_ON; + if (-1 == hctx->fd) { + buffer *handler = cgi_get_handler(p->conf.cgi, con->physical.path); + if (!handler) return HANDLER_GO_ON; /*(should not happen; checked in cgi_is_handled())*/ + if (cgi_create_env(srv, con, p, hctx, handler)) { + con->http_status = 500; + con->mode = DIRECT; + + return HANDLER_FINISHED; + } + } + #if 0 log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", hctx, hctx->pid); #endif diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c index 358faf85..c7cdede0 100644 --- a/src/mod_fastcgi.c +++ b/src/mod_fastcgi.c @@ -39,10 +39,6 @@ #include -#ifdef HAVE_SYS_FILIO_H -# include -#endif - #include "sys-socket.h" #ifdef HAVE_SYS_UIO_H @@ -325,7 +321,6 @@ typedef struct { /* connection specific data */ typedef enum { - FCGI_STATE_UNSET, FCGI_STATE_INIT, FCGI_STATE_CONNECT_DELAYED, FCGI_STATE_PREPARE_WRITE, @@ -1089,7 +1084,7 @@ static int fcgi_spawn_connection(server *srv, /* log_error_write(srv, __FILE__, __LINE__, "sbs", "execve failed for:", host->bin_path, strerror(errno)); */ - exit(errno); + _exit(errno); break; } @@ -1517,8 +1512,6 @@ static void fcgi_connection_close(server *srv, handler_ctx *hctx) { plugin_data *p; connection *con; - if (NULL == hctx) return; - p = hctx->plugin_data; con = hctx->remote_conn; @@ -1547,6 +1540,22 @@ static void fcgi_connection_close(server *srv, handler_ctx *hctx) { handler_ctx_free(srv, hctx); con->plugin_ctx[p->id] = NULL; + + /* finish response (if not already finished) */ + if (con->mode == p->id && con->state == CON_STATE_HANDLE_REQUEST) { + /* (not CON_STATE_ERROR and not CON_STATE_RESPONSE_END, + * i.e. not called from fcgi_connection_reset()) */ + + /* Send an error if we haven't sent any data yet */ + if (0 == con->file_started) { + con->http_status = 500; + con->mode = DIRECT; + } + else if (!con->file_finished) { + http_chunk_close(srv, con); + con->file_finished = 1; + } + } } static int fcgi_reconnect(server *srv, handler_ctx *hctx) { @@ -1609,8 +1618,8 @@ static int fcgi_reconnect(server *srv, handler_ctx *hctx) { static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d) { plugin_data *p = p_d; - - fcgi_connection_close(srv, con->plugin_ctx[p->id]); + handler_ctx *hctx = con->plugin_ctx[p->id]; + if (hctx) fcgi_connection_close(srv, hctx); return HANDLER_GO_ON; } @@ -2521,7 +2530,6 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) { con->parsed_response &= ~HTTP_CONTENT_LENGTH; con->response.content_length = -1; hctx->send_content_body = 0; /* ignore the content */ - joblist_append(srv, con); } else { log_error_write(srv, __FILE__, __LINE__, "sb", "send-file error: couldn't get stat_cache entry for:", @@ -2542,7 +2550,6 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) { } http_chunk_append_buffer(srv, con, packet.b); - joblist_append(srv, con); } } else if (hctx->send_content_body && !buffer_string_is_empty(packet.b)) { if (con->request.http_version == HTTP_VERSION_1_1 && @@ -2552,7 +2559,6 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) { } http_chunk_append_buffer(srv, con, packet.b); - joblist_append(srv, con); } break; case FCGI_STDERR: @@ -2570,7 +2576,6 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) { con->http_status == 200)) { /* send chunk-end if necessary */ http_chunk_close(srv, con); - joblist_append(srv, con); } fin = 1; @@ -2789,7 +2794,7 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { switch(hctx->state) { case FCGI_STATE_CONNECT_DELAYED: /* should never happen */ - break; + return HANDLER_WAIT_FOR_EVENT; case FCGI_STATE_INIT: /* do we have a running process for this host (max-procs) ? */ hctx->proc = NULL; @@ -2972,34 +2977,24 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { } else { fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); - return HANDLER_WAIT_FOR_EVENT; } - break; + return HANDLER_WAIT_FOR_EVENT; case FCGI_STATE_READ: /* waiting for a response */ - break; + return HANDLER_WAIT_FOR_EVENT; default: log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state"); return HANDLER_ERROR; } - - return HANDLER_WAIT_FOR_EVENT; } /* might be called on fdevent after a connect() is delay too * */ -SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) { - plugin_data *p = p_d; - - handler_ctx *hctx = con->plugin_ctx[p->id]; +static handler_t fcgi_send_request(server *srv, handler_ctx *hctx) { fcgi_extension_host *host; - - if (NULL == hctx) return HANDLER_GO_ON; - - /* not my job */ - if (con->mode != p->id) return HANDLER_GO_ON; + handler_t rc; /* we don't have a host yet, choose one * -> this happens in the first round @@ -3034,9 +3029,6 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) { fcgi_connection_close(srv, hctx); - con->http_status = 500; - con->mode = DIRECT; - return HANDLER_FINISHED; } @@ -3060,8 +3052,13 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) { } /* ok, create the request */ - switch(fcgi_write_request(srv, hctx)) { - case HANDLER_ERROR: + rc = fcgi_write_request(srv, hctx); + if (HANDLER_ERROR != rc) { + return rc; + } else { + plugin_data *p = hctx->plugin_data; + connection *con = hctx->remote_conn; + if (hctx->state == FCGI_STATE_INIT || hctx->state == FCGI_STATE_CONNECT_DELAYED) { fcgi_restart_dead_procs(srv, p, host); @@ -3069,43 +3066,40 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) { /* cleanup this request and let the request handler start this request again */ if (hctx->reconnects < 5) { fcgi_reconnect(srv, hctx); - joblist_append(srv, con); /* in case we come from the event-handler */ - return HANDLER_WAIT_FOR_FD; + return HANDLER_COMEBACK; } else { fcgi_connection_close(srv, hctx); - - buffer_reset(con->physical.path); - con->mode = DIRECT; con->http_status = 503; - joblist_append(srv, con); /* in case we come from the event-handler */ return HANDLER_FINISHED; } } else { + int status = con->http_status; fcgi_connection_close(srv, hctx); + con->http_status = (status == 400) ? 400 : 503; /* see FCGI_ENV_ADD_CHECK() for 400 error */ - buffer_reset(con->physical.path); - con->mode = DIRECT; - if (con->http_status != 400) con->http_status = 503; - joblist_append(srv, con); /* really ? */ - - return HANDLER_FINISHED; - } - 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; } } + +SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) { + plugin_data *p = p_d; + + handler_ctx *hctx = con->plugin_ctx[p->id]; + + if (NULL == hctx) return HANDLER_GO_ON; + + /* not my job */ + if (con->mode != p->id) return HANDLER_GO_ON; + + return (hctx->state != FCGI_STATE_READ) + ? fcgi_send_request(srv, hctx) + : HANDLER_WAIT_FOR_EVENT; +} + static handler_t fcgi_handle_fdevent(server *srv, void *ctx, int revents) { handler_ctx *hctx = ctx; connection *con = hctx->remote_conn; @@ -3114,6 +3108,8 @@ static handler_t fcgi_handle_fdevent(server *srv, void *ctx, int revents) { fcgi_proc *proc = hctx->proc; fcgi_extension_host *host= hctx->host; + joblist_append(srv, con); + if ((revents & FDEVENT_IN) && hctx->state == FCGI_STATE_READ) { switch (fcgi_demux_response(srv, hctx)) { @@ -3135,9 +3131,9 @@ static handler_t fcgi_handle_fdevent(server *srv, void *ctx, int revents) { buffer_copy_buffer(con->physical.path, host->docroot); buffer_append_string_buffer(con->physical.path, con->uri.path); - fcgi_connection_close(srv, hctx); - con->mode = DIRECT; + con->mode = DIRECT;/*(avoid changing con->state, con->http_status)*/ + fcgi_connection_close(srv, hctx); con->http_status = 0; con->file_started = 1; /* fcgi_extension won't touch the request afterwards */ } else { @@ -3145,7 +3141,6 @@ static handler_t fcgi_handle_fdevent(server *srv, void *ctx, int revents) { fcgi_connection_close(srv, hctx); } - joblist_append(srv, con); return HANDLER_FINISHED; case -1: if (proc->pid && proc->state != PROC_STATE_DIED) { @@ -3199,14 +3194,15 @@ static handler_t fcgi_handle_fdevent(server *srv, void *ctx, int revents) { if (hctx->wb->bytes_out == 0 && hctx->reconnects < 5) { - fcgi_reconnect(srv, hctx); log_error_write(srv, __FILE__, __LINE__, "ssbsBSBs", "response not received, request not sent", "on socket:", proc->connection_name, "for", con->uri.path, "?", con->uri.query, ", reconnecting"); - return HANDLER_WAIT_FOR_FD; + fcgi_reconnect(srv, hctx); + + return HANDLER_COMEBACK; } log_error_write(srv, __FILE__, __LINE__, "sosbsBSBs", @@ -3215,27 +3211,19 @@ static handler_t fcgi_handle_fdevent(server *srv, void *ctx, int revents) { "for", con->uri.path, "?", con->uri.query, ", closing connection"); fcgi_connection_close(srv, hctx); - - connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); - buffer_reset(con->physical.path); - con->http_status = 500; - con->mode = DIRECT; } else { /* response might have been already started, kill the connection */ - fcgi_connection_close(srv, hctx); - log_error_write(srv, __FILE__, __LINE__, "ssbsBSBs", "response already sent out, but backend returned error", "on socket:", proc->connection_name, "for", con->uri.path, "?", con->uri.query, ", terminating connection"); - connection_set_state(srv, con, CON_STATE_ERROR); + con->keep_alive = 0; + con->file_finished = 1; + con->mode = DIRECT; /*(avoid sending final chunked block)*/ + fcgi_connection_close(srv, hctx); } - /* */ - - - joblist_append(srv, con); return HANDLER_FINISHED; } } @@ -3248,7 +3236,7 @@ static handler_t fcgi_handle_fdevent(server *srv, void *ctx, int revents) { * 1. in an unfinished connect() call * 2. in an unfinished write() call (long POST request) */ - return mod_fastcgi_handle_subrequest(srv, con, p); + return fcgi_send_request(srv, hctx); /*(might invalidate hctx)*/ } else { log_error_write(srv, __FILE__, __LINE__, "sd", "got a FDEVENT_OUT and didn't know why:", @@ -3268,7 +3256,7 @@ static handler_t fcgi_handle_fdevent(server *srv, void *ctx, int revents) { * FIXME: as it is a bit ugly. * */ - return mod_fastcgi_handle_subrequest(srv, con, p); + fcgi_send_request(srv, hctx); } else if (hctx->state == FCGI_STATE_READ && hctx->proc->port == 0) { /* FIXME: @@ -3283,23 +3271,23 @@ static handler_t fcgi_handle_fdevent(server *srv, void *ctx, int revents) { "(no fastcgi process on socket:", proc->connection_name, "?)", hctx->state); - connection_set_state(srv, con, CON_STATE_ERROR); fcgi_connection_close(srv, hctx); - joblist_append(srv, con); } } else if (revents & FDEVENT_ERR) { log_error_write(srv, __FILE__, __LINE__, "s", "fcgi: got a FDEVENT_ERR. Don't know why."); - /* kill all connections to the fastcgi process */ - - connection_set_state(srv, con, CON_STATE_ERROR); + if (con->file_started) { + con->keep_alive = 0; + con->file_finished = 1; + con->mode = DIRECT; /*(avoid sending final chunked block)*/ + } fcgi_connection_close(srv, hctx); - joblist_append(srv, con); } return HANDLER_FINISHED; } + #define PATCH(x) \ p->conf.x = s->x; static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) { @@ -3445,8 +3433,8 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i if (!host) { /* sorry, we don't have a server alive for this ext */ - buffer_reset(con->physical.path); con->http_status = 500; + con->mode = DIRECT; /* only send the 'no handler' once */ if (!extension->note_is_sent) { @@ -3602,14 +3590,6 @@ JOBLIST_FUNC(mod_fastcgi_handle_joblist) { } -static handler_t fcgi_connection_close_callback(server *srv, connection *con, void *p_d) { - plugin_data *p = p_d; - - fcgi_connection_close(srv, con->plugin_ctx[p->id]); - - return HANDLER_GO_ON; -} - TRIGGER_FUNC(mod_fastcgi_handle_trigger) { plugin_data *p = p_d; size_t i, j, n; @@ -3714,7 +3694,7 @@ int mod_fastcgi_plugin_init(plugin *p) { p->cleanup = mod_fastcgi_free; p->set_defaults = mod_fastcgi_set_defaults; p->connection_reset = fcgi_connection_reset; - p->handle_connection_close = fcgi_connection_close_callback; + p->handle_connection_close = fcgi_connection_reset; p->handle_uri_clean = fcgi_check_extension_1; p->handle_subrequest_start = fcgi_check_extension_2; p->handle_subrequest = mod_fastcgi_handle_subrequest; diff --git a/src/mod_proxy.c b/src/mod_proxy.c index 90a7517f..ee83d7c8 100644 --- a/src/mod_proxy.c +++ b/src/mod_proxy.c @@ -28,10 +28,6 @@ #include -#ifdef HAVE_SYS_FILIO_H -# include -#endif - #include "sys-socket.h" #define data_proxy data_fastcgi @@ -86,8 +82,7 @@ typedef enum { PROXY_STATE_CONNECT, PROXY_STATE_PREPARE_WRITE, PROXY_STATE_WRITE, - PROXY_STATE_READ, - PROXY_STATE_ERROR + PROXY_STATE_READ } proxy_connection_state_t; enum { PROXY_STDOUT, PROXY_END_REQUEST }; @@ -338,8 +333,6 @@ static void proxy_connection_close(server *srv, handler_ctx *hctx) { plugin_data *p; connection *con; - if (NULL == hctx) return; - p = hctx->plugin_data; con = hctx->remote_conn; @@ -357,6 +350,22 @@ static void proxy_connection_close(server *srv, handler_ctx *hctx) { handler_ctx_free(hctx); con->plugin_ctx[p->id] = NULL; + + /* finish response (if not already finished) */ + if (con->mode == p->id && con->state == CON_STATE_HANDLE_REQUEST) { + /* (not CON_STATE_ERROR and not CON_STATE_RESPONSE_END, + * i.e. not called from proxy_connection_reset()) */ + + /* Send an error if we haven't sent any data yet */ + if (0 == con->file_started) { + con->http_status = 500; + con->mode = DIRECT; + } + else if (!con->file_finished) { + http_chunk_close(srv, con); + con->file_finished = 1; + } + } } static int proxy_establish_connection(server *srv, handler_ctx *hctx) { @@ -692,11 +701,9 @@ static int proxy_demux_response(server *srv, handler_ctx *hctx) { con->file_started = 1; if (blen > 0) http_chunk_append_mem(srv, con, c + 4, blen); buffer_reset(hctx->response); - joblist_append(srv, con); } } else { http_chunk_append_buffer(srv, con, hctx->response); - joblist_append(srv, con); buffer_reset(hctx->response); } @@ -705,7 +712,6 @@ static int proxy_demux_response(server *srv, handler_ctx *hctx) { con->file_finished = 1; http_chunk_close(srv, con); - joblist_append(srv, con); fin = 1; } @@ -720,7 +726,7 @@ static handler_t proxy_write_request(server *srv, handler_ctx *hctx) { int ret; - if (!host || buffer_string_is_empty(host->host) || !host->port) return -1; + if (!host || buffer_string_is_empty(host->host) || !host->port) return HANDLER_ERROR; switch(hctx->state) { case PROXY_STATE_CONNECT: @@ -732,8 +738,6 @@ static handler_t proxy_write_request(server *srv, handler_ctx *hctx) { /* wait */ return HANDLER_WAIT_FOR_EVENT; - break; - case PROXY_STATE_INIT: #if defined(HAVE_SYS_UN_H) if (strstr(host->host->ptr,"/")) { @@ -819,8 +823,6 @@ static handler_t proxy_write_request(server *srv, handler_ctx *hctx) { fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); } else { fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); - - return HANDLER_WAIT_FOR_EVENT; } return HANDLER_WAIT_FOR_EVENT; @@ -831,8 +833,6 @@ static handler_t proxy_write_request(server *srv, handler_ctx *hctx) { log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state"); return HANDLER_ERROR; } - - return HANDLER_GO_ON; } #define PATCH(x) \ @@ -871,24 +871,14 @@ static int mod_proxy_patch_connection(server *srv, connection *con, plugin_data } #undef PATCH -SUBREQUEST_FUNC(mod_proxy_handle_subrequest) { - 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; - +static handler_t proxy_send_request(server *srv, handler_ctx *hctx) { /* ok, create the request */ - switch(proxy_write_request(srv, hctx)) { - case HANDLER_ERROR: + handler_t rc = proxy_write_request(srv, hctx); + if (HANDLER_ERROR != rc) { + return rc; + } else { + data_proxy *host = hctx->host; + connection *con = hctx->remote_conn; log_error_write(srv, __FILE__, __LINE__, "sbdd", "proxy-server disabled:", host->host, host->port, @@ -898,33 +888,28 @@ SUBREQUEST_FUNC(mod_proxy_handle_subrequest) { host->is_disabled = 1; 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); + con->mode = hctx->plugin_data->id; /* p->id */ - /* reset the enviroment and restart the sub-request */ - buffer_reset(con->physical.path); - con->mode = DIRECT; + return HANDLER_COMEBACK; + } +} + +SUBREQUEST_FUNC(mod_proxy_handle_subrequest) { + plugin_data *p = p_d; - joblist_append(srv, con); + handler_ctx *hctx = con->plugin_ctx[p->id]; - /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop - * and hope that the childs will be restarted - * - */ + if (NULL == hctx) return HANDLER_GO_ON; - return HANDLER_WAIT_FOR_FD; - case HANDLER_WAIT_FOR_EVENT: - break; - case HANDLER_WAIT_FOR_FD: - return HANDLER_WAIT_FOR_FD; - default: - break; - } + /* not my job */ + if (con->mode != p->id) return HANDLER_GO_ON; - if (con->file_started == 1) { - return HANDLER_FINISHED; - } else { - return HANDLER_WAIT_FOR_EVENT; - } + return (hctx->state != PROXY_STATE_READ) + ? proxy_send_request(srv, hctx) + : HANDLER_WAIT_FOR_EVENT; } static handler_t proxy_handle_fdevent(server *srv, void *ctx, int revents) { @@ -932,6 +917,7 @@ static handler_t proxy_handle_fdevent(server *srv, void *ctx, int revents) { connection *con = hctx->remote_conn; plugin_data *p = hctx->plugin_data; + joblist_append(srv, con); if ((revents & FDEVENT_IN) && hctx->state == PROXY_STATE_READ) { @@ -948,20 +934,19 @@ static handler_t proxy_handle_fdevent(server *srv, void *ctx, int revents) { /* 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; + /* reading response headers failed */ } else { /* response might have been already started, kill the connection */ - connection_set_state(srv, con, CON_STATE_ERROR); + con->keep_alive = 0; + con->file_finished = 1; + con->mode = DIRECT; /*(avoid sending final chunked block)*/ } - joblist_append(srv, con); + proxy_connection_close(srv, hctx); + return HANDLER_FINISHED; } } @@ -985,7 +970,6 @@ static handler_t proxy_handle_fdevent(server *srv, void *ctx, int revents) { log_error_write(srv, __FILE__, __LINE__, "ss", "getsockopt failed:", strerror(errno)); - joblist_append(srv, con); return HANDLER_FINISHED; } if (socket_error != 0) { @@ -993,7 +977,6 @@ static handler_t proxy_handle_fdevent(server *srv, void *ctx, int revents) { "establishing connection failed:", strerror(socket_error), "port:", hctx->host->port); - joblist_append(srv, con); return HANDLER_FINISHED; } if (p->conf.debug) { @@ -1010,7 +993,7 @@ static handler_t proxy_handle_fdevent(server *srv, void *ctx, int revents) { * 1. after a just finished connect() call * 2. in a unfinished write() call (long POST request) */ - return mod_proxy_handle_subrequest(srv, con, p); + return proxy_send_request(srv, hctx); /*(might invalidate hctx)*/ } else { log_error_write(srv, __FILE__, __LINE__, "sd", "proxy: out", hctx->state); @@ -1044,38 +1027,25 @@ static handler_t proxy_handle_fdevent(server *srv, void *ctx, int revents) { hctx->host->is_disabled = 1; 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); - - /* reset the enviroment and restart the sub-request */ - buffer_reset(con->physical.path); - con->mode = DIRECT; - - joblist_append(srv, con); + con->mode = p->id; } else { proxy_connection_close(srv, hctx); - joblist_append(srv, con); - - con->mode = DIRECT; con->http_status = 503; } - - return HANDLER_FINISHED; - } - - if (!con->file_finished) { - http_chunk_close(srv, con); + } else { + proxy_connection_close(srv, hctx); } - - con->file_finished = 1; - proxy_connection_close(srv, hctx); - joblist_append(srv, con); } 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); - con->file_finished = 1; - joblist_append(srv, con); + if (con->file_started) { + con->keep_alive = 0; + con->file_finished = 1; + con->mode = DIRECT; /*(avoid sending final chunked block)*/ + } proxy_connection_close(srv, hctx); } @@ -1301,10 +1271,10 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p 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; - - proxy_connection_close(srv, con->plugin_ctx[p->id]); + handler_ctx *hctx = con->plugin_ctx[p->id]; + if (hctx) proxy_connection_close(srv, hctx); return HANDLER_GO_ON; } @@ -1359,8 +1329,8 @@ int mod_proxy_plugin_init(plugin *p) { p->init = mod_proxy_init; p->cleanup = mod_proxy_free; p->set_defaults = mod_proxy_set_defaults; - p->connection_reset = mod_proxy_connection_close_callback; /* end of req-resp cycle */ - p->handle_connection_close = mod_proxy_connection_close_callback; /* end of client connection */ + p->connection_reset = mod_proxy_connection_reset; /* end of req-resp cycle */ + p->handle_connection_close = mod_proxy_connection_reset; /* end of client connection */ p->handle_uri_clean = mod_proxy_check_extension; p->handle_subrequest = mod_proxy_handle_subrequest; p->handle_trigger = mod_proxy_trigger; diff --git a/src/mod_scgi.c b/src/mod_scgi.c index 9e500c14..a48c36f9 100644 --- a/src/mod_scgi.c +++ b/src/mod_scgi.c @@ -27,10 +27,6 @@ #include -#ifdef HAVE_SYS_FILIO_H -# include -#endif - #include "sys-socket.h" #ifdef HAVE_SYS_UIO_H @@ -869,7 +865,7 @@ static int scgi_spawn_connection(server *srv, log_error_write(srv, __FILE__, __LINE__, "sbs", "execl failed for:", host->bin_path, strerror(errno)); - exit(errno); + _exit(errno); break; } @@ -1253,12 +1249,10 @@ static int scgi_set_state(server *srv, handler_ctx *hctx, scgi_connection_state_ } -static void scgi_connection_cleanup(server *srv, handler_ctx *hctx) { +static void scgi_connection_close(server *srv, handler_ctx *hctx) { plugin_data *p; connection *con; - if (NULL == hctx) return; - p = hctx->plugin_data; con = hctx->remote_conn; @@ -1290,6 +1284,22 @@ static void scgi_connection_cleanup(server *srv, handler_ctx *hctx) { handler_ctx_free(hctx); con->plugin_ctx[p->id] = NULL; + + /* finish response (if not already finished) */ + if (con->mode == p->id && con->state == CON_STATE_HANDLE_REQUEST) { + /* (not CON_STATE_ERROR and not CON_STATE_RESPONSE_END, + * i.e. not called from scgi_connection_reset()) */ + + /* Send an error if we haven't sent any data yet */ + if (0 == con->file_started) { + con->http_status = 500; + con->mode = DIRECT; + } + else if (!con->file_finished) { + http_chunk_close(srv, con); + con->file_finished = 1; + } + } } static int scgi_reconnect(server *srv, handler_ctx *hctx) { @@ -1340,8 +1350,8 @@ static int scgi_reconnect(server *srv, handler_ctx *hctx) { static handler_t scgi_connection_reset(server *srv, connection *con, void *p_d) { plugin_data *p = p_d; - - scgi_connection_cleanup(srv, con->plugin_ctx[p->id]); + handler_ctx *hctx = con->plugin_ctx[p->id]; + if (hctx) scgi_connection_close(srv, hctx); return HANDLER_GO_ON; } @@ -1813,7 +1823,6 @@ static int scgi_demux_response(server *srv, handler_ctx *hctx) { /* send final chunk */ http_chunk_close(srv, con); - joblist_append(srv, con); return 1; } @@ -1890,7 +1899,6 @@ static int scgi_demux_response(server *srv, handler_ctx *hctx) { } http_chunk_append_buffer(srv, con, hctx->response_header); - joblist_append(srv, con); } else { size_t blen = buffer_string_length(hctx->response_header) - hlen; @@ -1908,7 +1916,6 @@ static int scgi_demux_response(server *srv, handler_ctx *hctx) { if (blen > 0) { http_chunk_append_mem(srv, con, hctx->response_header->ptr + hlen, blen); - joblist_append(srv, con); } } @@ -1916,7 +1923,6 @@ static int scgi_demux_response(server *srv, handler_ctx *hctx) { } } else { http_chunk_append_buffer(srv, con, hctx->response); - joblist_append(srv, con); } #if 0 @@ -2320,7 +2326,7 @@ static handler_t scgi_write_request(server *srv, handler_ctx *hctx) { scgi_reconnect(srv, hctx); - return HANDLER_WAIT_FOR_FD; + return HANDLER_COMEBACK; } /* not reconnected ... why @@ -2352,38 +2358,28 @@ static handler_t scgi_write_request(server *srv, handler_ctx *hctx) { } else { fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); - return HANDLER_WAIT_FOR_EVENT; } - break; + return HANDLER_WAIT_FOR_EVENT; case FCGI_STATE_READ: /* waiting for a response */ - break; + return HANDLER_WAIT_FOR_EVENT; default: log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state"); return HANDLER_ERROR; } - - return HANDLER_WAIT_FOR_EVENT; } -SUBREQUEST_FUNC(mod_scgi_handle_subrequest) { - 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; - +static handler_t scgi_send_request(server *srv, handler_ctx *hctx) { /* ok, create the request */ - switch(scgi_write_request(srv, hctx)) { - case HANDLER_ERROR: - proc = hctx->proc; - host = hctx->host; + handler_t rc = scgi_write_request(srv, hctx); + if (HANDLER_ERROR != rc) { + return rc; + } 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 && 0 == proc->is_local && @@ -2432,55 +2428,33 @@ SUBREQUEST_FUNC(mod_scgi_handle_subrequest) { } scgi_restart_dead_procs(srv, p, host); - scgi_connection_cleanup(srv, hctx); - - buffer_reset(con->physical.path); - con->mode = DIRECT; - joblist_append(srv, con); + con->mode = DIRECT;/*(avoid changing con->state, con->http_status)*/ + scgi_connection_close(srv, hctx); + con->mode = p->id; - /* 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; + return HANDLER_COMEBACK; } else { - scgi_connection_cleanup(srv, hctx); - - buffer_reset(con->physical.path); - con->mode = DIRECT; + scgi_connection_close(srv, hctx); con->http_status = 503; 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; - - if (NULL == hctx) return HANDLER_GO_ON; +SUBREQUEST_FUNC(mod_scgi_handle_subrequest) { + plugin_data *p = p_d; - con = hctx->remote_conn; + handler_ctx *hctx = con->plugin_ctx[p->id]; - log_error_write(srv, __FILE__, __LINE__, "ssdsd", - "emergency exit: scgi:", - "connection-fd:", con->fd, - "fcgi-fd:", hctx->fd); + if (NULL == hctx) return HANDLER_GO_ON; - scgi_connection_cleanup(srv, hctx); + /* not my job */ + if (con->mode != p->id) return HANDLER_GO_ON; - return HANDLER_FINISHED; + return (hctx->state != FCGI_STATE_READ) + ? scgi_send_request(srv, hctx) + : HANDLER_WAIT_FOR_EVENT; } @@ -2492,6 +2466,8 @@ static handler_t scgi_handle_fdevent(server *srv, void *ctx, int revents) { scgi_proc *proc = hctx->proc; scgi_extension_host *host= hctx->host; + joblist_append(srv, con); + if ((revents & FDEVENT_IN) && hctx->state == FCGI_STATE_READ) { switch (scgi_demux_response(srv, hctx)) { @@ -2499,9 +2475,8 @@ static handler_t scgi_handle_fdevent(server *srv, void *ctx, int revents) { break; case 1: /* we are done */ - scgi_connection_cleanup(srv, hctx); + scgi_connection_close(srv, hctx); - joblist_append(srv, con); return HANDLER_FINISHED; case -1: if (proc->pid && proc->state != PROC_STATE_DIED) { @@ -2555,14 +2530,15 @@ static handler_t scgi_handle_fdevent(server *srv, void *ctx, int revents) { if (hctx->wb->bytes_out == 0 && hctx->reconnects < 5) { - scgi_reconnect(srv, hctx); log_error_write(srv, __FILE__, __LINE__, "ssdsd", "response not sent, request not sent, reconnection.", "connection-fd:", con->fd, "fcgi-fd:", hctx->fd); - return HANDLER_WAIT_FOR_FD; + scgi_reconnect(srv, hctx); + + return HANDLER_COMEBACK; } log_error_write(srv, __FILE__, __LINE__, "sosdsd", @@ -2570,12 +2546,7 @@ static handler_t scgi_handle_fdevent(server *srv, void *ctx, int revents) { "connection-fd:", con->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; + scgi_connection_close(srv, hctx); } else { /* response might have been already started, kill the connection */ log_error_write(srv, __FILE__, __LINE__, "ssdsd", @@ -2583,15 +2554,12 @@ static handler_t scgi_handle_fdevent(server *srv, void *ctx, int revents) { "connection-fd:", con->fd, "fcgi-fd:", hctx->fd); - scgi_connection_cleanup(srv, hctx); - - connection_set_state(srv, con, CON_STATE_ERROR); + con->keep_alive = 0; + con->file_finished = 1; + con->mode = DIRECT; /*(avoid sending final chunked block)*/ + scgi_connection_close(srv, hctx); } - /* */ - - - joblist_append(srv, con); return HANDLER_FINISHED; } } @@ -2604,7 +2572,7 @@ static handler_t scgi_handle_fdevent(server *srv, void *ctx, int revents) { * 1. in a unfinished connect() call * 2. in a unfinished write() call (long POST request) */ - return mod_scgi_handle_subrequest(srv, con, p); + return scgi_send_request(srv, hctx); /*(might invalidate hctx)*/ } else { log_error_write(srv, __FILE__, __LINE__, "sd", "got a FDEVENT_OUT and didn't know why:", @@ -2624,7 +2592,7 @@ static handler_t scgi_handle_fdevent(server *srv, void *ctx, int revents) { * 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 && hctx->proc->port == 0) { /* FIXME: @@ -2643,19 +2611,18 @@ static handler_t scgi_handle_fdevent(server *srv, void *ctx, int revents) { " ?)", hctx->state); - connection_set_state(srv, con, CON_STATE_ERROR); scgi_connection_close(srv, hctx); - joblist_append(srv, con); } } else if (revents & FDEVENT_ERR) { log_error_write(srv, __FILE__, __LINE__, "s", "fcgi: got a FDEVENT_ERR. Don't know why."); - /* kill all connections to the scgi process */ - - connection_set_state(srv, con, CON_STATE_ERROR); + if (con->file_started) { + con->keep_alive = 0; + con->file_finished = 1; + con->mode = DIRECT; /*(avoid sending final chunked block)*/ + } scgi_connection_close(srv, hctx); - joblist_append(srv, con); } return HANDLER_FINISHED; @@ -2763,8 +2730,8 @@ static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, i if (!host) { /* sorry, we don't have a server alive for this ext */ - buffer_reset(con->physical.path); con->http_status = 500; + con->mode = DIRECT; /* only send the 'no handler' once */ if (!extension->note_is_sent) { @@ -2913,12 +2880,6 @@ JOBLIST_FUNC(mod_scgi_handle_joblist) { } -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) { plugin_data *p = p_d; size_t i, j, n; @@ -3120,7 +3081,7 @@ int mod_scgi_plugin_init(plugin *p) { p->cleanup = mod_scgi_free; p->set_defaults = mod_scgi_set_defaults; 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_subrequest_start = scgi_check_extension_2; p->handle_subrequest = mod_scgi_handle_subrequest;