the upcoming 2.0 version
https://redmine.lighttpd.net/projects/lighttpd2
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
304 lines
7.3 KiB
304 lines
7.3 KiB
|
|
#include <lighttpd/base.h> |
|
#include <lighttpd/plugin_core.h> |
|
|
|
static filter* filter_new() { |
|
filter *f = g_slice_new0(filter); |
|
return f; |
|
} |
|
|
|
static void filter_free(filter *f) { |
|
g_slice_free(filter, f); |
|
} |
|
|
|
static void filters_init(filters *fs) { |
|
fs->queue = g_ptr_array_new(); |
|
fs->in = chunkqueue_new(); |
|
fs->out = chunkqueue_new(); |
|
} |
|
|
|
static void filters_clean(filters *fs) { |
|
guint i; |
|
for (i = 0; i < fs->queue->len; i++) { |
|
filter_free((filter*) g_ptr_array_index(fs->queue, i)); |
|
} |
|
g_ptr_array_free(fs->queue, TRUE); |
|
chunkqueue_free(fs->in); |
|
chunkqueue_free(fs->out); |
|
} |
|
|
|
static void filters_reset(filters *fs) { |
|
guint i; |
|
for (i = 0; i < fs->queue->len; i++) { |
|
filter_free((filter*) g_ptr_array_index(fs->queue, i)); |
|
} |
|
g_ptr_array_set_size(fs->queue, 0); |
|
chunkqueue_reset(fs->in); |
|
chunkqueue_reset(fs->out); |
|
} |
|
|
|
vrequest* vrequest_new(connection *con, vrequest_handler handle_response_headers, vrequest_handler handle_response_body, vrequest_handler handle_response_error, vrequest_handler handle_request_headers) { |
|
vrequest *vr = g_slice_new0(vrequest); |
|
|
|
vr->con = con; |
|
vr->state = VRS_CLEAN; |
|
|
|
vr->handle_response_headers = handle_response_headers; |
|
vr->handle_response_body = handle_response_body; |
|
vr->handle_response_error = handle_response_error; |
|
vr->handle_request_headers = handle_request_headers; |
|
|
|
request_init(&vr->request); |
|
physical_init(&vr->physical); |
|
response_init(&vr->response); |
|
|
|
filters_init(&vr->filters_in); |
|
filters_init(&vr->filters_out); |
|
vr->vr_in = vr->filters_in.in; |
|
vr->in = vr->filters_in.out; |
|
vr->out = vr->filters_out.in; |
|
vr->vr_out = vr->filters_out.out; |
|
|
|
action_stack_init(&vr->action_stack); |
|
|
|
return vr; |
|
} |
|
|
|
void vrequest_free(vrequest* vr) { |
|
request_clear(&vr->request); |
|
physical_clear(&vr->physical); |
|
response_clear(&vr->response); |
|
|
|
filters_clean(&vr->filters_in); |
|
filters_clean(&vr->filters_out); |
|
|
|
action_stack_clear(vr->con->srv, &vr->action_stack); |
|
|
|
g_slice_free(vrequest, vr); |
|
} |
|
|
|
void vrequest_reset(vrequest *vr) { |
|
vr->state = VRS_CLEAN; |
|
|
|
vr->handle_request_body = NULL; |
|
|
|
request_reset(&vr->request); |
|
physical_reset(&vr->physical); |
|
response_reset(&vr->response); |
|
|
|
filters_reset(&vr->filters_in); |
|
filters_reset(&vr->filters_out); |
|
|
|
action_stack_reset(vr->con->srv, &vr->action_stack); |
|
} |
|
|
|
void vrequest_error(vrequest *vr) { |
|
vr->state = VRS_ERROR; |
|
vrequest_joblist_append(vr); |
|
} |
|
|
|
/* received all request headers */ |
|
void vrequest_handle_request_headers(vrequest *vr) { |
|
if (VRS_CLEAN == vr->state) { |
|
vr->state = VRS_HANDLE_REQUEST_HEADERS; |
|
} |
|
vrequest_joblist_append(vr); |
|
} |
|
|
|
/* received (partial) request content */ |
|
void vrequest_handle_request_body(vrequest *vr) { |
|
if (VRS_READ_CONTENT <= vr->state) { |
|
vrequest_joblist_append(vr); |
|
} |
|
} |
|
|
|
/* received all response headers/status code - call once from your indirect handler */ |
|
void vrequest_handle_response_headers(vrequest *vr) { |
|
if (VRS_HANDLE_RESPONSE_HEADERS > vr->state) { |
|
vr->state = VRS_HANDLE_RESPONSE_HEADERS; |
|
} |
|
vrequest_joblist_append(vr); |
|
} |
|
|
|
/* received (partial) response content - call from your indirect handler */ |
|
void vrequest_handle_response_body(vrequest *vr) { |
|
if (VRS_WRITE_CONTENT == vr->state) { |
|
vrequest_joblist_append(vr); |
|
} |
|
} |
|
|
|
/* response completely ready */ |
|
gboolean vrequest_handle_direct(vrequest *vr) { |
|
if (vr->state < VRS_READ_CONTENT) { |
|
vr->state = VRS_HANDLE_RESPONSE_HEADERS; |
|
vr->out->is_closed = TRUE; |
|
vr->handle_request_body = NULL; |
|
return TRUE; |
|
} else { |
|
return FALSE; |
|
} |
|
} |
|
|
|
/* handle request over time */ |
|
gboolean vrequest_handle_indirect(vrequest *vr, vrequest_handler handle_request_body) { |
|
if (vr->state < VRS_READ_CONTENT) { |
|
vr->state = VRS_READ_CONTENT; |
|
vr->handle_request_body = handle_request_body; |
|
return TRUE; |
|
} else { |
|
return FALSE; |
|
} |
|
} |
|
|
|
static gboolean vrequest_do_handle_actions(vrequest *vr) { |
|
handler_t res = action_execute(vr); |
|
switch (res) { |
|
case HANDLER_GO_ON: |
|
case HANDLER_FINISHED: |
|
if (vr->state == VRS_HANDLE_REQUEST_HEADERS) { |
|
VR_ERROR(vr, "%s", "actions didn't handle request"); |
|
/* request not handled */ |
|
vrequest_error(vr); |
|
return FALSE; |
|
} |
|
/* otherwise state already changed */ |
|
break; |
|
case HANDLER_COMEBACK: |
|
vrequest_joblist_append(vr); /* come back later */ |
|
return FALSE; |
|
case HANDLER_WAIT_FOR_FD: /* TODO: wait for fd */ |
|
case HANDLER_WAIT_FOR_EVENT: |
|
return FALSE; |
|
case HANDLER_ERROR: |
|
vrequest_error(vr); |
|
return FALSE; |
|
} |
|
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->handle_request_body) { |
|
chunkqueue_steal_all(vr->in, vr->vr_in); /* TODO: filters */ |
|
if (vr->vr_in->is_closed) vr->in->is_closed = TRUE; |
|
res = vr->handle_request_body(vr); |
|
switch (res) { |
|
case HANDLER_GO_ON: |
|
case HANDLER_FINISHED: |
|
break; |
|
case HANDLER_COMEBACK: |
|
vrequest_joblist_append(vr); /* come back later */ |
|
return FALSE; |
|
case HANDLER_WAIT_FOR_FD: /* TODO: wait for fd */ |
|
case HANDLER_WAIT_FOR_EVENT: |
|
return FALSE; |
|
case HANDLER_ERROR: |
|
vrequest_error(vr); |
|
break; |
|
} |
|
} else { |
|
chunkqueue_skip_all(vr->vr_in); |
|
if (vr->vr_in->is_closed) vr->in->is_closed = TRUE; |
|
} |
|
return TRUE; |
|
} |
|
|
|
static gboolean vrequest_do_handle_write(vrequest *vr) { |
|
handler_t res; |
|
chunkqueue_steal_all(vr->vr_out, vr->out); /* TODO: filters */ |
|
if (vr->out->is_closed) vr->vr_out->is_closed = TRUE; |
|
res = vr->handle_response_body(vr); |
|
switch (res) { |
|
case HANDLER_GO_ON: |
|
case HANDLER_FINISHED: |
|
break; |
|
case HANDLER_COMEBACK: |
|
vrequest_joblist_append(vr); /* come back later */ |
|
return FALSE; |
|
case HANDLER_WAIT_FOR_FD: /* TODO: wait for fd */ |
|
case HANDLER_WAIT_FOR_EVENT: |
|
return FALSE; |
|
case HANDLER_ERROR: |
|
vrequest_error(vr); |
|
break; |
|
} |
|
return TRUE; |
|
} |
|
|
|
void vrequest_state_machine(vrequest *vr) { |
|
gboolean done = FALSE; |
|
handler_t res; |
|
do { |
|
switch (vr->state) { |
|
case VRS_CLEAN: |
|
done = TRUE; |
|
break; |
|
|
|
case VRS_HANDLE_REQUEST_HEADERS: |
|
if (CORE_OPTION(CORE_OPTION_DEBUG_REQUEST_HANDLING).boolean) { |
|
VR_TRACE(vr, "%s", "handle request header"); |
|
} |
|
if (!vrequest_do_handle_actions(vr)) return; |
|
res = vr->handle_request_headers(vr); |
|
switch (res) { |
|
case HANDLER_GO_ON: |
|
case HANDLER_FINISHED: |
|
break; |
|
case HANDLER_COMEBACK: |
|
vrequest_joblist_append(vr); /* come back later */ |
|
done = TRUE; |
|
break; |
|
case HANDLER_WAIT_FOR_FD: /* TODO: wait for fd */ |
|
case HANDLER_WAIT_FOR_EVENT: |
|
done = TRUE; |
|
break; |
|
case HANDLER_ERROR: |
|
vrequest_error(vr); |
|
break; |
|
} |
|
break; |
|
|
|
case VRS_READ_CONTENT: |
|
done = !vrequest_do_handle_read(vr); |
|
break; |
|
|
|
case VRS_HANDLE_RESPONSE_HEADERS: |
|
if (!vrequest_do_handle_actions(vr)) return; |
|
res = vr->handle_response_headers(vr); |
|
switch (res) { |
|
case HANDLER_GO_ON: |
|
case HANDLER_FINISHED: |
|
vr->state = VRS_WRITE_CONTENT; |
|
break; |
|
case HANDLER_COMEBACK: |
|
vrequest_joblist_append(vr); /* come back later */ |
|
done = TRUE; |
|
break; |
|
case HANDLER_WAIT_FOR_FD: /* TODO: wait for fd */ |
|
case HANDLER_WAIT_FOR_EVENT: |
|
done = TRUE; |
|
break; |
|
case HANDLER_ERROR: |
|
vrequest_error(vr); |
|
break; |
|
} |
|
break; |
|
|
|
case VRS_WRITE_CONTENT: |
|
vrequest_do_handle_read(vr); |
|
vrequest_do_handle_write(vr); |
|
done = TRUE; |
|
break; |
|
|
|
case VRS_ERROR: |
|
vr->handle_response_error(vr); |
|
return; |
|
} |
|
} while (!done); |
|
} |
|
|
|
void vrequest_joblist_append(vrequest *vr) { |
|
/* TODO */ |
|
vrequest_state_machine(vr); |
|
}
|
|
|