File diff 000000000000 → 000000000000
www-servers/lighttpd/files/lighttpd-1.4.23-mod_uploadprogress.patch
Show inline comments
 
new file 100644
 
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.22/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.22/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.22/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.22/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.22/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;
 
+}