| diff -Nru lighttpd-1.4.22.orig/src/connections.c lighttpd-1.4.22/src/connections.c |
| --- lighttpd-1.4.22.orig/src/connections.c 2009-02-19 14:15:14.000000000 +0100 |
| +++ lighttpd-1.4.28/src/connections.c 2009-04-22 17:45:20.000000000 +0200 |
| @@ -1401,11 +1401,15 @@ |
| if (http_request_parse(srv, con)) { |
| /* we have to read some data from the POST request */ |
| |
| + plugins_call_handle_request_end(srv, con); |
| + |
| connection_set_state(srv, con, CON_STATE_READ_POST); |
| |
| break; |
| } |
| |
| + plugins_call_handle_request_end(srv, con); |
| + |
| connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); |
| |
| break; |
| diff -Nru lighttpd-1.4.22.orig/src/Makefile.am lighttpd-1.4.22/src/Makefile.am |
| --- lighttpd-1.4.22.orig/src/Makefile.am 2009-02-19 14:15:14.000000000 +0100 |
| +++ lighttpd-1.4.28/src/Makefile.am 2009-04-22 17:46:34.000000000 +0200 |
| @@ -246,6 +246,11 @@ |
| mod_accesslog_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined |
| mod_accesslog_la_LIBADD = $(common_libadd) |
| |
| +lib_LTLIBRARIES += mod_uploadprogress.la |
| +mod_uploadprogress_la_SOURCES = mod_uploadprogress.c |
| +mod_uploadprogress_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined |
| +mod_uploadprogress_la_LIBADD = $(common_libadd) |
| + |
| |
| hdr = server.h buffer.h network.h log.h keyvalue.h \ |
| response.h request.h fastcgi.h chunk.h \ |
| diff -Nru lighttpd-1.4.22.orig/src/plugin.c lighttpd-1.4.22/src/plugin.c |
| --- lighttpd-1.4.22.orig/src/plugin.c 2009-02-19 14:15:14.000000000 +0100 |
| +++ lighttpd-1.4.28/src/plugin.c 2009-04-22 17:45:20.000000000 +0200 |
| @@ -34,6 +34,7 @@ |
| PLUGIN_FUNC_UNSET, |
| PLUGIN_FUNC_HANDLE_URI_CLEAN, |
| PLUGIN_FUNC_HANDLE_URI_RAW, |
| + PLUGIN_FUNC_HANDLE_REQUEST_END, |
| PLUGIN_FUNC_HANDLE_REQUEST_DONE, |
| PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, |
| PLUGIN_FUNC_HANDLE_TRIGGER, |
| @@ -262,6 +263,7 @@ |
| |
| PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean) |
| PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw) |
| +PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_END, handle_request_end) |
| PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done) |
| PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close) |
| PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest) |
| @@ -389,6 +391,7 @@ |
| |
| PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean); |
| PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw); |
| + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_END, handle_request_end); |
| PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done); |
| PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close); |
| PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger); |
| diff -Nru lighttpd-1.4.22.orig/src/plugin.h lighttpd-1.4.22/src/plugin.h |
| --- lighttpd-1.4.22.orig/src/plugin.h 2009-02-19 14:15:14.000000000 +0100 |
| +++ lighttpd-1.4.28/src/plugin.h 2009-04-22 17:45:20.000000000 +0200 |
| @@ -42,12 +42,12 @@ |
| handler_t (* handle_uri_clean) (server *srv, connection *con, void *p_d); /* after uri is set */ |
| handler_t (* handle_docroot) (server *srv, connection *con, void *p_d); /* getting the document-root */ |
| handler_t (* handle_physical) (server *srv, connection *con, void *p_d); /* mapping url to physical path */ |
| + handler_t (* handle_request_end) (server *srv, connection *con, void *p_d); /* a handler for the request content */ |
| handler_t (* handle_request_done) (server *srv, connection *con, void *p_d); /* at the end of a request */ |
| handler_t (* handle_connection_close)(server *srv, connection *con, void *p_d); /* at the end of a connection */ |
| handler_t (* handle_joblist) (server *srv, connection *con, void *p_d); /* after all events are handled */ |
| |
| |
| - |
| handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d); |
| |
| /* when a handler for the request |
| @@ -68,6 +68,7 @@ |
| handler_t plugins_call_handle_uri_clean(server *srv, connection *con); |
| handler_t plugins_call_handle_subrequest_start(server *srv, connection *con); |
| handler_t plugins_call_handle_subrequest(server *srv, connection *con); |
| +handler_t plugins_call_handle_request_end(server *srv, connection *con); |
| handler_t plugins_call_handle_request_done(server *srv, connection *con); |
| handler_t plugins_call_handle_docroot(server *srv, connection *con); |
| handler_t plugins_call_handle_physical(server *srv, connection *con); |
| diff -Nru lighttpd-1.4.22.orig/src/mod_uploadprogress.c lighttpd-1.4.22/src/mod_uploadprogress.c |
| --- lighttpd-1.4.22.orig/src/mod_uploadprogress.c 1970-01-01 01:00:00.000000000 +0100 |
| +++ lighttpd-1.4.28/src/mod_uploadprogress.c 2009-04-22 17:32:38.000000000 +0200 |
| @@ -0,0 +1,648 @@ |
| +#include <ctype.h> |
| +#include <stdlib.h> |
| +#include <string.h> |
| + |
| +#include "base.h" |
| +#include "log.h" |
| +#include "buffer.h" |
| + |
| +#include "plugin.h" |
| + |
| +#include "response.h" |
| +#include "stat_cache.h" |
| + |
| +#define CONFIG_UPLOAD_PROGRESS_URL "upload-progress.progress-url" |
| +#define CONFIG_UPLOAD_PROGRESS_TIMEOUT "upload-progress.remove-timeout" |
| +#define CONFIG_UPLOAD_PROGRESS_DEBUG "upload-progress.debug" |
| + |
| +#define SAFE_BUF_STR(x) x && x->ptr ? x->ptr : "(null)" |
| + |
| +/** |
| + * uploadprogress for lighttpd |
| + * |
| + * Initial: Jan Kneschke <jan@kneschke.de> |
| + * Timeout+Status addon: Bjoern Kalkbrenner <terminar@cyberphoria.org> [20070112] |
| + * |
| + * Ported to Lighttpd 1.4.22 by Radek Senfeld <rush@logic.cz> |
| + * |
| + * Backport based on revision 2369 |
| + * http://redmine.lighttpd.net/projects/lighttpd/repository/changes/trunk/src/mod_uploadprogress.c |
| + * |
| + * the timeout is used to keep in the status information intact even if the parent |
| + * connection is gone already |
| + * |
| + */ |
| + |
| +typedef struct { |
| + buffer *tracking_id; |
| + connection *con; |
| + |
| + time_t timeout; |
| + int status; |
| + off_t size; |
| +} connection_map_entry; |
| + |
| +typedef struct { |
| + connection_map_entry **ptr; |
| + |
| + size_t used; |
| + size_t size; |
| +} connection_map; |
| + |
| +/* plugin config for all request/connections */ |
| + |
| +typedef struct { |
| + buffer *progress_url; |
| + unsigned short debug; |
| + unsigned short remove_timeout; |
| +} plugin_config; |
| + |
| +typedef struct { |
| + PLUGIN_DATA; |
| + |
| + connection_map *con_map; |
| + |
| + buffer *tmp_buf; /** used as temporary buffer for extracting the tracking id */ |
| + |
| + plugin_config **config_storage; |
| + |
| + plugin_config conf; |
| +} plugin_data; |
| + |
| +/** |
| + * |
| + * connection maps |
| + * |
| + */ |
| + |
| +/* init the plugin data */ |
| +static connection_map *connection_map_init() { |
| + connection_map *cm; |
| + |
| + cm = calloc(1, sizeof(*cm)); |
| + |
| + return cm; |
| +} |
| + |
| +static void connection_map_free(connection_map *cm) { |
| + size_t i; |
| + for (i = 0; i < cm->size; i++) { |
| + connection_map_entry *cme = cm->ptr[i]; |
| + |
| + if (!cme) break; |
| + |
| + if (cme->tracking_id) { |
| + buffer_free(cme->tracking_id); |
| + } |
| + free(cme); |
| + } |
| + |
| + free(cm); |
| +} |
| + |
| +static connection_map_entry *connection_map_insert(connection_map *cm, buffer *tracking_id, connection *con) { |
| + connection_map_entry *cme; |
| + size_t i; |
| + |
| + if (cm->size == 0) { |
| + cm->size = 16; |
| + cm->ptr = malloc(cm->size * sizeof(*(cm->ptr))); |
| + for (i = 0; i < cm->size; i++) { |
| + cm->ptr[i] = NULL; |
| + } |
| + } else if (cm->used == cm->size) { |
| + cm->size += 16; |
| + cm->ptr = realloc(cm->ptr, cm->size * sizeof(*(cm->ptr))); |
| + for (i = cm->used; i < cm->size; i++) { |
| + cm->ptr[i] = NULL; |
| + } |
| + } |
| + |
| + if (cm->ptr[cm->used]) { |
| + /* is already alloced, just reuse it */ |
| + cme = cm->ptr[cm->used]; |
| + } else { |
| + cme = malloc(sizeof(*cme)); |
| + cme->tracking_id = buffer_init(); |
| + } |
| + cme->timeout = 0; |
| + cme->status = 0; |
| + buffer_copy_string_buffer(cme->tracking_id, tracking_id); |
| + cme->con = con; |
| + |
| + cm->ptr[cm->used++] = cme; |
| + |
| + return cme; |
| +} |
| + |
| +static connection_map_entry *connection_map_get_connection_entry(connection_map *cm, buffer *tracking_id) { |
| + size_t i; |
| + |
| + for (i = 0; i < cm->used; i++) { |
| + connection_map_entry *cme = cm->ptr[i]; |
| + |
| + if (buffer_is_equal(cme->tracking_id, tracking_id)) { |
| + /* found connection */ |
| + return cme; |
| + } |
| + } |
| + return NULL; |
| +} |
| + |
| +static void connection_map_remove_connection(connection_map *cm, size_t i) { |
| + connection_map_entry *cme = cm->ptr[i]; |
| + |
| + buffer_reset(cme->tracking_id); |
| + cme->timeout=0; |
| + cme->status=0; |
| + |
| + cm->used--; |
| + |
| + /* swap positions with the last entry */ |
| + if (cm->used) { |
| + cm->ptr[i] = cm->ptr[cm->used]; |
| + cm->ptr[cm->used] = cme; |
| + } |
| +} |
| + |
| +/** |
| + * remove dead tracking IDs |
| + * |
| + * uploadprogress.remove-timeout sets a grace-period in which the |
| + * connection status is still known even of the connection is already |
| + * being removed |
| + * |
| + */ |
| +static void connection_map_clear_timeout_connections(connection_map *cm) { |
| + size_t i; |
| + time_t now_t = time(NULL); |
| + |
| + for (i = 0; i < cm->used; i++) { |
| + connection_map_entry *cme = cm->ptr[i]; |
| + |
| + if (cme->timeout != 0 && cme->timeout < now_t) { |
| + /* found connection */ |
| + connection_map_remove_connection(cm, i); |
| + } |
| + } |
| +} |
| + |
| +/** |
| + * extract the tracking-id from the parameters |
| + * |
| + * for POST requests it is part of the request headers |
| + * for GET requests ... too |
| + */ |
| +static buffer *get_tracking_id(plugin_data *p, server *srv, connection *con) { |
| + data_string *ds; |
| + buffer *b = NULL; |
| + char *qstr=NULL; |
| + size_t i; |
| + |
| + /* the request has to contain a 32byte ID */ |
| + if (NULL == (ds = (data_string *)array_get_element(con->request.headers, "X-Progress-ID"))) { |
| + char *amp = NULL; |
| + |
| + /* perhaps the POST request is using the querystring to pass the X-Progress-ID */ |
| + if (buffer_is_empty(con->uri.query)) { |
| + /* |
| + * con->uri.query will not be parsed out if a 413 error happens |
| + */ |
| + if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) { |
| + /** extract query string from request.uri */ |
| + buffer_copy_string(con->uri.query, qstr + 1); |
| + } else { |
| + return NULL; |
| + } |
| + } |
| + |
| + /** split the query-string and extract the X-Progress-ID */ |
| + do { |
| + char *eq = NULL; |
| + char *start = amp ? amp + 1 : con->uri.query->ptr; |
| + |
| + amp = strchr(start, '&'); |
| + |
| + /* check the string between start and amp for = */ |
| + |
| + if (amp) { |
| + buffer_copy_string_len(p->tmp_buf, start, amp - start); |
| + } else { |
| + buffer_copy_string(p->tmp_buf, start); |
| + } |
| + |
| + eq = strchr(p->tmp_buf->ptr, '='); |
| + |
| + if (eq) { |
| + *eq = '\0'; |
| + |
| + if (0 == strcmp(p->tmp_buf->ptr, "X-Progress-ID")) { |
| + size_t key_len = sizeof("X-Progress-ID") - 1; |
| + size_t var_len = p->tmp_buf->used - 1; |
| + /* found */ |
| + |
| + buffer_copy_string_len(p->tmp_buf, start + key_len + 1, var_len - key_len - 1); |
| + |
| + b = p->tmp_buf; |
| + |
| + break; |
| + } |
| + } |
| + } while (amp); |
| + |
| + if (!b) return NULL; |
| + } else { |
| + /* request header was found, use it */ |
| + b = ds->value; |
| + } |
| + |
| + if (b->used != 32 + 1) { |
| + if (p->conf.debug) log_error_write(srv, __FILE__, __LINE__, "sds", "the Progress-ID has to be 32 characters long, got", b->used - 1, "characters"); |
| + return NULL; |
| + } |
| + |
| + for (i = 0; i < b->used - 1; i++) { |
| + char c = b->ptr[i]; |
| + |
| + if (!light_isxdigit(c)) { |
| + if (p->conf.debug) log_error_write(srv, __FILE__, __LINE__, "sds", "only hex-digits are allowed (0-9 + a-f): (ascii:", c, ")"); |
| + return NULL; |
| + } |
| + } |
| + |
| + return b; |
| +} |
| + |
| +/* init the plugin data */ |
| +INIT_FUNC(mod_uploadprogress_init) { |
| + plugin_data *p; |
| + |
| + p = calloc(1, sizeof(*p)); |
| + |
| + p->con_map = connection_map_init(); |
| + p->tmp_buf = buffer_init(); |
| + |
| + return p; |
| +} |
| + |
| +/* detroy the plugin data */ |
| +FREE_FUNC(mod_uploadprogress_free) { |
| + plugin_data *p = p_d; |
| + |
| + UNUSED(srv); |
| + |
| + if (!p) return HANDLER_GO_ON; |
| + |
| + if (p->config_storage) { |
| + size_t i; |
| + for (i = 0; i < srv->config_context->used; i++) { |
| + plugin_config *s = p->config_storage[i]; |
| + |
| + buffer_free(s->progress_url); |
| + s->remove_timeout=0; |
| + |
| + free(s); |
| + } |
| + free(p->config_storage); |
| + } |
| + |
| + connection_map_free(p->con_map); |
| + buffer_free(p->tmp_buf); |
| + |
| + free(p); |
| + |
| + return HANDLER_GO_ON; |
| +} |
| + |
| +/* handle plugin config and check values */ |
| + |
| +SETDEFAULTS_FUNC(mod_uploadprogress_set_defaults) { |
| + plugin_data *p = p_d; |
| + size_t i = 0; |
| + |
| + config_values_t cv[] = { |
| + { CONFIG_UPLOAD_PROGRESS_URL, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ |
| + { CONFIG_UPLOAD_PROGRESS_TIMEOUT, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ |
| + { CONFIG_UPLOAD_PROGRESS_DEBUG, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ |
| + { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } |
| + }; |
| + |
| + if (!p) return HANDLER_ERROR; |
| + |
| + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); |
| + |
| + for (i = 0; i < srv->config_context->used; i++) { |
| + plugin_config *s; |
| + |
| + s = calloc(1, sizeof(plugin_config)); |
| + s->progress_url = buffer_init(); |
| + s->remove_timeout = 60; |
| + s->debug = 0; |
| + |
| + cv[0].destination = s->progress_url; |
| + cv[1].destination = &(s->remove_timeout); |
| + cv[2].destination = &(s->debug); |
| + |
| + p->config_storage[i] = s; |
| + |
| + if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { |
| + return HANDLER_ERROR; |
| + } |
| + } |
| + |
| + return HANDLER_GO_ON; |
| +} |
| + |
| +#define PATCH_OPTION(x) \ |
| + p->conf.x = s->x; |
| +static int mod_uploadprogress_patch_connection(server *srv, connection *con, plugin_data *p) { |
| + size_t i, j; |
| + plugin_config *s = p->config_storage[0]; |
| + |
| + PATCH_OPTION(progress_url); |
| + PATCH_OPTION(remove_timeout); |
| + PATCH_OPTION(debug); |
| + |
| + /* skip the first, the global context */ |
| + for (i = 1; i < srv->config_context->used; i++) { |
| + data_config *dc = (data_config *)srv->config_context->data[i]; |
| + s = p->config_storage[i]; |
| + |
| + /* condition didn't match */ |
| + if (!config_check_cond(srv, con, dc)) continue; |
| + |
| + /* merge config */ |
| + for (j = 0; j < dc->value->used; j++) { |
| + data_unset *du = dc->value->data[j]; |
| + |
| + if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_UPLOAD_PROGRESS_URL))) { |
| + PATCH_OPTION(progress_url); |
| + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_UPLOAD_PROGRESS_TIMEOUT))) { |
| + PATCH_OPTION(remove_timeout); |
| + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_UPLOAD_PROGRESS_DEBUG))) { |
| + PATCH_OPTION(debug); |
| + } |
| + } |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +/** |
| + * |
| + * the idea: |
| + * |
| + * for the first request we check if it is a post-request |
| + * |
| + * if no, move out, don't care about them |
| + * |
| + * if yes, take the connection structure and register it locally |
| + * in the progress-struct together with an session-id (md5 ... ) |
| + * |
| + * if the connections closes, cleanup the entry in the progress-struct |
| + * |
| + * a second request can now get the info about the size of the upload, |
| + * the received bytes |
| + * |
| + */ |
| + |
| +URIHANDLER_FUNC(mod_uploadprogress_uri_handler) { |
| + plugin_data *p = p_d; |
| + buffer *tracking_id; |
| + buffer *b; |
| + connection_map_entry *post_con_entry = NULL; |
| + connection_map_entry *map_con_entry = NULL; |
| + |
| + if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON; |
| + |
| + /* no progress URL set, ignore request */ |
| + if (buffer_is_empty(p->conf.progress_url)) return HANDLER_GO_ON; |
| + |
| + switch(con->request.http_method) { |
| + case HTTP_METHOD_POST: |
| + /** |
| + * a POST request is the UPLOAD itself |
| + * |
| + * get the unique tracker id |
| + */ |
| + if (NULL == (tracking_id = get_tracking_id(p, srv, con))) { |
| + return HANDLER_GO_ON; |
| + } |
| + |
| + if (NULL == (map_con_entry = connection_map_get_connection_entry(p->con_map, tracking_id))) { |
| + connection_map_insert(p->con_map, tracking_id, con); |
| + |
| + if (p->conf.debug) log_error_write(srv, __FILE__, __LINE__, "ss", "POST: connection is new, registered:", SAFE_BUF_STR(tracking_id)); |
| + } else { |
| + map_con_entry->timeout = 0; |
| + map_con_entry->status = 0; |
| + |
| + if (p->conf.debug) log_error_write(srv, __FILE__, __LINE__, "ss", "POST: connection is known, id:", SAFE_BUF_STR(tracking_id)); |
| + } |
| + |
| + return HANDLER_GO_ON; |
| + case HTTP_METHOD_GET: |
| + /** |
| + * the status request for the current connection |
| + */ |
| + if (p->conf.debug) log_error_write(srv, __FILE__, __LINE__, "ssss", "(uploadprogress) urls", SAFE_BUF_STR(con->uri.path), "==", SAFE_BUF_STR(p->conf.progress_url)); |
| + |
| + if (!buffer_is_equal(con->uri.path, p->conf.progress_url)) { |
| + return HANDLER_GO_ON; |
| + } |
| + |
| + /* get the tracker id */ |
| + if (NULL == (tracking_id = get_tracking_id(p, srv, con))) { |
| + return HANDLER_GO_ON; |
| + } |
| + |
| + buffer_reset(con->physical.path); |
| + |
| + con->file_started = 1; |
| + con->http_status = 200; |
| + con->file_finished = 1; |
| + |
| + /* send JSON content */ |
| + |
| + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/javascript")); |
| + |
| + /* just an attempt the force the IE/proxies to NOT cache the request */ |
| + response_header_overwrite(srv, con, CONST_STR_LEN("Pragma"), CONST_STR_LEN("no-cache")); |
| + response_header_overwrite(srv, con, CONST_STR_LEN("Expires"), CONST_STR_LEN("Thu, 19 Nov 1981 08:52:00 GMT")); |
| + response_header_overwrite(srv, con, CONST_STR_LEN("Cache-Control"), |
| + CONST_STR_LEN("no-store, no-cache, must-revalidate, post-check=0, pre-check=0")); |
| + |
| + b = chunkqueue_get_append_buffer(con->write_queue); |
| + |
| + /* get the connection */ |
| + if (NULL == (post_con_entry = connection_map_get_connection_entry(p->con_map, tracking_id))) { |
| + /** |
| + * looks like we don't know the tracking id yet, GET and POST out of sync ? */ |
| + buffer_append_string_len(b, CONST_STR_LEN("{ \"state\" : \"unknown\" }\r\n")); |
| + con->response.content_length += b->used - 1; |
| + |
| + if (p->conf.debug) log_error_write(srv, __FILE__, __LINE__, "ssss", "connection unknown:", SAFE_BUF_STR(tracking_id), ", sending:", SAFE_BUF_STR(b)); |
| + |
| + return HANDLER_FINISHED; |
| + } |
| + |
| + buffer_copy_string_len(b, CONST_STR_LEN("{ \"state\" : ")); |
| + |
| + if (post_con_entry->status == 413) { |
| + /* the upload was too large */ |
| + buffer_append_string_len(b, CONST_STR_LEN("\"error\", \"status\" : 413")); |
| + } else if (post_con_entry->con == NULL) { |
| + /* the connection is already gone */ |
| + buffer_append_string_len(b, CONST_STR_LEN("\"done\", \"size\" : ")); |
| + buffer_append_off_t(b, post_con_entry->size); |
| + } else { |
| + /* the upload is already done, but the connection might be still open */ |
| + buffer_append_string(b, post_con_entry->con->state == CON_STATE_READ_POST ? "\"uploading\"" : "\"done\""); |
| + buffer_append_string_len(b, CONST_STR_LEN(", \"received\" : ")); |
| + buffer_append_off_t(b, post_con_entry->con->bytes_read); |
| + buffer_append_string_len(b, CONST_STR_LEN(", \"size\" : ")); |
| + buffer_append_off_t(b, post_con_entry->con->request.content_length); |
| + } |
| + buffer_append_string_len(b, CONST_STR_LEN("}\r\n")); |
| + con->response.content_length += b->used - 1; |
| + |
| + if (p->conf.debug) log_error_write(srv, __FILE__, __LINE__, "ssss", "connection is known:", SAFE_BUF_STR(tracking_id), ", sending:", SAFE_BUF_STR(b)); |
| + |
| + return HANDLER_FINISHED; |
| + default: |
| + break; |
| + } |
| + |
| + return HANDLER_GO_ON; |
| +} |
| + |
| +/** |
| + * check for POST request |
| + */ |
| +CONNECTION_FUNC(mod_uploadprogress_request_end) { |
| + plugin_data *p = p_d; |
| + |
| + buffer *tracking_id; |
| + connection_map_entry *map_con_entry = NULL; |
| + |
| + UNUSED(srv); |
| + |
| + /* no request URL, ignore request */ |
| + if (buffer_is_empty(con->request.uri)) return HANDLER_GO_ON; |
| + |
| + mod_uploadprogress_patch_connection(srv, con, p); |
| + |
| + /* |
| + * we only want to process the upload (POST request) |
| + */ |
| + if (con->request.http_method != HTTP_METHOD_POST) { |
| + return HANDLER_GO_ON; |
| + } |
| + |
| + if (p->conf.debug) { |
| + log_error_write(srv, __FILE__, __LINE__, "sxsdsd", "request_end: con=", (void *) con, ", http_method=", con->request.http_method, ", http_status=", con->http_status); |
| + } |
| + |
| + /* get the tracker id */ |
| + if (NULL == (tracking_id = get_tracking_id(p, srv, con))) { |
| + return HANDLER_GO_ON; |
| + } |
| + |
| + if (NULL == (map_con_entry = connection_map_get_connection_entry(p->con_map, tracking_id))) { |
| + /** |
| + * in case the request parser meant the request was too large the URI handler won't |
| + * get called. Insert the connection mapping here |
| + */ |
| + if (NULL == (map_con_entry = connection_map_insert(p->con_map, tracking_id, con))) { |
| + return HANDLER_GO_ON; |
| + } |
| + } |
| + |
| + /* ok, found our entries, setting status */ |
| + map_con_entry->status = con->http_status; |
| + |
| + return HANDLER_GO_ON; |
| +} |
| + |
| +/** |
| + * remove the parent connection from the connection mapping |
| + * when it got closed |
| + * |
| + * keep the mapping active for a while to send a valid final status |
| + */ |
| +CONNECTION_FUNC(mod_uploadprogress_request_done) { |
| + plugin_data *p = p_d; |
| + buffer *tracking_id; |
| + connection_map_entry *cm = NULL; |
| + |
| + UNUSED(srv); |
| + |
| + if (buffer_is_empty(con->request.uri)) return HANDLER_GO_ON; |
| + |
| + /* |
| + * only need to handle the upload request. |
| + */ |
| + if (con->request.http_method != HTTP_METHOD_POST) { |
| + return HANDLER_GO_ON; |
| + } |
| + |
| + if (NULL == (tracking_id = get_tracking_id(p, srv, con))) { |
| + return HANDLER_GO_ON; |
| + } |
| + |
| + if (p->conf.debug) { |
| + log_error_write(srv, __FILE__, __LINE__, "sssd", "upload is done, moving tracking-id to backlog: tracking-id=", SAFE_BUF_STR(tracking_id), ", http_status=", con->http_status); |
| + } |
| + |
| + /* |
| + * set timeout on the upload's connection_map_entry. |
| + */ |
| + if (NULL == (cm = connection_map_get_connection_entry(p->con_map, tracking_id))) { |
| + if (p->conf.debug) { |
| + log_error_write(srv, __FILE__, __LINE__, "sss", "tracking ID", SAFE_BUF_STR(tracking_id), "not found, can't set timeout"); |
| + } |
| + return HANDLER_GO_ON; |
| + } |
| + |
| + /* save request size to be able to report it even when cm->con == NULL */ |
| + cm->size = con->request.content_length; |
| + |
| + cm->timeout = time(NULL) + p->conf.remove_timeout; |
| + cm->con = NULL; /* con becomes invalid very soon */ |
| + |
| + return HANDLER_GO_ON; |
| +} |
| + |
| +/** |
| + * remove dead connections once in while |
| + */ |
| +TRIGGER_FUNC(mod_uploadprogress_trigger) { |
| + plugin_data *p = p_d; |
| + |
| + if ((srv->cur_ts % 10) != 0) return HANDLER_GO_ON; |
| + |
| + connection_map_clear_timeout_connections(p->con_map); |
| + |
| + return HANDLER_GO_ON; |
| +} |
| + |
| + |
| +/* this function is called at dlopen() time and inits the callbacks */ |
| + |
| +int mod_uploadprogress_plugin_init(plugin *p) { |
| + p->version = LIGHTTPD_VERSION_ID; |
| + p->name = buffer_init_string("uploadprogress"); |
| + |
| + p->init = mod_uploadprogress_init; |
| + p->handle_uri_clean = mod_uploadprogress_uri_handler; |
| + p->handle_request_end = mod_uploadprogress_request_end; |
| + p->handle_request_done = mod_uploadprogress_request_done; |
| +// p->connection_reset = mod_uploadprogress_request_done; |
| + p->set_defaults = mod_uploadprogress_set_defaults; |
| + p->cleanup = mod_uploadprogress_free; |
| + p->handle_trigger = mod_uploadprogress_trigger; |
| + |
| + p->data = NULL; |
| + |
| + return 0; |
| +} |