Browse Source

[core]: fix connection/vrequest callbacks to return FALSE after they got reset, so handling stops

personal/stbuehler/wip
Stefan Bühler 12 years ago
parent
commit
d9cc24b8e6
  1. 2
      include/lighttpd/virtualrequest.h
  2. 52
      src/main/connection.c
  3. 26
      src/main/subrequest_lua.c
  4. 95
      src/main/virtualrequest.c

2
include/lighttpd/virtualrequest.h

@ -36,7 +36,7 @@ typedef enum {
typedef liHandlerResult (*liFilterHandlerCB)(liVRequest *vr, liFilter *f);
typedef void (*liFilterFreeCB)(liVRequest *vr, liFilter *f);
typedef liHandlerResult (*liVRequestHandlerCB)(liVRequest *vr);
typedef G_GNUC_WARN_UNUSED_RESULT gboolean (*liVRequestHandlerCB)(liVRequest *vr);
typedef liHandlerResult (*liVRequestPluginHandlerCB)(liVRequest *vr, liPlugin *p);
typedef gboolean (*liVRequestCheckIOCB)(liVRequest *vr);

52
src/main/connection.c

@ -3,7 +3,7 @@
#include <lighttpd/plugin_core.h>
static void li_connection_reset_keep_alive(liConnection *con);
static void li_connection_internal_error(liConnection *con);
static G_GNUC_WARN_UNUSED_RESULT gboolean li_connection_internal_error(liConnection *con);
static void update_io_events(liConnection *con) {
int events = 0;
@ -51,7 +51,7 @@ static void parse_request_body(liConnection *con) {
}
}
static void forward_response_body(liConnection *con) {
static G_GNUC_WARN_UNUSED_RESULT gboolean forward_response_body(liConnection *con) {
liVRequest *vr = con->mainvr;
if (con->state >= LI_CON_STATE_HANDLE_MAINVR) {
if (!con->response_headers_sent) {
@ -61,8 +61,7 @@ static void forward_response_body(liConnection *con) {
con->response_headers_sent = TRUE;
if (!li_response_send_headers(con)) {
con->response_headers_sent = FALSE;
li_connection_internal_error(con);
return;
return li_connection_internal_error(con);
}
li_vrequest_joblist_append(vr);
}
@ -80,6 +79,8 @@ static void forward_response_body(liConnection *con) {
con->info.out_queue_length = con->raw_out->length;
}
}
return TRUE;
}
/* don't use con afterwards */
@ -132,13 +133,14 @@ void li_connection_error(liConnection *con) {
li_worker_con_put(con);
}
static void li_connection_internal_error(liConnection *con) {
static G_GNUC_WARN_UNUSED_RESULT gboolean li_connection_internal_error(liConnection *con) {
liVRequest *vr = con->mainvr;
if (con->response_headers_sent) {
if (CORE_OPTION(LI_CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) {
VR_DEBUG(vr, "%s", "Couldn't send '500 Internal Error': headers already sent");
}
li_connection_error(con);
return FALSE;
} else {
if (CORE_OPTION(LI_CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) {
VR_DEBUG(vr, "%s", "internal error");
@ -154,11 +156,11 @@ static void li_connection_internal_error(liConnection *con) {
li_chunkqueue_reset(con->out);
con->out->is_closed = TRUE;
con->in->is_closed = TRUE;
forward_response_body(con);
return forward_response_body(con);
}
}
static gboolean connection_handle_read(liConnection *con) {
static G_GNUC_WARN_UNUSED_RESULT gboolean connection_handle_read(liConnection *con) {
liVRequest *vr = con->mainvr;
if (con->raw_in->length == 0) return TRUE;
@ -210,7 +212,7 @@ static gboolean connection_handle_read(liConnection *con) {
li_vrequest_handle_direct(con->mainvr);
con->state = LI_CON_STATE_WRITE;
con->in->is_closed = TRUE;
forward_response_body(con);
if (!forward_response_body(con)) return FALSE;
return TRUE;
}
@ -234,7 +236,7 @@ static gboolean connection_handle_read(liConnection *con) {
li_vrequest_handle_direct(con->mainvr);
con->state = LI_CON_STATE_WRITE;
con->in->is_closed = TRUE;
forward_response_body(con);
if (!forward_response_body(con)) return FALSE;
return TRUE;
}
@ -249,7 +251,7 @@ static gboolean connection_handle_read(liConnection *con) {
con->state = LI_CON_STATE_WRITE;
con->info.keep_alive = FALSE;
con->in->is_closed = TRUE;
forward_response_body(con);
if (!forward_response_body(con)) return FALSE;
} else {
/* When does a client ask for 100 Continue? probably not while trying to ddos us
* as post content probably goes to a dynamic backend anyway, we don't
@ -283,7 +285,7 @@ static void connection_update_io_timeout(liConnection *con) {
}
}
static gboolean connection_try_read(liConnection *con) {
static G_GNUC_WARN_UNUSED_RESULT gboolean connection_try_read(liConnection *con) {
liNetworkStatus res;
/* con->can_read = TRUE; */
@ -329,7 +331,7 @@ static gboolean connection_try_read(liConnection *con) {
return TRUE;
}
static gboolean connection_try_write(liConnection *con) {
static G_GNUC_WARN_UNUSED_RESULT gboolean connection_try_write(liConnection *con) {
liNetworkStatus res;
con->can_write = TRUE;
@ -427,7 +429,7 @@ static void connection_keepalive_cb(struct ev_loop *loop, ev_timer *w, int reven
li_worker_con_put(con);
}
static liHandlerResult mainvr_handle_response_headers(liVRequest *vr) {
static G_GNUC_WARN_UNUSED_RESULT gboolean mainvr_handle_response_headers(liVRequest *vr) {
liConnection *con = LI_CONTAINER_OF(vr->coninfo, liConnection, info);
if (CORE_OPTION(LI_CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) {
VR_DEBUG(vr, "%s", "read request/handle response header");
@ -443,12 +445,12 @@ static liHandlerResult mainvr_handle_response_headers(liVRequest *vr) {
update_io_events(con);
return LI_HANDLER_GO_ON;
return TRUE;
}
static liHandlerResult mainvr_handle_response_body(liVRequest *vr) {
static G_GNUC_WARN_UNUSED_RESULT gboolean mainvr_handle_response_body(liVRequest *vr) {
liConnection *con = LI_CONTAINER_OF(vr->coninfo, liConnection, info);
if (!check_response_done(con)) return LI_HANDLER_GO_ON;
if (!check_response_done(con)) return TRUE;
if (CORE_OPTION(LI_CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) {
VR_DEBUG(vr, "%s", "write response");
@ -458,22 +460,22 @@ static liHandlerResult mainvr_handle_response_body(liVRequest *vr) {
if (!connection_try_read(con)) return FALSE;
parse_request_body(con);
forward_response_body(con);
if (!forward_response_body(con)) return FALSE;
if (con->can_write)
if (!connection_try_write(con)) return FALSE;
if (!check_response_done(con)) return LI_HANDLER_GO_ON;
if (!check_response_done(con)) return TRUE;
update_io_events(con);
return LI_HANDLER_GO_ON;
return TRUE;
}
static liHandlerResult mainvr_handle_response_error(liVRequest *vr) {
static G_GNUC_WARN_UNUSED_RESULT gboolean mainvr_handle_response_error(liVRequest *vr) {
liConnection *con = LI_CONTAINER_OF(vr->coninfo, liConnection, info);
li_connection_internal_error(con);
if (!li_connection_internal_error(con)) return FALSE;
if (con->can_read)
if (!connection_try_read(con)) return FALSE;
@ -482,10 +484,10 @@ static liHandlerResult mainvr_handle_response_error(liVRequest *vr) {
update_io_events(con);
return LI_HANDLER_GO_ON;
return FALSE;
}
static liHandlerResult mainvr_handle_request_headers(liVRequest *vr) {
static G_GNUC_WARN_UNUSED_RESULT gboolean mainvr_handle_request_headers(liVRequest *vr) {
liConnection *con = LI_CONTAINER_OF(vr->coninfo, liConnection, info);
/* start reading input */
@ -495,7 +497,7 @@ static liHandlerResult mainvr_handle_request_headers(liVRequest *vr) {
parse_request_body(con);
update_io_events(con);
return LI_HANDLER_GO_ON;
return TRUE;
}
static gboolean mainvr_handle_check_io(liVRequest *vr) {
@ -707,7 +709,7 @@ static void li_connection_reset_keep_alive(liConnection *con) {
if (con->raw_in->length != 0) {
/* start handling next request if data is already available */
connection_handle_read(con);
if (!connection_handle_read(con)) return;
}
}

26
src/main/subrequest_lua.c

@ -246,7 +246,7 @@ static void subvr_bind_lua(liSubrequest *sr, lua_State *L, int notify_ndx, int e
sr->func_error_ref = luaL_ref(L, LUA_REGISTRYINDEX); /* -1 */
}
static liHandlerResult subvr_check(liVRequest *vr) {
static void subvr_check(liVRequest *vr) {
liSubrequest *sr = LI_CONTAINER_OF(vr->coninfo, liSubrequest, coninfo);
if (sr->notified_out_bytes < vr->vr_out->bytes_in
@ -262,22 +262,24 @@ static liHandlerResult subvr_check(liVRequest *vr) {
if (sr->notified_out_closed) { /* reques done */
li_job_async(sr->parentvr_ref);
}
return LI_HANDLER_GO_ON;
}
static liHandlerResult subvr_handle_response_headers(liVRequest *vr) {
static G_GNUC_WARN_UNUSED_RESULT gboolean subvr_handle_response_headers(liVRequest *vr) {
liSubrequest *sr = LI_CONTAINER_OF(vr->coninfo, liSubrequest, coninfo);
sr->have_response_headers = TRUE;
return subvr_check(vr);
subvr_check(vr);
return TRUE;
}
static liHandlerResult subvr_handle_response_body(liVRequest *vr) {
return subvr_check(vr);
static G_GNUC_WARN_UNUSED_RESULT gboolean subvr_handle_response_body(liVRequest *vr) {
subvr_check(vr);
return TRUE;
}
static liHandlerResult subvr_handle_response_error(liVRequest *vr) {
static G_GNUC_WARN_UNUSED_RESULT gboolean subvr_handle_response_error(liVRequest *vr) {
liSubrequest *sr = LI_CONTAINER_OF(vr->coninfo, liSubrequest, coninfo);
li_vrequest_free(sr->vr);
@ -286,11 +288,13 @@ static liHandlerResult subvr_handle_response_error(liVRequest *vr) {
subvr_run_lua(sr, sr->func_error_ref);
subvr_release_lua(sr);
return LI_HANDLER_GO_ON;
return FALSE;
}
static liHandlerResult subvr_handle_request_headers(liVRequest *vr) {
return subvr_check(vr);
static G_GNUC_WARN_UNUSED_RESULT gboolean subvr_handle_request_headers(liVRequest *vr) {
subvr_check(vr);
return TRUE;
}
static gboolean subvr_handle_check_io(liVRequest *vr) {

95
src/main/virtualrequest.c

@ -409,23 +409,24 @@ static liHandlerResult vrequest_do_handle_actions(liVRequest *vr) {
case LI_HANDLER_WAIT_FOR_EVENT:
return LI_HANDLER_WAIT_FOR_EVENT;
case LI_HANDLER_ERROR:
li_vrequest_error(vr);
return LI_HANDLER_ERROR;
}
return LI_HANDLER_GO_ON;
}
static gboolean vrequest_do_handle_read(liVRequest *vr) {
static G_GNUC_WARN_UNUSED_RESULT gboolean vrequest_do_handle_read(liVRequest *vr) {
if (vr->backend && vr->backend->handle_request_body) {
goffset lim_avail;
if (vr->in->is_closed) vr->in_memory->is_closed = TRUE;
if (!filters_handle_out_close(vr, &vr->filters_in)) {
li_vrequest_error(vr);
return FALSE;
}
if (!filters_run(vr, &vr->filters_in)) {
li_vrequest_error(vr);
return FALSE;
}
if (vr->in_buffer_state.tempfile || vr->request.content_length < 0 || vr->request.content_length > 64*1024 ||
@ -440,7 +441,7 @@ static gboolean vrequest_do_handle_read(liVRequest *vr) {
return FALSE;
case LI_HANDLER_ERROR:
li_vrequest_error(vr);
break;
return FALSE;
}
} else {
li_chunkqueue_steal_all(vr->in, vr->in_memory);
@ -457,7 +458,7 @@ static gboolean vrequest_do_handle_read(liVRequest *vr) {
return FALSE;
case LI_HANDLER_ERROR:
li_vrequest_error(vr);
break;
return FALSE;
}
} else {
li_chunkqueue_skip_all(vr->vr_in);
@ -466,34 +467,23 @@ static gboolean vrequest_do_handle_read(liVRequest *vr) {
return TRUE;
}
static void vrequest_do_handle_write(liVRequest *vr) {
static G_GNUC_WARN_UNUSED_RESULT gboolean vrequest_do_handle_write(liVRequest *vr) {
if (!filters_handle_out_close(vr, &vr->filters_out)) {
li_vrequest_error(vr);
return;
return FALSE;
}
if (!filters_run(vr, &vr->filters_out)) {
li_vrequest_error(vr);
return;
return FALSE;
}
switch (vr->coninfo->callbacks->handle_response_body(vr)) {
case LI_HANDLER_GO_ON:
break;
case LI_HANDLER_COMEBACK:
li_vrequest_joblist_append(vr); /* come back later */
return;
case LI_HANDLER_WAIT_FOR_EVENT:
return;
case LI_HANDLER_ERROR:
li_vrequest_error(vr);
break;
}
return;
if (!vr->coninfo->callbacks->handle_response_body(vr)) return FALSE;
return TRUE;
}
void li_vrequest_state_machine(liVRequest *vr) {
gboolean done = FALSE;
liHandlerResult res;
do {
switch (vr->state) {
case LI_VRS_CLEAN:
@ -514,33 +504,22 @@ void li_vrequest_state_machine(liVRequest *vr) {
if (vr->state == LI_VRS_HANDLE_REQUEST_HEADERS) return;
break; /* go on to get post data/response headers if request is already handled */
case LI_HANDLER_ERROR:
li_vrequest_error(vr);
return;
}
res = vr->coninfo->callbacks->handle_request_headers(vr);
switch (res) {
case LI_HANDLER_GO_ON:
if (vr->state == LI_VRS_HANDLE_REQUEST_HEADERS) {
if (vr->request.http_method == LI_HTTP_METHOD_OPTIONS) {
vr->response.http_status = 200;
li_http_header_append(vr->response.headers, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
} else {
/* unhandled request */
vr->response.http_status = 404;
}
li_vrequest_handle_direct(vr);
if (vr->state == LI_VRS_HANDLE_REQUEST_HEADERS) {
if (vr->request.http_method == LI_HTTP_METHOD_OPTIONS) {
vr->response.http_status = 200;
li_http_header_append(vr->response.headers, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
} else {
/* unhandled request */
vr->response.http_status = 404;
}
break;
case LI_HANDLER_COMEBACK:
li_vrequest_joblist_append(vr); /* come back later */
done = TRUE;
break;
case LI_HANDLER_WAIT_FOR_EVENT:
done = (vr->state == LI_VRS_HANDLE_REQUEST_HEADERS);
break;
case LI_HANDLER_ERROR:
li_vrequest_error(vr);
break;
li_vrequest_handle_direct(vr);
}
if (!vr->coninfo->callbacks->handle_request_headers(vr)) return;
break;
case LI_VRS_READ_CONTENT:
@ -562,33 +541,20 @@ void li_vrequest_state_machine(liVRequest *vr) {
return;
case LI_HANDLER_WAIT_FOR_EVENT:
return; /* wait to handle response headers */
case LI_HANDLER_ERROR:
return;
}
res = vr->coninfo->callbacks->handle_response_headers(vr);
switch (res) {
case LI_HANDLER_GO_ON:
vr->state = LI_VRS_WRITE_CONTENT;
break;
case LI_HANDLER_COMEBACK:
li_vrequest_joblist_append(vr); /* come back later */
done = TRUE;
break;
case LI_HANDLER_WAIT_FOR_EVENT:
done = (vr->state == LI_VRS_HANDLE_REQUEST_HEADERS);
break;
case LI_HANDLER_ERROR:
li_vrequest_error(vr);
break;
return;
}
if (!vr->coninfo->callbacks->handle_response_headers(vr)) return;
vr->state = LI_VRS_WRITE_CONTENT;
break;
case LI_VRS_WRITE_CONTENT:
if (CORE_OPTION(LI_CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) {
VR_DEBUG(vr, "%s", "write content");
}
vrequest_do_handle_read(vr);
vrequest_do_handle_write(vr);
if (!vrequest_do_handle_read(vr)) return;
if (!vrequest_do_handle_write(vr)) return;
done = TRUE;
break;
@ -596,9 +562,8 @@ void li_vrequest_state_machine(liVRequest *vr) {
if (CORE_OPTION(LI_CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) {
VR_DEBUG(vr, "%s", "error");
}
/* this will probably reset the vrequest, so stop handling after it */
vr->coninfo->callbacks->handle_response_error(vr);
return;
if (!vr->coninfo->callbacks->handle_response_error(vr)) return;
return; /* stop anyway */
}
} while (!done);
}

Loading…
Cancel
Save