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 [32/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_dirlisting.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_dirlisting.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_dirlisting.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_dirlisting.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,909 @@
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+
+#include "plugin.h"
+
+#include "response.h"
+#include "stat_cache.h"
+#include "stream.h"
+
+/**
+ * this is a dirlisting for a lighttpd plugin
+ */
+
+
+#ifdef HAVE_SYS_SYSLIMITS_H
+#include <sys/syslimits.h>
+#endif
+
+#ifdef HAVE_ATTR_ATTRIBUTES_H
+#include <attr/attributes.h>
+#endif
+
+/* plugin config for all request/connections */
+
+typedef struct {
+#ifdef HAVE_PCRE_H
+ pcre *regex;
+#endif
+ buffer *string;
+} excludes;
+
+typedef struct {
+ excludes **ptr;
+
+ size_t used;
+ size_t size;
+} excludes_buffer;
+
+typedef struct {
+ unsigned short dir_listing;
+ unsigned short hide_dot_files;
+ unsigned short show_readme;
+ unsigned short hide_readme_file;
+ unsigned short show_header;
+ unsigned short hide_header_file;
+
+ excludes_buffer *excludes;
+
+ buffer *external_css;
+ buffer *encoding;
+ buffer *set_footer;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ buffer *tmp_buf;
+ buffer *content_charset;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+excludes_buffer *excludes_buffer_init(void) {
+ excludes_buffer *exb;
+
+ exb = calloc(1, sizeof(*exb));
+
+ return exb;
+}
+
+int excludes_buffer_append(excludes_buffer *exb, buffer *string) {
+#ifdef HAVE_PCRE_H
+ size_t i;
+ const char *errptr;
+ int erroff;
+
+ if (!string) return -1;
+
+ if (exb->size == 0) {
+ exb->size = 4;
+ exb->used = 0;
+
+ exb->ptr = malloc(exb->size * sizeof(*exb->ptr));
+
+ for(i = 0; i < exb->size ; i++) {
+ exb->ptr[i] = calloc(1, sizeof(**exb->ptr));
+ }
+ } else if (exb->used == exb->size) {
+ exb->size += 4;
+
+ exb->ptr = realloc(exb->ptr, exb->size * sizeof(*exb->ptr));
+
+ for(i = exb->used; i < exb->size; i++) {
+ exb->ptr[i] = calloc(1, sizeof(**exb->ptr));
+ }
+ }
+
+
+ if (NULL == (exb->ptr[exb->used]->regex = pcre_compile(string->ptr, 0,
+ &errptr, &erroff, NULL))) {
+ return -1;
+ }
+
+ exb->ptr[exb->used]->string = buffer_init();
+ buffer_copy_string_buffer(exb->ptr[exb->used]->string, string);
+
+ exb->used++;
+
+ return 0;
+#else
+ UNUSED(exb);
+ UNUSED(string);
+
+ return -1;
+#endif
+}
+
+void excludes_buffer_free(excludes_buffer *exb) {
+#ifdef HAVE_PCRE_H
+ size_t i;
+
+ for (i = 0; i < exb->size; i++) {
+ if (exb->ptr[i]->regex) pcre_free(exb->ptr[i]->regex);
+ if (exb->ptr[i]->string) buffer_free(exb->ptr[i]->string);
+ free(exb->ptr[i]);
+ }
+
+ if (exb->ptr) free(exb->ptr);
+#endif
+
+ free(exb);
+}
+
+/* init the plugin data */
+INIT_FUNC(mod_dirlisting_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->tmp_buf = buffer_init();
+ p->content_charset = buffer_init();
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_dirlisting_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;
+
+ excludes_buffer_free(s->excludes);
+ buffer_free(s->external_css);
+ buffer_free(s->encoding);
+ buffer_free(s->set_footer);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ buffer_free(p->tmp_buf);
+ buffer_free(p->content_charset);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+static int parse_config_entry(server *srv, plugin_config *s, array *ca, const char *option) {
+ data_unset *du;
+
+ if (NULL != (du = array_get_element(ca, option))) {
+ data_array *da = (data_array *)du;
+ size_t j;
+
+ if (du->type != TYPE_ARRAY) {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "unexpected type for key: ", option, "array of strings");
+
+ return HANDLER_ERROR;
+ }
+
+ da = (data_array *)du;
+
+ for (j = 0; j < da->value->used; j++) {
+ if (da->value->data[j]->type != TYPE_STRING) {
+ log_error_write(srv, __FILE__, __LINE__, "sssbs",
+ "unexpected type for key: ", option, "[",
+ da->value->data[j]->key, "](string)");
+
+ return HANDLER_ERROR;
+ }
+
+ if (0 != excludes_buffer_append(s->excludes,
+ ((data_string *)(da->value->data[j]))->value)) {
+#ifdef HAVE_PCRE_H
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "pcre-compile failed for", ((data_string *)(da->value->data[j]))->value);
+#else
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "pcre support is missing, please install libpcre and the headers");
+#endif
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* handle plugin config and check values */
+
+#define CONFIG_EXCLUDE "dir-listing.exclude"
+#define CONFIG_ACTIVATE "dir-listing.activate"
+#define CONFIG_HIDE_DOTFILES "dir-listing.hide-dotfiles"
+#define CONFIG_EXTERNAL_CSS "dir-listing.external-css"
+#define CONFIG_ENCODING "dir-listing.encoding"
+#define CONFIG_SHOW_README "dir-listing.show-readme"
+#define CONFIG_HIDE_README_FILE "dir-listing.hide-readme-file"
+#define CONFIG_SHOW_HEADER "dir-listing.show-header"
+#define CONFIG_HIDE_HEADER_FILE "dir-listing.hide-header-file"
+#define CONFIG_DIR_LISTING "server.dir-listing"
+#define CONFIG_SET_FOOTER "dir-listing.set-footer"
+
+
+SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { CONFIG_EXCLUDE, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { CONFIG_ACTIVATE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { CONFIG_HIDE_DOTFILES, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { CONFIG_EXTERNAL_CSS, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { CONFIG_ENCODING, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { CONFIG_SHOW_README, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
+ { CONFIG_HIDE_README_FILE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
+ { CONFIG_SHOW_HEADER, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
+ { CONFIG_HIDE_HEADER_FILE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
+ { CONFIG_DIR_LISTING, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
+ { CONFIG_SET_FOOTER, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
+
+ { 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;
+ array *ca;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->excludes = excludes_buffer_init();
+ s->dir_listing = 0;
+ s->external_css = buffer_init();
+ s->hide_dot_files = 0;
+ s->show_readme = 0;
+ s->hide_readme_file = 0;
+ s->show_header = 0;
+ s->hide_header_file = 0;
+ s->encoding = buffer_init();
+ s->set_footer = buffer_init();
+
+ cv[0].destination = s->excludes;
+ cv[1].destination = &(s->dir_listing);
+ cv[2].destination = &(s->hide_dot_files);
+ cv[3].destination = s->external_css;
+ cv[4].destination = s->encoding;
+ cv[5].destination = &(s->show_readme);
+ cv[6].destination = &(s->hide_readme_file);
+ cv[7].destination = &(s->show_header);
+ cv[8].destination = &(s->hide_header_file);
+ cv[9].destination = &(s->dir_listing); /* old name */
+ cv[10].destination = s->set_footer;
+
+ 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;
+ }
+
+ parse_config_entry(srv, s, ca, CONFIG_EXCLUDE);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(dir_listing);
+ PATCH(external_css);
+ PATCH(hide_dot_files);
+ PATCH(encoding);
+ PATCH(show_readme);
+ PATCH(hide_readme_file);
+ PATCH(show_header);
+ PATCH(hide_header_file);
+ PATCH(excludes);
+ PATCH(set_footer);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_ACTIVATE)) ||
+ buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_DIR_LISTING))) {
+ PATCH(dir_listing);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_HIDE_DOTFILES))) {
+ PATCH(hide_dot_files);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_EXTERNAL_CSS))) {
+ PATCH(external_css);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_ENCODING))) {
+ PATCH(encoding);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_SHOW_README))) {
+ PATCH(show_readme);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_HIDE_README_FILE))) {
+ PATCH(hide_readme_file);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_SHOW_HEADER))) {
+ PATCH(show_header);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_HIDE_HEADER_FILE))) {
+ PATCH(hide_header_file);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_SET_FOOTER))) {
+ PATCH(set_footer);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_EXCLUDE))) {
+ PATCH(excludes);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+typedef struct {
+ size_t namelen;
+ time_t mtime;
+ off_t size;
+} dirls_entry_t;
+
+typedef struct {
+ dirls_entry_t **ent;
+ size_t used;
+ size_t size;
+} dirls_list_t;
+
+#define DIRLIST_ENT_NAME(ent) ((char*)(ent) + sizeof(dirls_entry_t))
+#define DIRLIST_BLOB_SIZE 16
+
+/* simple combsort algorithm */
+static void http_dirls_sort(dirls_entry_t **ent, int num) {
+ int gap = num;
+ int i, j;
+ int swapped;
+ dirls_entry_t *tmp;
+
+ do {
+ gap = (gap * 10) / 13;
+ if (gap == 9 || gap == 10)
+ gap = 11;
+ if (gap < 1)
+ gap = 1;
+ swapped = 0;
+
+ for (i = 0; i < num - gap; i++) {
+ j = i + gap;
+ if (strcmp(DIRLIST_ENT_NAME(ent[i]), DIRLIST_ENT_NAME(ent[j])) > 0) {
+ tmp = ent[i];
+ ent[i] = ent[j];
+ ent[j] = tmp;
+ swapped = 1;
+ }
+ }
+
+ } while (gap > 1 || swapped);
+}
+
+/* buffer must be able to hold "999.9K"
+ * conversion is simple but not perfect
+ */
+static int http_list_directory_sizefmt(char *buf, off_t size) {
+ const char unit[] = "KMGTPE"; /* Kilo, Mega, Tera, Peta, Exa */
+ const char *u = unit - 1; /* u will always increment at least once */
+ int remain;
+ char *out = buf;
+
+ if (size < 100)
+ size += 99;
+ if (size < 100)
+ size = 0;
+
+ while (1) {
+ remain = (int) size & 1023;
+ size >>= 10;
+ u++;
+ if ((size & (~0 ^ 1023)) == 0)
+ break;
+ }
+
+ remain /= 100;
+ if (remain > 9)
+ remain = 9;
+ if (size > 999) {
+ size = 0;
+ remain = 9;
+ u++;
+ }
+
+ out += LI_ltostr(out, size);
+ out[0] = '.';
+ out[1] = remain + '0';
+ out[2] = *u;
+ out[3] = '\0';
+
+ return (out + 3 - buf);
+}
+
+static void http_list_directory_header(server *srv, connection *con, plugin_data *p, buffer *out) {
+ UNUSED(srv);
+
+ BUFFER_APPEND_STRING_CONST(out,
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n"
+ "<head>\n"
+ "<title>Index of "
+ );
+ buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_MINIMAL_XML);
+ BUFFER_APPEND_STRING_CONST(out, "</title>\n");
+
+ if (p->conf.external_css->used > 1) {
+ BUFFER_APPEND_STRING_CONST(out, "<link rel=\"stylesheet\" type=\"text/css\" href=\"");
+ buffer_append_string_buffer(out, p->conf.external_css);
+ BUFFER_APPEND_STRING_CONST(out, "\" />\n");
+ } else {
+ BUFFER_APPEND_STRING_CONST(out,
+ "<style type=\"text/css\">\n"
+ "a, a:active {text-decoration: none; color: blue;}\n"
+ "a:visited {color: #48468F;}\n"
+ "a:hover, a:focus {text-decoration: underline; color: red;}\n"
+ "body {background-color: #F5F5F5;}\n"
+ "h2 {margin-bottom: 12px;}\n"
+ "table {margin-left: 12px;}\n"
+ "th, td {"
+ " font: 90% monospace;"
+ " text-align: left;"
+ "}\n"
+ "th {"
+ " font-weight: bold;"
+ " padding-right: 14px;"
+ " padding-bottom: 3px;"
+ "}\n"
+ );
+ BUFFER_APPEND_STRING_CONST(out,
+ "td {padding-right: 14px;}\n"
+ "td.s, th.s {text-align: right;}\n"
+ "div.list {"
+ " background-color: white;"
+ " border-top: 1px solid #646464;"
+ " border-bottom: 1px solid #646464;"
+ " padding-top: 10px;"
+ " padding-bottom: 14px;"
+ "}\n"
+ "div.foot {"
+ " font: 90% monospace;"
+ " color: #787878;"
+ " padding-top: 4px;"
+ "}\n"
+ "</style>\n"
+ );
+ }
+
+ BUFFER_APPEND_STRING_CONST(out, "</head>\n<body>\n");
+
+ /* HEADER.txt */
+ if (p->conf.show_header) {
+ stream s;
+ /* if we have a HEADER file, display it in <pre class="header"></pre> */
+
+ buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
+ BUFFER_APPEND_SLASH(p->tmp_buf);
+ BUFFER_APPEND_STRING_CONST(p->tmp_buf, "HEADER.txt");
+
+ if (-1 != stream_open(&s, p->tmp_buf)) {
+ BUFFER_APPEND_STRING_CONST(out, "<pre class=\"header\">");
+ buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
+ BUFFER_APPEND_STRING_CONST(out, "</pre>");
+ }
+ stream_close(&s);
+ }
+
+ BUFFER_APPEND_STRING_CONST(out, "<h2>Index of ");
+ buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_MINIMAL_XML);
+ BUFFER_APPEND_STRING_CONST(out,
+ "</h2>\n"
+ "<div class=\"list\">\n"
+ "<table summary=\"Directory Listing\" cellpadding=\"0\" cellspacing=\"0\">\n"
+ "<thead>"
+ "<tr>"
+ "<th class=\"n\">Name</th>"
+ "<th class=\"m\">Last Modified</th>"
+ "<th class=\"s\">Size</th>"
+ "<th class=\"t\">Type</th>"
+ "</tr>"
+ "</thead>\n"
+ "<tbody>\n"
+ "<tr>"
+ "<td class=\"n\"><a href=\"../\">Parent Directory</a>/</td>"
+ "<td class=\"m\"> </td>"
+ "<td class=\"s\">- </td>"
+ "<td class=\"t\">Directory</td>"
+ "</tr>\n"
+ );
+}
+
+static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) {
+ UNUSED(srv);
+
+ BUFFER_APPEND_STRING_CONST(out,
+ "</tbody>\n"
+ "</table>\n"
+ "</div>\n"
+ );
+
+ if (p->conf.show_readme) {
+ stream s;
+ /* if we have a README file, display it in <pre class="readme"></pre> */
+
+ buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
+ BUFFER_APPEND_SLASH(p->tmp_buf);
+ BUFFER_APPEND_STRING_CONST(p->tmp_buf, "README.txt");
+
+ if (-1 != stream_open(&s, p->tmp_buf)) {
+ BUFFER_APPEND_STRING_CONST(out, "<pre class=\"readme\">");
+ buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
+ BUFFER_APPEND_STRING_CONST(out, "</pre>");
+ }
+ stream_close(&s);
+ }
+
+ BUFFER_APPEND_STRING_CONST(out,
+ "<div class=\"foot\">"
+ );
+
+ if (p->conf.set_footer->used > 1) {
+ buffer_append_string_buffer(out, p->conf.set_footer);
+ } else if (buffer_is_empty(con->conf.server_tag)) {
+ BUFFER_APPEND_STRING_CONST(out, PACKAGE_NAME "/" PACKAGE_VERSION);
+ } else {
+ buffer_append_string_buffer(out, con->conf.server_tag);
+ }
+
+ BUFFER_APPEND_STRING_CONST(out,
+ "</div>\n"
+ "</body>\n"
+ "</html>\n"
+ );
+}
+
+static int http_list_directory(server *srv, connection *con, plugin_data *p, buffer *dir) {
+ DIR *dp;
+ buffer *out;
+ struct dirent *dent;
+ struct stat st;
+ char *path, *path_file;
+ size_t i;
+ int hide_dotfiles = p->conf.hide_dot_files;
+ dirls_list_t dirs, files, *list;
+ dirls_entry_t *tmp;
+ char sizebuf[sizeof("999.9K")];
+ char datebuf[sizeof("2005-Jan-01 22:23:24")];
+ size_t k;
+ const char *content_type;
+ long name_max;
+#ifdef HAVE_XATTR
+ char attrval[128];
+ int attrlen;
+#endif
+#ifdef HAVE_LOCALTIME_R
+ struct tm tm;
+#endif
+
+ if (dir->used == 0) return -1;
+
+ i = dir->used - 1;
+
+#ifdef HAVE_PATHCONF
+ if (-1 == (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) {
+#ifdef NAME_MAX
+ name_max = NAME_MAX;
+#else
+ name_max = 255; /* stupid default */
+#endif
+ }
+#elif defined __WIN32
+ name_max = FILENAME_MAX;
+#else
+ name_max = NAME_MAX;
+#endif
+
+ path = malloc(dir->used + name_max);
+ assert(path);
+ strcpy(path, dir->ptr);
+ path_file = path + i;
+
+ if (NULL == (dp = opendir(path))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "opendir failed:", dir, strerror(errno));
+
+ free(path);
+ return -1;
+ }
+
+ dirs.ent = (dirls_entry_t**) malloc(sizeof(dirls_entry_t*) * DIRLIST_BLOB_SIZE);
+ assert(dirs.ent);
+ dirs.size = DIRLIST_BLOB_SIZE;
+ dirs.used = 0;
+ files.ent = (dirls_entry_t**) malloc(sizeof(dirls_entry_t*) * DIRLIST_BLOB_SIZE);
+ assert(files.ent);
+ files.size = DIRLIST_BLOB_SIZE;
+ files.used = 0;
+
+ while ((dent = readdir(dp)) != NULL) {
+ unsigned short exclude_match = 0;
+
+ if (dent->d_name[0] == '.') {
+ if (hide_dotfiles)
+ continue;
+ if (dent->d_name[1] == '\0')
+ continue;
+ if (dent->d_name[1] == '.' && dent->d_name[2] == '\0')
+ continue;
+ }
+
+ if (p->conf.hide_readme_file) {
+ if (strcmp(dent->d_name, "README.txt") == 0)
+ continue;
+ }
+ if (p->conf.hide_header_file) {
+ if (strcmp(dent->d_name, "HEADER.txt") == 0)
+ continue;
+ }
+
+ /* compare d_name against excludes array
+ * elements, skipping any that match.
+ */
+#ifdef HAVE_PCRE_H
+ for(i = 0; i < p->conf.excludes->used; i++) {
+ int n;
+#define N 10
+ int ovec[N * 3];
+ pcre *regex = p->conf.excludes->ptr[i]->regex;
+
+ if ((n = pcre_exec(regex, NULL, dent->d_name,
+ strlen(dent->d_name), 0, 0, ovec, 3 * N)) < 0) {
+ if (n != PCRE_ERROR_NOMATCH) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "execution error while matching:", n);
+
+ return -1;
+ }
+ }
+ else {
+ exclude_match = 1;
+ break;
+ }
+ }
+
+ if (exclude_match) {
+ continue;
+ }
+#endif
+
+ i = strlen(dent->d_name);
+
+ /* NOTE: the manual says, d_name is never more than NAME_MAX
+ * so this should actually not be a buffer-overflow-risk
+ */
+ if (i > (size_t)name_max) continue;
+
+ memcpy(path_file, dent->d_name, i + 1);
+ if (stat(path, &st) != 0)
+ continue;
+
+ list = &files;
+ if (S_ISDIR(st.st_mode))
+ list = &dirs;
+
+ if (list->used == list->size) {
+ list->size += DIRLIST_BLOB_SIZE;
+ list->ent = (dirls_entry_t**) realloc(list->ent, sizeof(dirls_entry_t*) * list->size);
+ assert(list->ent);
+ }
+
+ tmp = (dirls_entry_t*) malloc(sizeof(dirls_entry_t) + 1 + i);
+ tmp->mtime = st.st_mtime;
+ tmp->size = st.st_size;
+ tmp->namelen = i;
+ memcpy(DIRLIST_ENT_NAME(tmp), dent->d_name, i + 1);
+
+ list->ent[list->used++] = tmp;
+ }
+ closedir(dp);
+
+ if (dirs.used) http_dirls_sort(dirs.ent, dirs.used);
+
+ if (files.used) http_dirls_sort(files.ent, files.used);
+
+ out = chunkqueue_get_append_buffer(con->write_queue);
+ BUFFER_COPY_STRING_CONST(out, "<?xml version=\"1.0\" encoding=\"");
+ if (buffer_is_empty(p->conf.encoding)) {
+ BUFFER_APPEND_STRING_CONST(out, "iso-8859-1");
+ } else {
+ buffer_append_string_buffer(out, p->conf.encoding);
+ }
+ BUFFER_APPEND_STRING_CONST(out, "\"?>\n");
+ http_list_directory_header(srv, con, p, out);
+
+ /* directories */
+ for (i = 0; i < dirs.used; i++) {
+ tmp = dirs.ent[i];
+
+#ifdef HAVE_LOCALTIME_R
+ localtime_r(&(tmp->mtime), &tm);
+ strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
+#else
+ strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
+#endif
+
+ BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
+ buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
+ BUFFER_APPEND_STRING_CONST(out, "/\">");
+ buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_MINIMAL_XML);
+ BUFFER_APPEND_STRING_CONST(out, "</a>/</td><td class=\"m\">");
+ buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1);
+ BUFFER_APPEND_STRING_CONST(out, "</td><td class=\"s\">- </td><td class=\"t\">Directory</td></tr>\n");
+
+ free(tmp);
+ }
+
+ /* files */
+ for (i = 0; i < files.used; i++) {
+ tmp = files.ent[i];
+
+ content_type = NULL;
+#ifdef HAVE_XATTR
+
+ if (con->conf.use_xattr) {
+ memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
+ attrlen = sizeof(attrval) - 1;
+ if (attr_get(path, "Content-Type", attrval, &attrlen, 0) == 0) {
+ attrval[attrlen] = '\0';
+ content_type = attrval;
+ }
+ }
+#endif
+
+ if (content_type == NULL) {
+ content_type = "application/octet-stream";
+ for (k = 0; k < con->conf.mimetypes->used; k++) {
+ data_string *ds = (data_string *)con->conf.mimetypes->data[k];
+ size_t ct_len;
+
+ if (ds->key->used == 0)
+ continue;
+
+ ct_len = ds->key->used - 1;
+ if (tmp->namelen < ct_len)
+ continue;
+
+ if (0 == strncasecmp(DIRLIST_ENT_NAME(tmp) + tmp->namelen - ct_len, ds->key->ptr, ct_len)) {
+ content_type = ds->value->ptr;
+ break;
+ }
+ }
+ }
+
+#ifdef HAVE_LOCALTIME_R
+ localtime_r(&(tmp->mtime), &tm);
+ strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
+#else
+ strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
+#endif
+ http_list_directory_sizefmt(sizebuf, tmp->size);
+
+ BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
+ buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
+ BUFFER_APPEND_STRING_CONST(out, "\">");
+ buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_MINIMAL_XML);
+ BUFFER_APPEND_STRING_CONST(out, "</a></td><td class=\"m\">");
+ buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1);
+ BUFFER_APPEND_STRING_CONST(out, "</td><td class=\"s\">");
+ buffer_append_string(out, sizebuf);
+ BUFFER_APPEND_STRING_CONST(out, "</td><td class=\"t\">");
+ buffer_append_string(out, content_type);
+ BUFFER_APPEND_STRING_CONST(out, "</td></tr>\n");
+
+ free(tmp);
+ }
+
+ free(files.ent);
+ free(dirs.ent);
+ free(path);
+
+ http_list_directory_footer(srv, con, p, out);
+
+ /* Insert possible charset to Content-Type */
+ if (buffer_is_empty(p->conf.encoding)) {
+ response_header_insert(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
+ } else {
+ buffer_copy_string(p->content_charset, "text/html; charset=");
+ buffer_append_string_buffer(p->content_charset, p->conf.encoding);
+ response_header_insert(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->content_charset));
+ }
+
+ con->file_finished = 1;
+
+ return 0;
+}
+
+
+
+URIHANDLER_FUNC(mod_dirlisting_subrequest) {
+ plugin_data *p = p_d;
+ stat_cache_entry *sce = NULL;
+
+ UNUSED(srv);
+
+ if (con->physical.path->used == 0) return HANDLER_GO_ON;
+ 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_dirlisting_patch_connection(srv, con, p);
+
+ if (!p->conf.dir_listing) return HANDLER_GO_ON;
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- handling the request as Dir-Listing");
+ log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path);
+ }
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+ fprintf(stderr, "%s.%d: %s\n", __FILE__, __LINE__, con->physical.path->ptr);
+ SEGFAULT();
+ }
+
+ if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
+
+ if (http_list_directory(srv, con, p, con->physical.path)) {
+ /* dirlisting failed */
+ con->http_status = 403;
+ }
+
+ buffer_reset(con->physical.path);
+
+ /* not found */
+ return HANDLER_FINISHED;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_dirlisting_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("dirlisting");
+
+ p->init = mod_dirlisting_init;
+ p->handle_subrequest_start = mod_dirlisting_subrequest;
+ p->set_defaults = mod_dirlisting_set_defaults;
+ p->cleanup = mod_dirlisting_free;
+
+ p->data = NULL;
+
+ return 0;
+}
Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_evasive.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_evasive.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_evasive.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_evasive.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,178 @@
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+
+#include "plugin.h"
+
+#include "inet_ntop_cache.h"
+
+/**
+ * mod_evasive
+ *
+ * we indent to implement all features the mod_evasive from apache has
+ *
+ * - limit of connections per IP
+ * - provide a list of block-listed ip/networks (no access)
+ * - provide a white-list of ips/network which is not affected by the limit
+ * (hmm, conditionals might be enough)
+ * - provide a bandwidth limiter per IP
+ *
+ * started by:
+ * - w1zzard@techpowerup.com
+ */
+
+typedef struct {
+ unsigned short max_conns;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+INIT_FUNC(mod_evasive_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ return p;
+}
+
+FREE_FUNC(mod_evasive_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];
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_evasive_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "evasive.max-conns-per-ip", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
+ { 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;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->max_conns = 0;
+
+ cv[0].destination = &(s->max_conns);
+
+ 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_evasive_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(max_conns);
+
+ /* 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("evasive.max-conns-per-ip"))) {
+ PATCH(max_conns);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+URIHANDLER_FUNC(mod_evasive_uri_handler) {
+ plugin_data *p = p_d;
+ size_t conns_by_ip = 0;
+ size_t j;
+
+ if (con->uri.path->used == 0) return HANDLER_GO_ON;
+
+ mod_evasive_patch_connection(srv, con, p);
+
+ /* no limit set, nothing to block */
+ if (p->conf.max_conns == 0) return HANDLER_GO_ON;
+
+ for (j = 0; j < srv->conns->used; j++) {
+ connection *c = srv->conns->ptr[j];
+
+ /* check if other connections are already actively serving data for the same IP
+ * we can only ban connections which are already behind the 'read request' state
+ * */
+ if (c->dst_addr.ipv4.sin_addr.s_addr == con->dst_addr.ipv4.sin_addr.s_addr &&
+ c->state > CON_STATE_REQUEST_END) {
+ conns_by_ip++;
+
+ if (conns_by_ip > p->conf.max_conns) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ inet_ntop_cache_get_ip(srv, &(con->dst_addr)),
+ "turned away. Too many connections.");
+
+ con->http_status = 403;
+ return HANDLER_FINISHED;
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+int mod_evasive_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("evasive");
+
+ p->init = mod_evasive_init;
+ p->set_defaults = mod_evasive_set_defaults;
+ p->handle_uri_clean = mod_evasive_uri_handler;
+ p->cleanup = mod_evasive_free;
+
+ p->data = NULL;
+
+ return 0;
+}
Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_evhost.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_evhost.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_evhost.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_evhost.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,334 @@
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "plugin.h"
+#include "log.h"
+#include "response.h"
+#include "stat_cache.h"
+
+typedef struct {
+ /* unparsed pieces */
+ buffer *path_pieces_raw;
+
+ /* pieces for path creation */
+ size_t len;
+ buffer **path_pieces;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+ buffer *tmp_buf;
+
+ plugin_config **config_storage;
+ plugin_config conf;
+} plugin_data;
+
+INIT_FUNC(mod_evhost_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->tmp_buf = buffer_init();
+
+ return p;
+}
+
+FREE_FUNC(mod_evhost_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;
+
+ if(s->path_pieces) {
+ size_t j;
+ for (j = 0; j < s->len; j++) {
+ buffer_free(s->path_pieces[j]);
+ }
+
+ free(s->path_pieces);
+ }
+
+ buffer_free(s->path_pieces_raw);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ buffer_free(p->tmp_buf);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+static void mod_evhost_parse_pattern(plugin_config *s) {
+ char *ptr = s->path_pieces_raw->ptr,*pos;
+
+ s->path_pieces = NULL;
+
+ for(pos=ptr;*ptr;ptr++) {
+ if(*ptr == '%') {
+ s->path_pieces = realloc(s->path_pieces,(s->len+2) * sizeof(*s->path_pieces));
+ s->path_pieces[s->len] = buffer_init();
+ s->path_pieces[s->len+1] = buffer_init();
+
+ buffer_copy_string_len(s->path_pieces[s->len],pos,ptr-pos);
+ pos = ptr + 2;
+
+ buffer_copy_string_len(s->path_pieces[s->len+1],ptr++,2);
+
+ s->len += 2;
+ }
+ }
+
+ if(*pos != '\0') {
+ s->path_pieces = realloc(s->path_pieces,(s->len+1) * sizeof(*s->path_pieces));
+ s->path_pieces[s->len] = buffer_init();
+
+ buffer_append_memory(s->path_pieces[s->len],pos,ptr-pos);
+
+ s->len += 1;
+ }
+}
+
+SETDEFAULTS_FUNC(mod_evhost_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i;
+
+ /**
+ *
+ * #
+ * # define a pattern for the host url finding
+ * # %% => % sign
+ * # %0 => domain name + tld
+ * # %1 => tld
+ * # %2 => domain name without tld
+ * # %3 => subdomain 1 name
+ * # %4 => subdomain 2 name
+ * #
+ * evhost.path-pattern = "/home/ckruse/dev/www/%3/htdocs/"
+ *
+ */
+
+ config_values_t cv[] = {
+ { "evhost.path-pattern", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { 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->path_pieces_raw = buffer_init();
+ s->path_pieces = NULL;
+ s->len = 0;
+
+ cv[0].destination = s->path_pieces_raw;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
+ return HANDLER_ERROR;
+ }
+
+ if (s->path_pieces_raw->used != 0) {
+ mod_evhost_parse_pattern(s);
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+/**
+ * assign the different parts of the domain to array-indezes
+ * - %0 - full hostname (authority w/o port)
+ * - %1 - tld
+ * - %2 - domain.tld
+ * - %3 -
+ */
+
+static int mod_evhost_parse_host(connection *con,array *host) {
+ /* con->uri.authority->used is always > 0 if we come here */
+ register char *ptr = con->uri.authority->ptr + con->uri.authority->used - 1;
+ char *colon = ptr; /* needed to filter out the colon (if exists) */
+ int first = 1;
+ data_string *ds;
+ int i;
+
+ /* first, find the domain + tld */
+ for(;ptr > con->uri.authority->ptr;ptr--) {
+ if(*ptr == '.') {
+ if(first) first = 0;
+ else break;
+ } else if(*ptr == ':') {
+ colon = ptr;
+ first = 1;
+ }
+ }
+
+ ds = data_string_init();
+ buffer_copy_string(ds->key,"%0");
+
+ /* if we stopped at a dot, skip the dot */
+ if (*ptr == '.') ptr++;
+ buffer_copy_string_len(ds->value, ptr, colon-ptr);
+
+ array_insert_unique(host,(data_unset *)ds);
+
+ /* if the : is not the start of the authority, go on parsing the hostname */
+
+ if (colon != con->uri.authority->ptr) {
+ for(ptr = colon - 1, i = 1; ptr > con->uri.authority->ptr; ptr--) {
+ if(*ptr == '.') {
+ if (ptr != colon - 1) {
+ /* is something between the dots */
+ ds = data_string_init();
+ buffer_copy_string(ds->key,"%");
+ buffer_append_long(ds->key, i++);
+ buffer_copy_string_len(ds->value,ptr+1,colon-ptr-1);
+
+ array_insert_unique(host,(data_unset *)ds);
+ }
+ colon = ptr;
+ }
+ }
+
+ /* if the . is not the first charactor of the hostname */
+ if (colon != ptr) {
+ ds = data_string_init();
+ buffer_copy_string(ds->key,"%");
+ buffer_append_long(ds->key, i++);
+ buffer_copy_string_len(ds->value,ptr,colon-ptr);
+
+ array_insert_unique(host,(data_unset *)ds);
+ }
+ }
+
+ return 0;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_evhost_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(path_pieces);
+ PATCH(len);
+
+ /* 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("evhost.path-pattern"))) {
+ PATCH(path_pieces);
+ PATCH(len);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+
+static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+ size_t i;
+ array *parsed_host;
+ register char *ptr;
+ int not_good = 0;
+ stat_cache_entry *sce = NULL;
+
+ /* not authority set */
+ if (con->uri.authority->used == 0) return HANDLER_GO_ON;
+
+ mod_evhost_patch_connection(srv, con, p);
+
+ /* missing even default(global) conf */
+ if (0 == p->conf.len) {
+ return HANDLER_GO_ON;
+ }
+
+ parsed_host = array_init();
+
+ mod_evhost_parse_host(con, parsed_host);
+
+ /* build document-root */
+ buffer_reset(p->tmp_buf);
+
+ for (i = 0; i < p->conf.len; i++) {
+ ptr = p->conf.path_pieces[i]->ptr;
+ if (*ptr == '%') {
+ data_string *ds;
+
+ if (*(ptr+1) == '%') {
+ /* %% */
+ BUFFER_APPEND_STRING_CONST(p->tmp_buf,"%");
+ } else if (NULL != (ds = (data_string *)array_get_element(parsed_host,p->conf.path_pieces[i]->ptr))) {
+ if (ds->value->used) {
+ buffer_append_string_buffer(p->tmp_buf,ds->value);
+ }
+ } else {
+ /* unhandled %-sequence */
+ }
+ } else {
+ buffer_append_string_buffer(p->tmp_buf,p->conf.path_pieces[i]);
+ }
+ }
+
+ BUFFER_APPEND_SLASH(p->tmp_buf);
+
+ array_free(parsed_host);
+
+ 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);
+ not_good = 1;
+ } else if(!S_ISDIR(sce->st.st_mode)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "not a directory:", p->tmp_buf);
+ not_good = 1;
+ }
+
+ if (!not_good) {
+ buffer_copy_string_buffer(con->physical.doc_root, p->tmp_buf);
+ }
+
+ return HANDLER_GO_ON;
+}
+
+int mod_evhost_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("evhost");
+ p->init = mod_evhost_init;
+ p->set_defaults = mod_evhost_set_defaults;
+ p->handle_docroot = mod_evhost_uri_handler;
+ p->cleanup = mod_evhost_free;
+
+ p->data = NULL;
+
+ return 0;
+}
+
+/* eof */
Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_expire.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_expire.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_expire.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_expire.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,369 @@
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "response.h"
+
+#include "plugin.h"
+#include "stat_cache.h"
+
+/**
+ * this is a expire module for a lighttpd
+ *
+ * set 'Expires:' HTTP Headers on demand
+ */
+
+
+
+/* plugin config for all request/connections */
+
+typedef struct {
+ array *expire_url;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ buffer *expire_tstmp;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_expire_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->expire_tstmp = buffer_init();
+
+ buffer_prepare_copy(p->expire_tstmp, 255);
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_expire_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ buffer_free(p->expire_tstmp);
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ array_free(s->expire_url);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+static int mod_expire_get_offset(server *srv, plugin_data *p, buffer *expire, int *offset) {
+ char *ts;
+ int type = -1;
+ int retts = 0;
+
+ UNUSED(p);
+
+ /*
+ * parse
+ *
+ * '(access|now|modification) [plus] {<num> <type>}*'
+ *
+ * e.g. 'access 1 years'
+ */
+
+ if (expire->used == 0) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "empty:");
+ return -1;
+ }
+
+ ts = expire->ptr;
+
+ if (0 == strncmp(ts, "access ", 7)) {
+ type = 0;
+ ts += 7;
+ } else if (0 == strncmp(ts, "now ", 4)) {
+ type = 0;
+ ts += 4;
+ } else if (0 == strncmp(ts, "modification ", 13)) {
+ type = 1;
+ ts += 13;
+ } else {
+ /* invalid type-prefix */
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "invalid <base>:", ts);
+ return -1;
+ }
+
+ if (0 == strncmp(ts, "plus ", 5)) {
+ /* skip the optional plus */
+ ts += 5;
+ }
+
+ /* the rest is just <number> (years|months|weeks|days|hours|minutes|seconds) */
+ while (1) {
+ char *space, *err;
+ int num;
+
+ if (NULL == (space = strchr(ts, ' '))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "missing space after <num>:", ts);
+ return -1;
+ }
+
+ num = strtol(ts, &err, 10);
+ if (*err != ' ') {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "missing <type> after <num>:", ts);
+ return -1;
+ }
+
+ ts = space + 1;
+
+ if (NULL != (space = strchr(ts, ' '))) {
+ int slen;
+ /* */
+
+ slen = space - ts;
+
+ if (slen == 5 &&
+ 0 == strncmp(ts, "years", slen)) {
+ num *= 60 * 60 * 24 * 30 * 12;
+ } else if (slen == 6 &&
+ 0 == strncmp(ts, "months", slen)) {
+ num *= 60 * 60 * 24 * 30;
+ } else if (slen == 5 &&
+ 0 == strncmp(ts, "weeks", slen)) {
+ num *= 60 * 60 * 24 * 7;
+ } else if (slen == 4 &&
+ 0 == strncmp(ts, "days", slen)) {
+ num *= 60 * 60 * 24;
+ } else if (slen == 5 &&
+ 0 == strncmp(ts, "hours", slen)) {
+ num *= 60 * 60;
+ } else if (slen == 7 &&
+ 0 == strncmp(ts, "minutes", slen)) {
+ num *= 60;
+ } else if (slen == 7 &&
+ 0 == strncmp(ts, "seconds", slen)) {
+ num *= 1;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "unknown type:", ts);
+ return -1;
+ }
+
+ retts += num;
+
+ ts = space + 1;
+ } else {
+ if (0 == strcmp(ts, "years")) {
+ num *= 60 * 60 * 24 * 30 * 12;
+ } else if (0 == strcmp(ts, "months")) {
+ num *= 60 * 60 * 24 * 30;
+ } else if (0 == strcmp(ts, "weeks")) {
+ num *= 60 * 60 * 24 * 7;
+ } else if (0 == strcmp(ts, "days")) {
+ num *= 60 * 60 * 24;
+ } else if (0 == strcmp(ts, "hours")) {
+ num *= 60 * 60;
+ } else if (0 == strcmp(ts, "minutes")) {
+ num *= 60;
+ } else if (0 == strcmp(ts, "seconds")) {
+ num *= 1;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "unknown type:", ts);
+ return -1;
+ }
+
+ retts += num;
+
+ break;
+ }
+ }
+
+ if (offset != NULL) *offset = retts;
+
+ return type;
+}
+
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_expire_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0, k;
+
+ config_values_t cv[] = {
+ { "expire.url", 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->expire_url = array_init();
+
+ cv[0].destination = s->expire_url;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
+ return HANDLER_ERROR;
+ }
+
+ for (k = 0; k < s->expire_url->used; k++) {
+ data_string *ds = (data_string *)s->expire_url->data[k];
+
+ /* parse lines */
+ if (-1 == mod_expire_get_offset(srv, p, ds->value, NULL)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "parsing expire.url failed:", ds->value);
+ return HANDLER_ERROR;
+ }
+ }
+ }
+
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_expire_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(expire_url);
+
+ /* 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("expire.url"))) {
+ PATCH(expire_url);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+URIHANDLER_FUNC(mod_expire_path_handler) {
+ plugin_data *p = p_d;
+ int s_len;
+ size_t k;
+
+ if (con->uri.path->used == 0) return HANDLER_GO_ON;
+
+ mod_expire_patch_connection(srv, con, p);
+
+ s_len = con->uri.path->used - 1;
+
+ for (k = 0; k < p->conf.expire_url->used; k++) {
+ data_string *ds = (data_string *)p->conf.expire_url->data[k];
+ int ct_len = ds->key->used - 1;
+
+ if (ct_len > s_len) continue;
+ if (ds->key->used == 0) continue;
+
+ if (0 == strncmp(con->uri.path->ptr, ds->key->ptr, ct_len)) {
+ int ts;
+ time_t t;
+ size_t len;
+ stat_cache_entry *sce = NULL;
+
+ stat_cache_get_entry(srv, con, con->physical.path, &sce);
+
+ switch(mod_expire_get_offset(srv, p, ds->value, &ts)) {
+ case 0:
+ /* access */
+ t = (ts + srv->cur_ts);
+ break;
+ case 1:
+ /* modification */
+
+ t = (ts + sce->st.st_mtime);
+ break;
+ default:
+ /* -1 is handled at parse-time */
+ break;
+ }
+
+
+ if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1,
+ "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(t))))) {
+ /* could not set expire header, out of mem */
+
+ return HANDLER_GO_ON;
+
+ }
+
+ p->expire_tstmp->used = len + 1;
+
+ /* HTTP/1.0 */
+ response_header_overwrite(srv, con, CONST_STR_LEN("Expires"), CONST_BUF_LEN(p->expire_tstmp));
+
+ /* HTTP/1.1 */
+ buffer_copy_string(p->expire_tstmp, "max-age=");
+ buffer_append_long(p->expire_tstmp, ts);
+
+ response_header_overwrite(srv, con, CONST_STR_LEN("Cache-Control"), CONST_BUF_LEN(p->expire_tstmp));
+
+ return HANDLER_GO_ON;
+ }
+ }
+
+ /* not found */
+ return HANDLER_GO_ON;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_expire_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("expire");
+
+ p->init = mod_expire_init;
+ p->handle_subrequest_start = mod_expire_path_handler;
+ p->set_defaults = mod_expire_set_defaults;
+ p->cleanup = mod_expire_free;
+
+ p->data = NULL;
+
+ return 0;
+}
Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_extforward.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_extforward.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_extforward.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/mod_extforward.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,496 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <netinet/in.h>
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+
+#include "plugin.h"
+
+#include "inet_ntop_cache.h"
+#include "configfile.h"
+
+/**
+ * mod_extforward.c for lighttpd, by comman.kang <at> gmail <dot> com
+ * extended, modified by Lionel Elie Mamane (LEM), lionel <at> mamane <dot> lu
+ * support chained proxies by glen@delfi.ee, #1528
+ *
+ * Config example:
+ *
+ * Trust proxy 10.0.0.232 and 10.0.0.232
+ * extforward.forwarder = ( "10.0.0.232" => "trust",
+ * "10.0.0.233" => "trust" )
+ *
+ * Trust all proxies (NOT RECOMMENDED!)
+ * extforward.forwarder = ( "all" => "trust")
+ *
+ * Note that "all" has precedence over specific entries,
+ * so "all except" setups will not work.
+ *
+ * In case you have chained proxies, you can add all their IP's to the
+ * config. However "all" has effect only on connecting IP, as the
+ * X-Forwarded-For header can not be trusted.
+ *
+ * Note: The effect of this module is variable on $HTTP["remotip"] directives and
+ * other module's remote ip dependent actions.
+ * Things done by modules before we change the remoteip or after we reset it will match on the proxy's IP.
+ * Things done in between these two moments will match on the real client's IP.
+ * The moment things are done by a module depends on in which hook it does things and within the same hook
+ * on whether they are before/after us in the module loading order
+ * (order in the server.modules directive in the config file).
+ *
+ * Tested behaviours:
+ *
+ * mod_access: Will match on the real client.
+ *
+ * mod_accesslog:
+ * In order to see the "real" ip address in access log ,
+ * you'll have to load mod_extforward after mod_accesslog.
+ * like this:
+ *
+ * server.modules = (
+ * .....
+ * mod_accesslog,
+ * mod_extforward
+ * )
+ *
+ * Known issues:
+ * seems causing segfault with mod_ssl and $HTTP{"socket"} directives
+ * LEM 2006.05.26: Fixed segfault $SERVER["socket"] directive. Untested with SSL.
+ *
+ * ChangeLog:
+ * 2005.12.19 Initial Version
+ * 2005.12.19 fixed conflict with conditional directives
+ * 2006.05.26 LEM: IPv6 support
+ * 2006.05.26 LEM: Fix a segfault with $SERVER["socket"] directive.
+ * 2006.05.26 LEM: Run at uri_raw time, as we don't need to see the URI
+ * In this manner, we run before mod_access and $HTTP["remoteip"] directives work!
+ * 2006.05.26 LEM: Clean config_cond cache of tests whose result we probably change.
+ */
+
+
+/* plugin config for all request/connections */
+
+typedef struct {
+ array *forwarder;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+
+/* context , used for restore remote ip */
+
+typedef struct {
+ sock_addr saved_remote_addr;
+ buffer *saved_remote_addr_buf;
+} handler_ctx;
+
+
+static handler_ctx * handler_ctx_init(sock_addr oldaddr, buffer *oldaddr_buf) {
+ handler_ctx * hctx;
+ hctx = calloc(1, sizeof(*hctx));
+ hctx->saved_remote_addr = oldaddr;
+ hctx->saved_remote_addr_buf = oldaddr_buf;
+ return hctx;
+}
+
+static void handler_ctx_free(handler_ctx *hctx) {
+ free(hctx);
+}
+
+/* init the plugin data */
+INIT_FUNC(mod_extforward_init) {
+ plugin_data *p;
+ p = calloc(1, sizeof(*p));
+ return p;
+}
+
+/* destroy the plugin data */
+FREE_FUNC(mod_extforward_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->forwarder);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_extforward_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "extforward.forwarder", 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->forwarder = array_init();
+
+ cv[0].destination = s->forwarder;
+
+ 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_extforward_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(forwarder);
+
+ /* 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("extforward.forwarder"))) {
+ PATCH(forwarder);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+
+static void put_string_into_array_len(array *ary, const char *str, int len)
+{
+ data_string *tempdata;
+ if (len == 0)
+ return;
+ tempdata = data_string_init();
+ buffer_copy_string_len(tempdata->value,str,len);
+ array_insert_unique(ary,(data_unset *)tempdata);
+}
+/*
+ extract a forward array from the environment
+*/
+static array *extract_forward_array(buffer *pbuffer)
+{
+ array *result = array_init();
+ if (pbuffer->used > 0) {
+ char *base, *curr;
+ /* state variable, 0 means not in string, 1 means in string */
+ int in_str = 0;
+ for (base = pbuffer->ptr, curr = pbuffer->ptr; *curr; curr++) {
+ if (in_str) {
+ if ((*curr > '9' || *curr < '0') && *curr != '.' && *curr != ':') {
+ /* found an separator , insert value into result array */
+ put_string_into_array_len(result, base, curr - base);
+ /* change state to not in string */
+ in_str = 0;
+ }
+ } else {
+ if (*curr >= '0' && *curr <= '9') {
+ /* found leading char of an IP address, move base pointer and change state */
+ base = curr;
+ in_str = 1;
+ }
+ }
+ }
+ /* if breaking out while in str, we got to the end of string, so add it */
+ if (in_str) {
+ put_string_into_array_len(result, base, curr - base);
+ }
+ }
+ return result;
+}
+
+#define IP_TRUSTED 1
+#define IP_UNTRUSTED 0
+/*
+ * check whether ip is trusted, return 1 for trusted , 0 for untrusted
+ */
+static int is_proxy_trusted(const char *ipstr, plugin_data *p)
+{
+ data_string* allds = (data_string *)array_get_element(p->conf.forwarder, "all");
+
+ if (allds) {
+ if (strcasecmp(allds->value->ptr, "trust") == 0) {
+ return IP_TRUSTED;
+ } else {
+ return IP_UNTRUSTED;
+ }
+ }
+
+ return (data_string *)array_get_element(p->conf.forwarder, ipstr) ? IP_TRUSTED : IP_UNTRUSTED;
+}
+
+/*
+ * Return char *ip of last address of proxy that is not trusted.
+ * Do not accept "all" keyword here.
+ */
+static const char *last_not_in_array(array *a, plugin_data *p)
+{
+ array *forwarder = p->conf.forwarder;
+
+ for (int i = a->used - 1; i >= 0; i--) {
+ data_string *ds = (data_string *)a->data[i];
+ const char *ip = ds->value->ptr;
+
+ if (!array_get_element(forwarder, ip)) {
+ return ip;
+ }
+ }
+ return NULL;
+}
+
+struct addrinfo *ipstr_to_sockaddr(const char *host)
+{
+ struct addrinfo hints, *res0;
+ int result;
+
+ memset(&hints, 0, sizeof(hints));
+#ifndef AI_NUMERICSERV
+/**
+ * quoting $ man getaddrinfo
+ *
+ * NOTES
+ * AI_ADDRCONFIG, AI_ALL, and AI_V4MAPPED are available since glibc 2.3.3.
+ * AI_NUMERICSERV is available since glibc 2.3.4.
+ */
+#define AI_NUMERICSERV 0
+#endif
+ hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
+
+ result = getaddrinfo(host, NULL, &hints, &res0);
+ if ( result != 0 )
+ {
+ fprintf(stderr,"could not resolve hostname %s because %s\n", host,gai_strerror(result));
+ if (result == EAI_SYSTEM)
+ perror("The system error is ");
+ return NULL;
+ }
+ else
+ if (res0==0)
+ fprintf(stderr, "Problem in resolving hostname %s: succeeded, but no information returned\n", host);
+
+ return res0;
+}
+
+
+
+static void clean_cond_cache(server *srv, connection *con) {
+ config_cond_cache_reset_item(srv, con, COMP_HTTP_REMOTE_IP);
+}
+
+URIHANDLER_FUNC(mod_extforward_uri_handler) {
+ plugin_data *p = p_d;
+ data_string *forwarded = NULL;
+#ifdef HAVE_IPV6
+ char b2[INET6_ADDRSTRLEN + 1];
+ struct addrinfo *addrlist = NULL;
+#endif
+ const char *dst_addr_str = NULL;
+ array *forward_array = NULL;
+ const char *real_remote_addr = NULL;
+#ifdef HAVE_IPV6
+#endif
+
+ if (!con->request.headers) return HANDLER_GO_ON;
+
+ mod_extforward_patch_connection(srv, con, p);
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "-- mod_extforward_uri_handler called");
+ }
+
+ if ((NULL == (forwarded = (data_string *) array_get_element(con->request.headers,"X-Forwarded-For")) &&
+ NULL == (forwarded = (data_string *) array_get_element(con->request.headers, "Forwarded-For")))) {
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "no X-Forwarded-For|Forwarded-For: found, skipping");
+ }
+
+ return HANDLER_GO_ON;
+ }
+
+#ifdef HAVE_IPV6
+ dst_addr_str = inet_ntop(con->dst_addr.plain.sa_family,
+ con->dst_addr.plain.sa_family == AF_INET6 ?
+ (struct sockaddr *)&(con->dst_addr.ipv6.sin6_addr) :
+ (struct sockaddr *)&(con->dst_addr.ipv4.sin_addr),
+ b2,
+ (sizeof b2) - 1);
+#else
+ dst_addr_str = inet_ntoa(con->dst_addr.ipv4.sin_addr);
+#endif
+
+ /* if the remote ip itself is not trusted, then do nothing */
+ if (IP_UNTRUSTED == is_proxy_trusted(dst_addr_str, p)) {
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "remote address is NOT a trusted proxy, skipping");
+ }
+
+ return HANDLER_GO_ON;
+ }
+
+ /* build forward_array from forwarded data_string */
+ forward_array = extract_forward_array(forwarded->value);
+ real_remote_addr = last_not_in_array(forward_array, p);
+
+ if (real_remote_addr != NULL) { /* parsed */
+ sock_addr sock;
+ struct addrinfo *addrs_left;
+ server_socket *srv_sock = con->srv_socket;
+ data_string *forwarded_proto = (data_string *)array_get_element(con->request.headers, "X-Forwarded-Proto");
+
+ if (forwarded_proto && !strcmp(forwarded_proto->value->ptr, "https")) {
+ srv_sock->is_proxy_ssl = 1;
+ } else {
+ srv_sock->is_proxy_ssl = 0;
+ }
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "using address:", real_remote_addr);
+ }
+#ifdef HAVE_IPV6
+ addrlist = ipstr_to_sockaddr(real_remote_addr);
+ sock.plain.sa_family = AF_UNSPEC;
+ for (addrs_left = addrlist; addrs_left != NULL; addrs_left = addrs_left -> ai_next) {
+ sock.plain.sa_family = addrs_left->ai_family;
+ if (sock.plain.sa_family == AF_INET) {
+ sock.ipv4.sin_addr = ((struct sockaddr_in*)addrs_left->ai_addr)->sin_addr;
+ break;
+ } else if (sock.plain.sa_family == AF_INET6) {
+ sock.ipv6.sin6_addr = ((struct sockaddr_in6*)addrs_left->ai_addr)->sin6_addr;
+ break;
+ }
+ }
+#else
+ sock.ipv4.sin_addr.s_addr = inet_addr(real_remote_addr);
+ sock.plain.sa_family = (sock.ipv4.sin_addr.s_addr == 0xFFFFFFFF) ? AF_UNSPEC : AF_INET;
+#endif
+ if (sock.plain.sa_family != AF_UNSPEC) {
+ /* we found the remote address, modify current connection and save the old address */
+ if (con->plugin_ctx[p->id]) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "patching an already patched connection!");
+ handler_ctx_free(con->plugin_ctx[p->id]);
+ con->plugin_ctx[p->id] = NULL;
+ }
+ /* save old address */
+ con->plugin_ctx[p->id] = handler_ctx_init(con->dst_addr, con->dst_addr_buf);
+ /* patch connection address */
+ con->dst_addr = sock;
+ con->dst_addr_buf = buffer_init();
+ buffer_copy_string(con->dst_addr_buf, real_remote_addr);
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "patching con->dst_addr_buf for the accesslog:", real_remote_addr);
+ }
+ /* Now, clean the conf_cond cache, because we may have changed the results of tests */
+ clean_cond_cache(srv, con);
+ }
+#ifdef HAVE_IPV6
+ if (addrlist != NULL ) freeaddrinfo(addrlist);
+#endif
+ }
+ array_free(forward_array);
+
+ /* not found */
+ return HANDLER_GO_ON;
+}
+
+CONNECTION_FUNC(mod_extforward_restore) {
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+
+ if (!hctx) return HANDLER_GO_ON;
+
+ con->dst_addr = hctx->saved_remote_addr;
+ buffer_free(con->dst_addr_buf);
+
+ con->dst_addr_buf = hctx->saved_remote_addr_buf;
+
+ handler_ctx_free(hctx);
+
+ con->plugin_ctx[p->id] = NULL;
+
+ /* Now, clean the conf_cond cache, because we may have changed the results of tests */
+ clean_cond_cache(srv, con);
+
+ return HANDLER_GO_ON;
+}
+
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_extforward_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("extforward");
+
+ p->init = mod_extforward_init;
+ p->handle_uri_raw = mod_extforward_uri_handler;
+ p->handle_request_done = mod_extforward_restore;
+ p->connection_reset = mod_extforward_restore;
+ p->set_defaults = mod_extforward_set_defaults;
+ p->cleanup = mod_extforward_free;
+
+ p->data = NULL;
+
+ return 0;
+}
+