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;
+}