You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-dev@axis.apache.org by di...@apache.org on 2008/07/22 06:35:46 UTC

svn commit: r678637 [34/46] - in /webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd: ./ autom4te.cache/ cygwin/ doc/ openwrt/ src/ tests/ tests/docroot/ tests/docroot/123/ tests/docroot/www/ tests/docroot/www/dummydir/ tests/docroot/www/expire/ ...

Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_flv_streaming.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_flv_streaming.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_flv_streaming.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_flv_streaming.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,278 @@
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "response.h"
+#include "http_chunk.h"
+#include "stat_cache.h"
+
+#include "plugin.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* plugin config for all request/connections */
+
+typedef struct {
+	array *extensions;
+} plugin_config;
+
+typedef struct {
+	PLUGIN_DATA;
+
+	buffer *query_str;
+	array *get_params;
+
+	plugin_config **config_storage;
+
+	plugin_config conf;
+} plugin_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_flv_streaming_init) {
+	plugin_data *p;
+
+	p = calloc(1, sizeof(*p));
+
+	p->query_str = buffer_init();
+	p->get_params = array_init();
+
+	return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_flv_streaming_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];
+
+			if (!s) continue;
+
+			array_free(s->extensions);
+
+			free(s);
+		}
+		free(p->config_storage);
+	}
+
+	buffer_free(p->query_str);
+	array_free(p->get_params);
+
+	free(p);
+
+	return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) {
+	plugin_data *p = p_d;
+	size_t i = 0;
+
+	config_values_t cv[] = {
+		{ "flv-streaming.extensions",   NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
+		{ 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->extensions     = array_init();
+
+		cv[0].destination = s->extensions;
+
+		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(x) \
+	p->conf.x = s->x;
+static int mod_flv_streaming_patch_connection(server *srv, connection *con, plugin_data *p) {
+	size_t i, j;
+	plugin_config *s = p->config_storage[0];
+
+	PATCH(extensions);
+
+	/* 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("flv-streaming.extensions"))) {
+				PATCH(extensions);
+			}
+		}
+	}
+
+	return 0;
+}
+#undef PATCH
+
+static int split_get_params(array *get_params, buffer *qrystr) {
+	size_t is_key = 1;
+	size_t i;
+	char *key = NULL, *val = NULL;
+
+	key = qrystr->ptr;
+
+	/* we need the \0 */
+	for (i = 0; i < qrystr->used; i++) {
+		switch(qrystr->ptr[i]) {
+		case '=':
+			if (is_key) {
+				val = qrystr->ptr + i + 1;
+
+				qrystr->ptr[i] = '\0';
+
+				is_key = 0;
+			}
+
+			break;
+		case '&':
+		case '\0': /* fin symbol */
+			if (!is_key) {
+				data_string *ds;
+				/* we need at least a = since the last & */
+
+				/* terminate the value */
+				qrystr->ptr[i] = '\0';
+
+				if (NULL == (ds = (data_string *)array_get_unused_element(get_params, TYPE_STRING))) {
+					ds = data_string_init();
+				}
+				buffer_copy_string_len(ds->key, key, strlen(key));
+				buffer_copy_string_len(ds->value, val, strlen(val));
+
+				array_insert_unique(get_params, (data_unset *)ds);
+			}
+
+			key = qrystr->ptr + i + 1;
+			val = NULL;
+			is_key = 1;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+URIHANDLER_FUNC(mod_flv_streaming_path_handler) {
+	plugin_data *p = p_d;
+	int s_len;
+	size_t k;
+
+	UNUSED(srv);
+
+	if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
+
+	mod_flv_streaming_patch_connection(srv, con, p);
+
+	s_len = con->physical.path->used - 1;
+
+	for (k = 0; k < p->conf.extensions->used; k++) {
+		data_string *ds = (data_string *)p->conf.extensions->data[k];
+		int ct_len = ds->value->used - 1;
+
+		if (ct_len > s_len) continue;
+		if (ds->value->used == 0) continue;
+
+		if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
+			data_string *get_param;
+			stat_cache_entry *sce = NULL;
+			buffer *b;
+			int start;
+			char *err = NULL;
+			/* if there is a start=[0-9]+ in the header use it as start,
+			 * otherwise send the full file */
+
+			array_reset(p->get_params);
+			buffer_copy_string_buffer(p->query_str, con->uri.query);
+			split_get_params(p->get_params, p->query_str);
+
+			if (NULL == (get_param = (data_string *)array_get_element(p->get_params, "start"))) {
+				return HANDLER_GO_ON;
+			}
+
+			/* too short */
+			if (get_param->value->used < 2) return HANDLER_GO_ON;
+
+			/* check if it is a number */
+			start = strtol(get_param->value->ptr, &err, 10);
+			if (*err != '\0') {
+				return HANDLER_GO_ON;
+			}
+
+			if (start <= 0) return HANDLER_GO_ON;
+
+			/* check if start is > filesize */
+			if (HANDLER_GO_ON != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+				return HANDLER_GO_ON;
+			}
+
+			if (start > sce->st.st_size) {
+				return HANDLER_GO_ON;
+			}
+
+			/* we are safe now, let's build a flv header */
+			b = chunkqueue_get_append_buffer(con->write_queue);
+			BUFFER_COPY_STRING_CONST(b, "FLV\x1\x1\0\0\0\x9\0\0\0\x9");
+
+			http_chunk_append_file(srv, con, con->physical.path, start, sce->st.st_size - start);
+
+			response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("video/x-flv"));
+
+			con->file_finished = 1;
+
+			return HANDLER_FINISHED;
+		}
+	}
+
+	/* not found */
+	return HANDLER_GO_ON;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_flv_streaming_plugin_init(plugin *p) {
+	p->version     = LIGHTTPD_VERSION_ID;
+	p->name        = buffer_init_string("flv_streaming");
+
+	p->init        = mod_flv_streaming_init;
+	p->handle_physical = mod_flv_streaming_path_handler;
+	p->set_defaults  = mod_flv_streaming_set_defaults;
+	p->cleanup     = mod_flv_streaming_free;
+
+	p->data        = NULL;
+
+	return 0;
+}

Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_indexfile.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_indexfile.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_indexfile.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_indexfile.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,219 @@
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+
+#include "plugin.h"
+
+#include "stat_cache.h"
+
+/* plugin config for all request/connections */
+
+typedef struct {
+	array *indexfiles;
+} plugin_config;
+
+typedef struct {
+	PLUGIN_DATA;
+
+	buffer *tmp_buf;
+
+	plugin_config **config_storage;
+
+	plugin_config conf;
+} plugin_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_indexfile_init) {
+	plugin_data *p;
+
+	p = calloc(1, sizeof(*p));
+
+	p->tmp_buf = buffer_init();
+
+	return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_indexfile_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];
+
+			if (!s) continue;
+
+			array_free(s->indexfiles);
+
+			free(s);
+		}
+		free(p->config_storage);
+	}
+
+	buffer_free(p->tmp_buf);
+
+	free(p);
+
+	return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_indexfile_set_defaults) {
+	plugin_data *p = p_d;
+	size_t i = 0;
+
+	config_values_t cv[] = {
+		{ "index-file.names",           NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
+		{ "server.indexfiles",          NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
+		{ 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->indexfiles    = array_init();
+
+		cv[0].destination = s->indexfiles;
+		cv[1].destination = s->indexfiles; /* old name for [0] */
+
+		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(x) \
+	p->conf.x = s->x;
+static int mod_indexfile_patch_connection(server *srv, connection *con, plugin_data *p) {
+	size_t i, j;
+	plugin_config *s = p->config_storage[0];
+
+	PATCH(indexfiles);
+
+	/* 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("server.indexfiles"))) {
+				PATCH(indexfiles);
+			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("index-file.names"))) {
+				PATCH(indexfiles);
+			}
+		}
+	}
+
+	return 0;
+}
+#undef PATCH
+
+URIHANDLER_FUNC(mod_indexfile_subrequest) {
+	plugin_data *p = p_d;
+	size_t k;
+	stat_cache_entry *sce = NULL;
+
+	if (con->uri.path->used == 0) return HANDLER_GO_ON;
+	if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
+
+	mod_indexfile_patch_connection(srv, con, p);
+
+	if (con->conf.log_request_handling) {
+		log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling the request as Indexfile");
+		log_error_write(srv, __FILE__, __LINE__,  "sb", "URI          :", con->uri.path);
+	}
+
+	/* indexfile */
+	for (k = 0; k < p->conf.indexfiles->used; k++) {
+		data_string *ds = (data_string *)p->conf.indexfiles->data[k];
+
+		if (ds->value && ds->value->ptr[0] == '/') {
+			/* if the index-file starts with a prefix as use this file as
+			 * index-generator */
+			buffer_copy_string_buffer(p->tmp_buf, con->physical.doc_root);
+		} else {
+			buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
+		}
+		buffer_append_string_buffer(p->tmp_buf, ds->value);
+
+		if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
+			if (errno == EACCES) {
+				con->http_status = 403;
+				buffer_reset(con->physical.path);
+
+				return HANDLER_FINISHED;
+			}
+
+			if (errno != ENOENT &&
+			    errno != ENOTDIR) {
+				/* we have no idea what happend. let's tell the user so. */
+
+				con->http_status = 500;
+
+				log_error_write(srv, __FILE__, __LINE__, "ssbsb",
+						"file not found ... or so: ", strerror(errno),
+						con->uri.path,
+						"->", con->physical.path);
+
+				buffer_reset(con->physical.path);
+
+				return HANDLER_FINISHED;
+			}
+			continue;
+		}
+
+		/* rewrite uri.path to the real path (/ -> /index.php) */
+		buffer_append_string_buffer(con->uri.path, ds->value);
+		buffer_copy_string_buffer(con->physical.path, p->tmp_buf);
+
+		/* fce is already set up a few lines above */
+
+		return HANDLER_GO_ON;
+	}
+
+	/* not found */
+	return HANDLER_GO_ON;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_indexfile_plugin_init(plugin *p) {
+	p->version     = LIGHTTPD_VERSION_ID;
+	p->name        = buffer_init_string("indexfile");
+
+	p->init        = mod_indexfile_init;
+	p->handle_subrequest_start = mod_indexfile_subrequest;
+	p->set_defaults  = mod_indexfile_set_defaults;
+	p->cleanup     = mod_indexfile_free;
+
+	p->data        = NULL;
+
+	return 0;
+}

Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_magnet.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_magnet.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_magnet.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_magnet.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,851 @@
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <setjmp.h>
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+
+#include "plugin.h"
+
+#include "mod_magnet_cache.h"
+#include "response.h"
+#include "stat_cache.h"
+#include "status_counter.h"
+#include "etag.h"
+
+#ifdef HAVE_LUA_H
+#include <lua.h>
+#include <lauxlib.h>
+
+#define MAGNET_CONFIG_RAW_URL       "magnet.attract-raw-url-to"
+#define MAGNET_CONFIG_PHYSICAL_PATH "magnet.attract-physical-path-to"
+#define MAGNET_RESTART_REQUEST      99
+
+/* plugin config for all request/connections */
+
+static jmp_buf exceptionjmp;
+
+typedef struct {
+	array *url_raw;
+	array *physical_path;
+} plugin_config;
+
+typedef struct {
+	PLUGIN_DATA;
+
+	script_cache *cache;
+
+	buffer *encode_buf;
+
+	plugin_config **config_storage;
+
+	plugin_config conf;
+} plugin_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_magnet_init) {
+	plugin_data *p;
+
+	p = calloc(1, sizeof(*p));
+
+	p->cache = script_cache_init();
+	p->encode_buf = buffer_init();
+
+	return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_magnet_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];
+
+			if (!s) continue;
+
+			array_free(s->url_raw);
+			array_free(s->physical_path);
+
+			free(s);
+		}
+		free(p->config_storage);
+	}
+
+	script_cache_free(p->cache);
+	buffer_free(p->encode_buf);
+
+	free(p);
+
+	return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_magnet_set_defaults) {
+	plugin_data *p = p_d;
+	size_t i = 0;
+
+	config_values_t cv[] = {
+		{ MAGNET_CONFIG_RAW_URL,       NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
+		{ MAGNET_CONFIG_PHYSICAL_PATH, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
+		{ 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->url_raw  = array_init();
+		s->physical_path = array_init();
+
+		cv[0].destination = s->url_raw;
+		cv[1].destination = s->physical_path;
+
+		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(x) \
+	p->conf.x = s->x;
+static int mod_magnet_patch_connection(server *srv, connection *con, plugin_data *p) {
+	size_t i, j;
+	plugin_config *s = p->config_storage[0];
+
+	PATCH(url_raw);
+	PATCH(physical_path);
+
+	/* 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(MAGNET_CONFIG_RAW_URL))) {
+				PATCH(url_raw);
+			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN(MAGNET_CONFIG_PHYSICAL_PATH))) {
+				PATCH(physical_path);
+			}
+		}
+	}
+
+	return 0;
+}
+#undef PATCH
+
+static int magnet_print(lua_State *L) {
+	const char *s = luaL_checkstring(L, 1);
+	server *srv;
+
+	lua_pushstring(L, "lighty.srv");
+	lua_gettable(L, LUA_REGISTRYINDEX);
+	srv = lua_touserdata(L, -1);
+	lua_pop(L, 1);
+
+	log_error_write(srv, __FILE__, __LINE__, "ss",
+			"(lua-print)", s);
+
+	return 0;
+}
+
+static int magnet_stat(lua_State *L) {
+	const char *s = luaL_checkstring(L, 1);
+	server *srv;
+	connection *con;
+	buffer sb;
+	stat_cache_entry *sce = NULL;
+
+	lua_pushstring(L, "lighty.srv");
+	lua_gettable(L, LUA_REGISTRYINDEX);
+	srv = lua_touserdata(L, -1);
+	lua_pop(L, 1);
+
+	lua_pushstring(L, "lighty.con");
+	lua_gettable(L, LUA_REGISTRYINDEX);
+	con = lua_touserdata(L, -1);
+	lua_pop(L, 1);
+
+	sb.ptr = (char *)s;
+	sb.used = sb.size = strlen(s) + 1;
+	
+	if (HANDLER_GO_ON != stat_cache_get_entry(srv, con, &sb, &sce)) {
+		lua_pushnil(L);
+
+		return 1;
+	}
+
+	lua_newtable(L);
+
+	lua_pushboolean(L, S_ISREG(sce->st.st_mode));
+	lua_setfield(L, -2, "is_file");
+	
+	lua_pushboolean(L, S_ISDIR(sce->st.st_mode));
+	lua_setfield(L, -2, "is_dir");
+
+	lua_pushboolean(L, S_ISCHR(sce->st.st_mode));
+	lua_setfield(L, -2, "is_char");
+
+	lua_pushboolean(L, S_ISBLK(sce->st.st_mode));
+	lua_setfield(L, -2, "is_block");
+
+	lua_pushboolean(L, S_ISSOCK(sce->st.st_mode));
+	lua_setfield(L, -2, "is_socket");
+
+	lua_pushboolean(L, S_ISLNK(sce->st.st_mode));
+	lua_setfield(L, -2, "is_link");
+
+	lua_pushboolean(L, S_ISFIFO(sce->st.st_mode));
+	lua_setfield(L, -2, "is_fifo");
+
+	lua_pushinteger(L, sce->st.st_mtime);
+	lua_setfield(L, -2, "st_mtime");
+
+	lua_pushinteger(L, sce->st.st_ctime);
+	lua_setfield(L, -2, "st_ctime");
+
+	lua_pushinteger(L, sce->st.st_atime);
+	lua_setfield(L, -2, "st_atime");
+
+	lua_pushinteger(L, sce->st.st_uid);
+	lua_setfield(L, -2, "st_uid");
+
+	lua_pushinteger(L, sce->st.st_gid);
+	lua_setfield(L, -2, "st_gid");
+
+	lua_pushinteger(L, sce->st.st_size);
+	lua_setfield(L, -2, "st_size");
+
+	lua_pushinteger(L, sce->st.st_ino);
+	lua_setfield(L, -2, "st_ino");
+
+
+	if (!buffer_is_empty(sce->etag)) {
+		/* we have to mutate the etag */
+		buffer *b = buffer_init();
+		etag_mutate(b, sce->etag);
+
+		lua_pushlstring(L, b->ptr, b->used - 1);
+		buffer_free(b);
+	} else {
+		lua_pushnil(L);
+	}
+	lua_setfield(L, -2, "etag");
+
+	if (!buffer_is_empty(sce->content_type)) {
+		lua_pushlstring(L, sce->content_type->ptr, sce->content_type->used - 1);
+	} else {
+		lua_pushnil(L);
+	}
+	lua_setfield(L, -2, "content-type");
+
+	return 1;
+}
+
+
+static int magnet_atpanic(lua_State *L) {
+	const char *s = luaL_checkstring(L, 1);
+	server *srv;
+
+	lua_pushstring(L, "lighty.srv");
+	lua_gettable(L, LUA_REGISTRYINDEX);
+	srv = lua_touserdata(L, -1);
+	lua_pop(L, 1);
+
+	log_error_write(srv, __FILE__, __LINE__, "ss",
+			"(lua-atpanic)", s);
+
+	longjmp(exceptionjmp, 1);
+}
+
+static int magnet_reqhdr_get(lua_State *L) {
+	server *srv;
+	connection *con;
+	data_string *ds;
+
+	const char *key = luaL_checkstring(L, 2);
+
+	lua_pushstring(L, "lighty.srv");
+	lua_gettable(L, LUA_REGISTRYINDEX);
+	srv = lua_touserdata(L, -1);
+	lua_pop(L, 1);
+
+	lua_pushstring(L, "lighty.con");
+	lua_gettable(L, LUA_REGISTRYINDEX);
+	con = lua_touserdata(L, -1);
+	lua_pop(L, 1);
+
+	if (NULL != (ds = (data_string *)array_get_element(con->request.headers, key))) {
+		if (ds->value->used) {
+			lua_pushlstring(L, ds->value->ptr, ds->value->used - 1);
+		} else {
+			lua_pushnil(L);
+		}
+	} else {
+		lua_pushnil(L);
+	}
+	return 1;
+}
+
+static int magnet_status_get(lua_State *L) {
+	data_integer *di;
+	server *srv;
+	size_t key_len = 0;
+
+	const char *key = luaL_checklstring(L, 2, &key_len);
+
+	lua_pushstring(L, "lighty.srv");
+	lua_gettable(L, LUA_REGISTRYINDEX);
+	srv = lua_touserdata(L, -1);
+	lua_pop(L, 1);
+
+	di = status_counter_get_counter(srv, key, key_len);
+
+	lua_pushnumber(L, (double)di->value);
+
+	return 1;
+}
+
+static int magnet_status_set(lua_State *L) {
+	size_t key_len = 0;
+	server *srv;
+
+	const char *key = luaL_checklstring(L, 2, &key_len);
+	int counter = luaL_checkint(L, 3);
+
+	lua_pushstring(L, "lighty.srv");
+	lua_gettable(L, LUA_REGISTRYINDEX);
+	srv = lua_touserdata(L, -1);
+	lua_pop(L, 1);
+
+	status_counter_set(srv, key, key_len, counter);
+
+	return 0;
+}
+
+typedef struct {
+	const char *name;
+	enum {
+		MAGNET_ENV_UNSET,
+
+		MAGNET_ENV_PHYICAL_PATH,
+		MAGNET_ENV_PHYICAL_REL_PATH,
+		MAGNET_ENV_PHYICAL_DOC_ROOT,
+
+		MAGNET_ENV_URI_PATH,
+		MAGNET_ENV_URI_PATH_RAW,
+		MAGNET_ENV_URI_SCHEME,
+		MAGNET_ENV_URI_AUTHORITY,
+		MAGNET_ENV_URI_QUERY,
+
+		MAGNET_ENV_REQUEST_METHOD,
+		MAGNET_ENV_REQUEST_URI,
+		MAGNET_ENV_REQUEST_ORIG_URI,
+		MAGNET_ENV_REQUEST_PROTOCOL
+       	} type;
+} magnet_env_t;
+
+static buffer *magnet_env_get_buffer(server *srv, connection *con, const char *key) {
+	buffer *dest = NULL;
+	size_t i;
+
+	const magnet_env_t env[] = {
+		{ "physical.path", MAGNET_ENV_PHYICAL_PATH },
+		{ "physical.rel-path", MAGNET_ENV_PHYICAL_REL_PATH },
+		{ "physical.doc-root", MAGNET_ENV_PHYICAL_DOC_ROOT },
+
+		{ "uri.path", MAGNET_ENV_URI_PATH },
+		{ "uri.path-raw", MAGNET_ENV_URI_PATH_RAW },
+		{ "uri.scheme", MAGNET_ENV_URI_SCHEME },
+		{ "uri.authority", MAGNET_ENV_URI_AUTHORITY },
+		{ "uri.query", MAGNET_ENV_URI_QUERY },
+
+		{ "request.method", MAGNET_ENV_REQUEST_METHOD },
+		{ "request.uri", MAGNET_ENV_REQUEST_URI },
+		{ "request.orig-uri", MAGNET_ENV_REQUEST_ORIG_URI },
+		{ "request.protocol", MAGNET_ENV_REQUEST_PROTOCOL },
+
+		{ NULL, MAGNET_ENV_UNSET }
+	};
+
+	UNUSED(srv);
+
+	/**
+	 * map all internal variables to lua
+	 *
+	 */
+
+	for (i = 0; env[i].name; i++) {
+		if (0 == strcmp(key, env[i].name)) break;
+	}
+
+	switch (env[i].type) {
+	case MAGNET_ENV_PHYICAL_PATH: dest = con->physical.path; break;
+	case MAGNET_ENV_PHYICAL_REL_PATH: dest = con->physical.rel_path; break;
+	case MAGNET_ENV_PHYICAL_DOC_ROOT: dest = con->physical.doc_root; break;
+
+	case MAGNET_ENV_URI_PATH: dest = con->uri.path; break;
+	case MAGNET_ENV_URI_PATH_RAW: dest = con->uri.path_raw; break;
+	case MAGNET_ENV_URI_SCHEME: dest = con->uri.scheme; break;
+	case MAGNET_ENV_URI_AUTHORITY: dest = con->uri.authority; break;
+	case MAGNET_ENV_URI_QUERY: dest = con->uri.query; break;
+
+	case MAGNET_ENV_REQUEST_METHOD:   break;
+	case MAGNET_ENV_REQUEST_URI:      dest = con->request.uri; break;
+	case MAGNET_ENV_REQUEST_ORIG_URI: dest = con->request.orig_uri; break;
+	case MAGNET_ENV_REQUEST_PROTOCOL: break;
+
+	case MAGNET_ENV_UNSET: break;
+	}
+
+	return dest;
+}
+
+static int magnet_env_get(lua_State *L) {
+	server *srv;
+	connection *con;
+
+	const char *key = luaL_checkstring(L, 2);
+	buffer *dest = NULL;
+
+	lua_pushstring(L, "lighty.srv");
+	lua_gettable(L, LUA_REGISTRYINDEX);
+	srv = lua_touserdata(L, -1);
+	lua_pop(L, 1);
+
+	lua_pushstring(L, "lighty.con");
+	lua_gettable(L, LUA_REGISTRYINDEX);
+	con = lua_touserdata(L, -1);
+	lua_pop(L, 1);
+
+	dest = magnet_env_get_buffer(srv, con, key);
+
+	if (dest && dest->used) {
+		lua_pushlstring(L, dest->ptr, dest->used - 1);
+	} else {
+		lua_pushnil(L);
+	}
+
+	return 1;
+}
+
+static int magnet_env_set(lua_State *L) {
+	server *srv;
+	connection *con;
+
+	const char *key = luaL_checkstring(L, 2);
+	const char *val = luaL_checkstring(L, 3);
+	buffer *dest = NULL;
+
+	lua_pushstring(L, "lighty.srv");
+	lua_gettable(L, LUA_REGISTRYINDEX);
+	srv = lua_touserdata(L, -1);
+	lua_pop(L, 1);
+
+	lua_pushstring(L, "lighty.con");
+	lua_gettable(L, LUA_REGISTRYINDEX);
+	con = lua_touserdata(L, -1);
+	lua_pop(L, 1);
+
+	if (NULL != (dest = magnet_env_get_buffer(srv, con, key))) {
+		buffer_copy_string(dest, val);
+	} else {
+		/* couldn't save */
+
+		return luaL_error(L, "couldn't store '%s' in lighty.env[]", key);
+	}
+
+	return 0;
+}
+
+
+static int magnet_copy_response_header(server *srv, connection *con, plugin_data *p, lua_State *L) {
+	UNUSED(p);
+	/**
+	 * get the environment of the function
+	 */
+
+	lua_getfenv(L, -1); /* -1 is the function */
+
+	/* lighty.header */
+
+	lua_getfield(L, -1, "lighty"); /* lighty.* from the env  */
+	assert(lua_istable(L, -1));
+
+	lua_getfield(L, -1, "header"); /* lighty.header */
+	if (lua_istable(L, -1)) {
+		/* header is found, and is a table */
+
+		lua_pushnil(L);
+		while (lua_next(L, -2) != 0) {
+			if (lua_isstring(L, -1) && lua_isstring(L, -2)) {
+				const char *key, *val;
+				size_t key_len, val_len;
+
+				key = lua_tolstring(L, -2, &key_len);
+				val = lua_tolstring(L, -1, &val_len);
+
+				response_header_overwrite(srv, con, key, key_len, val, val_len);
+			}
+
+			lua_pop(L, 1);
+		}
+	}
+
+	lua_pop(L, 1); /* pop the header-table */
+	lua_pop(L, 1); /* pop the lighty-env */
+	lua_pop(L, 1); /* pop the function env */
+
+	return 0;
+}
+
+/**
+ * walk through the content array
+ *
+ * content = { "<pre>", { file = "/content" } , "</pre>" }
+ *
+ * header["Content-Type"] = "text/html"
+ *
+ * return 200
+ */
+static int magnet_attach_content(server *srv, connection *con, plugin_data *p, lua_State *L) {
+	UNUSED(p);
+	/**
+	 * get the environment of the function
+	 */
+
+	assert(lua_isfunction(L, -1));
+	lua_getfenv(L, -1); /* -1 is the function */
+
+	lua_getfield(L, -1, "lighty"); /* lighty.* from the env  */
+	assert(lua_istable(L, -1));
+
+	lua_getfield(L, -1, "content"); /* lighty.content */
+	if (lua_istable(L, -1)) {
+		int i;
+		/* header is found, and is a table */
+
+		for (i = 1; ; i++) {
+			lua_rawgeti(L, -1, i);
+
+			/* -1 is the value and should be the value ... aka a table */
+			if (lua_isstring(L, -1)) {
+				size_t s_len = 0;
+				const char *s = lua_tolstring(L, -1, &s_len);
+
+				chunkqueue_append_mem(con->write_queue, s, s_len + 1);
+			} else if (lua_istable(L, -1)) {
+				lua_getfield(L, -1, "filename");
+				lua_getfield(L, -2, "length");
+				lua_getfield(L, -3, "offset");
+
+				if (lua_isstring(L, -3)) { /* filename has to be a string */
+					buffer *fn = buffer_init();
+					stat_cache_entry *sce;
+
+					buffer_copy_string(fn, lua_tostring(L, -3));
+
+					if (HANDLER_GO_ON == stat_cache_get_entry(srv, con, fn, &sce)) {
+						off_t off = 0;
+						off_t len = 0;
+
+						if (lua_isnumber(L, -1)) {
+							off = lua_tonumber(L, -1);
+						}
+
+						if (lua_isnumber(L, -2)) {
+							len = lua_tonumber(L, -2);
+						} else {
+							len = sce->st.st_size;
+						}
+
+						if (off < 0) {
+							return luaL_error(L, "offset for '%s' is negative", fn->ptr);
+						}
+
+						if (len < off) {
+							return luaL_error(L, "offset > length for '%s'", fn->ptr);
+						}
+
+						chunkqueue_append_file(con->write_queue, fn, off, len - off);
+					}
+
+					buffer_free(fn);
+				} else {
+					lua_pop(L, 3 + 2); /* correct the stack */
+
+					return luaL_error(L, "content[%d] is a table and requires the field \"filename\"", i);
+				}
+
+				lua_pop(L, 3);
+			} else if (lua_isnil(L, -1)) {
+				/* oops, end of list */
+
+				lua_pop(L, 1);
+
+				break;
+			} else {
+				lua_pop(L, 4);
+
+				return luaL_error(L, "content[%d] is neither a string nor a table: ", i);
+			}
+
+			lua_pop(L, 1); /* pop the content[...] table */
+		}
+	} else {
+		return luaL_error(L, "lighty.content has to be a table");
+	}
+	lua_pop(L, 1); /* pop the header-table */
+	lua_pop(L, 1); /* pop the lighty-table */
+	lua_pop(L, 1); /* php the function env */
+
+	return 0;
+}
+
+static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, buffer *name) {
+	lua_State *L;
+	int lua_return_value = -1;
+	/* get the script-context */
+
+
+	L = script_cache_get_script(srv, con, p->cache, name);
+
+	if (lua_isstring(L, -1)) {
+		log_error_write(srv, __FILE__, __LINE__,
+				"sbss",
+				"loading script",
+				name,
+				"failed:",
+				lua_tostring(L, -1));
+
+		lua_pop(L, 1);
+
+		assert(lua_gettop(L) == 0); /* only the function should be on the stack */
+
+		con->http_status = 500;
+
+		return HANDLER_FINISHED;
+	}
+
+	lua_pushstring(L, "lighty.srv");
+	lua_pushlightuserdata(L, srv);
+	lua_settable(L, LUA_REGISTRYINDEX); /* registery[<id>] = srv */
+
+	lua_pushstring(L, "lighty.con");
+	lua_pushlightuserdata(L, con);
+	lua_settable(L, LUA_REGISTRYINDEX); /* registery[<id>] = con */
+
+	lua_atpanic(L, magnet_atpanic);
+
+	/**
+	 * we want to create empty environment for our script
+	 *
+	 * setmetatable({}, {__index = _G})
+	 *
+	 * if a function, symbol is not defined in our env, __index will lookup
+	 * in the global env.
+	 *
+	 * all variables created in the script-env will be thrown
+	 * away at the end of the script run.
+	 */
+	lua_newtable(L); /* my empty environment aka {}              (sp += 1) */
+
+	/* we have to overwrite the print function */
+	lua_pushcfunction(L, magnet_print);                       /* (sp += 1) */
+	lua_setfield(L, -2, "print"); /* -1 is the env we want to set(sp -= 1) */
+
+	/**
+	 * lighty.request[] has the HTTP-request headers
+	 * lighty.content[] is a table of string/file
+	 * lighty.header[] is a array to set response headers
+	 */
+
+	lua_newtable(L); /* lighty.*                                 (sp += 1) */
+
+	lua_newtable(L); /*  {}                                      (sp += 1) */
+	lua_newtable(L); /* the meta-table for the request-table     (sp += 1) */
+	lua_pushcfunction(L, magnet_reqhdr_get);                  /* (sp += 1) */
+	lua_setfield(L, -2, "__index");                           /* (sp -= 1) */
+	lua_setmetatable(L, -2); /* tie the metatable to request     (sp -= 1) */
+	lua_setfield(L, -2, "request"); /* content = {}              (sp -= 1) */
+
+	lua_newtable(L); /*  {}                                      (sp += 1) */
+	lua_newtable(L); /* the meta-table for the request-table     (sp += 1) */
+	lua_pushcfunction(L, magnet_env_get);                     /* (sp += 1) */
+	lua_setfield(L, -2, "__index");                           /* (sp -= 1) */
+	lua_pushcfunction(L, magnet_env_set);                     /* (sp += 1) */
+	lua_setfield(L, -2, "__newindex");                        /* (sp -= 1) */
+	lua_setmetatable(L, -2); /* tie the metatable to request     (sp -= 1) */
+	lua_setfield(L, -2, "env"); /* content = {}                  (sp -= 1) */
+
+	lua_newtable(L); /*  {}                                      (sp += 1) */
+	lua_newtable(L); /* the meta-table for the request-table     (sp += 1) */
+	lua_pushcfunction(L, magnet_status_get);                  /* (sp += 1) */
+	lua_setfield(L, -2, "__index");                           /* (sp -= 1) */
+	lua_pushcfunction(L, magnet_status_set);                  /* (sp += 1) */
+	lua_setfield(L, -2, "__newindex");                        /* (sp -= 1) */
+	lua_setmetatable(L, -2); /* tie the metatable to request     (sp -= 1) */
+	lua_setfield(L, -2, "status"); /* content = {}               (sp -= 1) */
+
+	/* add empty 'content' and 'header' tables */
+	lua_newtable(L); /*  {}                                      (sp += 1) */
+	lua_setfield(L, -2, "content"); /* content = {}              (sp -= 1) */
+
+	lua_newtable(L); /*  {}                                      (sp += 1) */
+	lua_setfield(L, -2, "header"); /* header = {}                (sp -= 1) */
+
+	lua_pushinteger(L, MAGNET_RESTART_REQUEST);
+	lua_setfield(L, -2, "RESTART_REQUEST");
+
+	lua_pushcfunction(L, magnet_stat);                        /* (sp += 1) */
+	lua_setfield(L, -2, "stat"); /* -1 is the env we want to set (sp -= 1) */
+
+	lua_setfield(L, -2, "lighty"); /* lighty.*                   (sp -= 1) */
+
+	lua_newtable(L); /* the meta-table for the new env           (sp += 1) */
+	lua_pushvalue(L, LUA_GLOBALSINDEX);                       /* (sp += 1) */
+	lua_setfield(L, -2, "__index"); /* { __index = _G }          (sp -= 1) */
+	lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) (sp -= 1) */
+
+
+	lua_setfenv(L, -2); /* on the stack should be a modified env (sp -= 1) */
+
+	if (lua_pcall(L, 0, 1, 0)) {
+		log_error_write(srv, __FILE__, __LINE__,
+			"ss",
+			"lua_pcall():",
+			lua_tostring(L, -1));
+		lua_pop(L, 1); /* remove the error-msg and the function copy from the stack */
+
+		assert(lua_gettop(L) == 1); /* only the function should be on the stack */
+
+		con->http_status = 500;
+
+		return HANDLER_FINISHED;
+	}
+
+	/* we should have the function-copy and the return value on the stack */
+	assert(lua_gettop(L) == 2);
+
+	if (lua_isnumber(L, -1)) {
+		/* if the ret-value is a number, take it */
+		lua_return_value = (int)lua_tonumber(L, -1);
+	}
+	lua_pop(L, 1); /* pop the ret-value */
+
+	magnet_copy_response_header(srv, con, p, L);
+
+	if (lua_return_value > 99) {
+		con->http_status = lua_return_value;
+		con->file_finished = 1;
+
+		/* try { ...*/
+		if (0 == setjmp(exceptionjmp)) {
+			magnet_attach_content(srv, con, p, L);
+		} else {
+			/* } catch () { */
+			con->http_status = 500;
+		}
+
+		assert(lua_gettop(L) == 1); /* only the function should be on the stack */
+
+		/* we are finished */
+		return HANDLER_FINISHED;
+	} else if (MAGNET_RESTART_REQUEST == lua_return_value) {
+		assert(lua_gettop(L) == 1); /* only the function should be on the stack */
+
+		return HANDLER_COMEBACK;
+	} else {
+		assert(lua_gettop(L) == 1); /* only the function should be on the stack */
+
+		return HANDLER_GO_ON;
+	}
+}
+
+static handler_t magnet_attract_array(server *srv, connection *con, plugin_data *p, array *files) {
+	size_t i;
+
+	/* no filename set */
+	if (files->used == 0) return HANDLER_GO_ON;
+
+	/**
+	 * execute all files and jump out on the first !HANDLER_GO_ON
+	 */
+	for (i = 0; i < files->used; i++) {
+		data_string *ds = (data_string *)files->data[i];
+		handler_t ret;
+
+		if (buffer_is_empty(ds->value)) continue;
+
+		ret = magnet_attract(srv, con, p, ds->value);
+
+		if (ret != HANDLER_GO_ON) return ret;
+	}
+
+	return HANDLER_GO_ON;
+}
+
+URIHANDLER_FUNC(mod_magnet_uri_handler) {
+	plugin_data *p = p_d;
+
+	mod_magnet_patch_connection(srv, con, p);
+
+	return magnet_attract_array(srv, con, p, p->conf.url_raw);
+}
+
+URIHANDLER_FUNC(mod_magnet_physical) {
+	plugin_data *p = p_d;
+
+	mod_magnet_patch_connection(srv, con, p);
+
+	return magnet_attract_array(srv, con, p, p->conf.physical_path);
+}
+
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_magnet_plugin_init(plugin *p) {
+	p->version     = LIGHTTPD_VERSION_ID;
+	p->name        = buffer_init_string("magnet");
+
+	p->init        = mod_magnet_init;
+	p->handle_uri_clean  = mod_magnet_uri_handler;
+	p->handle_physical   = mod_magnet_physical;
+	p->set_defaults  = mod_magnet_set_defaults;
+	p->cleanup     = mod_magnet_free;
+
+	p->data        = NULL;
+
+	return 0;
+}
+
+#else
+int mod_magnet_plugin_init(plugin *p) {
+	UNUSED(p);
+	return -1;
+}
+#endif

Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_magnet_cache.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_magnet_cache.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_magnet_cache.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_magnet_cache.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,137 @@
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+
+#include "mod_magnet_cache.h"
+#include "stat_cache.h"
+
+#ifdef HAVE_LUA_H
+#include <lualib.h>
+#include <lauxlib.h>
+
+script *script_init() {
+	script *sc;
+
+	sc = calloc(1, sizeof(*sc));
+	sc->name = buffer_init();
+	sc->etag = buffer_init();
+
+	return sc;
+}
+
+void script_free(script *sc) {
+	if (!sc) return;
+
+	lua_pop(sc->L, 1); /* the function copy */
+
+	buffer_free(sc->name);
+	buffer_free(sc->etag);
+
+	lua_close(sc->L);
+
+	free(sc);
+}
+
+script_cache *script_cache_init() {
+	script_cache *p;
+
+	p = calloc(1, sizeof(*p));
+
+	return p;
+}
+
+void script_cache_free(script_cache *p) {
+	size_t i;
+
+	if (!p) return;
+
+	for (i = 0; i < p->used; i++) {
+		script_free(p->ptr[i]);
+	}
+
+	free(p->ptr);
+
+	free(p);
+}
+
+lua_State *script_cache_get_script(server *srv, connection *con, script_cache *cache, buffer *name) {
+	size_t i;
+	script *sc = NULL;
+	stat_cache_entry *sce;
+
+	for (i = 0; i < cache->used; i++) {
+		sc = cache->ptr[i];
+
+		if (buffer_is_equal(name, sc->name)) {
+			sc->last_used = time(NULL);
+
+			/* oops, the script failed last time */
+
+			if (lua_gettop(sc->L) == 0) break;
+
+			if (HANDLER_ERROR == stat_cache_get_entry(srv, con, sc->name, &sce)) {
+				lua_pop(sc->L, 1); /* pop the old function */
+				break;
+			}
+
+			if (!buffer_is_equal(sce->etag, sc->etag)) {
+				/* the etag is outdated, reload the function */
+				lua_pop(sc->L, 1);
+				break;
+			}
+
+			assert(lua_isfunction(sc->L, -1));
+			lua_pushvalue(sc->L, -1); /* copy the function-reference */
+
+			return sc->L;
+		}
+
+		sc = NULL;
+	}
+
+	/* if the script was script already loaded but either got changed or
+	 * failed to load last time */
+	if (sc == NULL) {
+		sc = script_init();
+
+		if (cache->size == 0) {
+			cache->size = 16;
+			cache->ptr = malloc(cache->size * sizeof(*(cache->ptr)));
+		} else if (cache->used == cache->size) {
+			cache->size += 16;
+			cache->ptr = realloc(cache->ptr, cache->size * sizeof(*(cache->ptr)));
+		}
+
+		cache->ptr[cache->used++] = sc;
+
+		buffer_copy_string_buffer(sc->name, name);
+
+		sc->L = luaL_newstate();
+		luaL_openlibs(sc->L);
+	}
+
+	sc->last_used = time(NULL);
+
+	if (0 != luaL_loadfile(sc->L, name->ptr)) {
+		/* oops, an error, return it */
+
+		return sc->L;
+	}
+
+	if (HANDLER_GO_ON == stat_cache_get_entry(srv, con, sc->name, &sce)) {
+		buffer_copy_string_buffer(sc->etag, sce->etag);
+	}
+
+	/**
+	 * pcall() needs the function on the stack
+	 *
+	 * as pcall() will pop the script from the stack when done, we have to
+	 * duplicate it here
+	 */
+	assert(lua_isfunction(sc->L, -1));
+	lua_pushvalue(sc->L, -1); /* copy the function-reference */
+
+	return sc->L;
+}
+
+#endif

Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_magnet_cache.h
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_magnet_cache.h?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_magnet_cache.h (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_magnet_cache.h Mon Jul 21 21:35:35 2008
@@ -0,0 +1,33 @@
+#ifndef _MOD_MAGNET_CACHE_H_
+#define _MOD_MAGNET_CACHE_H_
+
+#include "buffer.h"
+#include "base.h"
+
+#ifdef HAVE_LUA_H
+#include <lua.h>
+
+typedef struct {
+	buffer *name;
+	buffer *etag;
+
+	lua_State *L;
+
+	time_t last_used; /* LRU */
+} script;
+
+typedef struct {
+	script **ptr;
+
+	size_t used;
+	size_t size;
+} script_cache;
+
+script_cache *script_cache_init(void);
+void script_cache_free(script_cache *cache);
+
+lua_State *script_cache_get_script(server *srv, connection *con,
+	       	script_cache *cache, buffer *name);
+
+#endif
+#endif

Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_mysql_vhost.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_mysql_vhost.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_mysql_vhost.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_mysql_vhost.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,438 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <strings.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_MYSQL
+#include <mysql.h>
+#endif
+
+#include "plugin.h"
+#include "log.h"
+
+#include "stat_cache.h"
+#ifdef DEBUG_MOD_MYSQL_VHOST
+#define DEBUG
+#endif
+
+/*
+ * Plugin for lighttpd to use MySQL
+ *   for domain to directory lookups,
+ *   i.e virtual hosts (vhosts).
+ *
+ * Optionally sets fcgi_offset and fcgi_arg
+ *   in preparation for fcgi.c to handle
+ *   per-user fcgi chroot jails.
+ *
+ * /ada@riksnet.se 2004-12-06
+ */
+
+#ifdef HAVE_MYSQL
+typedef struct {
+	MYSQL 	*mysql;
+
+	buffer  *mydb;
+	buffer  *myuser;
+	buffer  *mypass;
+	buffer  *mysock;
+
+	buffer  *hostname;
+	unsigned short port;
+
+	buffer  *mysql_pre;
+	buffer  *mysql_post;
+} plugin_config;
+
+/* global plugin data */
+typedef struct {
+	PLUGIN_DATA;
+
+	buffer 	*tmp_buf;
+
+	plugin_config **config_storage;
+
+	plugin_config conf;
+} plugin_data;
+
+/* per connection plugin data */
+typedef struct {
+	buffer	*server_name;
+	buffer	*document_root;
+	buffer	*fcgi_arg;
+	unsigned fcgi_offset;
+} plugin_connection_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_mysql_vhost_init) {
+	plugin_data *p;
+
+	p = calloc(1, sizeof(*p));
+
+	p->tmp_buf = buffer_init();
+
+	return p;
+}
+
+/* cleanup the plugin data */
+SERVER_FUNC(mod_mysql_vhost_cleanup) {
+	plugin_data *p = p_d;
+
+	UNUSED(srv);
+
+#ifdef DEBUG
+	log_error_write(srv, __FILE__, __LINE__, "ss",
+		"mod_mysql_vhost_cleanup", p ? "yes" : "NO");
+#endif
+	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];
+
+			if (!s) continue;
+
+			mysql_close(s->mysql);
+
+			buffer_free(s->mydb);
+			buffer_free(s->myuser);
+			buffer_free(s->mypass);
+			buffer_free(s->mysock);
+			buffer_free(s->mysql_pre);
+			buffer_free(s->mysql_post);
+			buffer_free(s->hostname);
+
+			free(s);
+		}
+		free(p->config_storage);
+	}
+	buffer_free(p->tmp_buf);
+
+	free(p);
+
+	return HANDLER_GO_ON;
+}
+
+/* handle the plugin per connection data */
+static void* mod_mysql_vhost_connection_data(server *srv, connection *con, void *p_d)
+{
+	plugin_data *p = p_d;
+	plugin_connection_data *c = con->plugin_ctx[p->id];
+
+	UNUSED(srv);
+
+#ifdef DEBUG
+        log_error_write(srv, __FILE__, __LINE__, "ss",
+		"mod_mysql_connection_data", c ? "old" : "NEW");
+#endif
+
+	if (c) return c;
+	c = calloc(1, sizeof(*c));
+
+	c->server_name = buffer_init();
+	c->document_root = buffer_init();
+	c->fcgi_arg = buffer_init();
+	c->fcgi_offset = 0;
+
+	return con->plugin_ctx[p->id] = c;
+}
+
+/* destroy the plugin per connection data */
+CONNECTION_FUNC(mod_mysql_vhost_handle_connection_close) {
+	plugin_data *p = p_d;
+	plugin_connection_data *c = con->plugin_ctx[p->id];
+
+	UNUSED(srv);
+
+#ifdef DEBUG
+	log_error_write(srv, __FILE__, __LINE__, "ss",
+		"mod_mysql_vhost_handle_connection_close", c ? "yes" : "NO");
+#endif
+
+	if (!c) return HANDLER_GO_ON;
+
+	buffer_free(c->server_name);
+	buffer_free(c->document_root);
+	buffer_free(c->fcgi_arg);
+	c->fcgi_offset = 0;
+
+	free(c);
+
+	con->plugin_ctx[p->id] = NULL;
+	return HANDLER_GO_ON;
+}
+
+/* set configuration values */
+SERVER_FUNC(mod_mysql_vhost_set_defaults) {
+	plugin_data *p = p_d;
+
+	char *qmark;
+	size_t i = 0;
+
+	config_values_t cv[] = {
+		{ "mysql-vhost.db",	NULL, T_CONFIG_STRING, 	T_CONFIG_SCOPE_SERVER },
+		{ "mysql-vhost.user",	NULL, T_CONFIG_STRING, 	T_CONFIG_SCOPE_SERVER },
+		{ "mysql-vhost.pass",	NULL, T_CONFIG_STRING, 	T_CONFIG_SCOPE_SERVER },
+		{ "mysql-vhost.sock",	NULL, T_CONFIG_STRING, 	T_CONFIG_SCOPE_SERVER },
+		{ "mysql-vhost.sql",	NULL, T_CONFIG_STRING, 	T_CONFIG_SCOPE_SERVER },
+		{ "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER },
+		{ "mysql-vhost.port",   NULL, T_CONFIG_SHORT,   T_CONFIG_SCOPE_SERVER },
+                { NULL,			NULL, T_CONFIG_UNSET,	T_CONFIG_SCOPE_UNSET }
+        };
+
+	p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
+
+	for (i = 0; i < srv->config_context->used; i++) {
+		plugin_config *s;
+		buffer *sel;
+
+
+		s = calloc(1, sizeof(plugin_config));
+		s->mydb = buffer_init();
+		s->myuser = buffer_init();
+		s->mypass = buffer_init();
+		s->mysock = buffer_init();
+		s->hostname = buffer_init();
+		s->port   = 0;               /* default port for mysql */
+		sel = buffer_init();
+		s->mysql = NULL;
+
+		s->mysql_pre = buffer_init();
+		s->mysql_post = buffer_init();
+
+		cv[0].destination = s->mydb;
+		cv[1].destination = s->myuser;
+		cv[2].destination = s->mypass;
+		cv[3].destination = s->mysock;
+		cv[4].destination = sel;
+		cv[5].destination = s->hostname;
+		cv[6].destination = &(s->port);
+
+		p->config_storage[i] = s;
+
+        	if (config_insert_values_global(srv,
+			((data_config *)srv->config_context->data[i])->value,
+			cv)) return HANDLER_ERROR;
+
+		s->mysql_pre = buffer_init();
+		s->mysql_post = buffer_init();
+
+		if (sel->used && (qmark = strchr(sel->ptr, '?'))) {
+			*qmark = '\0';
+			buffer_copy_string(s->mysql_pre, sel->ptr);
+			buffer_copy_string(s->mysql_post, qmark+1);
+		} else {
+			buffer_copy_string_buffer(s->mysql_pre, sel);
+		}
+
+		/* required:
+		 * - username
+		 * - database
+		 *
+		 * optional:
+		 * - password, default: empty
+		 * - socket, default: mysql default
+		 * - hostname, if set overrides socket
+		 * - port, default: 3306
+		 */
+
+		/* all have to be set */
+		if (!(buffer_is_empty(s->myuser) ||
+		      buffer_is_empty(s->mydb))) {
+			my_bool reconnect = 1;
+			int fd;
+
+			if (NULL == (s->mysql = mysql_init(NULL))) {
+				log_error_write(srv, __FILE__, __LINE__, "s", "mysql_init() failed, exiting...");
+
+				return HANDLER_ERROR;
+			}
+
+#if MYSQL_VERSION_ID >= 50013
+			/* in mysql versions above 5.0.3 the reconnect flag is off by default */
+			mysql_options(s->mysql, MYSQL_OPT_RECONNECT, &reconnect);
+#endif
+
+#define FOO(x) (s->x->used ? s->x->ptr : NULL)
+
+			if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass),
+						FOO(mydb), s->port, FOO(mysock), 0)) {
+				log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(s->mysql));
+
+				return HANDLER_ERROR;
+			}
+#undef FOO
+			/* set close_on_exec for mysql the hard way */
+			/* Note: this only works as it is done during startup, */
+			/* otherwise we cannot be sure that mysql is fd i-1 */
+			if (-1 == (fd = open("/dev/null", 0))) {
+				close(fd);
+				fcntl(fd-1, F_SETFD, FD_CLOEXEC);
+			}
+		}
+	}
+
+
+
+        return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+	p->conf.x = s->x;
+static int mod_mysql_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
+	size_t i, j;
+	plugin_config *s = p->config_storage[0];
+
+	PATCH(mysql_pre);
+	PATCH(mysql_post);
+#ifdef HAVE_MYSQL
+	PATCH(mysql);
+#endif
+
+	/* 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("mysql-vhost.sql"))) {
+				PATCH(mysql_pre);
+				PATCH(mysql_post);
+			}
+		}
+
+		if (s->mysql) {
+			PATCH(mysql);
+		}
+	}
+
+	return 0;
+}
+#undef PATCH
+
+
+/* handle document root request */
+CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
+	plugin_data *p = p_d;
+	plugin_connection_data *c;
+	stat_cache_entry *sce;
+
+	unsigned  cols;
+	MYSQL_ROW row;
+	MYSQL_RES *result = NULL;
+
+	/* no host specified? */
+	if (!con->uri.authority->used) return HANDLER_GO_ON;
+
+	mod_mysql_vhost_patch_connection(srv, con, p);
+
+	if (!p->conf.mysql) return HANDLER_GO_ON;
+
+	/* sets up connection data if not done yet */
+	c = mod_mysql_vhost_connection_data(srv, con, p_d);
+
+	/* check if cached this connection */
+	if (c->server_name->used && /* con->uri.authority->used && */
+            buffer_is_equal(c->server_name, con->uri.authority)) goto GO_ON;
+
+	/* build and run SQL query */
+	buffer_copy_string_buffer(p->tmp_buf, p->conf.mysql_pre);
+	if (p->conf.mysql_post->used) {
+		buffer_append_string_buffer(p->tmp_buf, con->uri.authority);
+		buffer_append_string_buffer(p->tmp_buf, p->conf.mysql_post);
+	}
+   	if (mysql_query(p->conf.mysql, p->tmp_buf->ptr)) {
+		log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(p->conf.mysql));
+		goto ERR500;
+	}
+	result = mysql_store_result(p->conf.mysql);
+	cols = mysql_num_fields(result);
+	row = mysql_fetch_row(result);
+	if (!row || cols < 1) {
+		/* no such virtual host */
+		mysql_free_result(result);
+		return HANDLER_GO_ON;
+	}
+
+	/* sanity check that really is a directory */
+	buffer_copy_string(p->tmp_buf, row[0]);
+	BUFFER_APPEND_SLASH(p->tmp_buf);
+
+	if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
+		log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
+		goto ERR500;
+	}
+        if (!S_ISDIR(sce->st.st_mode)) {
+		log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->tmp_buf);
+		goto ERR500;
+	}
+
+	/* cache the data */
+	buffer_copy_string_buffer(c->server_name, con->uri.authority);
+	buffer_copy_string_buffer(c->document_root, p->tmp_buf);
+
+	/* fcgi_offset and fcgi_arg are optional */
+	if (cols > 1 && row[1]) {
+		c->fcgi_offset = atoi(row[1]);
+
+		if (cols > 2 && row[2]) {
+			buffer_copy_string(c->fcgi_arg, row[2]);
+		} else {
+			c->fcgi_arg->used = 0;
+		}
+	} else {
+		c->fcgi_offset = c->fcgi_arg->used = 0;
+	}
+	mysql_free_result(result);
+
+	/* fix virtual server and docroot */
+GO_ON:	buffer_copy_string_buffer(con->server_name, c->server_name);
+	buffer_copy_string_buffer(con->physical.doc_root, c->document_root);
+
+#ifdef DEBUG
+	log_error_write(srv, __FILE__, __LINE__, "sbbdb",
+		result ? "NOT CACHED" : "cached",
+		con->server_name, con->physical.doc_root,
+		c->fcgi_offset, c->fcgi_arg);
+#endif
+	return HANDLER_GO_ON;
+
+ERR500:	if (result) mysql_free_result(result);
+	con->http_status = 500; /* Internal Error */
+	return HANDLER_FINISHED;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+int mod_mysql_vhost_plugin_init(plugin *p) {
+	p->version     = LIGHTTPD_VERSION_ID;
+	p->name        			= buffer_init_string("mysql_vhost");
+
+	p->init        			= mod_mysql_vhost_init;
+	p->cleanup     			= mod_mysql_vhost_cleanup;
+	p->handle_request_done	 	= mod_mysql_vhost_handle_connection_close;
+
+	p->set_defaults			= mod_mysql_vhost_set_defaults;
+	p->handle_docroot  		= mod_mysql_vhost_handle_docroot;
+
+	return 0;
+}
+#else
+/* we don't have mysql support, this plugin does nothing */
+int mod_mysql_vhost_plugin_init(plugin *p) {
+	p->version     = LIGHTTPD_VERSION_ID;
+	p->name        			= buffer_init_string("mysql_vhost");
+
+	return 0;
+}
+#endif

Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_post_to_disk.loT
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_post_to_disk.loT?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_post_to_disk.loT (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_post_to_disk.loT Mon Jul 21 21:35:35 2008
@@ -0,0 +1,7 @@
+# mod_post_to_disk.lo - a libtool object file
+# Generated by ltmain.sh - GNU libtool 1.5.26 Debian 1.5.26-4 (1.1220.2.493 2008/02/01 16:58:18)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.

Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_proxy.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_proxy.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_proxy.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_proxy.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,1327 @@
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "buffer.h"
+#include "server.h"
+#include "keyvalue.h"
+#include "log.h"
+
+#include "http_chunk.h"
+#include "fdevent.h"
+#include "connections.h"
+#include "response.h"
+#include "joblist.h"
+
+#include "plugin.h"
+
+#include "inet_ntop_cache.h"
+#include "crc32.h"
+
+#include <stdio.h>
+
+#ifdef HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+#endif
+
+#include "sys-socket.h"
+
+#define data_proxy data_fastcgi
+#define data_proxy_init data_fastcgi_init
+
+#define PROXY_RETRY_TIMEOUT 60
+
+/**
+ *
+ * the proxy module is based on the fastcgi module
+ *
+ * 28.06.2004 Jan Kneschke     The first release
+ * 01.07.2004 Evgeny Rodichev  Several bugfixes and cleanups
+ *            - co-ordinate up- and downstream flows correctly (proxy_demux_response
+ *              and proxy_handle_fdevent)
+ *            - correctly transfer upstream http_response_status;
+ *            - some unused structures removed.
+ *
+ * TODO:      - delay upstream read if write_queue is too large
+ *              (to prevent memory eating, like in apache). Shoud be
+ *              configurable).
+ *            - persistent connection with upstream servers
+ *            - HTTP/1.1
+ */
+typedef enum {
+	PROXY_BALANCE_UNSET,
+	PROXY_BALANCE_FAIR,
+	PROXY_BALANCE_HASH,
+	PROXY_BALANCE_RR
+} proxy_balance_t;
+
+typedef struct {
+	array *extensions;
+	unsigned short debug;
+
+	proxy_balance_t balance;
+} plugin_config;
+
+typedef struct {
+	PLUGIN_DATA;
+
+	buffer *parse_response;
+	buffer *balance_buf;
+
+	plugin_config **config_storage;
+
+	plugin_config conf;
+} plugin_data;
+
+typedef enum {
+	PROXY_STATE_INIT,
+	PROXY_STATE_CONNECT,
+	PROXY_STATE_PREPARE_WRITE,
+	PROXY_STATE_WRITE,
+	PROXY_STATE_READ,
+	PROXY_STATE_ERROR
+} proxy_connection_state_t;
+
+enum { PROXY_STDOUT, PROXY_END_REQUEST };
+
+typedef struct {
+	proxy_connection_state_t state;
+	time_t state_timestamp;
+
+	data_proxy *host;
+
+	buffer *response;
+	buffer *response_header;
+
+	chunkqueue *wb;
+
+	int fd; /* fd to the proxy process */
+	int fde_ndx; /* index into the fd-event buffer */
+
+	size_t path_info_offset; /* start of path_info in uri.path */
+
+	connection *remote_conn;  /* dump pointer */
+	plugin_data *plugin_data; /* dump pointer */
+} handler_ctx;
+
+
+/* ok, we need a prototype */
+static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents);
+
+static handler_ctx * handler_ctx_init() {
+	handler_ctx * hctx;
+
+
+	hctx = calloc(1, sizeof(*hctx));
+
+	hctx->state = PROXY_STATE_INIT;
+	hctx->host = NULL;
+
+	hctx->response = buffer_init();
+	hctx->response_header = buffer_init();
+
+	hctx->wb = chunkqueue_init();
+
+	hctx->fd = -1;
+	hctx->fde_ndx = -1;
+
+	return hctx;
+}
+
+static void handler_ctx_free(handler_ctx *hctx) {
+	buffer_free(hctx->response);
+	buffer_free(hctx->response_header);
+	chunkqueue_free(hctx->wb);
+
+	free(hctx);
+}
+
+INIT_FUNC(mod_proxy_init) {
+	plugin_data *p;
+
+	p = calloc(1, sizeof(*p));
+
+	p->parse_response = buffer_init();
+	p->balance_buf = buffer_init();
+
+	return p;
+}
+
+
+FREE_FUNC(mod_proxy_free) {
+	plugin_data *p = p_d;
+
+	UNUSED(srv);
+
+	buffer_free(p->parse_response);
+	buffer_free(p->balance_buf);
+
+	if (p->config_storage) {
+		size_t i;
+		for (i = 0; i < srv->config_context->used; i++) {
+			plugin_config *s = p->config_storage[i];
+
+			if (s) {
+
+				array_free(s->extensions);
+
+				free(s);
+			}
+		}
+		free(p->config_storage);
+	}
+
+	free(p);
+
+	return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
+	plugin_data *p = p_d;
+	data_unset *du;
+	size_t i = 0;
+
+	config_values_t cv[] = {
+		{ "proxy.server",              NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
+		{ "proxy.debug",               NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
+		{ "proxy.balance",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 2 */
+		{ NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+	};
+
+	p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
+
+	for (i = 0; i < srv->config_context->used; i++) {
+		plugin_config *s;
+		array *ca;
+
+		s = malloc(sizeof(plugin_config));
+		s->extensions    = array_init();
+		s->debug         = 0;
+
+		cv[0].destination = s->extensions;
+		cv[1].destination = &(s->debug);
+		cv[2].destination = p->balance_buf;
+
+		buffer_reset(p->balance_buf);
+
+		p->config_storage[i] = s;
+		ca = ((data_config *)srv->config_context->data[i])->value;
+
+		if (0 != config_insert_values_global(srv, ca, cv)) {
+			return HANDLER_ERROR;
+		}
+
+		if (buffer_is_empty(p->balance_buf)) {
+			s->balance = PROXY_BALANCE_FAIR;
+		} else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("fair"))) {
+			s->balance = PROXY_BALANCE_FAIR;
+		} else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("round-robin"))) {
+			s->balance = PROXY_BALANCE_RR;
+		} else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("hash"))) {
+			s->balance = PROXY_BALANCE_HASH;
+		} else {
+			log_error_write(srv, __FILE__, __LINE__, "sb",
+				        "proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf);
+			return HANDLER_ERROR;
+		}
+
+		if (NULL != (du = array_get_element(ca, "proxy.server"))) {
+			size_t j;
+			data_array *da = (data_array *)du;
+
+			if (du->type != TYPE_ARRAY) {
+				log_error_write(srv, __FILE__, __LINE__, "sss",
+						"unexpected type for key: ", "proxy.server", "array of strings");
+
+				return HANDLER_ERROR;
+			}
+
+			/*
+			 * proxy.server = ( "<ext>" => ...,
+			 *                  "<ext>" => ... )
+			 */
+
+			for (j = 0; j < da->value->used; j++) {
+				data_array *da_ext = (data_array *)da->value->data[j];
+				size_t n;
+
+				if (da_ext->type != TYPE_ARRAY) {
+					log_error_write(srv, __FILE__, __LINE__, "sssbs",
+							"unexpected type for key: ", "proxy.server",
+							"[", da->value->data[j]->key, "](string)");
+
+					return HANDLER_ERROR;
+				}
+
+				/*
+				 * proxy.server = ( "<ext>" =>
+				 *                     ( "<host>" => ( ... ),
+				 *                       "<host>" => ( ... )
+				 *                     ),
+				 *                    "<ext>" => ... )
+				 */
+
+				for (n = 0; n < da_ext->value->used; n++) {
+					data_array *da_host = (data_array *)da_ext->value->data[n];
+
+					data_proxy *df;
+					data_array *dfa;
+
+					config_values_t pcv[] = {
+						{ "host",              NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },      /* 0 */
+						{ "port",              NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
+						{ NULL,                NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+					};
+
+					if (da_host->type != TYPE_ARRAY) {
+						log_error_write(srv, __FILE__, __LINE__, "ssSBS",
+								"unexpected type for key:",
+								"proxy.server",
+								"[", da_ext->value->data[n]->key, "](string)");
+
+						return HANDLER_ERROR;
+					}
+
+					df = data_proxy_init();
+
+					df->port = 80;
+
+					buffer_copy_string_buffer(df->key, da_host->key);
+
+					pcv[0].destination = df->host;
+					pcv[1].destination = &(df->port);
+
+					if (0 != config_insert_values_internal(srv, da_host->value, pcv)) {
+						return HANDLER_ERROR;
+					}
+
+					if (buffer_is_empty(df->host)) {
+						log_error_write(srv, __FILE__, __LINE__, "sbbbs",
+								"missing key (string):",
+								da->key,
+								da_ext->key,
+								da_host->key,
+								"host");
+
+						return HANDLER_ERROR;
+					}
+
+					/* if extension already exists, take it */
+
+					if (NULL == (dfa = (data_array *)array_get_element(s->extensions, da_ext->key->ptr))) {
+						dfa = data_array_init();
+
+						buffer_copy_string_buffer(dfa->key, da_ext->key);
+
+						array_insert_unique(dfa->value, (data_unset *)df);
+						array_insert_unique(s->extensions, (data_unset *)dfa);
+					} else {
+						array_insert_unique(dfa->value, (data_unset *)df);
+					}
+				}
+			}
+		}
+	}
+
+	return HANDLER_GO_ON;
+}
+
+void proxy_connection_close(server *srv, handler_ctx *hctx) {
+	plugin_data *p;
+	connection *con;
+
+	if (NULL == hctx) return;
+
+	p    = hctx->plugin_data;
+	con  = hctx->remote_conn;
+
+	if (hctx->fd != -1) {
+		fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
+		fdevent_unregister(srv->ev, hctx->fd);
+
+		close(hctx->fd);
+		srv->cur_fds--;
+	}
+
+	handler_ctx_free(hctx);
+	con->plugin_ctx[p->id] = NULL;
+}
+
+static int proxy_establish_connection(server *srv, handler_ctx *hctx) {
+	struct sockaddr *proxy_addr;
+	struct sockaddr_in proxy_addr_in;
+	socklen_t servlen;
+
+	plugin_data *p    = hctx->plugin_data;
+	data_proxy *host= hctx->host;
+	int proxy_fd       = hctx->fd;
+
+	memset(&proxy_addr, 0, sizeof(proxy_addr));
+
+	proxy_addr_in.sin_family = AF_INET;
+	proxy_addr_in.sin_addr.s_addr = inet_addr(host->host->ptr);
+	proxy_addr_in.sin_port = htons(host->port);
+	servlen = sizeof(proxy_addr_in);
+
+	proxy_addr = (struct sockaddr *) &proxy_addr_in;
+
+	if (-1 == connect(proxy_fd, proxy_addr, servlen)) {
+		if (errno == EINPROGRESS || errno == EALREADY) {
+			if (p->conf.debug) {
+				log_error_write(srv, __FILE__, __LINE__, "sd",
+						"connect delayed:", proxy_fd);
+			}
+
+			return 1;
+		} else {
+
+			log_error_write(srv, __FILE__, __LINE__, "sdsd",
+					"connect failed:", proxy_fd, strerror(errno), errno);
+
+			return -1;
+		}
+	}
+	if (p->conf.debug) {
+		log_error_write(srv, __FILE__, __LINE__, "sd",
+				"connect succeeded: ", proxy_fd);
+	}
+
+	return 0;
+}
+
+void proxy_set_header(connection *con, const char *key, const char *value) {
+    data_string *ds_dst;
+
+    if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
+          ds_dst = data_string_init();
+    }
+
+    buffer_copy_string(ds_dst->key, key);
+    buffer_copy_string(ds_dst->value, value);
+    array_insert_unique(con->request.headers, (data_unset *)ds_dst);
+}
+
+void proxy_append_header(connection *con, const char *key, const char *value) {
+    data_string *ds_dst;
+
+    if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
+          ds_dst = data_string_init();
+    }
+
+    buffer_copy_string(ds_dst->key, key);
+    buffer_append_string(ds_dst->value, value);
+    array_insert_unique(con->request.headers, (data_unset *)ds_dst);
+}
+
+
+static int proxy_create_env(server *srv, handler_ctx *hctx) {
+	size_t i;
+
+	connection *con   = hctx->remote_conn;
+	buffer *b;
+
+	/* build header */
+
+	b = chunkqueue_get_append_buffer(hctx->wb);
+
+	/* request line */
+	buffer_copy_string(b, get_http_method_name(con->request.http_method));
+	BUFFER_APPEND_STRING_CONST(b, " ");
+
+	buffer_append_string_buffer(b, con->request.uri);
+	BUFFER_APPEND_STRING_CONST(b, " HTTP/1.0\r\n");
+
+	proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
+	/* http_host is NOT is just a pointer to a buffer
+	 * which is NULL if it is not set */
+	if (con->request.http_host &&
+	    !buffer_is_empty(con->request.http_host)) {
+		proxy_set_header(con, "X-Host", con->request.http_host->ptr);
+	}
+	proxy_set_header(con, "X-Forwarded-Proto", con->conf.is_ssl ? "https" : "http");
+
+	/* request header */
+	for (i = 0; i < con->request.headers->used; i++) {
+		data_string *ds;
+
+		ds = (data_string *)con->request.headers->data[i];
+
+		if (ds->value->used && ds->key->used) {
+			if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
+
+			buffer_append_string_buffer(b, ds->key);
+			BUFFER_APPEND_STRING_CONST(b, ": ");
+			buffer_append_string_buffer(b, ds->value);
+			BUFFER_APPEND_STRING_CONST(b, "\r\n");
+		}
+	}
+
+	BUFFER_APPEND_STRING_CONST(b, "\r\n");
+
+	hctx->wb->bytes_in += b->used - 1;
+	/* body */
+
+	if (con->request.content_length) {
+		chunkqueue *req_cq = con->request_content_queue;
+		chunk *req_c;
+		off_t offset;
+
+		/* something to send ? */
+		for (offset = 0, req_c = req_cq->first; offset != req_cq->bytes_in; req_c = req_c->next) {
+			off_t weWant = req_cq->bytes_in - offset;
+			off_t weHave = 0;
+
+			/* we announce toWrite octects
+			 * now take all the request_content chunk that we need to fill this request
+			 * */
+
+			switch (req_c->type) {
+			case FILE_CHUNK:
+				weHave = req_c->file.length - req_c->offset;
+
+				if (weHave > weWant) weHave = weWant;
+
+				chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave);
+
+				req_c->offset += weHave;
+				req_cq->bytes_out += weHave;
+
+				hctx->wb->bytes_in += weHave;
+
+				break;
+			case MEM_CHUNK:
+				/* append to the buffer */
+				weHave = req_c->mem->used - 1 - req_c->offset;
+
+				if (weHave > weWant) weHave = weWant;
+
+				b = chunkqueue_get_append_buffer(hctx->wb);
+				buffer_append_memory(b, req_c->mem->ptr + req_c->offset, weHave);
+				b->used++; /* add virtual \0 */
+
+				req_c->offset += weHave;
+				req_cq->bytes_out += weHave;
+
+				hctx->wb->bytes_in += weHave;
+
+				break;
+			default:
+				break;
+			}
+
+			offset += weHave;
+		}
+
+	}
+
+	return 0;
+}
+
+static int proxy_set_state(server *srv, handler_ctx *hctx, proxy_connection_state_t state) {
+	hctx->state = state;
+	hctx->state_timestamp = srv->cur_ts;
+
+	return 0;
+}
+
+
+static int proxy_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
+	char *s, *ns;
+	int http_response_status = -1;
+
+	UNUSED(srv);
+
+	/* \r\n -> \0\0 */
+
+	buffer_copy_string_buffer(p->parse_response, in);
+
+	for (s = p->parse_response->ptr; NULL != (ns = strstr(s, "\r\n")); s = ns + 2) {
+		char *key, *value;
+		int key_len;
+		data_string *ds;
+		int copy_header;
+
+		ns[0] = '\0';
+		ns[1] = '\0';
+
+		if (-1 == http_response_status) {
+			/* The first line of a Response message is the Status-Line */
+
+			for (key=s; *key && *key != ' '; key++);
+
+			if (*key) {
+				http_response_status = (int) strtol(key, NULL, 10);
+				if (http_response_status <= 0) http_response_status = 502;
+			} else {
+				http_response_status = 502;
+			}
+
+			con->http_status = http_response_status;
+			con->parsed_response |= HTTP_STATUS;
+			continue;
+		}
+
+		if (NULL == (value = strchr(s, ':'))) {
+			/* now we expect: "<key>: <value>\n" */
+
+			continue;
+		}
+
+		key = s;
+		key_len = value - key;
+
+		value++;
+		/* strip WS */
+		while (*value == ' ' || *value == '\t') value++;
+
+		copy_header = 1;
+
+		switch(key_len) {
+		case 4:
+			if (0 == strncasecmp(key, "Date", key_len)) {
+				con->parsed_response |= HTTP_DATE;
+			}
+			break;
+		case 8:
+			if (0 == strncasecmp(key, "Location", key_len)) {
+				con->parsed_response |= HTTP_LOCATION;
+			}
+			break;
+		case 10:
+			if (0 == strncasecmp(key, "Connection", key_len)) {
+				copy_header = 0;
+			}
+			break;
+		case 14:
+			if (0 == strncasecmp(key, "Content-Length", key_len)) {
+				con->response.content_length = strtol(value, NULL, 10);
+				con->parsed_response |= HTTP_CONTENT_LENGTH;
+			}
+			break;
+		default:
+			break;
+		}
+
+		if (copy_header) {
+			if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
+				ds = data_response_init();
+			}
+			buffer_copy_string_len(ds->key, key, key_len);
+			buffer_copy_string(ds->value, value);
+
+			array_insert_unique(con->response.headers, (data_unset *)ds);
+		}
+	}
+
+	return 0;
+}
+
+
+static int proxy_demux_response(server *srv, handler_ctx *hctx) {
+	int fin = 0;
+	int b;
+	ssize_t r;
+
+	plugin_data *p    = hctx->plugin_data;
+	connection *con   = hctx->remote_conn;
+	int proxy_fd       = hctx->fd;
+
+	/* check how much we have to read */
+	if (ioctl(hctx->fd, FIONREAD, &b)) {
+		log_error_write(srv, __FILE__, __LINE__, "sd",
+				"ioctl failed: ",
+				proxy_fd);
+		return -1;
+	}
+
+
+	if (p->conf.debug) {
+		log_error_write(srv, __FILE__, __LINE__, "sd",
+			       "proxy - have to read:", b);
+	}
+
+	if (b > 0) {
+		if (hctx->response->used == 0) {
+			/* avoid too small buffer */
+			buffer_prepare_append(hctx->response, b + 1);
+			hctx->response->used = 1;
+		} else {
+			buffer_prepare_append(hctx->response, hctx->response->used + b);
+		}
+
+		if (-1 == (r = read(hctx->fd, hctx->response->ptr + hctx->response->used - 1, b))) {
+			if (errno == EAGAIN) return 0;
+			log_error_write(srv, __FILE__, __LINE__, "sds",
+					"unexpected end-of-file (perhaps the proxy process died):",
+					proxy_fd, strerror(errno));
+			return -1;
+		}
+
+		/* this should be catched by the b > 0 above */
+		assert(r);
+
+		hctx->response->used += r;
+		hctx->response->ptr[hctx->response->used - 1] = '\0';
+
+#if 0
+		log_error_write(srv, __FILE__, __LINE__, "sdsbs",
+				"demux: Response buffer len", hctx->response->used, ":", hctx->response, ":");
+#endif
+
+		if (0 == con->got_response) {
+			con->got_response = 1;
+			buffer_prepare_copy(hctx->response_header, 128);
+		}
+
+		if (0 == con->file_started) {
+			char *c;
+
+			/* search for the \r\n\r\n in the string */
+			if (NULL != (c = buffer_search_string_len(hctx->response, "\r\n\r\n", 4))) {
+				size_t hlen = c - hctx->response->ptr + 4;
+				size_t blen = hctx->response->used - hlen - 1;
+				/* found */
+
+				buffer_append_string_len(hctx->response_header, hctx->response->ptr, c - hctx->response->ptr + 4);
+#if 0
+				log_error_write(srv, __FILE__, __LINE__, "sb", "Header:", hctx->response_header);
+#endif
+				/* parse the response header */
+				proxy_response_parse(srv, con, p, hctx->response_header);
+
+				/* enable chunked-transfer-encoding */
+				if (con->request.http_version == HTTP_VERSION_1_1 &&
+				    !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
+					con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
+				}
+
+				con->file_started = 1;
+				if (blen) {
+					http_chunk_append_mem(srv, con, c + 4, blen + 1);
+					joblist_append(srv, con);
+				}
+				hctx->response->used = 0;
+			}
+		} else {
+			http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
+			joblist_append(srv, con);
+			hctx->response->used = 0;
+		}
+
+	} else {
+		/* reading from upstream done */
+		con->file_finished = 1;
+
+		http_chunk_append_mem(srv, con, NULL, 0);
+		joblist_append(srv, con);
+
+		fin = 1;
+	}
+
+	return fin;
+}
+
+
+static handler_t proxy_write_request(server *srv, handler_ctx *hctx) {
+	data_proxy *host= hctx->host;
+	plugin_data *p    = hctx->plugin_data;
+	connection *con   = hctx->remote_conn;
+
+	int ret;
+
+	if (!host ||
+	    (!host->host->used || !host->port)) return -1;
+
+	switch(hctx->state) {
+	case PROXY_STATE_INIT:
+		if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
+			log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
+			return HANDLER_ERROR;
+		}
+		hctx->fde_ndx = -1;
+
+		srv->cur_fds++;
+
+		fdevent_register(srv->ev, hctx->fd, proxy_handle_fdevent, hctx);
+
+		if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
+			log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
+
+			return HANDLER_ERROR;
+		}
+
+		/* fall through */
+
+	case PROXY_STATE_CONNECT:
+		/* try to finish the connect() */
+		if (hctx->state == PROXY_STATE_INIT) {
+			/* first round */
+			switch (proxy_establish_connection(srv, hctx)) {
+			case 1:
+				proxy_set_state(srv, hctx, PROXY_STATE_CONNECT);
+
+				/* connection is in progress, wait for an event and call getsockopt() below */
+
+				fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
+
+				return HANDLER_WAIT_FOR_EVENT;
+			case -1:
+				/* if ECONNREFUSED choose another connection -> FIXME */
+				hctx->fde_ndx = -1;
+
+				return HANDLER_ERROR;
+			default:
+				/* everything is ok, go on */
+				break;
+			}
+		} else {
+			int socket_error;
+			socklen_t socket_error_len = sizeof(socket_error);
+
+			/* we don't need it anymore */
+			fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
+
+			/* try to finish the connect() */
+			if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
+				log_error_write(srv, __FILE__, __LINE__, "ss",
+						"getsockopt failed:", strerror(errno));
+
+				return HANDLER_ERROR;
+			}
+			if (socket_error != 0) {
+				log_error_write(srv, __FILE__, __LINE__, "ss",
+						"establishing connection failed:", strerror(socket_error),
+						"port:", hctx->host->port);
+
+				return HANDLER_ERROR;
+			}
+			if (p->conf.debug) {
+				log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - connect - delayed success");
+			}
+		}
+
+		proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE);
+		/* fall through */
+	case PROXY_STATE_PREPARE_WRITE:
+		proxy_create_env(srv, hctx);
+
+		proxy_set_state(srv, hctx, PROXY_STATE_WRITE);
+
+		/* fall through */
+	case PROXY_STATE_WRITE:;
+		ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
+
+		chunkqueue_remove_finished_chunks(hctx->wb);
+
+		if (-1 == ret) {
+			if (errno != EAGAIN &&
+			    errno != EINTR) {
+				log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
+
+				return HANDLER_ERROR;
+			} else {
+				fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
+
+				return HANDLER_WAIT_FOR_EVENT;
+			}
+		}
+
+		if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
+			proxy_set_state(srv, hctx, PROXY_STATE_READ);
+
+			fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
+			fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
+		} else {
+			fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
+
+			return HANDLER_WAIT_FOR_EVENT;
+		}
+
+		return HANDLER_WAIT_FOR_EVENT;
+	case PROXY_STATE_READ:
+		/* waiting for a response */
+		return HANDLER_WAIT_FOR_EVENT;
+	default:
+		log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
+		return HANDLER_ERROR;
+	}
+
+	return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+	p->conf.x = s->x;
+static int mod_proxy_patch_connection(server *srv, connection *con, plugin_data *p) {
+	size_t i, j;
+	plugin_config *s = p->config_storage[0];
+
+	PATCH(extensions);
+	PATCH(debug);
+	PATCH(balance);
+
+	/* 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("proxy.server"))) {
+				PATCH(extensions);
+			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.debug"))) {
+				PATCH(debug);
+			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.balance"))) {
+				PATCH(balance);
+			}
+		}
+	}
+
+	return 0;
+}
+#undef PATCH
+
+SUBREQUEST_FUNC(mod_proxy_handle_subrequest) {
+	plugin_data *p = p_d;
+
+	handler_ctx *hctx = con->plugin_ctx[p->id];
+	data_proxy *host;
+
+	if (NULL == hctx) return HANDLER_GO_ON;
+
+	mod_proxy_patch_connection(srv, con, p);
+
+	host = hctx->host;
+
+	/* not my job */
+	if (con->mode != p->id) return HANDLER_GO_ON;
+
+	/* ok, create the request */
+	switch(proxy_write_request(srv, hctx)) {
+	case HANDLER_ERROR:
+		log_error_write(srv, __FILE__, __LINE__,  "sbdd", "proxy-server disabled:",
+				host->host,
+				host->port,
+				hctx->fd);
+
+		/* disable this server */
+		host->is_disabled = 1;
+		host->disable_ts = srv->cur_ts;
+
+		proxy_connection_close(srv, hctx);
+
+		/* reset the enviroment and restart the sub-request */
+		buffer_reset(con->physical.path);
+		con->mode = DIRECT;
+
+		joblist_append(srv, con);
+
+		/* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
+		 * and hope that the childs will be restarted
+		 *
+		 */
+
+		return HANDLER_WAIT_FOR_FD;
+	case HANDLER_WAIT_FOR_EVENT:
+		return HANDLER_WAIT_FOR_EVENT;
+	case HANDLER_WAIT_FOR_FD:
+		return HANDLER_WAIT_FOR_FD;
+	default:
+		break;
+	}
+
+	if (con->file_started == 1) {
+		return HANDLER_FINISHED;
+	} else {
+		return HANDLER_WAIT_FOR_EVENT;
+	}
+}
+
+static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) {
+	server      *srv  = (server *)s;
+	handler_ctx *hctx = ctx;
+	connection  *con  = hctx->remote_conn;
+	plugin_data *p    = hctx->plugin_data;
+
+
+	if ((revents & FDEVENT_IN) &&
+	    hctx->state == PROXY_STATE_READ) {
+
+		if (p->conf.debug) {
+			log_error_write(srv, __FILE__, __LINE__, "sd",
+					"proxy: fdevent-in", hctx->state);
+		}
+
+		switch (proxy_demux_response(srv, hctx)) {
+		case 0:
+			break;
+		case 1:
+			hctx->host->usage--;
+
+			/* we are done */
+			proxy_connection_close(srv, hctx);
+
+			joblist_append(srv, con);
+			return HANDLER_FINISHED;
+		case -1:
+			if (con->file_started == 0) {
+				/* nothing has been send out yet, send a 500 */
+				connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
+				con->http_status = 500;
+				con->mode = DIRECT;
+			} else {
+				/* response might have been already started, kill the connection */
+				connection_set_state(srv, con, CON_STATE_ERROR);
+			}
+
+			joblist_append(srv, con);
+			return HANDLER_FINISHED;
+		}
+	}
+
+	if (revents & FDEVENT_OUT) {
+		if (p->conf.debug) {
+			log_error_write(srv, __FILE__, __LINE__, "sd",
+					"proxy: fdevent-out", hctx->state);
+		}
+
+		if (hctx->state == PROXY_STATE_CONNECT ||
+		    hctx->state == PROXY_STATE_WRITE) {
+			/* we are allowed to send something out
+			 *
+			 * 1. in a unfinished connect() call
+			 * 2. in a unfinished write() call (long POST request)
+			 */
+			return mod_proxy_handle_subrequest(srv, con, p);
+		} else {
+			log_error_write(srv, __FILE__, __LINE__, "sd",
+					"proxy: out", hctx->state);
+		}
+	}
+
+	/* perhaps this issue is already handled */
+	if (revents & FDEVENT_HUP) {
+		if (p->conf.debug) {
+			log_error_write(srv, __FILE__, __LINE__, "sd",
+					"proxy: fdevent-hup", hctx->state);
+		}
+
+		if (hctx->state == PROXY_STATE_CONNECT) {
+			/* connect() -> EINPROGRESS -> HUP */
+
+			/**
+			 * what is proxy is doing if it can't reach the next hop ?
+			 *
+			 */
+
+			proxy_connection_close(srv, hctx);
+			joblist_append(srv, con);
+
+			con->http_status = 503;
+			con->mode = DIRECT;
+
+			return HANDLER_FINISHED;
+		}
+
+		con->file_finished = 1;
+
+		proxy_connection_close(srv, hctx);
+		joblist_append(srv, con);
+	} else if (revents & FDEVENT_ERR) {
+		/* kill all connections to the proxy process */
+
+		log_error_write(srv, __FILE__, __LINE__, "sd", "proxy-FDEVENT_ERR, but no HUP", revents);
+
+		joblist_append(srv, con);
+		proxy_connection_close(srv, hctx);
+	}
+
+	return HANDLER_FINISHED;
+}
+
+static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p_d) {
+	plugin_data *p = p_d;
+	size_t s_len;
+	unsigned long last_max = ULONG_MAX;
+	int max_usage = INT_MAX;
+	int ndx = -1;
+	size_t k;
+	buffer *fn;
+	data_array *extension = NULL;
+	size_t path_info_offset;
+
+	/* Possibly, we processed already this request */
+	if (con->file_started == 1) return HANDLER_GO_ON;
+
+	mod_proxy_patch_connection(srv, con, p);
+
+	fn = con->uri.path;
+
+	if (fn->used == 0) {
+		return HANDLER_ERROR;
+	}
+
+	s_len = fn->used - 1;
+
+
+	path_info_offset = 0;
+
+	if (p->conf.debug) {
+		log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - start");
+	}
+
+	/* check if extension matches */
+	for (k = 0; k < p->conf.extensions->used; k++) {
+		size_t ct_len;
+
+		extension = (data_array *)p->conf.extensions->data[k];
+
+		if (extension->key->used == 0) continue;
+
+		ct_len = extension->key->used - 1;
+
+		if (s_len < ct_len) continue;
+
+		/* check extension in the form "/proxy_pattern" */
+		if (*(extension->key->ptr) == '/') {
+			if (strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
+				if (s_len > ct_len + 1) {
+					char *pi_offset;
+
+					if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) {
+						path_info_offset = pi_offset - fn->ptr;
+					}
+				}
+				break;
+			}
+		} else if (0 == strncmp(fn->ptr + s_len - ct_len, extension->key->ptr, ct_len)) {
+			/* check extension in the form ".fcg" */
+			break;
+		}
+	}
+
+	if (k == p->conf.extensions->used) {
+		return HANDLER_GO_ON;
+	}
+
+	if (p->conf.debug) {
+		log_error_write(srv, __FILE__, __LINE__,  "s", "proxy - ext found");
+	}
+
+	switch(p->conf.balance) {
+	case PROXY_BALANCE_HASH:
+		/* hash balancing */
+
+		if (p->conf.debug) {
+			log_error_write(srv, __FILE__, __LINE__,  "sd",
+					"proxy - used hash balancing, hosts:", extension->value->used);
+		}
+
+		for (k = 0, ndx = -1, last_max = ULONG_MAX; k < extension->value->used; k++) {
+			data_proxy *host = (data_proxy *)extension->value->data[k];
+			unsigned long cur_max;
+
+			if (host->is_disabled) continue;
+
+			cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
+				generate_crc32c(CONST_BUF_LEN(host->host)) + /* we can cache this */
+				generate_crc32c(CONST_BUF_LEN(con->uri.authority));
+
+			if (p->conf.debug) {
+				log_error_write(srv, __FILE__, __LINE__,  "sbbbd",
+						"proxy - election:",
+						con->uri.path,
+						host->host,
+						con->uri.authority,
+						cur_max);
+			}
+
+			if ((last_max == ULONG_MAX) || /* first round */
+		   	    (cur_max > last_max)) {
+				last_max = cur_max;
+
+				ndx = k;
+			}
+		}
+
+		break;
+	case PROXY_BALANCE_FAIR:
+		/* fair balancing */
+		if (p->conf.debug) {
+			log_error_write(srv, __FILE__, __LINE__,  "s",
+					"proxy - used fair balancing");
+		}
+
+		for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
+			data_proxy *host = (data_proxy *)extension->value->data[k];
+
+			if (host->is_disabled) continue;
+
+			if (host->usage < max_usage) {
+				max_usage = host->usage;
+
+				ndx = k;
+			}
+		}
+
+		break;
+	case PROXY_BALANCE_RR:
+		/* round robin */
+		if (p->conf.debug) {
+			log_error_write(srv, __FILE__, __LINE__,  "s",
+					"proxy - used round-robin balancing");
+		}
+
+		/* just to be sure */
+		assert(extension->value->used < INT_MAX);
+
+		for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
+			data_proxy *host = (data_proxy *)extension->value->data[k];
+
+			if (host->is_disabled) continue;
+
+			/* first usable ndx */
+			if (max_usage == INT_MAX) {
+				max_usage = k;
+			}
+
+			/* get next ndx */
+			if ((int)k > host->last_used_ndx) {
+				ndx = k;
+				host->last_used_ndx = k;
+
+				break;
+			}
+		}
+
+		/* didn't found a higher id, wrap to the start */
+		if (ndx == -1 && max_usage != INT_MAX) {
+			ndx = max_usage;
+		}
+
+		break;
+	default:
+		break;
+	}
+
+	/* found a server */
+	if (ndx != -1) {
+		data_proxy *host = (data_proxy *)extension->value->data[ndx];
+
+		/*
+		 * if check-local is disabled, use the uri.path handler
+		 *
+		 */
+
+		/* init handler-context */
+		handler_ctx *hctx;
+		hctx = handler_ctx_init();
+
+		hctx->path_info_offset = path_info_offset;
+		hctx->remote_conn      = con;
+		hctx->plugin_data      = p;
+		hctx->host             = host;
+
+		con->plugin_ctx[p->id] = hctx;
+
+		host->usage++;
+
+		con->mode = p->id;
+
+		if (p->conf.debug) {
+			log_error_write(srv, __FILE__, __LINE__,  "sbd",
+					"proxy - found a host",
+					host->host, host->port);
+		}
+
+		return HANDLER_GO_ON;
+	} else {
+		/* no handler found */
+		con->http_status = 500;
+
+		log_error_write(srv, __FILE__, __LINE__,  "sb",
+				"no proxy-handler found for:",
+				fn);
+
+		return HANDLER_FINISHED;
+	}
+	return HANDLER_GO_ON;
+}
+
+static handler_t mod_proxy_connection_close_callback(server *srv, connection *con, void *p_d) {
+	plugin_data *p = p_d;
+
+	proxy_connection_close(srv, con->plugin_ctx[p->id]);
+
+	return HANDLER_GO_ON;
+}
+
+/**
+ *
+ * the trigger re-enables the disabled connections after the timeout is over
+ *
+ * */
+
+TRIGGER_FUNC(mod_proxy_trigger) {
+	plugin_data *p = p_d;
+
+	if (p->config_storage) {
+		size_t i, n, k;
+		for (i = 0; i < srv->config_context->used; i++) {
+			plugin_config *s = p->config_storage[i];
+
+			if (!s) continue;
+
+			/* get the extensions for all configs */
+
+			for (k = 0; k < s->extensions->used; k++) {
+				data_array *extension = (data_array *)s->extensions->data[k];
+
+				/* get all hosts */
+				for (n = 0; n < extension->value->used; n++) {
+					data_proxy *host = (data_proxy *)extension->value->data[n];
+
+					if (!host->is_disabled ||
+					    srv->cur_ts - host->disable_ts < 5) continue;
+
+					log_error_write(srv, __FILE__, __LINE__,  "sbd",
+							"proxy - re-enabled:",
+							host->host, host->port);
+
+					host->is_disabled = 0;
+				}
+			}
+		}
+	}
+
+	return HANDLER_GO_ON;
+}
+
+
+int mod_proxy_plugin_init(plugin *p) {
+	p->version      = LIGHTTPD_VERSION_ID;
+	p->name         = buffer_init_string("proxy");
+
+	p->init         = mod_proxy_init;
+	p->cleanup      = mod_proxy_free;
+	p->set_defaults = mod_proxy_set_defaults;
+	p->connection_reset        = mod_proxy_connection_close_callback; /* end of req-resp cycle */
+	p->handle_connection_close = mod_proxy_connection_close_callback; /* end of client connection */
+	p->handle_uri_clean        = mod_proxy_check_extension;
+	p->handle_subrequest       = mod_proxy_handle_subrequest;
+	p->handle_trigger          = mod_proxy_trigger;
+
+	p->data         = NULL;
+
+	return 0;
+}