summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Kneschke <jan@kneschke.de>2005-08-09 06:42:33 +0000
committerJan Kneschke <jan@kneschke.de>2005-08-09 06:42:33 +0000
commit75c3a8393a06bcdbf7d9bbfc627728619ae93261 (patch)
treeeabea4f43f18d4bbcc5de838cb9186a3dc906397
parent360aba360f5bb6c8db7f98717d67c08448b7a111 (diff)
downloadlighttpd-git-75c3a8393a06bcdbf7d9bbfc627728619ae93261.tar.gz
added include_shell option to configfiles (merged the rest of the trunk changesets)
git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-merge-1.4.x@530 152afb58-edef-0310-8abb-c4023f1b3aa9
-rw-r--r--configure.in138
-rw-r--r--doc/configuration.txt4
-rw-r--r--doc/lighttpd.conf5
-rw-r--r--src/.cvsignore2
-rw-r--r--src/Makefile.am14
-rw-r--r--src/array.h1
-rw-r--r--src/base.h11
-rw-r--r--src/configfile-glue.c94
-rw-r--r--src/configfile.c135
-rw-r--r--src/configfile.h1
-rw-r--r--src/configparser.y43
-rw-r--r--src/connections.c18
-rw-r--r--src/data_config.c11
-rw-r--r--src/keyvalue.c20
-rw-r--r--src/keyvalue.h3
-rw-r--r--src/mod_alias.c26
-rw-r--r--src/mod_redirect.c28
-rw-r--r--src/mod_rewrite.c13
-rw-r--r--src/plugin.c2
-rw-r--r--src/plugin.h1
-rw-r--r--src/proc_open.c386
-rw-r--r--src/proc_open.h25
-rw-r--r--src/response.c5
-rw-r--r--src/stream.c1
-rwxr-xr-xtests/LightyTest.pm8
-rwxr-xr-xtests/core-var-include.t33
-rw-r--r--tests/docroot/www/pathinfo.php3
-rw-r--r--tests/lighttpd.conf23
-rwxr-xr-xtests/mod-fastcgi.t10
-rwxr-xr-xtests/mod-redirect.t27
-rw-r--r--tests/var-include-sub.conf6
31 files changed, 933 insertions, 164 deletions
diff --git a/configure.in b/configure.in
index 59d059d1..d4e3d4ed 100644
--- a/configure.in
+++ b/configure.in
@@ -96,7 +96,7 @@ AC_ARG_WITH(mysql,
if test \! -x $withval; then
echo "--with-mysql=path-to-mysql_config"
fi
- if $withval | grep -- '--include' ; then
+ if $withval | grep -- '--include' > /dev/null ; then
MYSQL_INCLUDE="`$withval --include | sed s/\'//g`"
else
MYSQL_INCLUDE="`$withval --cflags | sed s/\'//g`"
@@ -364,6 +364,9 @@ AC_ARG_ENABLE(lfs,
esac],[CPPFLAGS="${CPPFLAGS} -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGE_FILES"])
AC_MSG_RESULT($enableval)
+AC_CHECK_SIZEOF(long)
+AC_CHECK_SIZEOF(off_t)
+
if test "x$ac_cv_func_sendfile" = xyes; then
# check if sendfile works
AC_MSG_CHECKING(if sendfile works)
@@ -409,6 +412,7 @@ if test x$ipv6 = xtrue; then
fi
fi
+
AM_CONDITIONAL(CROSS_COMPILING, test "x$cross_compiling" = xyes)
dnl check for fastcgi lib, for the tests only
@@ -440,51 +444,121 @@ AC_CONFIG_FILES([Makefile debian/Makefile src/Makefile doc/Makefile tests/Makefi
openwrt/Makefile openwrt/control openwrt/lighttpd.mk])
AC_OUTPUT
-$ECHO
-$ECHO "Plugins:"
-$ECHO
+
+do_build="mod_cgi mod_fastcgi mod_proxy mod_evhost mod_simple_vhost mod_access mod_alias mod_setenv mod_usertrack mod_auth mod_status mod_accesslog mod_rrdtool mod_secdownload mod_expire mod_compress mod_dirlisting mod_indexfiles mod_userdir"
+
+plugins="mod_rewrite mod_redirect mod_ssi"
+features="regex-conditionals"
if test ! "x$PCRE_LIB" = x; then
- $ECHO "mod_rewrite : enabled"
- $ECHO "mod_redirect : enabled"
- $ECHO "mod_ssi : enabled"
+ do_build="$do_build $plugins"
+ enable_feature="$features"
+else
+ no_build="$no_build $plugins"
+ disable_feature="$features"
+fi
+
+plugins="mod_mysql_vhost"
+if test ! "x$MYSQL_LIBS" = x; then
+ do_build="$do_build $plugins"
else
- $ECHO "mod_rewrite : disabled (libpcre missing)"
- $ECHO "mod_redirect : disabled (libpcre missing)"
- $ECHO "mod_ssi : disabled (libpcre missing)"
+ no_build="$no_build $plugins"
fi
-$ECHO "mod_cgi : enabled"
-$ECHO "mod_fastcgi : enabled"
-$ECHO "mod_proxy : enabled"
-$ECHO "mod_evhost : enabled"
-$ECHO "mod_simple_vhost: enabled"
+plugins="mod_trigger_b4_dl"
+if test ! "x$GDBM_LIB" = x; then
+ do_build="$do_build $plugins"
+else
+ no_build="$no_build $plugins"
+fi
+
+
+features="compress-gzip compress-deflate"
+if test ! "x$Z_LIB" = x; then
+ enable_feature="$enable_feature $features"
+else
+ disable_feature="$disable_feature $features"
+fi
+
+features="compress-bzip2"
+if test ! "x$BZ_LIB" = x; then
+ enable_feature="$enable_feature $features"
+else
+ disable_feature="$disable_feature $features"
+fi
-if test "x$MYSQL_LIBS" = x; then
- $ECHO "mod_mysql_vhost : disabled (libmysqlclient missing or mysql support disabled)"
+features="auth-ldap"
+if test ! "x$LDAP_LIB" = x; then
+ enable_feature="$enable_feature $features"
else
- $ECHO "mod_mysql_vhost : enabled"
+ disable_feature="$disable_feature $features"
fi
-$ECHO "mod_access : enabled"
-$ECHO "mod_alias : enabled"
-$ECHO "mod_setenv : enabled"
-$ECHO "mod_usertrack : enabled"
-if test "x$Z_LIB" = x; then
- $ECHO "mod_compress : disabled (libz missing)"
+features="network-openssl"
+if test ! "x$SSL_LIB" = x; then
+ enable_feature="$enable_feature $features"
else
- $ECHO "mod_compress : enabled"
+ disable_feature="$disable_feature $features"
fi
# no crypt call
+features="auth-crypt"
if test "$ac_cv_search_crypt" = no; then
- $ECHO "mod_auth : enabled, crypt() support disabled"
+ disable_feature="$disable_feature $features"
else
- $ECHO "mod_auth : enabled"
+ enable_feature="$enable_feature $features"
fi
-$ECHO "mod_status : enabled"
-$ECHO "mod_accesslog : enabled"
-$ECHO "mod_rrdtool : enabled"
-$ECHO "mod_secdownload : enabled"
-$ECHO "mod_expire : enabled"
+
+features="network-ipv6"
+if test "$ac_cv_ipv6_support" = yes; then
+ enable_feature="$enable_feature $features"
+else
+ disable_feature="$disable_feature $features"
+fi
+
+features="large-files"
+if test "$enable_lfs" = yes; then
+ enable_feature="$enable_feature $features"
+else
+ disable_feature="$disable_feature $features"
+fi
+
+## post processing
+do_build=`echo $do_build | sed 's/ /\n/g' | sort`
+no_build=`echo $no_build | sed 's/ /\n/g' | sort`
+enable_feature=`echo $enable_feature | sed 's/ /\n/g' | sort`
+disable_feature=`echo $disable_feature | sed 's/ /\n/g' | sort`
+
+## output
+
+$ECHO
+$ECHO "Plugins:"
+$ECHO
+
+$ECHO "enabled: "
+i=0
+for p in $do_build; do
+ $ECHO " $p"
+done
+
+$ECHO "disabled: "
+for p in $no_build; do
+ $ECHO " $p"
+done
+
+$ECHO
+$ECHO "Features:"
+$ECHO
+
+$ECHO "enabled: "
+i=0
+p=""
+for p in $enable_feature; do
+ $ECHO " $p"
+done
+
+$ECHO "disabled: "
+for p in $disable_feature; do
+ $ECHO " $p"
+done
$ECHO
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 66194973..ead31d0e 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -35,6 +35,7 @@ A BNF like notation: ::
<boolean>: ( "enable" | "disable" )
<array> : "(" [ <string> "=>" ] <value> [, [ <string> "=>" ] <value> ]* ")"
INCLUDE : "include" VALUE
+ INCLUDE_SHELL : "include_shell" STRING_VALUE
Example
-------
@@ -60,6 +61,9 @@ Example
# include, relative to dirname of main config file
include "mime.types.conf"
+ # read configuration from output of a command
+ include_shell "/usr/local/bin/confmimetype /etc/mime.types"
+
Conditional Configuration
=========================
diff --git a/doc/lighttpd.conf b/doc/lighttpd.conf
index 02464396..2e4b7cd9 100644
--- a/doc/lighttpd.conf
+++ b/doc/lighttpd.conf
@@ -301,3 +301,8 @@ $HTTP["url"] =~ "\.pdf$" {
#include /etc/lighttpd/lighttpd-inc.conf
## same as above if you run: "lighttpd -f /etc/lighttpd/lighttpd.conf"
#include "lighttpd-inc.conf"
+
+#### include_shell
+#include_shell "echo var.a=1"
+## the above is same as:
+#var.a=1
diff --git a/src/.cvsignore b/src/.cvsignore
index 7e68d178..55061b0a 100644
--- a/src/.cvsignore
+++ b/src/.cvsignore
@@ -9,6 +9,8 @@ lighttpd
.deps
.libs
array
+proc_open
+regex
mod_ssi_exprparser.c
mod_ssi_exprparser.h
configparser.c
diff --git a/src/Makefile.am b/src/Makefile.am
index d8e58f5c..8236b82a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,4 +1,4 @@
-noinst_PROGRAMS=array chunk lemon # simple-fcgi #graphic evalo bench ajp ssl error_test adserver gen-license
+noinst_PROGRAMS=proc_open lemon # simple-fcgi #graphic evalo bench ajp ssl error_test adserver gen-license
sbin_PROGRAMS=lighttpd
bin_PROGRAMS=spawn-fcgi
LEMON=$(top_builddir)/src/lemon
@@ -47,8 +47,7 @@ src = server.c response.c connections.c network.c \
network_write.c network_linux_sendfile.c \
network_freebsd_sendfile.c network_writev.c \
network_solaris_sendfilev.c network_openssl.c \
- configfile.c request.c
-
+ configfile.c request.c proc_open.c
spawn_fcgi_SOURCES=spawn-fcgi.c
@@ -208,7 +207,7 @@ hdr = server.h buffer.h network.h log.h keyvalue.h \
mod_ssi.h mod_ssi_expr.h inet_ntop_cache.h \
configparser.h mod_ssi_exprparser.h \
sys-mmap.h sys-socket.h mod_cml.h mod_cml_funcs.h \
- splaytree.h
+ splaytree.h proc_open.h
DEFS= @DEFS@ -DLIBRARY_DIR="\"$(libdir)\""
@@ -217,11 +216,8 @@ lighttpd_LDADD = $(PCRE_LIB) $(DL_LIB) $(SENDFILE_LIB) $(ATTR_LIB) $(common_liba
lighttpd_LDFLAGS = -export-dynamic
lighttpd_CCPFLAGS = $(FAM_CFLAGS)
-array_SOURCES = array.c buffer.c data_string.c data_count.c
-array_CPPFLAGS= -DDEBUG_ARRAY
-
-chunk_SOURCES = buffer.c chunk.c
-chunk_CPPFLAGS= -DDEBUG_CHUNK
+proc_open_SOURCES = proc_open.c buffer.c
+proc_open_CPPFLAGS= -DDEBUG_PROC_OPEN
#gen_license_SOURCES = license.c md5.c buffer.c gen_license.c
diff --git a/src/array.h b/src/array.h
index 12c18c61..7c79c321 100644
--- a/src/array.h
+++ b/src/array.h
@@ -64,7 +64,6 @@ typedef struct {
data_array *data_array_init(void);
typedef enum { CONFIG_COND_UNSET, CONFIG_COND_EQ, CONFIG_COND_MATCH, CONFIG_COND_NE, CONFIG_COND_NOMATCH } config_cond_t;
-typedef enum { COND_RESULT_FALSE, COND_RESULT_TRUE, COND_RESULT_UNSET } cond_result_t;
#define PATCHES NULL, "SERVERsocket", "HTTPurl", "HTTPhost", "HTTPreferer", "HTTPuseragent", "HTTPcookie", "HTTPremoteip"
typedef enum {
diff --git a/src/base.h b/src/base.h
index 84b2c142..fd3dce86 100644
--- a/src/base.h
+++ b/src/base.h
@@ -290,6 +290,14 @@ typedef struct {
typedef enum { CON_STATE_CONNECT, CON_STATE_REQUEST_START, CON_STATE_READ, CON_STATE_REQUEST_END, CON_STATE_READ_POST, CON_STATE_HANDLE_REQUEST, CON_STATE_RESPONSE_START, CON_STATE_WRITE, CON_STATE_RESPONSE_END, CON_STATE_ERROR, CON_STATE_CLOSE } connection_state_t;
+typedef enum { COND_RESULT_UNSET, COND_RESULT_FALSE, COND_RESULT_TRUE } cond_result_t;
+typedef struct {
+ cond_result_t result;
+ int patterncount;
+ int matches[3 * 10];
+ buffer *comp_value; /* just a pointer */
+} cond_cache_t;
+
typedef struct {
connection_state_t state;
@@ -336,6 +344,7 @@ typedef struct {
int http_status;
sock_addr dst_addr;
+ buffer *dst_addr_buf;
/* request */
buffer *parse_request;
@@ -361,7 +370,7 @@ typedef struct {
void **plugin_ctx; /* plugin connection specific config */
specific_config conf; /* global connection specific config */
- cond_result_t *cond_results_cache;
+ cond_cache_t *cond_cache;
buffer *server_name;
diff --git a/src/configfile-glue.c b/src/configfile-glue.c
index 00e28ea8..3f20f6e7 100644
--- a/src/configfile-glue.c
+++ b/src/configfile-glue.c
@@ -147,7 +147,7 @@ int config_insert_values_global(server *srv, array *ca, const config_values_t cv
return config_insert_values_internal(srv, ca, cv);
}
-static int config_check_cond_cached(server *srv, connection *con, data_config *dc);
+static cond_result_t config_check_cond_cached(server *srv, connection *con, data_config *dc);
static cond_result_t config_check_cond_nocache(server *srv, connection *con, data_config *dc) {
buffer *l;
@@ -155,21 +155,21 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
/* check parent first */
if (dc->parent && dc->parent->context_ndx) {
if (con->conf.log_condition_handling) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "go parent", dc->parent->string);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "go parent", dc->parent->key);
}
- if (!config_check_cond_cached(srv, con, dc->parent)) {
+ if (config_check_cond_cached(srv, con, dc->parent) == COND_RESULT_FALSE) {
return COND_RESULT_FALSE;
}
}
if (dc->prev) {
if (con->conf.log_condition_handling) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "go prev", dc->prev->string);
+ log_error_write(srv, __FILE__, __LINE__, "sb", "go prev", dc->prev->key);
}
/* make sure prev is checked first */
config_check_cond_cached(srv, con, dc->prev);
/* one of prev set me to FALSE */
- if (con->cond_results_cache[dc->context_ndx] == COND_RESULT_FALSE) {
+ if (COND_RESULT_FALSE == con->cond_cache[dc->context_ndx].result) {
return COND_RESULT_FALSE;
}
}
@@ -178,7 +178,8 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
l = srv->empty_string;
- if (COMP_HTTP_HOST == dc->comp) {
+ switch (dc->comp) {
+ case COMP_HTTP_HOST: {
l = con->uri.authority;
#if 0
/* FIXME: get this working again */
@@ -208,7 +209,9 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
break;
}
}
- } else if (COMP_HTTP_REMOTEIP == dc->comp) {
+ break;
+ }
+ case COMP_HTTP_REMOTEIP: {
char *nm_slash;
/* handle remoteip limitations
*
@@ -283,27 +286,40 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
buffer_copy_string(srv->cond_check_buf, s);
}
#endif
- } else if (COMP_HTTP_URL == dc->comp) {
+ break;
+ }
+ case COMP_HTTP_URL:
l = con->uri.path;
- } else if (COMP_SERVER_SOCKET == dc->comp) {
+ break;
+
+ case COMP_SERVER_SOCKET:
l = srv_sock->srv_token;
- } else if (COMP_HTTP_REFERER == dc->comp) {
+ break;
+
+ case COMP_HTTP_REFERER: {
data_string *ds;
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
l = ds->value;
}
- } else if (COMP_HTTP_COOKIE == dc->comp) {
+ break;
+ }
+ case COMP_HTTP_COOKIE: {
data_string *ds;
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
l = ds->value;
}
- } else if (COMP_HTTP_USERAGENT == dc->comp) {
+ break;
+ }
+ case COMP_HTTP_USERAGENT: {
data_string *ds;
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "User-Agent"))) {
l = ds->value;
}
- } else {
+ break;
+ }
+
+ default:
return COND_RESULT_FALSE;
}
@@ -322,15 +338,21 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
#ifdef HAVE_PCRE_H
case CONFIG_COND_NOMATCH:
case CONFIG_COND_MATCH: {
-#define N 10
- int ovec[N * 3];
+ cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
int n;
- n = pcre_exec(dc->regex, dc->regex_study, l->ptr, l->used - 1, 0, 0, ovec, N * 3);
+#ifndef elementsof
+#define elementsof(x) (sizeof(x) / sizeof(x[0]))
+#endif
+ n = pcre_exec(dc->regex, dc->regex_study, l->ptr, l->used - 1, 0, 0,
+ cache->matches, elementsof(cache->matches));
if (n > 0) {
+ cache->patterncount = n;
+ cache->comp_value = l;
return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
} else {
+ /* cache is already cleared */
return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
}
break;
@@ -344,36 +366,56 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
return COND_RESULT_FALSE;
}
-static int config_check_cond_cached(server *srv, connection *con, data_config *dc) {
- cond_result_t *cache = con->cond_results_cache;
+static cond_result_t config_check_cond_cached(server *srv, connection *con, data_config *dc) {
+ cond_cache_t *caches = con->cond_cache;
- if (cache[dc->context_ndx] == COND_RESULT_UNSET) {
- if (COND_RESULT_TRUE == (cache[dc->context_ndx] = config_check_cond_nocache(srv, con, dc))) {
+ if (COND_RESULT_UNSET == caches[dc->context_ndx].result) {
+ if (COND_RESULT_TRUE == (caches[dc->context_ndx].result = config_check_cond_nocache(srv, con, dc))) {
if (dc->next) {
data_config *c;
if (con->conf.log_condition_handling) {
- log_error_write(srv, __FILE__, __LINE__, "s", "setting remains of chaining to FALSE");
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "setting remains of chaining to false");
}
for (c = dc->next; c; c = c->next) {
- cache[c->context_ndx] = COND_RESULT_FALSE;
+ caches[c->context_ndx].result = COND_RESULT_FALSE;
}
}
}
if (con->conf.log_condition_handling) {
- log_error_write(srv, __FILE__, __LINE__, "dsd", dc->context_ndx, "(uncached) result:", cache[dc->context_ndx]);
+ log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
+ "(uncached) result:",
+ caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
}
}
else {
if (con->conf.log_condition_handling) {
- log_error_write(srv, __FILE__, __LINE__, "dsd", dc->context_ndx, "(cached) result:", cache[dc->context_ndx]);
+ log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
+ "(cached) result:",
+ caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
}
}
- return cache[dc->context_ndx];
+ return caches[dc->context_ndx].result;
}
int config_check_cond(server *srv, connection *con, data_config *dc) {
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "=== start of condition block ===");
}
- return config_check_cond_cached(srv, con, dc);
+ return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE);
}
+
+int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n)
+{
+ cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
+ if (n > cache->patterncount) {
+ return 0;
+ }
+
+ n <<= 1; /* n *= 2 */
+ buffer_append_string_len(buf,
+ cache->comp_value->ptr + cache->matches[n],
+ cache->matches[n + 1] - cache->matches[n]);
+ return 1;
+}
+
diff --git a/src/configfile.c b/src/configfile.c
index 0597eb3a..a58de1a1 100644
--- a/src/configfile.c
+++ b/src/configfile.c
@@ -19,6 +19,7 @@
#include "configparser.h"
#include "configfile.h"
+#include "proc_open.h"
static int config_insert(server *srv) {
@@ -225,11 +226,6 @@ static int config_insert(server *srv) {
#define PATCH(x) con->conf.x = s->x
int config_setup_connection(server *srv, connection *con) {
specific_config *s = srv->config_storage[0];
- int i;
-
- for (i = srv->config_context->used - 1; i >= 0; i --) {
- con->cond_results_cache[i] = COND_RESULT_UNSET;
- }
PATCH(allow_http11);
PATCH(mimetypes);
@@ -351,12 +347,12 @@ int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
return 0;
}
#undef PATCH
+
typedef struct {
int foo;
int bar;
- buffer *file;
- stream s;
+ const buffer *source;
const char *input;
size_t offset;
size_t size;
@@ -369,6 +365,7 @@ typedef struct {
int in_cond;
} tokenizer_t;
+#if 0
static int tokenizer_open(server *srv, tokenizer_t *t, buffer *basedir, const char *fn) {
if (buffer_is_empty(basedir) &&
(fn[0] == '/' || fn[0] == '\\') &&
@@ -404,7 +401,7 @@ static int tokenizer_close(server *srv, tokenizer_t *t) {
buffer_free(t->file);
return stream_close(&(t->s));
}
-
+#endif
static int config_skip_newline(tokenizer_t *t) {
int skipped = 1;
assert(t->input[t->offset] == '\r' || t->input[t->offset] == '\n');
@@ -445,7 +442,7 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
tid = TK_ARRAY_ASSIGN;
} else {
log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
- "file:", t->file,
+ "source:", t->source,
"line:", t->line, "pos:", t->line_pos,
"use => for assignments in arrays");
return -1;
@@ -465,7 +462,7 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
tid = TK_MATCH;
} else {
log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
- "file:", t->file,
+ "source:", t->source,
"line:", t->line, "pos:", t->line_pos,
"only =~ and == are allow in the condition");
return -1;
@@ -481,7 +478,7 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
t->line_pos++;
} else {
log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
- "file:", t->file,
+ "source:", t->source,
"line:", t->line, "pos:", t->line_pos,
"unexpected equal-sign: =");
return -1;
@@ -504,7 +501,7 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
tid = TK_NOMATCH;
} else {
log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
- "file:", t->file,
+ "source:", t->source,
"line:", t->line, "pos:", t->line_pos,
"only !~ and != are allow in the condition");
return -1;
@@ -513,7 +510,7 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
t->in_cond = 0;
} else {
log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
- "file:", t->file,
+ "source:", t->source,
"line:", t->line, "pos:", t->line_pos,
"unexpected exclamation-marks: !");
return -1;
@@ -603,7 +600,7 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
/* ERROR */
log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
- "file:", t->file,
+ "source:", t->source,
"line:", t->line, "pos:", t->line_pos,
"missing closing quote");
@@ -646,8 +643,7 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
t->offset += 2;
buffer_copy_string(token, "+=");
tid = TK_APPEND;
- }
- else {
+ } else {
t->offset++;
tid = TK_PLUS;
buffer_copy_string(token, "+");
@@ -708,7 +704,7 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
} else {
/* ERROR */
log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
- "file:", t->file,
+ "source:", t->source,
"line:", t->line, "pos:", t->line_pos,
"invalid character in condition");
return -1;
@@ -728,7 +724,7 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
} else {
/* ERROR */
log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
- "file:", t->file,
+ "source:", t->source,
"line:", t->line, "pos:", t->line_pos,
"unexpected EOF");
@@ -748,6 +744,8 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
if (strcmp(token->ptr, "include") == 0) {
tid = TK_INCLUDE;
+ } else if (strcmp(token->ptr, "include_shell") == 0) {
+ tid = TK_INCLUDE_SHELL;
} else if (strcmp(token->ptr, "else") == 0) {
tid = TK_ELSE;
} else {
@@ -759,7 +757,7 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
} else {
/* ERROR */
log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
- "file:", t->file,
+ "source:", t->source,
"line:", t->line, "pos:", t->line_pos,
"invalid character in variable name");
return -1;
@@ -773,7 +771,7 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
*token_id = tid;
#if 0
log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
- "file:", t->file,
+ "source:", t->source,
"line:", t->line, "pos:", t->line_pos,
token, token->used - 1, tid);
#endif
@@ -787,21 +785,16 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
return 0;
}
-int config_parse_file(server *srv, config_t *context, const char *fn) {
- tokenizer_t t;
+static int config_parse(server *srv, config_t *context, tokenizer_t *t) {
void *pParser;
int token_id;
buffer *token, *lasttoken;
int ret;
- if (tokenizer_open(srv, &t, context->basedir, fn) == -1) {
- return -1;
- }
-
pParser = configparserAlloc( malloc );
lasttoken = buffer_init();
token = buffer_init();
- while((1 == (ret = config_tokenizer(srv, &t, &token_id, token))) && context->ok) {
+ while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) {
buffer_copy_string_buffer(lasttoken, token);
configparser(pParser, token_id, token, context);
@@ -821,20 +814,98 @@ int config_parse_file(server *srv, config_t *context, const char *fn) {
if (ret == -1) {
log_error_write(srv, __FILE__, __LINE__, "sb",
"configfile parser failed:", lasttoken);
- }
- else if (context->ok == 0) {
+ } else if (context->ok == 0) {
log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
- "file:", t.file,
- "line:", t.line, "pos:", t.line_pos,
+ "source:", t->source,
+ "line:", t->line, "pos:", t->line_pos,
"parser failed somehow near here:", lasttoken);
ret = -1;
}
buffer_free(lasttoken);
- tokenizer_close(srv, &t);
return ret == -1 ? -1 : 0;
}
+static int tokenizer_init(tokenizer_t *t, const buffer *source, const char *input, size_t size) {
+
+ t->source = source;
+ t->input = input;
+ t->size = size;
+ t->offset = 0;
+ t->line = 1;
+ t->line_pos = 1;
+
+ t->in_key = 1;
+ t->in_brace = 0;
+ t->in_cond = 0;
+ return 0;
+}
+
+int config_parse_file(server *srv, config_t *context, const char *fn) {
+ tokenizer_t t;
+ stream s;
+ int ret;
+ buffer *filename;
+
+ if (buffer_is_empty(context->basedir) &&
+ (fn[0] == '/' || fn[0] == '\\') &&
+ (fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\'))) {
+ filename = buffer_init_string(fn);
+ } else {
+ filename = buffer_init_buffer(context->basedir);
+ buffer_append_string(filename, fn);
+ }
+
+ if (0 != stream_open(&s, filename)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
+ "opening configfile ", filename, "failed:", strerror(errno));
+ ret = -1;
+ } else {
+ tokenizer_init(&t, filename, s.start, s.size);
+ ret = config_parse(srv, context, &t);
+ }
+
+ stream_close(&s);
+ buffer_free(filename);
+ return ret;
+}
+
+int config_parse_cmd(server *srv, config_t *context, const char *cmd) {
+ proc_handler_t proc;
+ tokenizer_t t;
+ int ret;
+ buffer *source;
+ buffer *out;
+ char oldpwd[PATH_MAX];
+
+ if (NULL == getcwd(oldpwd, sizeof(oldpwd))) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "cannot get cwd", strerror(errno));
+ return -1;
+ }
+
+ source = buffer_init_string(cmd);
+ out = buffer_init();
+
+ if (!buffer_is_empty(context->basedir)) {
+ chdir(context->basedir->ptr);
+ }
+
+ if (0 != proc_open_buffer(&proc, cmd, NULL, out, NULL)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
+ "opening", source, "failed:", strerror(errno));
+ ret = -1;
+ } else {
+ tokenizer_init(&t, source, out->ptr, out->used);
+ ret = config_parse(srv, context, &t);
+ }
+
+ buffer_free(source);
+ buffer_free(out);
+ chdir(oldpwd);
+ return ret;
+}
+
static void context_init(server *srv, config_t *context) {
context->srv = srv;
context->ok = 1;
diff --git a/src/configfile.h b/src/configfile.h
index f8dc9bb2..a58a257d 100644
--- a/src/configfile.h
+++ b/src/configfile.h
@@ -18,5 +18,6 @@ void *configparserAlloc(void *(*mallocProc)(size_t));
void configparserFree(void *p, void (*freeProc)(void*));
void configparser(void *yyp, int yymajor, buffer *yyminor, config_t *ctx);
int config_parse_file(server *srv, config_t *context, const char *fn);
+int config_parse_cmd(server *srv, config_t *context, const char *cmd);
#endif
diff --git a/src/configparser.y b/src/configparser.y
index 23e19140..06fa6955 100644
--- a/src/configparser.y
+++ b/src/configparser.y
@@ -131,6 +131,7 @@ metalines ::= .
metaline ::= varline.
metaline ::= condlines(A) EOL. { A = NULL; }
metaline ::= include.
+metaline ::= include_shell.
metaline ::= EOL.
%type value {data_unset *}
@@ -141,17 +142,17 @@ metaline ::= EOL.
%type aelements {array *}
%type array {array *}
%type key {buffer *}
+%type stringop {buffer *}
%type cond {config_cond_t }
%destructor value { $$->free($$); }
%destructor expression { $$->free($$); }
%destructor aelement { $$->free($$); }
-%destructor condline { $$->free((data_unset *)$$); }
-%destructor condlines { $$->free((data_unset *)$$); }
%destructor aelements { array_free($$); }
%destructor array { array_free($$); }
%destructor key { buffer_free($$); }
+%destructor stringop { buffer_free($$); }
%token_type {buffer *}
%token_destructor { buffer_free($$); }
@@ -347,7 +348,7 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET STRING(C) RBRACKET cond(E) expression(
break;
default:
assert(0);
- break;
+ return;
}
b = buffer_init();
@@ -470,18 +471,36 @@ cond(A) ::= NOMATCH. {
A = CONFIG_COND_NOMATCH;
}
-include ::= INCLUDE expression(A). {
+stringop(A) ::= expression(B). {
+ A = NULL;
if (ctx->ok) {
- if (A->type != TYPE_STRING) {
- fprintf(stderr, "file must be string");
+ if (B->type != TYPE_STRING) {
+ fprintf(stderr, "operand must be string");
ctx->ok = 0;
} else {
- buffer *file = ((data_string*)A)->value;
- if (0 != config_parse_file(ctx->srv, ctx, file->ptr)) {
- ctx->ok = 0;
- }
+ A = buffer_init_buffer(((data_string*)B)->value);
}
}
- A->free(A);
- A = NULL;
+ B->free(B);
+ B = NULL;
+}
+
+include ::= INCLUDE stringop(A). {
+ if (ctx->ok) {
+ if (0 != config_parse_file(ctx->srv, ctx, A->ptr)) {
+ ctx->ok = 0;
+ }
+ buffer_free(A);
+ A = NULL;
+ }
+}
+
+include_shell ::= INCLUDE_SHELL stringop(A). {
+ if (ctx->ok) {
+ if (0 != config_parse_cmd(ctx->srv, ctx, A->ptr)) {
+ ctx->ok = 0;
+ }
+ buffer_free(A);
+ A = NULL;
+ }
}
diff --git a/src/connections.c b/src/connections.c
index 1842f3c6..f525a5d5 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -23,6 +23,8 @@
#include "plugin.h"
+#include "inet_ntop_cache.h"
+
#ifdef USE_OPENSSL
# include <openssl/ssl.h>
# include <openssl/err.h>
@@ -479,6 +481,7 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
break;
}
+ case 207:
break;
default:
if (con->request.http_method == HTTP_METHOD_HEAD ||
@@ -603,7 +606,8 @@ connection *connection_init(server *srv) {
con->plugin_ctx = calloc(srv->plugins.used + 1, sizeof(void *));
- con->cond_results_cache = calloc(srv->config_context->used, sizeof(cond_result_t));
+ con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t));
+ con->dst_addr_buf = buffer_init();
config_setup_connection(srv, con);
return con;
@@ -653,7 +657,7 @@ void connections_free(server *srv) {
CLEAN(error_handler);
#undef CLEAN
free(con->plugin_ctx);
- free(con->cond_results_cache);
+ free(con->cond_cache);
free(con);
}
@@ -753,6 +757,15 @@ int connection_reset(server *srv, connection *con) {
con->plugin_ctx[i] = NULL;
}
+#if COND_RESULT_UNSET
+ for (i = srv->config_context->used - 1; i >= 0; i --) {
+ con->cond_cache[i].result = COND_RESULT_UNSET;
+ con->cond_cache[i].patterncount = 0;
+ }
+#else
+ memset(con->cond_cache, 0, sizeof(cond_cache_t) * srv->config_context->used);
+#endif
+
con->header_len = 0;
con->in_error_handler = 0;
@@ -1132,6 +1145,7 @@ connection *connection_accept(server *srv, server_socket *srv_socket) {
con->connection_start = srv->cur_ts;
con->dst_addr = cnt_addr;
+ buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
con->srv_socket = srv_socket;
if (-1 == (fdevent_fcntl_set(srv->ev, con->fd))) {
diff --git a/src/data_config.c b/src/data_config.c
index 90cdd367..529df359 100644
--- a/src/data_config.c
+++ b/src/data_config.c
@@ -73,10 +73,13 @@ static void data_config_print(const data_unset *d, int depth) {
for (i = 0; i < ds->childs->used; i ++) {
data_unset *du = ds->childs->data[i];
- fprintf(stderr, "\n");
- array_print_indent(depth + 1);
- du->print(du, depth + 1);
- fprintf(stderr, "\n");
+ /* only the 1st block of chaining */
+ if (NULL == ((data_config *)du)->prev) {
+ fprintf(stderr, "\n");
+ array_print_indent(depth + 1);
+ du->print(du, depth + 1);
+ fprintf(stderr, "\n");
+ }
}
}
diff --git a/src/keyvalue.c b/src/keyvalue.c
index 9af6d510..74886985 100644
--- a/src/keyvalue.c
+++ b/src/keyvalue.c
@@ -292,6 +292,7 @@ int pcre_keyvalue_buffer_append(pcre_keyvalue_buffer *kvb, const char *key, cons
size_t i;
const char *errptr;
int erroff;
+ pcre_keyvalue *kv;
#endif
if (!key) return -1;
@@ -316,14 +317,20 @@ int pcre_keyvalue_buffer_append(pcre_keyvalue_buffer *kvb, const char *key, cons
}
}
- if (NULL == (kvb->kv[kvb->used]->key = pcre_compile(key,
+ kv = kvb->kv[kvb->used];
+ if (NULL == (kv->key = pcre_compile(key,
0, &errptr, &erroff, NULL))) {
fprintf(stderr, "%s.%d: rexexp compilation error at %s\n", __FILE__, __LINE__, errptr);
return -1;
}
+
+ if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&
+ errptr != NULL) {
+ return -1;
+ }
- kvb->kv[kvb->used]->value = strdup(value);
+ kv->value = buffer_init_string(value);
kvb->used++;
@@ -339,11 +346,14 @@ int pcre_keyvalue_buffer_append(pcre_keyvalue_buffer *kvb, const char *key, cons
void pcre_keyvalue_buffer_free(pcre_keyvalue_buffer *kvb) {
#ifdef HAVE_PCRE_H
size_t i;
+ pcre_keyvalue *kv;
for (i = 0; i < kvb->size; i++) {
- if (kvb->kv[i]->key) pcre_free(kvb->kv[i]->key);
- if (kvb->kv[i]->value) free(kvb->kv[i]->value);
- free(kvb->kv[i]);
+ kv = kvb->kv[i];
+ if (kv->key) pcre_free(kv->key);
+ if (kv->key_extra) pcre_free(kv->key_extra);
+ if (kv->value) buffer_free(kv->value);
+ free(kv);
}
if (kvb->kv) free(kvb->kv);
diff --git a/src/keyvalue.h b/src/keyvalue.h
index 9d31fab9..de7056ff 100644
--- a/src/keyvalue.h
+++ b/src/keyvalue.h
@@ -25,9 +25,10 @@ typedef struct {
typedef struct {
#ifdef HAVE_PCRE_H
pcre *key;
+ pcre_extra *key_extra;
#endif
- char *value;
+ buffer *value;
} pcre_keyvalue;
typedef enum { HTTP_AUTH_BASIC, HTTP_AUTH_DIGEST } httpauth_type;
diff --git a/src/mod_alias.c b/src/mod_alias.c
index e4869493..4d898922 100644
--- a/src/mod_alias.c
+++ b/src/mod_alias.c
@@ -1,6 +1,7 @@
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
+#include <stdio.h>
#include "base.h"
#include "log.h"
@@ -86,6 +87,31 @@ SETDEFAULTS_FUNC(mod_alias_set_defaults) {
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
+ if (s->alias->used >= 2) {
+ const array *a = s->alias;
+ size_t j, k;
+
+ for (j = 0; j < a->used; j ++) {
+ const buffer *prefix = a->data[a->sorted[j]]->key;
+ for (k = j + 1; k < a->used; k ++) {
+ const buffer *key = a->data[a->sorted[k]]->key;
+
+ if (key->used < prefix->used) {
+ break;
+ }
+ if (memcmp(key->ptr, prefix->ptr, prefix->used - 1) != 0) {
+ break;
+ }
+ /* ok, they have same prefix. check position */
+ if (a->sorted[j] < a->sorted[k]) {
+ fprintf(stderr, "url.alias: `%s' will never match as `%s' matched first\n",
+ key->ptr,
+ prefix->ptr);
+ return HANDLER_ERROR;
+ }
+ }
+ }
+ }
}
return HANDLER_GO_ON;
diff --git a/src/mod_redirect.c b/src/mod_redirect.c
index e6578ffa..aa0c8207 100644
--- a/src/mod_redirect.c
+++ b/src/mod_redirect.c
@@ -15,6 +15,7 @@
typedef struct {
pcre_keyvalue_buffer *redirect;
+ data_config *context; /* to which apply me */
} plugin_config;
typedef struct {
@@ -165,6 +166,7 @@ static int mod_redirect_patch_connection(server *srv, connection *con, plugin_da
if (0 == strcmp(du->key->ptr, "url.redirect")) {
p->conf.redirect = s->redirect;
+ p->conf.context = dc;
}
}
}
@@ -190,19 +192,22 @@ static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_
for (i = 0; i < p->conf.redirect->used; i++) {
pcre *match;
+ pcre_extra *extra;
const char *pattern;
size_t pattern_len;
int n;
+ pcre_keyvalue *kv = p->conf.redirect->kv[i];
# define N 10
int ovec[N * 3];
- match = p->conf.redirect->kv[i]->key;
- pattern = p->conf.redirect->kv[i]->value;
- pattern_len = strlen(pattern);
+ match = kv->key;
+ extra = kv->key_extra;
+ pattern = kv->value->ptr;
+ pattern_len = kv->value->used - 1;
- if ((n = pcre_exec(match, NULL, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
+ if ((n = pcre_exec(match, extra, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
if (n != PCRE_ERROR_NOMATCH) {
- log_error_write(srv, __FILE__, __LINE__, "sd"
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"execution error while matching: ", n);
return HANDLER_ERROR;
}
@@ -210,6 +215,7 @@ static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_
const char **list;
size_t start, end;
size_t k;
+
/* it matched */
pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
@@ -219,7 +225,7 @@ static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_
start = 0; end = pattern_len;
for (k = 0; k < pattern_len; k++) {
- if (pattern[k] == '$' &&
+ if ((pattern[k] == '$' || pattern[k] == '%') &&
isdigit((unsigned char)pattern[k + 1])) {
/* got one */
@@ -229,9 +235,13 @@ static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_
buffer_append_string_len(p->location, pattern + start, end - start);
- /* n is always > 0 */
- if (num < (size_t)n) {
- buffer_append_string(p->location, list[num]);
+ if (pattern[k] == '$') {
+ /* n is always > 0 */
+ if (num < (size_t)n) {
+ buffer_append_string(p->location, list[num]);
+ }
+ } else {
+ config_append_cond_match_buffer(con, p->conf.context, p->location, num);
}
k++;
diff --git a/src/mod_rewrite.c b/src/mod_rewrite.c
index 345f6f6c..8674c59a 100644
--- a/src/mod_rewrite.c
+++ b/src/mod_rewrite.c
@@ -31,6 +31,7 @@ typedef struct {
typedef struct {
rewrite_rule_buffer *rewrite;
+ data_config *context; /* to which apply me */
} plugin_config;
typedef struct {
@@ -377,7 +378,7 @@ URIHANDLER_FUNC(mod_rewrite_uri_handler) {
start = 0; end = pattern_len;
for (k = 0; k < pattern_len; k++) {
- if (pattern[k] == '$' &&
+ if ((pattern[k] == '$' || pattern[k] == '%') &&
isdigit((unsigned char)pattern[k + 1])) {
/* got one */
@@ -387,9 +388,13 @@ URIHANDLER_FUNC(mod_rewrite_uri_handler) {
buffer_append_string_len(con->request.uri, pattern + start, end - start);
- /* n is always larger than 0 */
- if (num < (size_t)n) {
- buffer_append_string(con->request.uri, list[num]);
+ if (pattern[k] == '$') {
+ /* n is always > 0 */
+ if (num < (size_t)n) {
+ buffer_append_string(con->request.uri, list[num]);
+ }
+ } else {
+ config_append_cond_match_buffer(con, p->conf.context, con->request.uri, num);
}
k++;
diff --git a/src/plugin.c b/src/plugin.c
index 4e53a26e..d861b918 100644
--- a/src/plugin.c
+++ b/src/plugin.c
@@ -62,7 +62,7 @@ static void plugin_free(plugin *p) {
int use_dlclose = 1;
if (p->name) buffer_free(p->name);
#ifdef HAVE_VALGRIND_VALGRIND_H
- if (RUNNING_ON_VALGRIND) use_dlclose = 0;
+ /*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
#endif
if (use_dlclose && p->lib) {
diff --git a/src/plugin.h b/src/plugin.h
index dad01424..dd2b59a9 100644
--- a/src/plugin.h
+++ b/src/plugin.h
@@ -89,5 +89,6 @@ int config_insert_values_internal(server *srv, array *ca, const config_values_t
int config_setup_connection(server *srv, connection *con);
int config_patch_connection(server *srv, connection *con, comp_key_t comp);
int config_check_cond(server *srv, connection *con, data_config *dc);
+int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n);
#endif
diff --git a/src/proc_open.c b/src/proc_open.c
new file mode 100644
index 00000000..ecea815a
--- /dev/null
+++ b/src/proc_open.c
@@ -0,0 +1,386 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include "proc_open.h"
+
+#ifdef WIN32
+#include <io.h>
+#include <fcntl.h>
+#else
+#include <sys/wait.h>
+#include <unistd.h>
+#endif
+
+
+#ifdef WIN32
+/* {{{ win32 stuff */
+# define SHELLENV "ComSpec"
+# define SECURITY_DC , SECURITY_ATTRIBUTES *security
+# define SECURITY_CC , security
+# define pipe(pair) (CreatePipe(&pair[0], &pair[1], security, 2048L) ? 0 : -1)
+static inline HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
+{
+ HANDLE copy, self = GetCurrentProcess();
+
+ if (!DuplicateHandle(self, src, self, &copy, 0, inherit, DUPLICATE_SAME_ACCESS |
+ (closeorig ? DUPLICATE_CLOSE_SOURCE : 0)))
+ return NULL;
+ return copy;
+}
+# define close_descriptor(fd) CloseHandle(fd)
+static void pipe_close_parent(pipe_t *p) {
+ /* don't let the child inherit the parent side of the pipe */
+ p->parent = dup_handle(p->parent, FALSE, TRUE);
+}
+static void pipe_close_child(pipe_t *p) {
+ close_descriptor(p->child);
+ p->fd = _open_osfhandle((long)p->parent,
+ (p->fd == 0 ? O_RDONLY : O_WRONLY)|O_BINARY);
+}
+/* }}} */
+#else /* WIN32 */
+/* {{{ unix way */
+# define SHELLENV "SHELL"
+# define SECURITY_DC
+# define SECURITY_CC
+# define close_descriptor(fd) close(fd)
+static void pipe_close_parent(pipe_t *p) {
+ /* don't close stdin */
+ close_descriptor(p->parent);
+ if (dup2(p->child, p->fd) != p->fd) {
+ perror("pipe_child dup2");
+ } else {
+ close_descriptor(p->child);
+ p->child = p->fd;
+ }
+}
+static void pipe_close_child(pipe_t *p) {
+ close_descriptor(p->child);
+ p->fd = p->parent;
+}
+/* }}} */
+#endif /* WIN32 */
+
+/* {{{ pipe_close */
+static void pipe_close(pipe_t *p) {
+ close_descriptor(p->parent);
+ close_descriptor(p->child);
+#ifdef WIN32
+ close(p->fd);
+#endif
+}
+/* }}} */
+/* {{{ pipe_open */
+static int pipe_open(pipe_t *p, int fd SECURITY_DC) {
+ descriptor_t newpipe[2];
+
+ if (0 != pipe(newpipe)) {
+ fprintf(stderr, "can't open pipe");
+ return -1;
+ }
+ if (0 == fd) {
+ p->parent = newpipe[1]; /* write */
+ p->child = newpipe[0]; /* read */
+ } else {
+ p->parent = newpipe[0]; /* read */
+ p->child = newpipe[1]; /* write */
+ }
+ p->fd = fd;
+
+ return 0;
+}
+/* }}} */
+
+/* {{{ proc_open_pipes */
+static int proc_open_pipes(proc_handler_t *proc SECURITY_DC) {
+ if (pipe_open(&(proc->in), 0 SECURITY_CC) != 0) {
+ return -1;
+ }
+ if (pipe_open(&(proc->out), 1 SECURITY_CC) != 0) {
+ return -1;
+ }
+ if (pipe_open(&(proc->err), 2 SECURITY_CC) != 0) {
+ return -1;
+ }
+ return 0;
+}
+/* }}} */
+/* {{{ proc_close_pipes */
+static void proc_close_pipes(proc_handler_t *proc) {
+ pipe_close(&proc->in);
+ pipe_close(&proc->out);
+ pipe_close(&proc->err);
+}
+/* }}} */
+/* {{{ proc_close_parents */
+static void proc_close_parents(proc_handler_t *proc) {
+ pipe_close_parent(&proc->in);
+ pipe_close_parent(&proc->out);
+ pipe_close_parent(&proc->err);
+}
+/* }}} */
+/* {{{ proc_close_childs */
+static void proc_close_childs(proc_handler_t *proc) {
+ pipe_close_child(&proc->in);
+ pipe_close_child(&proc->out);
+ pipe_close_child(&proc->err);
+}
+/* }}} */
+
+#ifdef WIN32
+/* {{{ proc_close */
+int proc_close(proc_handler_t *proc) {
+ proc_pid_t child = proc->child;
+ DWORD wstatus;
+
+ proc_close_pipes(proc);
+ WaitForSingleObject(child, INFINITE);
+ GetExitCodeProcess(child, &wstatus);
+ CloseHandle(child);
+
+ return wstatus;
+}
+/* }}} */
+/* {{{ proc_open */
+int proc_open(proc_handler_t *proc, const char *command) {
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si;
+ BOOL procok;
+ SECURITY_ATTRIBUTES security;
+ const char *shell;
+ buffer *cmdline;
+
+ if (NULL == (shell = getenv(SHELLENV))) {
+ fprintf(stderr, "env %s is required", SHELLENV);
+ return -1;
+ }
+
+ /* we use this to allow the child to inherit handles */
+ memset(&security, 0, sizeof(security));
+ security.nLength = sizeof(security);
+ security.bInheritHandle = TRUE;
+ security.lpSecurityDescriptor = NULL;
+
+ if (proc_open_pipes(proc, &security) != 0) {
+ return -1;
+ }
+ proc_close_parents(proc);
+
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdInput = proc->in.child;
+ si.hStdOutput = proc->out.child;
+ si.hStdError = proc->err.child;
+
+ memset(&pi, 0, sizeof(pi));
+
+ cmdline = buffer_init();
+ buffer_append_string(cmdline, shell);
+ buffer_append_string_len(cmdline, CONST_STR_LEN(" /c "));
+ buffer_append_string(cmdline, command);
+ procok = CreateProcess(NULL, cmdline->ptr, &security, &security, TRUE,
+ NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
+ buffer_free(cmdline);
+
+ if (FALSE == procok) {
+ fprintf(stderr, "failed to CreateProcess");
+ return -1;
+ }
+
+ proc->child = pi.hProcess;
+ CloseHandle(pi.hThread);
+
+ proc_close_childs(proc);
+
+ return 0;
+}
+/* }}} */
+#else /* WIN32 */
+/* {{{ proc_close */
+int proc_close(proc_handler_t *proc) {
+ pid_t child = proc->child;
+ int wstatus;
+ pid_t wait_pid;
+
+ proc_close_pipes(proc);
+
+ do {
+ wait_pid = waitpid(child, &wstatus, 0);
+ } while (wait_pid == -1 && errno == EINTR);
+
+ if (wait_pid == -1) {
+ return -1;
+ } else {
+ if (WIFEXITED(wstatus))
+ wstatus = WEXITSTATUS(wstatus);
+ }
+
+ return wstatus;
+}
+/* }}} */
+/* {{{ proc_open */
+int proc_open(proc_handler_t *proc, const char *command) {
+ pid_t child;
+ const char *shell;
+
+ if (NULL == (shell = getenv(SHELLENV))) {
+ fprintf(stderr, "env %s is required", SHELLENV);
+ return -1;
+ }
+
+ if (proc_open_pipes(proc) != 0) {
+ return -1;
+ }
+
+ /* the unix way */
+
+ child = fork();
+
+ if (child == 0) {
+ /* this is the child process */
+
+ /* close those descriptors that we just opened for the parent stuff,
+ * dup new descriptors into required descriptors and close the original
+ * cruft
+ */
+ proc_close_parents(proc);
+
+ execl(shell, shell, "-c", command, NULL);
+ _exit(127);
+
+ } else if (child < 0) {
+ fprintf(stderr, "failed to forking");
+ proc_close(proc);
+ return -1;
+
+ } else {
+ proc->child = child;
+ proc_close_childs(proc);
+ return 0;
+ }
+}
+/* }}} */
+#endif /* WIN32 */
+
+/* {{{ proc_read_fd_to_buffer */
+static void proc_read_fd_to_buffer(int fd, buffer *b) {
+ ssize_t s;
+
+ for (;;) {
+ buffer_prepare_append(b, 512);
+ if ((s = read(fd, (void *)(b->ptr + b->used), 512 - 1)) <= 0) {
+ break;
+ }
+ b->used += s;
+ }
+ b->ptr[b->used] = '\0';
+}
+/* }}} */
+/* {{{ proc_open_buffer */
+int proc_open_buffer(proc_handler_t *proc, const char *command, buffer *in, buffer *out, buffer *err) {
+
+ UNUSED(err);
+
+ if (proc_open(proc, command) != 0) {
+ return -1;
+ }
+
+ if (in) {
+ if (write(proc->in.fd, (void *)in->ptr, in->used) < 0) {
+ perror("error writing pipe");
+ return -1;
+ }
+ }
+ pipe_close(&proc->in);
+
+ if (out) {
+ proc_read_fd_to_buffer(proc->out.fd, out);
+ }
+ pipe_close(&proc->out);
+
+ if (err) {
+ proc_read_fd_to_buffer(proc->err.fd, err);
+ }
+ pipe_close(&proc->err);
+
+ return 0;
+}
+/* }}} */
+
+/* {{{ test */
+#ifdef DEBUG_PROC_OPEN
+int main() {
+ proc_handler_t proc;
+ buffer *in = buffer_init(), *out = buffer_init(), *err = buffer_init();
+ int wstatus;
+
+#define FREE() do { \
+ buffer_free(in); \
+ buffer_free(out); \
+ buffer_free(err); \
+} while (0)
+
+#define RESET() do { \
+ buffer_reset(in); \
+ buffer_reset(out); \
+ buffer_reset(err); \
+ wstatus = proc_close(&proc); \
+ if (0&&wstatus != 0) { \
+ fprintf(stdout, "exitstatus %d\n", wstatus); \
+ return __LINE__ - 200; \
+ } \
+} while (0)
+
+#define ERROR_OUT() do { \
+ fprintf(stdout, "failed opening proc\n"); \
+ wstatus = proc_close(&proc); \
+ fprintf(stdout, "exitstatus %d\n", wstatus); \
+ FREE(); \
+ return __LINE__ - 300; \
+} while (0)
+
+#ifdef WIN32
+#define CMD_CAT "pause"
+#else
+#define CMD_CAT "cat"
+#endif
+
+ do {
+ fprintf(stdout, "test: echo 123 without read\n");
+ if (proc_open(&proc, "echo 321") != 0) {
+ ERROR_OUT();
+ }
+ close_descriptor(proc.in.parent);
+ close_descriptor(proc.out.parent);
+ close_descriptor(proc.err.parent);
+ RESET();
+
+ fprintf(stdout, "test: echo 321 with read\n"); fflush(stdout);
+ if (proc_open_buffer(&proc, "echo 321", NULL, out, err) != 0) {
+ ERROR_OUT();
+ }
+ fprintf(stdout, "result: ->%s<-\n\n", out->ptr); fflush(stdout);
+ RESET();
+
+ fprintf(stdout, "test: echo 123 | " CMD_CAT "\n"); fflush(stdout);
+ buffer_copy_string_len(in, CONST_STR_LEN("123\n"));
+ if (proc_open_buffer(&proc, CMD_CAT, in, out, err) != 0) {
+ ERROR_OUT();
+ }
+ fprintf(stdout, "result: ->%s<-\n\n", out->ptr); fflush(stdout);
+ RESET();
+ } while (0);
+
+#undef RESET
+#undef ERROR_OUT
+
+ fprintf(stdout, "ok\n");
+
+ FREE();
+ return 0;
+}
+#endif /* DEBUG_PROC_OPEN */
+/* }}} */
+
diff --git a/src/proc_open.h b/src/proc_open.h
new file mode 100644
index 00000000..e07421a0
--- /dev/null
+++ b/src/proc_open.h
@@ -0,0 +1,25 @@
+
+#include "buffer.h"
+
+#ifdef WIN32
+#include <windows.h>
+typedef HANDLE descriptor_t;
+typedef HANDLE proc_pid_t;
+#else
+typedef int descriptor_t;
+typedef pid_t proc_pid_t;
+#endif
+
+typedef struct {
+ descriptor_t parent, child;
+ int fd;
+} pipe_t;
+
+typedef struct {
+ pipe_t in, out, err;
+ proc_pid_t child;
+} proc_handler_t;
+
+int proc_close(proc_handler_t *ht);
+int proc_open(proc_handler_t *ht, const char *command);
+int proc_open_buffer(proc_handler_t *ht, const char *command, buffer *in, buffer *out, buffer *err);
diff --git a/src/response.c b/src/response.c
index f15bf769..0e07396e 100644
--- a/src/response.c
+++ b/src/response.c
@@ -974,8 +974,10 @@ handler_t http_response_prepare(server *srv, connection *con) {
if (con->mode == DIRECT && con->physical.path->used == 0) {
char *qstr;
+ if (con->conf.log_condition_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "run condition");
+ }
config_patch_connection(srv, con, COMP_SERVER_SOCKET); /* SERVERsocket */
- config_patch_connection(srv, con, COMP_HTTP_REMOTEIP); /* Client-IP */
/**
* prepare strings
@@ -1003,6 +1005,7 @@ handler_t http_response_prepare(server *srv, connection *con) {
buffer_copy_string_buffer(con->uri.authority, con->request.http_host);
config_patch_connection(srv, con, COMP_HTTP_HOST); /* Host: */
+ config_patch_connection(srv, con, COMP_HTTP_REMOTEIP); /* Client-IP */
config_patch_connection(srv, con, COMP_HTTP_REFERER); /* Referer: */
config_patch_connection(srv, con, COMP_HTTP_USERAGENT); /* User-Agent: */
config_patch_connection(srv, con, COMP_HTTP_COOKIE); /* Cookie: */
diff --git a/src/stream.c b/src/stream.c
index d82a60db..fb6d0b7f 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -22,6 +22,7 @@ int stream_open(stream *f, buffer *fn) {
void *p;
#endif
+ f->start = NULL;
if (-1 == stat(fn->ptr, &st)) {
return -1;
diff --git a/tests/LightyTest.pm b/tests/LightyTest.pm
index a95ca06d..a4797245 100755
--- a/tests/LightyTest.pm
+++ b/tests/LightyTest.pm
@@ -110,8 +110,12 @@ sub handle_http {
my $remote =
IO::Socket::INET->new(Proto => "tcp",
PeerAddr => $host,
- PeerPort => $self->{PORT})
- or return -1;
+ PeerPort => $self->{PORT});
+
+ if (not defined $remote) {
+ diag("connect failed: $!");
+ return -1;
+ }
$remote->autoflush(1);
diff --git a/tests/core-var-include.t b/tests/core-var-include.t
index 538338fd..32830e07 100755
--- a/tests/core-var-include.t
+++ b/tests/core-var-include.t
@@ -8,7 +8,7 @@ BEGIN {
use strict;
use IO::Socket;
-use Test::More tests => 16;
+use Test::More tests => 17;
use LightyTest;
my $tf = LightyTest->new();
@@ -29,20 +29,22 @@ my $server_name = "test.example.org";
my $mystr = "string";
$mystr .= "_append";
my $tests = {
- "include" => "/good_include",
- "concat" => "/good_" . "concat",
- "servername1" => "/good_" . $server_name,
- "servername2" => $server_name . "/good_",
- "servername3" => "/good_" . $server_name . "/",
- "var.myvar" => "/good_var_myvar" . $myvar,
- "myvar" => "/good_myvar" . $myvar,
- "env" => "/" . $ENV{"env_test"},
-
- "number1" => "/good_number" . "1",
- "number2" => "1" . "/good_number",
- "array_append" => "/good_array_append",
- "string_append" => "/good_" . $mystr,
- "number_append" => "/good_" . "2"
+ "include" => "/good_include",
+ "concat" => "/good_" . "concat",
+ "servername1" => "/good_" . $server_name,
+ "servername2" => $server_name . "/good_",
+ "servername3" => "/good_" . $server_name . "/",
+ "var.myvar" => "/good_var_myvar" . $myvar,
+ "myvar" => "/good_myvar" . $myvar,
+ "env" => "/" . $ENV{"env_test"},
+
+ "number1" => "/good_number" . "1",
+ "number2" => "1" . "/good_number",
+ "array_append" => "/good_array_append",
+ "string_append" => "/good_" . $mystr,
+ "number_append" => "/good_" . "2",
+
+ "include_shell" => "/good_include_shell_" . "456"
};
foreach my $test (keys %{ $tests }) {
@@ -57,4 +59,3 @@ EOF
}
ok($tf->stop_proc == 0, "Stopping lighttpd");
-
diff --git a/tests/docroot/www/pathinfo.php b/tests/docroot/www/pathinfo.php
new file mode 100644
index 00000000..39cfce92
--- /dev/null
+++ b/tests/docroot/www/pathinfo.php
@@ -0,0 +1,3 @@
+<?php
+ print $_SERVER["PATH_INFO"];
+?>
diff --git a/tests/lighttpd.conf b/tests/lighttpd.conf
index 7863f543..4e92433c 100644
--- a/tests/lighttpd.conf
+++ b/tests/lighttpd.conf
@@ -67,7 +67,7 @@ setenv.add-request-header = ( "FOO" => "foo")
setenv.add-response-header = ( "BAR" => "foo")
fastcgi.debug = 0
-fastcgi.server = ( ".php" => ( ( "host" => "127.0.0.1", "port" => 1026 ) ),
+fastcgi.server = ( ".php" => ( ( "host" => "127.0.0.1", "port" => 1026, "broken-scriptfilename" => "enable" ) ),
"/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
)
@@ -115,8 +115,6 @@ auth.require = ( "/server-status" =>
url.access-deny = ( "~", ".inc")
-url.redirect = ( "^/redirect/$" => "http://localhost:2048/" )
-
url.rewrite = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
"^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
@@ -149,3 +147,22 @@ $HTTP["host"] !~ "(no-simple\.example\.org)" {
simple-vhost.default-host = "www.example.org"
}
+$HTTP["host"] =~ "(vvv).example.org" {
+ url.redirect = ( "^/redirect/$" => "http://localhost:2048/" )
+}
+
+$HTTP["host"] =~ "(zzz).example.org" {
+ url.redirect = ( "^/redirect/$" => "http://localhost:2048/%1" )
+}
+
+$HTTP["host"] =~ "(remoteip).example.org" {
+ $HTTP["remoteip"] =~ "(127.0.0.1)" {
+ url.redirect = ( "^/redirect/$" => "http://localhost:2048/%1" )
+ }
+}
+
+$HTTP["remoteip"] =~ "(127.0.0.1)" {
+ $HTTP["host"] =~ "(remoteip2).example.org" {
+ url.redirect = ( "^/redirect/$" => "http://localhost:2048/%1" )
+ }
+}
diff --git a/tests/mod-fastcgi.t b/tests/mod-fastcgi.t
index 8ead034d..515486fd 100755
--- a/tests/mod-fastcgi.t
+++ b/tests/mod-fastcgi.t
@@ -7,7 +7,7 @@ BEGIN {
}
use strict;
-use Test::More tests => 43;
+use Test::More tests => 44;
use LightyTest;
my $tf = LightyTest->new();
@@ -68,6 +68,14 @@ EOF
ok($tf->handle_http($t) == 0, '$_SERVER["PHP_SELF"]');
$t->{REQUEST} = ( <<EOF
+GET /pathinfo.php/foo HTTP/1.0
+Host: www.example.org
+EOF
+ );
+ $t->{RESPONSE} = ( { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '/foo' } );
+ ok($tf->handle_http($t) == 0, '$_SERVER["PATH_INFO"]');
+
+ $t->{REQUEST} = ( <<EOF
GET /phphost.php HTTP/1.0
Host: www.example.org
EOF
diff --git a/tests/mod-redirect.t b/tests/mod-redirect.t
index 6b6104c8..690acdd0 100755
--- a/tests/mod-redirect.t
+++ b/tests/mod-redirect.t
@@ -8,7 +8,7 @@ BEGIN {
use strict;
use IO::Socket;
-use Test::More tests => 3;
+use Test::More tests => 6;
use LightyTest;
my $tf = LightyTest->new();
@@ -18,11 +18,34 @@ ok($tf->start_proc == 0, "Starting lighttpd") or die();
$t->{REQUEST} = ( <<EOF
GET /redirect/ HTTP/1.0
+Host: vvv.example.org
EOF
);
$t->{RESPONSE} = ( { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => 'http://localhost:2048/' } );
ok($tf->handle_http($t) == 0, 'external redirect');
+$t->{REQUEST} = ( <<EOF
+GET /redirect/ HTTP/1.0
+Host: zzz.example.org
+EOF
+ );
+$t->{RESPONSE} = ( { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => 'http://localhost:2048/zzz' } );
+ok($tf->handle_http($t) == 0, 'external redirect with cond regsub');
-ok($tf->stop_proc == 0, "Stopping lighttpd");
+$t->{REQUEST} = ( <<EOF
+GET /redirect/ HTTP/1.0
+Host: remoteip.example.org
+EOF
+ );
+$t->{RESPONSE} = ( { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => 'http://localhost:2048/127.0.0.1' } );
+ok($tf->handle_http($t) == 0, 'external redirect with cond regsub on remoteip');
+
+$t->{REQUEST} = ( <<EOF
+GET /redirect/ HTTP/1.0
+Host: remoteip2.example.org
+EOF
+ );
+$t->{RESPONSE} = ( { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => 'http://localhost:2048/remoteip2' } );
+ok($tf->handle_http($t) == 0, 'external redirect with cond regsub on remoteip2');
+ok($tf->stop_proc == 0, "Stopping lighttpd");
diff --git a/tests/var-include-sub.conf b/tests/var-include-sub.conf
index 152e6de1..3e0c3b9c 100644
--- a/tests/var-include-sub.conf
+++ b/tests/var-include-sub.conf
@@ -25,4 +25,10 @@ $HTTP["host"] =~ "^" + server.name + "$" {
"^/string_append$" => "/good_" + mystr,
"^/number_append$" => "/good_" + one,
)
+
+ cmd = "echo cmd_ok=456"
+ include_shell cmd
+ url.redirect += (
+ "^/include_shell$" => "/good_include_shell_" + cmd_ok,
+ )
}