diff --git a/include/lighttpd/virtualrequest.h b/include/lighttpd/virtualrequest.h index d34b4ed..23889cc 100644 --- a/include/lighttpd/virtualrequest.h +++ b/include/lighttpd/virtualrequest.h @@ -97,6 +97,7 @@ LI_API vrequest* vrequest_new(struct connection *con, vrequest_handler handle_re LI_API void vrequest_free(vrequest *vr); LI_API void vrequest_reset(vrequest *vr); +/* Signals an internal error; handles the error in the _next_ loop */ LI_API void vrequest_error(vrequest *vr); LI_API void vrequest_backend_overloaded(vrequest *vr); diff --git a/src/connection.c b/src/connection.c index 445310a..aec6ea3 100644 --- a/src/connection.c +++ b/src/connection.c @@ -99,15 +99,21 @@ void connection_internal_error(connection *con) { VR_ERROR(vr, "%s", "Couldn't send '500 Internal Error': headers already sent"); connection_error(con); } else { - http_headers_reset(con->mainvr->response.headers); + http_version_t v; VR_ERROR(vr, "%s", "internal error"); + + /* We only need the http version from the http request */ + v = con->mainvr->request.http_version; + vrequest_reset(con->mainvr); + con->mainvr->request.http_version = v; + + con->keep_alive = FALSE; con->mainvr->response.http_status = 500; - con->state = CON_STATE_WRITE; - con->mainvr->state = VRS_WRITE_CONTENT; - chunkqueue_reset(con->mainvr->out); + con->state = CON_STATE_WRITE; /* skips further vrequest handling */ + chunkqueue_reset(con->out); - con->mainvr->out->is_closed = TRUE; con->out->is_closed = TRUE; + con->in->is_closed = TRUE; forward_response_body(con); } } @@ -222,7 +228,7 @@ static void connection_cb(struct ev_loop *loop, ev_io *w, int revents) { case NETWORK_STATUS_FATAL_ERROR: _ERROR(con->srv, con->mainvr, "%s", "network write fatal error"); connection_error(con); - break; + return; case NETWORK_STATUS_CONNECTION_CLOSE: connection_close(con); return; @@ -358,6 +364,7 @@ void connection_reset(connection *con) { ev_io_set(&con->sock_watcher, -1, 0); vrequest_reset(con->mainvr); + http_request_parser_reset(&con->req_parser_ctx); g_string_truncate(con->remote_addr_str, 0); g_string_truncate(con->local_addr_str, 0); @@ -366,8 +373,6 @@ void connection_reset(connection *con) { chunkqueue_reset(con->raw_in); chunkqueue_reset(con->raw_out); - http_request_parser_reset(&con->req_parser_ctx); - if (con->keep_alive_data.link) { g_queue_delete_link(&con->wrk->keep_alive_queue, con->keep_alive_data.link); con->keep_alive_data.link = NULL; diff --git a/src/modules/mod_fastcgi.c b/src/modules/mod_fastcgi.c index 9a5b74a..9ce7efd 100644 --- a/src/modules/mod_fastcgi.c +++ b/src/modules/mod_fastcgi.c @@ -392,14 +392,14 @@ static gboolean fastcgi_get_packet(fastcgi_connection *fcon) { return TRUE; } -static void fastcgi_parse_response(fastcgi_connection *fcon) { +static gboolean fastcgi_parse_response(fastcgi_connection *fcon) { while (fastcgi_get_packet(fcon)) { if (fcon->fcgi_in_record.version != FCGI_VERSION_1) { VR_ERROR(fcon->vr, "Unknown fastcgi protocol version %i", (gint) fcon->fcgi_in_record.version); close(fcon->fd); fcon->fd = -1; vrequest_error(fcon->vr); - return; + return FALSE; } chunkqueue_skip(fcon->fcgi_in, FCGI_HEADER_LEN); switch (fcon->fcgi_in_record.type) { @@ -421,6 +421,7 @@ static void fastcgi_parse_response(fastcgi_connection *fcon) { } chunkqueue_skip(fcon->fcgi_in, fcon->fcgi_in_record.paddingLength); } + return TRUE; } /**********************************************************************************/ @@ -500,7 +501,7 @@ static void fastcgi_fd_cb(struct ev_loop *loop, ev_io *w, int revents) { } } - fastcgi_parse_response(fcon); + if (!fastcgi_parse_response(fcon)) return; /* TODO: parse stdout response */ if (fcon->vr->out->bytes_in == 0 && fcon->stdout->length > 0) { diff --git a/src/virtualrequest.c b/src/virtualrequest.c index f10954a..0d16cbc 100644 --- a/src/virtualrequest.c +++ b/src/virtualrequest.c @@ -222,9 +222,9 @@ static gboolean vrequest_do_handle_actions(vrequest *vr) { return TRUE; } + static gboolean vrequest_do_handle_read(vrequest *vr) { handler_t res; - if (vr->in->is_closed && vr->in->bytes_in == vr->in->bytes_out) return TRUE; if (vr->backend && vr->backend->handle_request_body) { chunkqueue_steal_all(vr->in, vr->vr_in); /* TODO: filters */ if (vr->vr_in->is_closed) vr->in->is_closed = TRUE; @@ -309,6 +309,7 @@ void vrequest_state_machine(vrequest *vr) { case VRS_READ_CONTENT: done = !vrequest_do_handle_read(vr); + done = done || (vr->state == VRS_READ_CONTENT); break; case VRS_HANDLE_RESPONSE_HEADERS: @@ -339,6 +340,7 @@ void vrequest_state_machine(vrequest *vr) { break; case VRS_ERROR: + /* this will probably reset the vrequest, so stop handling after it */ vr->handle_response_error(vr); return; }