summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am14
-rw-r--r--src/Makefile.in14
-rw-r--r--src/SConscript195
-rw-r--r--src/array.h8
-rw-r--r--src/base.h1
-rw-r--r--src/configfile-glue.c20
-rw-r--r--src/configparser.c191
-rw-r--r--src/configparser.y50
-rw-r--r--src/connections.c29
-rw-r--r--src/etag.c9
-rw-r--r--src/fdevent_solaris_devpoll.c2
-rw-r--r--src/http_auth.c5
-rw-r--r--src/mod_auth.c4
-rw-r--r--src/mod_cgi.c9
-rw-r--r--src/mod_compress.c118
-rw-r--r--src/mod_extforward.c100
-rw-r--r--src/mod_fastcgi.c76
-rw-r--r--src/mod_proxy.c16
-rw-r--r--src/mod_scgi.c8
-rw-r--r--src/mod_secure_download.c3
-rw-r--r--src/mod_ssi.c108
-rw-r--r--src/mod_staticfile.c24
-rw-r--r--src/mod_status.c18
-rw-r--r--src/mod_userdir.c16
-rw-r--r--src/network_linux_sendfile.c5
-rw-r--r--src/network_openssl.c27
-rw-r--r--src/response.c46
-rw-r--r--src/server.c43
-rw-r--r--src/spawn-fcgi.c258
-rw-r--r--src/stream.c3
30 files changed, 952 insertions, 468 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 24967c8..a112789 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -16,20 +16,20 @@ if CROSS_COMPILING
configparser.c configparser.h:
mod_ssi_exprparser.c mod_ssi_exprparser.h:
else
-configparser.y: lemon
-mod_ssi_exprparser.y: lemon
+$(srcdir)/configparser.y: lemon
+$(srcdir)/mod_ssi_exprparser.y: lemon
-configparser.c configparser.h: configparser.y
+configparser.c configparser.h: $(srcdir)/configparser.y
rm -f configparser.h
$(LEMON) -q $(srcdir)/configparser.y $(srcdir)/lempar.c
-mod_ssi_exprparser.c mod_ssi_exprparser.h: mod_ssi_exprparser.y
+mod_ssi_exprparser.c mod_ssi_exprparser.h: $(srcdir)/mod_ssi_exprparser.y
rm -f mod_ssi_exprparser.h
$(LEMON) -q $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c
endif
-configfile.c: configparser.h
-mod_ssi_expr.c: mod_ssi_exprparser.h
+$(srcdir)/configfile.c: configparser.h
+$(srcdir)/mod_ssi_expr.c: mod_ssi_exprparser.h
common_src=buffer.c log.c \
keyvalue.c chunk.c \
@@ -281,4 +281,4 @@ proc_open_CPPFLAGS= -DDEBUG_PROC_OPEN
#ajp_SOURCES = ajp.c
noinst_HEADERS = $(hdr)
-EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c
+EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c SConscript
diff --git a/src/Makefile.in b/src/Makefile.in
index 2952518..826af20 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -755,7 +755,7 @@ proc_open_CPPFLAGS = -DDEBUG_PROC_OPEN
#bench_SOURCES = buffer.c bench.c
#ajp_SOURCES = ajp.c
noinst_HEADERS = $(hdr)
-EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c
+EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c SConscript
all: all-am
.SUFFIXES:
@@ -1669,19 +1669,19 @@ uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \
@CROSS_COMPILING_TRUE@configparser.c configparser.h:
@CROSS_COMPILING_TRUE@mod_ssi_exprparser.c mod_ssi_exprparser.h:
-@CROSS_COMPILING_FALSE@configparser.y: lemon
-@CROSS_COMPILING_FALSE@mod_ssi_exprparser.y: lemon
+@CROSS_COMPILING_FALSE@$(srcdir)/configparser.y: lemon
+@CROSS_COMPILING_FALSE@$(srcdir)/mod_ssi_exprparser.y: lemon
-@CROSS_COMPILING_FALSE@configparser.c configparser.h: configparser.y
+@CROSS_COMPILING_FALSE@configparser.c configparser.h: $(srcdir)/configparser.y
@CROSS_COMPILING_FALSE@ rm -f configparser.h
@CROSS_COMPILING_FALSE@ $(LEMON) -q $(srcdir)/configparser.y $(srcdir)/lempar.c
-@CROSS_COMPILING_FALSE@mod_ssi_exprparser.c mod_ssi_exprparser.h: mod_ssi_exprparser.y
+@CROSS_COMPILING_FALSE@mod_ssi_exprparser.c mod_ssi_exprparser.h: $(srcdir)/mod_ssi_exprparser.y
@CROSS_COMPILING_FALSE@ rm -f mod_ssi_exprparser.h
@CROSS_COMPILING_FALSE@ $(LEMON) -q $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c
-configfile.c: configparser.h
-mod_ssi_expr.c: mod_ssi_exprparser.h
+$(srcdir)/configfile.c: configparser.h
+$(srcdir)/mod_ssi_expr.c: mod_ssi_exprparser.h
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
diff --git a/src/SConscript b/src/SConscript
new file mode 100644
index 0000000..0ad2a4e
--- /dev/null
+++ b/src/SConscript
@@ -0,0 +1,195 @@
+import os
+import re
+import types
+
+Import('env')
+
+common_src = Split("buffer.c log.c \
+ keyvalue.c chunk.c \
+ http_chunk.c stream.c fdevent.c \
+ stat_cache.c plugin.c joblist.c etag.c array.c \
+ data_string.c data_count.c data_array.c \
+ data_integer.c md5.c data_fastcgi.c \
+ fdevent_select.c fdevent_linux_rtsig.c \
+ fdevent_poll.c fdevent_linux_sysepoll.c \
+ fdevent_solaris_devpoll.c fdevent_freebsd_kqueue.c \
+ data_config.c bitset.c \
+ inet_ntop_cache.c crc32.c \
+ connections-glue.c \
+ configfile-glue.c \
+ http-header-glue.c \
+ splaytree.c network_writev.c \
+ network_write.c network_linux_sendfile.c \
+ network_freebsd_sendfile.c \
+ network_solaris_sendfilev.c network_openssl.c \
+ status_counter.c \
+")
+
+src = Split("server.c response.c connections.c network.c \
+ configfile.c configparser.c request.c proc_open.c")
+
+lemon = env.Program('lemon', 'lemon.c')
+
+configparser = env.Command(['configparser.c', 'configparser.h'], 'configparser.y', '(cd build; ../' + lemon[0].path + ' -q ../$SOURCE ../src/lempar.c; cd ..)')
+env.Depends(configparser, lemon)
+
+mod_ssi_exprparser = env.Command(['mod_ssi_exprparser.c', 'mod_ssi_exprparser.h'], 'mod_ssi_exprparser.y', '(cd build; ../' + lemon[0].path + ' -q ../$SOURCE ../src/lempar.c; cd ..)')
+env.Depends(mod_ssi_exprparser, lemon)
+
+## the modules and how they are built
+modules = {
+ 'mod_access' : { 'src' : [ 'mod_access.c' ] },
+ 'mod_alias' : { 'src' : [ 'mod_alias.c' ] },
+ 'mod_cgi' : { 'src' : [ 'mod_cgi.c' ] },
+ 'mod_fastcgi' : { 'src' : [ 'mod_fastcgi.c' ] },
+ 'mod_scgi' : { 'src' : [ 'mod_scgi.c' ] },
+ 'mod_staticfile' : { 'src' : [ 'mod_staticfile.c' ] },
+ 'mod_dirlisting' : { 'src' : [ 'mod_dirlisting.c' ], 'lib' : [ env['LIBPCRE'] ] },
+ 'mod_indexfile' : { 'src' : [ 'mod_indexfile.c' ] },
+ 'mod_setenv' : { 'src' : [ 'mod_setenv.c' ] },
+ 'mod_rrdtool' : { 'src' : [ 'mod_rrdtool.c' ] },
+ 'mod_usertrack' : { 'src' : [ 'mod_usertrack.c' ] },
+ 'mod_proxy' : { 'src' : [ 'mod_proxy.c' ] },
+ 'mod_userdir' : { 'src' : [ 'mod_userdir.c' ] },
+ 'mod_secdownload' : { 'src' : [ 'mod_secure_download.c' ] },
+ 'mod_accesslog' : { 'src' : [ 'mod_accesslog.c' ] },
+ 'mod_simple_vhost' : { 'src' : [ 'mod_simple_vhost.c' ] },
+ 'mod_evhost' : { 'src' : [ 'mod_evhost.c' ] },
+ 'mod_expire' : { 'src' : [ 'mod_expire.c' ] },
+ 'mod_status' : { 'src' : [ 'mod_status.c' ] },
+ 'mod_compress' : { 'src' : [ 'mod_compress.c' ], 'lib' : [ env['LIBZ'], env['LIBBZ2'] ] },
+ 'mod_redirect' : { 'src' : [ 'mod_redirect.c' ], 'lib' : [ env['LIBPCRE'] ] },
+ 'mod_rewrite' : { 'src' : [ 'mod_rewrite.c' ], 'lib' : [ env['LIBPCRE'] ] },
+ 'mod_auth' : {
+ 'src' : [ 'mod_auth.c', 'http_auth_digest.c', 'http_auth.c' ],
+ 'lib' : [ env['LIBCRYPT'], env['LIBLDAP'], env['LIBLBER'] ] },
+ 'mod_webdav' : { 'src' : [ 'mod_webdav.c' ], 'lib' : [ env['LIBXML2'], env['LIBSQLITE3'], env['LIBUUID'] ] },
+ 'mod_mysql_vhost' : { 'src' : [ 'mod_mysql_vhost.c' ], 'lib' : [ env['LIBMYSQL'] ] },
+ 'mod_trigger_b4_dl' : { 'src' : [ 'mod_trigger_b4_dl.c' ], 'lib' : [ env['LIBPCRE'] ] },
+ 'mod_cml' : {
+ 'src' : [ 'mod_cml_lua.c', 'mod_cml.c', 'mod_cml_funcs.c' ],
+ 'lib' : [ env['LIBPCRE'], env['LIBMEMCACHE'], env['LIBLUA'], env['LIBLUALIB'] ] },
+ 'mod_uploadprogress' : { 'src' : [ 'mod_uploadprogress.c' ] },
+ 'mod_evasive' : { 'src' : [ 'mod_evasive.c' ] },
+ 'mod_ssi' : { 'src' : [ 'mod_ssi_exprparser.c', 'mod_ssi_expr.c', 'mod_ssi.c' ], 'lib' : [ env['LIBPCRE'] ] },
+ 'mod_flv_streaming' : { 'src' : [ 'mod_flv_streaming.c' ] },
+ 'mod_magnet' : { 'src' : [ 'mod_magnet.c', 'mod_magnet_cache.c' ], 'lib' : [ env['LIBLUA'] ] },
+}
+
+staticenv = env.Copy(CPPFLAGS=[ env['CPPFLAGS'], '-DLIGHTTPD_STATIC', '-DOPENSSL_NO_KRB5'])
+
+## all the core-sources + the modules
+staticsrc = src + common_src
+
+staticlib = env['LIBS']
+staticinit = ''
+for module in modules.keys():
+ staticsrc += modules[module]['src']
+ staticinit += "PLUGIN_INIT(%s)\n"%module
+ if modules[module].has_key('lib'):
+ staticlib += modules[module]['lib']
+
+open('plugin-static.h', 'w+').write(staticinit)
+
+## turn all src-files into objects
+staticobj = []
+for cfile in staticsrc:
+ staticobj += [ staticenv.Object('static-' + cfile.replace('.c', ''), cfile) ]
+
+staticbin = staticenv.Program('lighttpd-semi-static',
+ staticobj,
+ LIBS = staticlib
+ )
+
+## you might have to adjust the list of libs and the order for your setup
+## this is tricky, be warned
+fullstaticlib = []
+
+## try to calculate the libs for fullstatic with ldd
+## 1. find the lib
+## 2. check the deps
+## 3. add them to the libs
+searchlibs = os.pathsep.join([ '/lib/', '/usr/lib/', '/usr/local/lib/' ])
+lddre = re.compile(r'^\s+lib([^=-]+)(?:-[\.0-9]+)?\.so\.[0-9]+ =>', re.MULTILINE)
+for libs in staticlib:
+ if type(libs) is types.StringType: libs = [ libs ]
+ for lib in libs:
+ fullstaticlib += [ lib ]
+ solibpath = env.WhereIs('lib' + lib + '.so', searchlibs)
+ fullstaticlib += [ lib ]
+ if solibpath is None:
+ continue
+
+ f = os.popen('ldd ' + solibpath, 'r')
+ for aword in lddre.findall(f.read()):
+ fullstaticlib += [ aword ]
+ f.close
+
+
+fullstaticbin = staticenv.Program('lighttpd-static',
+ staticobj,
+ LIBS = fullstaticlib,
+ LINKFLAGS= ['-static']
+ )
+
+Alias('static', staticbin)
+Alias('fullstatic', fullstaticbin)
+
+implib = 'lighttpd.exe.a'
+bin_targets = ['lighttpd']
+bin_linkflags = [ env['LINKFLAGS'] ]
+if env['COMMON_LIB'] == 'lib':
+ common_lib = env.SharedLibrary('liblighttpd', common_src, LINKFLAGS = [ env['LINKFLAGS'], '-Wl,--export-dynamic' ])
+else:
+ src += common_src
+ common_lib = []
+ if env['COMMON_LIB'] == 'bin':
+ bin_linkflags += [ '-Wl,--export-all-symbols', '-Wl,--out-implib=build/' + implib ]
+ bin_targets += [ implib ]
+ else:
+ bin_linkflags += [ '-Wl,--export-dynamic' ]
+
+instbin = env.Program(bin_targets, src, LINKFLAGS = bin_linkflags, LIBS= [ env['LIBS'], common_lib, env['LIBDL'] ])
+env.Depends(instbin, configparser)
+
+spawn_fcgi = env.Program("spawn-fcgi", "spawn-fcgi.c")
+
+if env['COMMON_LIB'] == 'bin':
+ common_lib = instbin[1]
+
+env['SHLIBPREFIX'] = ''
+instlib = []
+for module in modules.keys():
+ libs = [ common_lib ]
+ if modules[module].has_key('lib'):
+ libs += modules[module]['lib']
+ instlib += env.SharedLibrary(module, modules[module]['src'], LIBS= [ libs ])
+
+inst = []
+
+Default(spawn_fcgi)
+inst += env.Install('${bindir}', spawn_fcgi)
+
+if env['build_dynamic']:
+ Default(instbin[0], instlib)
+ inst += env.Install('${sbindir}', instbin[0])
+ inst += env.Install('${libdir}', instlib)
+ if env['COMMON_LIB'] == 'lib':
+ Default(common_lib)
+ inst += env.Install('${bindir}', common_lib)
+
+if env['build_static']:
+ Default(staticbin)
+ inst += env.Install('${sbindir}', staticbin)
+
+if env['build_fullstatic']:
+ Default(fullstaticbin)
+ inst += env.Install('${sbindir}', fullstaticbin)
+
+env.Alias('dynamic', instbin)
+# default all to be installed
+env.Alias('install', inst)
+
+pkgdir = '.'
+tarname = env['package'] + '-' + env['version']
+
diff --git a/src/array.h b/src/array.h
index b8a8345..9dacf10 100644
--- a/src/array.h
+++ b/src/array.h
@@ -86,10 +86,12 @@ typedef enum {
COMP_HTTP_URL,
COMP_HTTP_HOST,
COMP_HTTP_REFERER,
- COMP_HTTP_USERAGENT,
+ COMP_HTTP_USER_AGENT,
COMP_HTTP_COOKIE,
- COMP_HTTP_REMOTEIP,
- COMP_HTTP_QUERYSTRING,
+ COMP_HTTP_REMOTE_IP,
+ COMP_HTTP_QUERY_STRING,
+ COMP_HTTP_SCHEME,
+ COMP_HTTP_REQUEST_METHOD,
COMP_LAST_ELEMENT
} comp_key_t;
diff --git a/src/base.h b/src/base.h
index abedf79..acaf533 100644
--- a/src/base.h
+++ b/src/base.h
@@ -515,6 +515,7 @@ typedef struct {
#ifdef USE_OPENSSL
SSL_CTX *ssl_ctx;
#endif
+ unsigned short is_proxy_ssl;
} server_socket;
typedef struct {
diff --git a/src/configfile-glue.c b/src/configfile-glue.c
index f6ead92..66a596e 100644
--- a/src/configfile-glue.c
+++ b/src/configfile-glue.c
@@ -277,7 +277,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
}
break;
}
- case COMP_HTTP_REMOTEIP: {
+ case COMP_HTTP_REMOTE_IP: {
char *nm_slash;
/* handle remoteip limitations
*
@@ -341,11 +341,15 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
}
break;
}
+ case COMP_HTTP_SCHEME:
+ l = con->uri.scheme;
+ break;
+
case COMP_HTTP_URL:
l = con->uri.path;
break;
- case COMP_HTTP_QUERYSTRING:
+ case COMP_HTTP_QUERY_STRING:
l = con->uri.query;
break;
@@ -372,7 +376,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
}
break;
}
- case COMP_HTTP_USERAGENT: {
+ case COMP_HTTP_USER_AGENT: {
data_string *ds;
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "User-Agent"))) {
l = ds->value;
@@ -381,7 +385,17 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
}
break;
}
+ case COMP_HTTP_REQUEST_METHOD: {
+ const char *method = get_http_method_name(con->request.http_method);
+
+ /* we only have the request method as const char but we need a buffer for comparing */
+
+ buffer_copy_string(srv->tmp_buf, method);
+ l = srv->tmp_buf;
+
+ break;
+ }
default:
return COND_RESULT_FALSE;
}
diff --git a/src/configparser.c b/src/configparser.c
index 363b395..58a03fe 100644
--- a/src/configparser.c
+++ b/src/configparser.c
@@ -54,7 +54,7 @@ static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
return NULL;
}
-/* op1 is to be eat/return by this function, op1->key is not cared
+/* op1 is to be eat/return by this function if success, op1->key is not cared
op2 is left untouch, unreferenced
*/
data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
@@ -72,7 +72,6 @@ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
return (data_unset *)ds;
} else {
fprintf(stderr, "data type mismatch, cannot be merge\n");
- op1->free(op1);
return NULL;
}
}
@@ -106,7 +105,7 @@ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
}
-#line 110 "configparser.c"
+#line 109 "configparser.c"
/* Next is all token values, in a form suitable for use by makeheaders.
** This section will be null unless lemon is run with the -m switch.
*/
@@ -515,42 +514,42 @@ static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
case 25:
#line 142 "./configparser.y"
{ buffer_free((yypminor->yy0)); }
-#line 518 "configparser.c"
+#line 517 "configparser.c"
break;
case 35:
#line 133 "./configparser.y"
{ (yypminor->yy41)->free((yypminor->yy41)); }
-#line 523 "configparser.c"
+#line 522 "configparser.c"
break;
case 36:
#line 134 "./configparser.y"
{ (yypminor->yy41)->free((yypminor->yy41)); }
-#line 528 "configparser.c"
+#line 527 "configparser.c"
break;
case 37:
#line 135 "./configparser.y"
{ (yypminor->yy41)->free((yypminor->yy41)); }
-#line 533 "configparser.c"
+#line 532 "configparser.c"
break;
case 39:
#line 136 "./configparser.y"
{ array_free((yypminor->yy40)); }
-#line 538 "configparser.c"
+#line 537 "configparser.c"
break;
case 40:
#line 137 "./configparser.y"
{ array_free((yypminor->yy40)); }
-#line 543 "configparser.c"
+#line 542 "configparser.c"
break;
case 41:
#line 138 "./configparser.y"
{ buffer_free((yypminor->yy43)); }
-#line 548 "configparser.c"
+#line 547 "configparser.c"
break;
case 42:
#line 139 "./configparser.y"
{ buffer_free((yypminor->yy43)); }
-#line 553 "configparser.c"
+#line 552 "configparser.c"
break;
default: break; /* If no destructor action specified: do nothing */
}
@@ -818,9 +817,9 @@ static void yy_reduce(
/* No destructor defined for global */
break;
case 5:
-#line 116 "./configparser.y"
+#line 115 "./configparser.y"
{ yymsp[-1].minor.yy78 = NULL; }
-#line 823 "configparser.c"
+#line 822 "configparser.c"
yy_destructor(1,&yymsp[0].minor);
break;
case 6:
@@ -835,31 +834,33 @@ static void yy_reduce(
case 9:
#line 144 "./configparser.y"
{
- buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
- if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
- fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
- ctx->current->context_ndx,
- ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
- ctx->ok = 0;
- } else if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
- array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
- yymsp[0].minor.yy41 = NULL;
- } else {
- fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n",
- ctx->current->context_ndx,
- ctx->current->key->ptr, yymsp[0].minor.yy41->key->ptr);
- ctx->ok = 0;
- yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
- yymsp[0].minor.yy41 = NULL;
+ if (ctx->ok) {
+ buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
+ if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
+ fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
+ ctx->current->context_ndx,
+ ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
+ ctx->ok = 0;
+ } else if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
+ array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
+ yymsp[0].minor.yy41 = NULL;
+ } else {
+ fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n",
+ ctx->current->context_ndx,
+ ctx->current->key->ptr, yymsp[0].minor.yy41->key->ptr);
+ ctx->ok = 0;
+ yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
+ yymsp[0].minor.yy41 = NULL;
+ }
}
buffer_free(yymsp[-2].minor.yy43);
yymsp[-2].minor.yy43 = NULL;
}
-#line 858 "configparser.c"
+#line 859 "configparser.c"
yy_destructor(2,&yymsp[-1].minor);
break;
case 10:
-#line 166 "./configparser.y"
+#line 168 "./configparser.y"
{
array *vars = ctx->current->value;
data_unset *du;
@@ -884,6 +885,7 @@ static void yy_reduce(
du = configparser_merge_data(du, yymsp[0].minor.yy41);
if (NULL == du) {
ctx->ok = 0;
+ du->free(du);
}
else {
buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
@@ -898,11 +900,11 @@ static void yy_reduce(
yymsp[-2].minor.yy43 = NULL;
yymsp[0].minor.yy41 = NULL;
}
-#line 901 "configparser.c"
+#line 903 "configparser.c"
yy_destructor(3,&yymsp[-1].minor);
break;
case 11:
-#line 205 "./configparser.y"
+#line 208 "./configparser.y"
{
if (strchr(yymsp[0].minor.yy0->ptr, '.') == NULL) {
yygotominor.yy43 = buffer_init_string("var.");
@@ -914,10 +916,10 @@ static void yy_reduce(
yymsp[0].minor.yy0 = NULL;
}
}
-#line 917 "configparser.c"
+#line 919 "configparser.c"
break;
case 12:
-#line 217 "./configparser.y"
+#line 220 "./configparser.y"
{
yygotominor.yy41 = configparser_merge_data(yymsp[-2].minor.yy41, yymsp[0].minor.yy41);
if (NULL == yygotominor.yy41) {
@@ -927,19 +929,19 @@ static void yy_reduce(
yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
yymsp[0].minor.yy41 = NULL;
}
-#line 930 "configparser.c"
+#line 932 "configparser.c"
yy_destructor(5,&yymsp[-1].minor);
break;
case 13:
-#line 227 "./configparser.y"
+#line 230 "./configparser.y"
{
yygotominor.yy41 = yymsp[0].minor.yy41;
yymsp[0].minor.yy41 = NULL;
}
-#line 939 "configparser.c"
+#line 941 "configparser.c"
break;
case 14:
-#line 232 "./configparser.y"
+#line 235 "./configparser.y"
{
yygotominor.yy41 = NULL;
if (strncmp(yymsp[0].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
@@ -966,59 +968,59 @@ static void yy_reduce(
buffer_free(yymsp[0].minor.yy43);
yymsp[0].minor.yy43 = NULL;
}
-#line 969 "configparser.c"
+#line 971 "configparser.c"
break;
case 15:
-#line 259 "./configparser.y"
+#line 262 "./configparser.y"
{
yygotominor.yy41 = (data_unset *)data_string_init();
buffer_copy_string_buffer(((data_string *)(yygotominor.yy41))->value, yymsp[0].minor.yy0);
buffer_free(yymsp[0].minor.yy0);
yymsp[0].minor.yy0 = NULL;
}
-#line 979 "configparser.c"
+#line 981 "configparser.c"
break;
case 16:
-#line 266 "./configparser.y"
+#line 269 "./configparser.y"
{
yygotominor.yy41 = (data_unset *)data_integer_init();
((data_integer *)(yygotominor.yy41))->value = strtol(yymsp[0].minor.yy0->ptr, NULL, 10);
buffer_free(yymsp[0].minor.yy0);
yymsp[0].minor.yy0 = NULL;
}
-#line 989 "configparser.c"
+#line 991 "configparser.c"
break;
case 17:
-#line 272 "./configparser.y"
+#line 275 "./configparser.y"
{
yygotominor.yy41 = (data_unset *)data_array_init();
array_free(((data_array *)(yygotominor.yy41))->value);
((data_array *)(yygotominor.yy41))->value = yymsp[0].minor.yy40;
yymsp[0].minor.yy40 = NULL;
}
-#line 999 "configparser.c"
+#line 1001 "configparser.c"
break;
case 18:
-#line 278 "./configparser.y"
+#line 281 "./configparser.y"
{
yygotominor.yy40 = array_init();
}
-#line 1006 "configparser.c"
+#line 1008 "configparser.c"
yy_destructor(8,&yymsp[-1].minor);
yy_destructor(9,&yymsp[0].minor);
break;
case 19:
-#line 281 "./configparser.y"
+#line 284 "./configparser.y"
{
yygotominor.yy40 = yymsp[-1].minor.yy40;
yymsp[-1].minor.yy40 = NULL;
}
-#line 1016 "configparser.c"
+#line 1018 "configparser.c"
yy_destructor(8,&yymsp[-2].minor);
yy_destructor(9,&yymsp[0].minor);
break;
case 20:
-#line 286 "./configparser.y"
+#line 289 "./configparser.y"
{
if (buffer_is_empty(yymsp[0].minor.yy41->key) ||
NULL == array_get_element(yymsp[-2].minor.yy40, yymsp[0].minor.yy41->key->ptr)) {
@@ -1035,37 +1037,37 @@ static void yy_reduce(
yygotominor.yy40 = yymsp[-2].minor.yy40;
yymsp[-2].minor.yy40 = NULL;
}
-#line 1038 "configparser.c"
+#line 1040 "configparser.c"
yy_destructor(10,&yymsp[-1].minor);
break;
case 21:
-#line 303 "./configparser.y"
+#line 306 "./configparser.y"
{
yygotominor.yy40 = yymsp[-1].minor.yy40;
yymsp[-1].minor.yy40 = NULL;
}
-#line 1047 "configparser.c"
+#line 1049 "configparser.c"
yy_destructor(10,&yymsp[0].minor);
break;
case 22:
-#line 308 "./configparser.y"
+#line 311 "./configparser.y"
{
yygotominor.yy40 = array_init();
array_insert_unique(yygotominor.yy40, yymsp[0].minor.yy41);
yymsp[0].minor.yy41 = NULL;
}
-#line 1057 "configparser.c"
+#line 1059 "configparser.c"
break;
case 23:
-#line 314 "./configparser.y"
+#line 317 "./configparser.y"
{
yygotominor.yy41 = yymsp[0].minor.yy41;
yymsp[0].minor.yy41 = NULL;
}
-#line 1065 "configparser.c"
+#line 1067 "configparser.c"
break;
case 24:
-#line 318 "./configparser.y"
+#line 321 "./configparser.y"
{
buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
buffer_free(yymsp[-2].minor.yy43);
@@ -1074,7 +1076,7 @@ static void yy_reduce(
yygotominor.yy41 = yymsp[0].minor.yy41;
yymsp[0].minor.yy41 = NULL;
}
-#line 1077 "configparser.c"
+#line 1079 "configparser.c"
yy_destructor(11,&yymsp[-1].minor);
break;
case 25:
@@ -1083,18 +1085,18 @@ static void yy_reduce(
case 26:
break;
case 27:
-#line 330 "./configparser.y"
+#line 333 "./configparser.y"
{
data_config *dc;
dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
assert(dc);
configparser_push(ctx, dc, 0);
}
-#line 1093 "configparser.c"
+#line 1095 "configparser.c"
yy_destructor(12,&yymsp[0].minor);
break;
case 28:
-#line 337 "./configparser.y"
+#line 340 "./configparser.y"
{
data_config *cur;
@@ -1103,16 +1105,16 @@ static void yy_reduce(
assert(cur && ctx->current);
- yygotominor.yy0 = cur;
+ yygotominor.yy78 = cur;
}
-#line 1108 "configparser.c"
+#line 1110 "configparser.c"
/* No destructor defined for globalstart */
yy_destructor(13,&yymsp[-2].minor);
/* No destructor defined for metalines */
yy_destructor(14,&yymsp[0].minor);
break;
case 29:
-#line 348 "./configparser.y"
+#line 351 "./configparser.y"
{
assert(yymsp[-3].minor.yy78->context_ndx < yymsp[0].minor.yy78->context_ndx);
yymsp[0].minor.yy78->prev = yymsp[-3].minor.yy78;
@@ -1121,20 +1123,20 @@ static void yy_reduce(
yymsp[-3].minor.yy78 = NULL;
yymsp[0].minor.yy78 = NULL;
}
-#line 1124 "configparser.c"
+#line 1126 "configparser.c"
/* No destructor defined for eols */
yy_destructor(15,&yymsp[-1].minor);
break;
case 30:
-#line 357 "./configparser.y"
+#line 360 "./configparser.y"
{
yygotominor.yy78 = yymsp[0].minor.yy78;
yymsp[0].minor.yy78 = NULL;
}
-#line 1134 "configparser.c"
+#line 1136 "configparser.c"
break;
case 31:
-#line 362 "./configparser.y"
+#line 365 "./configparser.y"
{
data_config *cur;
@@ -1145,14 +1147,14 @@ static void yy_reduce(
yygotominor.yy78 = cur;
}
-#line 1148 "configparser.c"
+#line 1150 "configparser.c"
/* No destructor defined for context */
yy_destructor(13,&yymsp[-2].minor);
/* No destructor defined for metalines */
yy_destructor(14,&yymsp[0].minor);
break;
case 32:
-#line 373 "./configparser.y"
+#line 376 "./configparser.y"
{
data_config *dc;
buffer *b, *rvalue, *op;
@@ -1201,10 +1203,15 @@ static void yy_reduce(
{ COMP_HTTP_URL, CONST_STR_LEN("HTTP[\"url\"]" ) },
{ COMP_HTTP_HOST, CONST_STR_LEN("HTTP[\"host\"]" ) },
{ COMP_HTTP_REFERER, CONST_STR_LEN("HTTP[\"referer\"]" ) },
- { COMP_HTTP_USERAGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) },
+ { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) },
+ { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"user-agent\"]" ) },
{ COMP_HTTP_COOKIE, CONST_STR_LEN("HTTP[\"cookie\"]" ) },
- { COMP_HTTP_REMOTEIP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) },
- { COMP_HTTP_QUERYSTRING, CONST_STR_LEN("HTTP[\"querystring\"]") },
+ { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) },
+ { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remote-ip\"]" ) },
+ { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"querystring\"]") },
+ { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"query-string\"]") },
+ { COMP_HTTP_REQUEST_METHOD, CONST_STR_LEN("HTTP[\"request-method\"]") },
+ { COMP_HTTP_SCHEME, CONST_STR_LEN("HTTP[\"scheme\"]" ) },
{ COMP_UNSET, NULL, 0 },
};
size_t i;
@@ -1288,45 +1295,45 @@ static void yy_reduce(
yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
yymsp[0].minor.yy41 = NULL;
}
-#line 1291 "configparser.c"
+#line 1298 "configparser.c"
yy_destructor(16,&yymsp[-6].minor);
yy_destructor(18,&yymsp[-4].minor);
yy_destructor(19,&yymsp[-2].minor);
break;
case 33:
-#line 508 "./configparser.y"
+#line 516 "./configparser.y"
{
yygotominor.yy27 = CONFIG_COND_EQ;
}
-#line 1301 "configparser.c"
+#line 1308 "configparser.c"
yy_destructor(20,&yymsp[0].minor);
break;
case 34:
-#line 511 "./configparser.y"
+#line 519 "./configparser.y"
{
yygotominor.yy27 = CONFIG_COND_MATCH;
}
-#line 1309 "configparser.c"
+#line 1316 "configparser.c"
yy_destructor(21,&yymsp[0].minor);
break;
case 35:
-#line 514 "./configparser.y"
+#line 522 "./configparser.y"
{
yygotominor.yy27 = CONFIG_COND_NE;
}
-#line 1317 "configparser.c"
+#line 1324 "configparser.c"
yy_destructor(22,&yymsp[0].minor);
break;
case 36:
-#line 517 "./configparser.y"
+#line 525 "./configparser.y"
{
yygotominor.yy27 = CONFIG_COND_NOMATCH;
}
-#line 1325 "configparser.c"
+#line 1332 "configparser.c"
yy_destructor(23,&yymsp[0].minor);
break;
case 37:
-#line 521 "./configparser.y"
+#line 529 "./configparser.y"
{
yygotominor.yy43 = NULL;
if (ctx->ok) {
@@ -1343,10 +1350,10 @@ static void yy_reduce(
yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
yymsp[0].minor.yy41 = NULL;
}
-#line 1346 "configparser.c"
+#line 1353 "configparser.c"
break;
case 38:
-#line 538 "./configparser.y"
+#line 546 "./configparser.y"
{
if (ctx->ok) {
if (0 != config_parse_file(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
@@ -1356,11 +1363,11 @@ static void yy_reduce(
yymsp[0].minor.yy43 = NULL;
}
}
-#line 1359 "configparser.c"
+#line 1366 "configparser.c"
yy_destructor(24,&yymsp[-1].minor);
break;
case 39:
-#line 548 "./configparser.y"
+#line 556 "./configparser.y"
{
if (ctx->ok) {
if (0 != config_parse_cmd(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
@@ -1370,7 +1377,7 @@ static void yy_reduce(
yymsp[0].minor.yy43 = NULL;
}
}
-#line 1373 "configparser.c"
+#line 1380 "configparser.c"
yy_destructor(25,&yymsp[-1].minor);
break;
};
@@ -1400,11 +1407,11 @@ static void yy_parse_failed(
while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
/* Here code is inserted which will be executed whenever the
** parser fails */
-#line 107 "./configparser.y"
+#line 106 "./configparser.y"
ctx->ok = 0;
-#line 1407 "configparser.c"
+#line 1414 "configparser.c"
configparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
diff --git a/src/configparser.y b/src/configparser.y
index 30f5fd9..57e2dc5 100644
--- a/src/configparser.y
+++ b/src/configparser.y
@@ -51,7 +51,7 @@ static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
return NULL;
}
-/* op1 is to be eat/return by this function, op1->key is not cared
+/* op1 is to be eat/return by this function if success, op1->key is not cared
op2 is left untouch, unreferenced
*/
data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
@@ -69,7 +69,6 @@ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
return (data_unset *)ds;
} else {
fprintf(stderr, "data type mismatch, cannot be merge\n");
- op1->free(op1);
return NULL;
}
}
@@ -123,6 +122,7 @@ metaline ::= EOL.
%type aelement {data_unset *}
%type condline {data_config *}
%type condlines {data_config *}
+%type global {data_config *}
%type aelements {array *}
%type array {array *}
%type key {buffer *}
@@ -142,22 +142,24 @@ metaline ::= EOL.
%token_destructor { buffer_free($$); }
varline ::= key(A) ASSIGN expression(B). {
- buffer_copy_string_buffer(B->key, A);
- if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
- fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
- ctx->current->context_ndx,
- ctx->current->key->ptr, A->ptr);
- ctx->ok = 0;
- } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
- array_insert_unique(ctx->current->value, B);
- B = NULL;
- } else {
- fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n",
- ctx->current->context_ndx,
- ctx->current->key->ptr, B->key->ptr);
- ctx->ok = 0;
- B->free(B);
- B = NULL;
+ if (ctx->ok) {
+ buffer_copy_string_buffer(B->key, A);
+ if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
+ fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
+ ctx->current->context_ndx,
+ ctx->current->key->ptr, A->ptr);
+ ctx->ok = 0;
+ } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
+ array_insert_unique(ctx->current->value, B);
+ B = NULL;
+ } else {
+ fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n",
+ ctx->current->context_ndx,
+ ctx->current->key->ptr, B->key->ptr);
+ ctx->ok = 0;
+ B->free(B);
+ B = NULL;
+ }
}
buffer_free(A);
A = NULL;
@@ -187,6 +189,7 @@ varline ::= key(A) APPEND expression(B). {
du = configparser_merge_data(du, B);
if (NULL == du) {
ctx->ok = 0;
+ du->free(du);
}
else {
buffer_copy_string_buffer(du->key, A);
@@ -418,10 +421,15 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio
{ COMP_HTTP_URL, CONST_STR_LEN("HTTP[\"url\"]" ) },
{ COMP_HTTP_HOST, CONST_STR_LEN("HTTP[\"host\"]" ) },
{ COMP_HTTP_REFERER, CONST_STR_LEN("HTTP[\"referer\"]" ) },
- { COMP_HTTP_USERAGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) },
+ { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) },
+ { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"user-agent\"]" ) },
{ COMP_HTTP_COOKIE, CONST_STR_LEN("HTTP[\"cookie\"]" ) },
- { COMP_HTTP_REMOTEIP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) },
- { COMP_HTTP_QUERYSTRING, CONST_STR_LEN("HTTP[\"querystring\"]") },
+ { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) },
+ { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remote-ip\"]" ) },
+ { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"querystring\"]") },
+ { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"query-string\"]") },
+ { COMP_HTTP_REQUEST_METHOD, CONST_STR_LEN("HTTP[\"request-method\"]") },
+ { COMP_HTTP_SCHEME, CONST_STR_LEN("HTTP[\"scheme\"]" ) },
{ COMP_UNSET, NULL, 0 },
};
size_t i;
diff --git a/src/connections.c b/src/connections.c
index 94d36b4..184ecb9 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -394,10 +394,13 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
* 403 is from the response handler when noone else catched it
*
* */
- if (con->uri.path->used &&
+ if ((!con->http_status || con->http_status == 200) && con->uri.path->used &&
con->uri.path->ptr[0] != '*') {
response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
+ con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
+ con->parsed_response &= ~HTTP_CONTENT_LENGTH;
+
con->http_status = 200;
con->file_finished = 1;
@@ -498,9 +501,11 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
case 207:
case 200: /* class: header + body */
case 201:
+ case 300:
case 301:
case 302:
case 303:
+ case 307:
break;
case 206: /* write_queue is already prepared */
@@ -511,13 +516,13 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
default:
/* disable chunked encoding again as we have no body */
con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
+ con->parsed_response &= ~HTTP_CONTENT_LENGTH;
chunkqueue_reset(con->write_queue);
con->file_finished = 1;
break;
}
-
if (con->file_finished) {
/* we have all the content and chunked encoding is not used, set a content-length */
@@ -536,12 +541,16 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
if ((con->http_status >= 100 && con->http_status < 200) ||
con->http_status == 204 ||
con->http_status == 304) {
+ data_string *ds;
/* no Content-Body, no Content-Length */
- } else if (qlen >= 0) {
+ if (NULL != (ds = (data_string*) array_get_element(con->response.headers, "Content-Length"))) {
+ buffer_reset(ds->value); // Headers with empty values are ignored for output
+ }
+ } else if (qlen > 0 || con->request.http_method != HTTP_METHOD_HEAD) {
/* qlen = 0 is important for Redirects (301, ...) as they MAY have
* a content. Browsers are waiting for a Content otherwise
*/
- buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->write_queue));
+ buffer_copy_off_t(srv->tmp_buf, qlen);
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf));
}
@@ -582,6 +591,8 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
* a HEAD request has the same as a GET
* without the content
*/
+ con->file_finished = 1;
+
chunkqueue_reset(con->write_queue);
con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
}
@@ -834,14 +845,8 @@ int connection_reset(server *srv, connection *con) {
con->plugin_ctx[pd->id] = 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
+ /* The cond_cache gets reset in response.c */
+// config_cond_cache_reset(srv, con);
#ifdef USE_OPENSSL
if (con->ssl_error_want_reuse_buffer) {
diff --git a/src/etag.c b/src/etag.c
index c1146c3..630956f 100644
--- a/src/etag.c
+++ b/src/etag.c
@@ -1,5 +1,14 @@
#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined HAVE_STDINT_H
#include <stdint.h>
+#elif defined HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
#include "buffer.h"
#include "etag.h"
diff --git a/src/fdevent_solaris_devpoll.c b/src/fdevent_solaris_devpoll.c
index f77daef..76414a4 100644
--- a/src/fdevent_solaris_devpoll.c
+++ b/src/fdevent_solaris_devpoll.c
@@ -67,7 +67,7 @@ static int fdevent_solaris_devpoll_poll(fdevents *ev, int timeout_ms) {
int ret;
dopoll.dp_timeout = timeout_ms;
- dopoll.dp_nfds = ev->maxfds;
+ dopoll.dp_nfds = ev->maxfds - 1;
dopoll.dp_fds = ev->devpollfds;
ret = ioctl(ev->devpoll_fd, DP_POLL, &dopoll);
diff --git a/src/http_auth.c b/src/http_auth.c
index 1bfb460..89abde6 100644
--- a/src/http_auth.c
+++ b/src/http_auth.c
@@ -29,6 +29,7 @@
#include "log.h"
#include "http_auth.h"
#include "http_auth_digest.h"
+#include "inet_ntop_cache.h"
#include "stream.h"
#ifdef USE_OPENSSL
@@ -862,7 +863,7 @@ int http_auth_basic_check(server *srv, connection *con, mod_auth_plugin_data *p,
/* password doesn't match */
if (http_auth_basic_password_compare(srv, p, req, username, realm->value, password, pw)) {
- log_error_write(srv, __FILE__, __LINE__, "sbb", "password doesn't match for", con->uri.path, username);
+ log_error_write(srv, __FILE__, __LINE__, "sbbss", "password doesn't match for ", con->uri.path, username, ", IP:", inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
buffer_free(username);
buffer_free(password);
@@ -1130,7 +1131,7 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p
}
log_error_write(srv, __FILE__, __LINE__, "sss",
- "digest: auth failed for", username, "wrong password");
+ "digest: auth failed for ", username, ": wrong password, IP:", inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
buffer_free(b);
return 0;
diff --git a/src/mod_auth.c b/src/mod_auth.c
index 19ed387..7bd306d 100644
--- a/src/mod_auth.c
+++ b/src/mod_auth.c
@@ -238,13 +238,13 @@ static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
int auth_type_len = auth_realm - http_authorization;
if ((auth_type_len == 5) &&
- (0 == strncmp(http_authorization, "Basic", auth_type_len))) {
+ (0 == strncasecmp(http_authorization, "Basic", auth_type_len))) {
if (0 == strcmp(method->value->ptr, "basic")) {
auth_satisfied = http_auth_basic_check(srv, con, p, req, con->uri.path, auth_realm+1);
}
} else if ((auth_type_len == 6) &&
- (0 == strncmp(http_authorization, "Digest", auth_type_len))) {
+ (0 == strncasecmp(http_authorization, "Digest", auth_type_len))) {
if (0 == strcmp(method->value->ptr, "digest")) {
if (-1 == (auth_satisfied = http_auth_digest_check(srv, con, p, req, con->uri.path, auth_realm+1))) {
con->http_status = 400;
diff --git a/src/mod_cgi.c b/src/mod_cgi.c
index f5e5b3a..82ae78b 100644
--- a/src/mod_cgi.c
+++ b/src/mod_cgi.c
@@ -1004,6 +1004,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
case -1:
/* error */
log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno));
+ return -1;
break;
default: {
handler_ctx *hctx;
@@ -1227,8 +1228,14 @@ TRIGGER_FUNC(cgi_trigger) {
#if 0
log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", p->cgi_pid.ptr[ndx]);
#endif
+ } else if (WIFSIGNALED(status)) {
+ /* FIXME: what if we killed the CGI script with a kill(..., SIGTERM) ?
+ */
+ if (WTERMSIG(status) != SIGTERM) {
+ log_error_write(srv, __FILE__, __LINE__, "sd", "cleaning up CGI: process died with signal", WTERMSIG(status));
+ }
} else {
- log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
+ log_error_write(srv, __FILE__, __LINE__, "s", "cleaning up CGI: ended unexpectedly");
}
cgi_pid_del(srv, p, p->cgi_pid.ptr[ndx]);
diff --git a/src/mod_compress.c b/src/mod_compress.c
index 464945e..79f6e74 100644
--- a/src/mod_compress.c
+++ b/src/mod_compress.c
@@ -102,6 +102,50 @@ FREE_FUNC(mod_compress_free) {
return HANDLER_GO_ON;
}
+// 0 on success, -1 for error
+int mkdir_recursive(char *dir) {
+ char *p = dir;
+
+ if (!dir || !dir[0])
+ return 0;
+
+ while ((p = strchr(p + 1, '/')) != NULL) {
+
+ *p = '\0';
+ if ((mkdir(dir, 0700) != 0) && (errno != EEXIST)) {
+ *p = '/';
+ return -1;
+ }
+
+ *p++ = '/';
+ if (!*p) return 0; // Ignore trailing slash
+ }
+
+ return (mkdir(dir, 0700) != 0) && (errno != EEXIST) ? -1 : 0;
+}
+
+// 0 on success, -1 for error
+int mkdir_for_file(char *filename) {
+ char *p = filename;
+
+ if (!filename || !filename[0])
+ return -1;
+
+ while ((p = strchr(p + 1, '/')) != NULL) {
+
+ *p = '\0';
+ if ((mkdir(filename, 0700) != 0) && (errno != EEXIST)) {
+ *p = '/';
+ return -1;
+ }
+
+ *p++ = '/';
+ if (!*p) return -1; // Unexpected trailing slash in filename
+ }
+
+ return 0;
+}
+
SETDEFAULTS_FUNC(mod_compress_setdefaults) {
plugin_data *p = p_d;
size_t i = 0;
@@ -134,6 +178,8 @@ SETDEFAULTS_FUNC(mod_compress_setdefaults) {
}
if (!buffer_is_empty(s->compress_cache_dir)) {
+ mkdir_recursive(s->compress_cache_dir->ptr);
+
struct stat st;
if (0 != stat(s->compress_cache_dir->ptr, &st)) {
log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir",
@@ -342,27 +388,8 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
BUFFER_APPEND_SLASH(p->ofn);
if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, con->physical.doc_root->used-1)) {
- size_t offset = p->ofn->used - 1;
- char *dir, *nextdir;
-
buffer_append_string(p->ofn, con->physical.path->ptr + con->physical.doc_root->used - 1);
-
buffer_copy_string_buffer(p->b, p->ofn);
-
- /* mkdir -p ... */
- for (dir = p->b->ptr + offset; NULL != (nextdir = strchr(dir, '/')); dir = nextdir + 1) {
- *nextdir = '\0';
-
- if (-1 == mkdir(p->b->ptr, 0700)) {
- if (errno != EEXIST) {
- log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cache-directory", p->b, "failed", strerror(errno));
-
- return -1;
- }
- }
-
- *nextdir = '/';
- }
} else {
buffer_append_string_buffer(p->ofn, con->uri.path);
}
@@ -384,6 +411,11 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
buffer_append_string_buffer(p->ofn, sce->etag);
+ if (-1 == mkdir_for_file(p->ofn->ptr)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "couldn't create directory for file", p->ofn);
+ return -1;
+ }
+
if (-1 == (ofd = open(p->ofn->ptr, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600))) {
if (errno == EEXIST) {
/* cache-entry exists */
@@ -407,6 +439,11 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
close(ofd);
+ /* Remove the incomplete cache file, so that later hits aren't served from it */
+ if (-1 == unlink(p->ofn->ptr)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "unlinking incomplete cachefile", p->ofn, "failed:", strerror(errno));
+ }
+
return -1;
}
@@ -416,6 +453,12 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
close(ofd);
close(ifd);
+
+ /* Remove the incomplete cache file, so that later hits aren't served from it */
+ if (-1 == unlink(p->ofn->ptr)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "unlinking incomplete cachefile", p->ofn, "failed:", strerror(errno));
+ }
+
return -1;
}
@@ -438,22 +481,29 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
break;
}
- if (-1 == (r = write(ofd, p->b->ptr, p->b->used))) {
- munmap(start, sce->st.st_size);
- close(ofd);
- close(ifd);
- return -1;
- }
-
- if ((size_t)r != p->b->used) {
-
+ if (ret == 0) {
+ r = write(ofd, p->b->ptr, p->b->used);
+ if (-1 == r) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "writing cachefile", p->ofn, "failed:", strerror(errno));
+ ret = -1;
+ } else if ((size_t)r != p->b->used) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "writing cachefile", p->ofn, "failed: not enough bytes written");
+ ret = -1;
+ }
}
munmap(start, sce->st.st_size);
close(ofd);
close(ifd);
- if (ret != 0) return -1;
+ if (ret != 0) {
+ /* Remove the incomplete cache file, so that later hits aren't served from it */
+ if (-1 == unlink(p->ofn->ptr)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "unlinking incomplete cachefile", p->ofn, "failed:", strerror(errno));
+ }
+
+ return -1;
+ }
buffer_copy_string_buffer(con->physical.path, p->ofn);
@@ -570,6 +620,8 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
off_t max_fsize;
stat_cache_entry *sce = NULL;
+ if (con->mode != DIRECT || con->http_status) return HANDLER_GO_ON;
+
/* only GET and POST can get compressed */
if (con->request.http_method != HTTP_METHOD_GET &&
con->request.http_method != HTTP_METHOD_POST) {
@@ -678,8 +730,16 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
}
} else if (0 == deflate_file_to_buffer(srv, con, p,
con->physical.path, sce, compression_type)) {
+ buffer *mtime;
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
+
+ mtime = strftime_cache_get(srv, sce->st.st_mtime);
+ response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
+
+ etag_mutate(con->physical.etag, sce->etag);
+ response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
+
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
return HANDLER_FINISHED;
diff --git a/src/mod_extforward.c b/src/mod_extforward.c
index 8ed336d..be7dd0f 100644
--- a/src/mod_extforward.c
+++ b/src/mod_extforward.c
@@ -20,6 +20,7 @@
/**
* 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:
*
@@ -33,6 +34,10 @@
* 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.
@@ -225,18 +230,16 @@ static array *extract_forward_array(buffer *pbuffer)
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++)
- {
+ for (base = pbuffer->ptr, curr = pbuffer->ptr; *curr; curr++) {
if (in_str) {
- if ( (*curr > '9' || *curr < '0') && *curr != '.' && *curr != ':' ) {
+ if ((*curr > '9' || *curr < '0') && *curr != '.' && *curr != ':') {
/* found an separator , insert value into result array */
- put_string_into_array_len(result, base, curr-base);
+ put_string_into_array_len(result, base, curr - base);
/* change state to not in string */
in_str = 0;
}
} else {
- if (*curr >= '0' && *curr <= '9')
- {
+ if (*curr >= '0' && *curr <= '9') {
/* found leading char of an IP address, move base pointer and change state */
base = curr;
in_str = 1;
@@ -244,9 +247,8 @@ static array *extract_forward_array(buffer *pbuffer)
}
}
/* 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);
+ if (in_str) {
+ put_string_into_array_len(result, base, curr - base);
}
}
return result;
@@ -255,18 +257,40 @@ static array *extract_forward_array(buffer *pbuffer)
#define IP_TRUSTED 1
#define IP_UNTRUSTED 0
/*
- check whether ip is trusted, return 1 for trusted , 0 for untrusted
-*/
+ * 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");
+ data_string* allds = (data_string *)array_get_element(p->conf.forwarder, "all");
+
if (allds) {
- if (strcasecmp(allds->value->ptr,"trust") == 0)
+ if (strcasecmp(allds->value->ptr, "trust") == 0) {
return IP_TRUSTED;
- else
+ } else {
return IP_UNTRUSTED;
+ }
}
- return (data_string *)array_get_element(p->conf.forwarder,ipstr) ? IP_TRUSTED : 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)
@@ -305,7 +329,7 @@ struct addrinfo *ipstr_to_sockaddr(const char *host)
static void clean_cond_cache(server *srv, connection *con) {
- config_cond_cache_reset_item(srv, con, COMP_HTTP_REMOTEIP);
+ config_cond_cache_reset_item(srv, con, COMP_HTTP_REMOTE_IP);
}
URIHANDLER_FUNC(mod_extforward_uri_handler) {
@@ -316,9 +340,8 @@ URIHANDLER_FUNC(mod_extforward_uri_handler) {
struct addrinfo *addrlist = NULL;
#endif
const char *dst_addr_str = NULL;
- int i;
array *forward_array = NULL;
- char *real_remote_addr = NULL;
+ const char *real_remote_addr = NULL;
#ifdef HAVE_IPV6
#endif
@@ -342,7 +365,6 @@ URIHANDLER_FUNC(mod_extforward_uri_handler) {
return HANDLER_GO_ON;
}
- /* if the remote ip itself is not trusted , then do nothing */
#ifdef HAVE_IPV6
dst_addr_str = inet_ntop(con->dst_addr.plain.sa_family,
con->dst_addr.plain.sa_family == AF_INET6 ?
@@ -353,7 +375,9 @@ URIHANDLER_FUNC(mod_extforward_uri_handler) {
#else
dst_addr_str = inet_ntoa(con->dst_addr.ipv4.sin_addr);
#endif
- if (IP_UNTRUSTED == is_proxy_trusted (dst_addr_str, p) ) {
+
+ /* 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");
@@ -362,40 +386,34 @@ URIHANDLER_FUNC(mod_extforward_uri_handler) {
return HANDLER_GO_ON;
}
+ /* build forward_array from forwarded data_string */
forward_array = extract_forward_array(forwarded->value);
-
- /* Testing shows that multiple headers and multiple values in one header
- come in _reverse_ order. So the first one we get is the last one in the request. */
- for (i = forward_array->used - 1; i >= 0; i--) {
- data_string *ds = (data_string *) forward_array->data[i];
- if (ds) {
- real_remote_addr = ds->value->ptr;
- break;
- } else {
- /* bug ? bailing out here */
- break;
- }
- }
+ 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);
+ 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) {
+ 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 ) {
+ 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 ) {
+ } else if (sock.plain.sa_family == AF_INET6) {
sock.ipv6.sin6_addr = ((struct sockaddr_in6*)addrs_left->ai_addr)->sin6_addr;
break;
}
@@ -430,7 +448,7 @@ URIHANDLER_FUNC(mod_extforward_uri_handler) {
if (addrlist != NULL ) freeaddrinfo(addrlist);
#endif
}
- array_free(forward_array);
+ array_free(forward_array);
/* not found */
return HANDLER_GO_ON;
diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c
index 75b52ad..9ce9556 100644
--- a/src/mod_fastcgi.c
+++ b/src/mod_fastcgi.c
@@ -162,8 +162,8 @@ typedef struct {
* if host is one of the local IP adresses the
* whole connection is local
*
- * if tcp/ip should be used host AND port have
- * to be specified
+ * if port is not 0, and host is not specified,
+ * "localhost" (INADDR_LOOPBACK) is assumed.
*
*/
buffer *host;
@@ -823,12 +823,12 @@ static int fcgi_spawn_connection(server *srv,
fcgi_addr_in.sin_family = AF_INET;
if (buffer_is_empty(host->host)) {
- fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
+ fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
} else {
struct hostent *he;
/* set a useful default */
- fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
+ fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (NULL == (he = gethostbyname(host->host->ptr))) {
@@ -858,7 +858,11 @@ static int fcgi_spawn_connection(server *srv,
fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
buffer_copy_string(proc->connection_name, "tcp:");
- buffer_append_string_buffer(proc->connection_name, host->host);
+ if (!buffer_is_empty(host->host)) {
+ buffer_append_string_buffer(proc->connection_name, host->host);
+ } else {
+ buffer_append_string(proc->connection_name, "localhost");
+ }
buffer_append_string(proc->connection_name, ":");
buffer_append_long(proc->connection_name, proc->port);
}
@@ -1687,12 +1691,16 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h
#endif
} else {
fcgi_addr_in.sin_family = AF_INET;
- if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
- "converting IP address failed for", host->host,
- "\nBe sure to specify an IP address here");
-
- return -1;
+ if (!buffer_is_empty(host->host)) {
+ if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "converting IP address failed for", host->host,
+ "\nBe sure to specify an IP address here");
+
+ return -1;
+ }
+ } else {
+ fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
}
fcgi_addr_in.sin_port = htons(proc->port);
servlen = sizeof(fcgi_addr_in);
@@ -1702,7 +1710,11 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h
if (buffer_is_empty(proc->connection_name)) {
/* on remote spawing we have to set the connection-name now */
buffer_copy_string(proc->connection_name, "tcp:");
- buffer_append_string_buffer(proc->connection_name, host->host);
+ if (!buffer_is_empty(host->host)) {
+ buffer_append_string_buffer(proc->connection_name, host->host);
+ } else {
+ buffer_append_string(proc->connection_name, "localhost");
+ }
buffer_append_string(proc->connection_name, ":");
buffer_append_long(proc->connection_name, proc->port);
}
@@ -2045,12 +2057,9 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
s = get_http_version_name(con->request.http_version);
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s)),con)
-#ifdef USE_OPENSSL
- if (srv_sock->is_ssl) {
+ if (srv_sock->is_ssl || srv_sock->is_proxy_ssl) {
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on")),con)
}
-#endif
-
FCGI_ENV_ADD_CHECK(fcgi_env_add_request_headers(srv, con, p), con);
@@ -2343,7 +2352,7 @@ static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_p
/* no header */
buffer_free(packet->b);
- log_error_write(srv, __FILE__, __LINE__, "s", "FastCGI: header too small");
+ log_error_write(srv, __FILE__, __LINE__, "sdsds", "FastCGI: header too small:", packet->b->used, "bytes <", sizeof(FCGI_Header), "bytes");
return -1;
}
@@ -2530,15 +2539,28 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
}
if (host->allow_xsendfile &&
- NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file"))) {
+ (NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file"))
+ || NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-Sendfile")))) {
stat_cache_entry *sce;
if (HANDLER_ERROR != stat_cache_get_entry(srv, con, ds->value, &sce)) {
+ data_string *dcls = data_string_init();
/* found */
-
http_chunk_append_file(srv, con, ds->value, 0, sce->st.st_size);
hctx->send_content_body = 0; /* ignore the content */
joblist_append(srv, con);
+
+ buffer_copy_string_len(dcls->key, "Content-Length", sizeof("Content-Length")-1);
+ buffer_copy_long(dcls->value, sce->st.st_size);
+ dcls = (data_string*) array_replace(con->response.headers, (data_unset *)dcls);
+ if (dcls) dcls->free((data_unset*)dcls);
+
+ con->parsed_response |= HTTP_CONTENT_LENGTH;
+ con->response.content_length = sce->st.st_size;
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "send-file error: couldn't get stat_cache entry for:",
+ ds->value);
}
}
@@ -2719,9 +2741,14 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
int ret;
- /* sanity check */
+ /* sanity check:
+ * - host != NULL
+ * - either:
+ * - tcp socket (do not check host->host->uses, as it may be not set which means INADDR_LOOPBACK)
+ * - unix socket
+ */
if (!host ||
- ((!host->host->used || !host->port) && !host->unixsocket->used)) {
+ (!host->port && !host->unixsocket->used)) {
log_error_write(srv, __FILE__, __LINE__, "sxddd",
"write-req: error",
host,
@@ -3456,8 +3483,9 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i
if (s_len < ct_len) continue;
/* check extension in the form "/fcgi_pattern" */
- if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
- break;
+ if (*(extension->key->ptr) == '/') {
+ if (strncmp(fn->ptr, extension->key->ptr, ct_len) == 0)
+ break;
} else if (0 == strncmp(fn->ptr + s_len - ct_len, extension->key->ptr, ct_len)) {
/* check extension in the form ".fcg" */
break;
@@ -3473,7 +3501,7 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i
for (k = 0; k < extension->used; k++) {
host = extension->hosts[k];
- /* we should have at least one proc that can do somthing */
+ /* we should have at least one proc that can do something */
if (host->active_procs == 0) {
host = NULL;
diff --git a/src/mod_proxy.c b/src/mod_proxy.c
index c4ac15f..4d8ecdd 100644
--- a/src/mod_proxy.c
+++ b/src/mod_proxy.c
@@ -1093,15 +1093,17 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p
if (s_len < ct_len) continue;
/* check extension in the form "/proxy_pattern" */
- if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
- if (s_len > ct_len + 1) {
- char *pi_offset;
+ if (*(extension->key->ptr) == '/') {
+ if (strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
+ if (s_len > ct_len + 1) {
+ char *pi_offset;
- if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) {
- path_info_offset = pi_offset - fn->ptr;
+ if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) {
+ path_info_offset = pi_offset - fn->ptr;
+ }
}
+ break;
}
- break;
} else if (0 == strncmp(fn->ptr + s_len - ct_len, extension->key->ptr, ct_len)) {
/* check extension in the form ".fcg" */
break;
@@ -1203,7 +1205,7 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p
}
/* didn't found a higher id, wrap to the start */
- if (ndx != -1 && max_usage != INT_MAX) {
+ if (ndx == -1 && max_usage != INT_MAX) {
ndx = max_usage;
}
diff --git a/src/mod_scgi.c b/src/mod_scgi.c
index bc487c5..b7287ba 100644
--- a/src/mod_scgi.c
+++ b/src/mod_scgi.c
@@ -1057,6 +1057,9 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
/* a local socket + self spawning */
size_t pno;
+ /* HACK: just to make sure the adaptive spawing is disabled */
+ df->min_procs = df->max_procs;
+
if (df->min_procs > df->max_procs) df->max_procs = df->min_procs;
if (df->max_load_per_proc < 1) df->max_load_per_proc = 0;
@@ -2694,8 +2697,9 @@ static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, i
if (s_len < ct_len) continue;
/* check extension in the form "/scgi_pattern" */
- if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
- break;
+ if (*(extension->key->ptr) == '/') {
+ if (strncmp(fn->ptr, extension->key->ptr, ct_len) == 0)
+ break;
} else if (0 == strncmp(fn->ptr + s_len - ct_len, extension->key->ptr, ct_len)) {
/* check extension in the form ".fcg" */
break;
diff --git a/src/mod_secure_download.c b/src/mod_secure_download.c
index 08a0554..57e407f 100644
--- a/src/mod_secure_download.c
+++ b/src/mod_secure_download.c
@@ -245,7 +245,8 @@ URIHANDLER_FUNC(mod_secdownload_uri_handler) {
/* timed-out */
if (srv->cur_ts - ts > p->conf.timeout ||
srv->cur_ts - ts < -p->conf.timeout) {
- con->http_status = 408;
+ /* "Gone" as the url will never be valid again instead of "408 - Timeout" where the request may be repeated */
+ con->http_status = 410;
return HANDLER_FINISHED;
}
diff --git a/src/mod_ssi.c b/src/mod_ssi.c
index e706e8f..d02d998 100644
--- a/src/mod_ssi.c
+++ b/src/mod_ssi.c
@@ -36,6 +36,11 @@
#include <sys/filio.h>
#endif
+#include "etag.h"
+
+/* The newest modified time of included files for include statement */
+static volatile time_t include_file_last_mtime = 0;
+
/* init the plugin data */
INIT_FUNC(mod_ssi_init) {
plugin_data *p;
@@ -575,6 +580,11 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
break;
case SSI_INCLUDE:
chunkqueue_append_file(con->write_queue, p->stat_fn, 0, st.st_size);
+
+ /* Keep the newest mtime of included files */
+ if (st.st_mtime > include_file_last_mtime)
+ include_file_last_mtime = st.st_mtime;
+
break;
}
} else {
@@ -718,50 +728,57 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
/* father */
int status;
ssize_t r;
+ int was_interrupted = 0;
close(from_exec_fds[1]);
/* wait for the client to end */
/*
- * FIXME: if we get interrupted by a SIGCHILD we count this as error
- *
- * for now it only happened on OpenBSD.
- *
- * that leads to zombies and missing output
+ * OpenBSD and Solaris send a EINTR on SIGCHILD even if we ignore it
*/
- if (-1 == waitpid(pid, &status, 0)) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno));
- } else if (WIFEXITED(status)) {
- int toread;
- /* read everything from client and paste it into the output */
-
- while(1) {
- if (ioctl(from_exec_fds[0], FIONREAD, &toread)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "unexpected end-of-file (perhaps the ssi-exec process died)");
- return -1;
+ do {
+ if (-1 == waitpid(pid, &status, 0)) {
+ if (errno == EINTR) {
+ was_interrupted++;
+ } else {
+ was_interrupted = 0;
+ log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno));
}
-
- if (toread > 0) {
- b = chunkqueue_get_append_buffer(con->write_queue);
-
- buffer_prepare_copy(b, toread + 1);
-
- if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) {
- /* read failed */
- break;
+ } else if (WIFEXITED(status)) {
+ int toread;
+ /* read everything from client and paste it into the output */
+ was_interrupted = 0;
+
+ while(1) {
+ if (ioctl(from_exec_fds[0], FIONREAD, &toread)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "unexpected end-of-file (perhaps the ssi-exec process died)");
+ return -1;
+ }
+
+ if (toread > 0) {
+ b = chunkqueue_get_append_buffer(con->write_queue);
+
+ buffer_prepare_copy(b, toread + 1);
+
+ if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) {
+ /* read failed */
+ break;
+ } else {
+ b->used = r;
+ b->ptr[b->used++] = '\0';
+ }
} else {
- b->used = r;
- b->ptr[b->used++] = '\0';
+ break;
}
- } else {
- break;
}
+ } else {
+ was_interrupted = 0;
+ log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally");
}
- } else {
- log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally");
- }
+ } while (was_interrupted > 0 && was_interrupted < 4); /* if waitpid() gets interrupted, retry, but max 4 times */
+
close(from_exec_fds[0]);
break;
@@ -912,6 +929,9 @@ static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p)
build_ssi_cgi_vars(srv, con, p);
p->if_is_false = 0;
+ /* Reset the modified time of included files */
+ include_file_last_mtime = 0;
+
if (-1 == stream_open(&s, con->physical.path)) {
log_error_write(srv, __FILE__, __LINE__, "sb",
"stream-open: ", con->physical.path);
@@ -1010,6 +1030,30 @@ static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p)
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
+ {
+ /* Generate "ETag" & "Last-Modified" headers */
+
+ stat_cache_entry *sce = NULL;
+ time_t lm_time = 0;
+ buffer *mtime = NULL;
+
+ stat_cache_get_entry(srv, con, con->physical.path, &sce);
+
+ etag_mutate(con->physical.etag, sce->etag);
+ response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
+
+ if (sce->st.st_mtime > include_file_last_mtime)
+ lm_time = sce->st.st_mtime;
+ else
+ lm_time = include_file_last_mtime;
+
+ mtime = strftime_cache_get(srv, lm_time);
+ response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
+ }
+
+ /* Reset the modified time of included files */
+ include_file_last_mtime = 0;
+
/* reset physical.path */
buffer_reset(con->physical.path);
diff --git a/src/mod_staticfile.c b/src/mod_staticfile.c
index 59fafee..0ffa901 100644
--- a/src/mod_staticfile.c
+++ b/src/mod_staticfile.c
@@ -352,7 +352,7 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) {
size_t k;
int s_len;
stat_cache_entry *sce = NULL;
- buffer *mtime;
+ buffer *mtime = NULL;
data_string *ds;
int allow_caching = 1;
@@ -450,7 +450,9 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) {
}
}
- response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes"));
+ if (con->conf.range_requests) {
+ response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes"));
+ }
if (allow_caching) {
if (p->conf.etags_used && con->etag_flags != 0 && !buffer_is_empty(sce->etag)) {
@@ -483,7 +485,23 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) {
/* if the value is the same as our ETag, we do a Range-request,
* otherwise a full 200 */
- if (!buffer_is_equal(ds->value, con->physical.etag)) {
+ if (ds->value->ptr[0] == '"') {
+ /**
+ * client wants a ETag
+ */
+ if (!con->physical.etag) {
+ do_range_request = 0;
+ } else if (!buffer_is_equal(ds->value, con->physical.etag)) {
+ do_range_request = 0;
+ }
+ } else if (!mtime) {
+ /**
+ * we don't have a Last-Modified and can match the If-Range:
+ *
+ * sending all
+ */
+ do_range_request = 0;
+ } else if (!buffer_is_equal(ds->value, mtime)) {
do_range_request = 0;
}
}
diff --git a/src/mod_status.c b/src/mod_status.c
index 80c0040..028cbc7 100644
--- a/src/mod_status.c
+++ b/src/mod_status.c
@@ -560,6 +560,8 @@ static handler_t mod_status_handle_server_status_text(server *srv, connection *c
double avg;
time_t ts;
char buf[32];
+ unsigned int k;
+ unsigned int l;
b = chunkqueue_get_append_buffer(con->write_queue);
@@ -588,6 +590,22 @@ static handler_t mod_status_handle_server_status_text(server *srv, connection *c
buffer_append_long(b, srv->conns->used);
BUFFER_APPEND_STRING_CONST(b, "\n");
+ BUFFER_APPEND_STRING_CONST(b, "IdleServers: ");
+ buffer_append_long(b, srv->conns->size - srv->conns->used);
+ BUFFER_APPEND_STRING_CONST(b, "\n");
+
+ /* output scoreboard */
+ BUFFER_APPEND_STRING_CONST(b, "Scoreboard: ");
+ for (k = 0; k < srv->conns->used; k++) {
+ connection *c = srv->conns->ptr[k];
+ const char *state = connection_get_short_state(c->state);
+ buffer_append_string_len(b, state, 1);
+ }
+ for (l = 0; l < srv->conns->size - srv->conns->used; l++) {
+ BUFFER_APPEND_STRING_CONST(b, "_");
+ }
+ BUFFER_APPEND_STRING_CONST(b, "\n");
+
/* set text/plain output */
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
diff --git a/src/mod_userdir.c b/src/mod_userdir.c
index 2fef0f2..e664bf2 100644
--- a/src/mod_userdir.c
+++ b/src/mod_userdir.c
@@ -21,6 +21,7 @@ typedef struct {
array *include_user;
buffer *path;
buffer *basepath;
+ unsigned short letterhomes;
} plugin_config;
typedef struct {
@@ -87,6 +88,7 @@ SETDEFAULTS_FUNC(mod_userdir_set_defaults) {
{ "userdir.exclude-user", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ "userdir.include-user", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
{ "userdir.basepath", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "userdir.letterhomes", NULL, T_CONFIG_BOOLEAN,T_CONFIG_SCOPE_CONNECTION }, /* 4 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
@@ -102,11 +104,13 @@ SETDEFAULTS_FUNC(mod_userdir_set_defaults) {
s->include_user = array_init();
s->path = buffer_init();
s->basepath = buffer_init();
+ s->letterhomes = 0;
cv[0].destination = s->path;
cv[1].destination = s->exclude_user;
cv[2].destination = s->include_user;
cv[3].destination = s->basepath;
+ cv[4].destination = &(s->letterhomes);
p->config_storage[i] = s;
@@ -128,6 +132,7 @@ static int mod_userdir_patch_connection(server *srv, connection *con, plugin_dat
PATCH(exclude_user);
PATCH(include_user);
PATCH(basepath);
+ PATCH(letterhomes);
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
@@ -149,6 +154,8 @@ static int mod_userdir_patch_connection(server *srv, connection *con, plugin_dat
PATCH(include_user);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.basepath"))) {
PATCH(basepath);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.letterhomes"))) {
+ PATCH(letterhomes);
}
}
}
@@ -170,6 +177,11 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) {
mod_userdir_patch_connection(srv, con, p);
+ /* enforce the userdir.path to be set in the config, ugly fix for #1587;
+ * should be replaced with a clean .enabled option in 1.5
+ */
+ if (p->conf.path->used == 0) return HANDLER_GO_ON;
+
uri_len = con->uri.path->used - 1;
/* /~user/foo.html -> /home/user/public_html/foo.html */
@@ -253,6 +265,10 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) {
buffer_copy_string_buffer(p->temp_path, p->conf.basepath);
BUFFER_APPEND_SLASH(p->temp_path);
+ if (p->conf.letterhomes) {
+ buffer_append_string_len(p->temp_path, p->username->ptr, 1);
+ BUFFER_APPEND_SLASH(p->temp_path);
+ }
buffer_append_string_buffer(p->temp_path, p->username);
}
BUFFER_APPEND_SLASH(p->temp_path);
diff --git a/src/network_linux_sendfile.c b/src/network_linux_sendfile.c
index 6586efb..5f01812 100644
--- a/src/network_linux_sendfile.c
+++ b/src/network_linux_sendfile.c
@@ -162,6 +162,7 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd,
switch (errno) {
case EAGAIN:
case EINTR:
+ /* ok, we can't send more, let's try later again */
r = 0;
break;
case EPIPE:
@@ -172,9 +173,7 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd,
"sendfile failed:", strerror(errno), fd);
return -1;
}
- }
-
- if (r == 0) {
+ } else if (r == 0) {
int oerrno = errno;
/* We got an event to write but we wrote nothing
*
diff --git a/src/network_openssl.c b/src/network_openssl.c
index e6df35e..ff9fb97 100644
--- a/src/network_openssl.c
+++ b/src/network_openssl.c
@@ -58,31 +58,6 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu
SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
}
- /* evil hack for opera 9.01 and 8.54 and earlier
- *
- * opera hangs if the trainling 0\r\n\r\n is in a seperate SSL-packet
- *
- * we try to move the packet into the previous mem-chunk if possible
- */
- if ((cq == con->write_queue) &&
- (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) &&
- (con->file_finished)) {
- /* merge the last chunk into the previous chunk */
-
- for(c = cq->first; c && c->next && c->next->next; c = c->next);
-
- if (c &&
- c->type == MEM_CHUNK &&
- c->next &&
- c->next->type == MEM_CHUNK &&
- c->next->mem->used == sizeof("0\r\n\r\n") &&
- 0 == strcmp(c->next->mem->ptr, "0\r\n\r\n")) {
- buffer_append_string_buffer(c->mem, c->next->mem);
-
- c->next->mem->used = 0;
- }
- }
-
for(c = cq->first; c; c = c->next) {
int chunk_finished = 0;
@@ -128,6 +103,7 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu
/* no, but we have errno */
switch(errno) {
case EPIPE:
+ case ECONNRESET:
return -2;
default:
log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
@@ -230,6 +206,7 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu
/* no, but we have errno */
switch(errno) {
case EPIPE:
+ case ECONNRESET:
return -2;
default:
log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
diff --git a/src/response.c b/src/response.c
index b8775f0..bc2bdd1 100644
--- a/src/response.c
+++ b/src/response.c
@@ -19,6 +19,7 @@
#include "stat_cache.h"
#include "chunk.h"
+#include "configfile.h"
#include "connections.h"
#include "plugin.h"
@@ -59,7 +60,8 @@ int http_response_write_header(server *srv, connection *con) {
ds = (data_string *)con->response.headers->data[i];
if (ds->value->used && ds->key->used &&
- 0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1)) {
+ 0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1) &&
+ 0 != strncmp(ds->key->ptr, "X-Sendfile", sizeof("X-Sendfile") - 1)) {
if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Date"))) have_date = 1;
if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Server"))) have_server = 1;
@@ -149,6 +151,9 @@ handler_t http_response_prepare(server *srv, connection *con) {
*
* */
+ config_cond_cache_reset(srv, con);
+ config_setup_connection(srv, con); // Perhaps this could be removed at other places.
+
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "run condition");
}
@@ -180,11 +185,13 @@ handler_t http_response_prepare(server *srv, connection *con) {
buffer_copy_string_buffer(con->uri.authority, con->request.http_host);
buffer_to_lower(con->uri.authority);
+ config_patch_connection(srv, con, COMP_HTTP_SCHEME); /* Scheme: */
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_REMOTE_IP); /* 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_USER_AGENT);/* User-Agent: */
config_patch_connection(srv, con, COMP_HTTP_COOKIE); /* Cookie: */
+ config_patch_connection(srv, con, COMP_HTTP_REQUEST_METHOD); /* REQUEST_METHOD */
/** their might be a fragment which has to be cut away */
if (NULL != (qstr = strchr(con->request.uri->ptr, '#'))) {
@@ -270,7 +277,7 @@ handler_t http_response_prepare(server *srv, connection *con) {
*/
config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */
- config_patch_connection(srv, con, COMP_HTTP_QUERYSTRING); /* HTTPqs */
+ config_patch_connection(srv, con, COMP_HTTP_QUERY_STRING); /* HTTPqs */
/* do we have to downgrade to 1.0 ? */
if (!con->conf.allow_http11) {
@@ -547,17 +554,14 @@ handler_t http_response_prepare(server *srv, connection *con) {
buffer_copy_string_buffer(srv->tmp_buf, con->physical.path);
do {
- struct stat st;
-
if (slash) {
buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr);
} else {
buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
}
- if (0 == stat(con->physical.path->ptr, &(st)) &&
- S_ISREG(st.st_mode)) {
- found = 1;
+ if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+ found = S_ISREG(sce->st.st_mode);
break;
}
@@ -589,6 +593,20 @@ handler_t http_response_prepare(server *srv, connection *con) {
return HANDLER_FINISHED;
}
+#ifdef HAVE_LSTAT
+ if ((sce->is_symlink != 0) && !con->conf.follow_symlink) {
+ con->http_status = 403;
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied due symlink restriction");
+ log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
+ }
+
+ buffer_reset(con->physical.path);
+ return HANDLER_FINISHED;
+ };
+#endif
+
/* we have a PATHINFO */
if (pathinfo) {
buffer_copy_string(con->request.pathinfo, pathinfo);
@@ -631,8 +649,14 @@ handler_t http_response_prepare(server *srv, connection *con) {
/* if we are still here, no one wanted the file, status 403 is ok I think */
- if (con->mode == DIRECT) {
- con->http_status = 403;
+ if (con->mode == DIRECT && con->http_status == 0) {
+ switch (con->request.http_method) {
+ case HTTP_METHOD_OPTIONS:
+ con->http_status = 200;
+ break;
+ default:
+ con->http_status = 403;
+ }
return HANDLER_FINISHED;
}
diff --git a/src/server.c b/src/server.c
index 132eb32..585a973 100644
--- a/src/server.c
+++ b/src/server.c
@@ -697,9 +697,6 @@ int main (int argc, char **argv) {
}
}
- /* #372: solaris need some fds extra for devpoll */
- if (rlim.rlim_cur > 10) rlim.rlim_cur -= 10;
-
if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
} else {
@@ -759,6 +756,19 @@ int main (int argc, char **argv) {
return -1;
}
+#ifdef HAVE_PWD_H
+ /*
+ * Change group before chroot, when we have access
+ * to /etc/group
+ * */
+ if (srv->srvconf.groupname->used) {
+ setgid(grp->gr_gid);
+ setgroups(0, NULL);
+ if (srv->srvconf.username->used) {
+ initgroups(srv->srvconf.username->ptr, grp->gr_gid);
+ }
+ }
+#endif
#ifdef HAVE_CHROOT
if (srv->srvconf.changeroot->used) {
tzset();
@@ -775,15 +785,7 @@ int main (int argc, char **argv) {
#endif
#ifdef HAVE_PWD_H
/* drop root privs */
- if (srv->srvconf.groupname->used) {
- setgid(grp->gr_gid);
- setgroups(0, NULL);
- }
-
if (srv->srvconf.username->used) {
- if (srv->srvconf.groupname->used) {
- initgroups(srv->srvconf.username->ptr, grp->gr_gid);
- }
setuid(pwd->pw_uid);
}
#endif
@@ -891,6 +893,17 @@ int main (int argc, char **argv) {
pid_fd = -1;
}
+ // Close stderr ASAP in the child process to make sure that nothing
+ // is being written to that fd which may not be valid anymore.
+ if (-1 == log_error_open(srv)) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "Opening errorlog failed. Going down.");
+
+ plugins_free(srv);
+ network_close(srv);
+ server_free(srv);
+ return -1;
+ }
+
if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) {
log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down.");
@@ -941,15 +954,7 @@ int main (int argc, char **argv) {
return -1;
}
- if (-1 == log_error_open(srv)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "opening errorlog failed, dying");
- plugins_free(srv);
- network_close(srv);
- server_free(srv);
- return -1;
- }
#ifdef HAVE_SIGACTION
diff --git a/src/spawn-fcgi.c b/src/spawn-fcgi.c
index 8237e79..60e02bd 100644
--- a/src/spawn-fcgi.c
+++ b/src/spawn-fcgi.c
@@ -37,7 +37,7 @@ typedef int socklen_t;
#endif
#ifdef HAVE_SYS_UN_H
-int fcgi_spawn_connection(char *appPath, char *addr, unsigned short port, const char *unixsocket, int child_count, int pid_fd, int nofork) {
+int fcgi_spawn_connection(char *appPath, char **appArgv, char *addr, unsigned short port, const char *unixsocket, int child_count, int pid_fd, int nofork) {
int fcgi_fd;
int socket_type, status;
struct timeval tv = { 0, 100 * 1000 };
@@ -48,6 +48,9 @@ int fcgi_spawn_connection(char *appPath, char *addr, unsigned short port, const
socklen_t servlen;
+ pid_t child;
+ int val;
+
if (child_count < 2) {
child_count = 5;
}
@@ -71,6 +74,25 @@ int fcgi_spawn_connection(char *appPath, char *addr, unsigned short port, const
#endif
socket_type = AF_UNIX;
fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
+
+ /* check if some backend is listening on the socket
+ * as if we delete the socket-file and rebind there will be no "socket already in use" error
+ */
+ if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
+ fprintf(stderr, "%s.%d\n",
+ __FILE__, __LINE__);
+ return -1;
+ }
+
+ if (-1 != connect(fcgi_fd, fcgi_addr, servlen)) {
+ fprintf(stderr, "%s.%d: socket is already used, can't spawn\n",
+ __FILE__, __LINE__);
+ return -1;
+ }
+
+ /* cleanup previous socket if it exists */
+ unlink(unixsocket);
+ close(fcgi_fd);
} else {
fcgi_addr_in.sin_family = AF_INET;
if (addr != NULL) {
@@ -85,144 +107,128 @@ int fcgi_spawn_connection(char *appPath, char *addr, unsigned short port, const
fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
}
+ /* open socket */
if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
fprintf(stderr, "%s.%d\n",
__FILE__, __LINE__);
return -1;
}
- if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
- /* server is not up, spawn in */
- pid_t child;
- int val;
+ val = 1;
+ if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
+ fprintf(stderr, "%s.%d\n",
+ __FILE__, __LINE__);
+ return -1;
+ }
- if (unixsocket) unlink(unixsocket);
+ /* create socket */
+ if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
+ fprintf(stderr, "%s.%d: bind failed: %s\n",
+ __FILE__, __LINE__,
+ strerror(errno));
+ return -1;
+ }
- close(fcgi_fd);
+ if (-1 == listen(fcgi_fd, 1024)) {
+ fprintf(stderr, "%s.%d: fd = -1\n",
+ __FILE__, __LINE__);
+ return -1;
+ }
- /* reopen socket */
- if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
- fprintf(stderr, "%s.%d\n",
- __FILE__, __LINE__);
- return -1;
- }
+ if (!nofork) {
+ child = fork();
+ } else {
+ child = 0;
+ }
- val = 1;
- if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
- fprintf(stderr, "%s.%d\n",
- __FILE__, __LINE__);
- return -1;
- }
+ switch (child) {
+ case 0: {
+ char cgi_childs[64];
- /* create socket */
- if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
- fprintf(stderr, "%s.%d: bind failed: %s\n",
- __FILE__, __LINE__,
- strerror(errno));
- return -1;
- }
+ int i = 0;
- if (-1 == listen(fcgi_fd, 1024)) {
- fprintf(stderr, "%s.%d: fd = -1\n",
- __FILE__, __LINE__);
- return -1;
- }
+ /* is safe as we limit to 256 childs */
+ sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count);
- if (!nofork) {
- child = fork();
- } else {
- child = 0;
+ if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
+ close(FCGI_LISTENSOCK_FILENO);
+ dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
+ close(fcgi_fd);
}
- switch (child) {
- case 0: {
- char cgi_childs[64];
- char *b;
-
- int i = 0;
-
- /* is save as we limit to 256 childs */
- sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count);
+ /* we don't need the client socket */
+ for (i = 3; i < 256; i++) {
+ close(i);
+ }
- if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
- close(FCGI_LISTENSOCK_FILENO);
- dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
- close(fcgi_fd);
- }
+ /* create environment */
- /* we don't need the client socket */
- for (i = 3; i < 256; i++) {
- close(i);
- }
+ putenv(cgi_childs);
- /* create environment */
+ /* fork and replace shell */
+ if (appArgv) {
+ execv(appArgv[0], appArgv);
- putenv(cgi_childs);
-
- /* fork and replace shell */
- b = malloc(strlen("exec ") + strlen(appPath) + 1);
+ } else {
+ char *b = malloc(strlen("exec ") + strlen(appPath) + 1);
strcpy(b, "exec ");
strcat(b, appPath);
/* exec the cgi */
execl("/bin/sh", "sh", "-c", b, (char *)NULL);
+ }
- exit(errno);
+ exit(errno);
+
+ break;
+ }
+ case -1:
+ /* error */
+ break;
+ default:
+ /* father */
+
+ /* wait */
+ select(0, NULL, NULL, NULL, &tv);
+
+ switch (waitpid(child, &status, WNOHANG)) {
+ case 0:
+ fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n",
+ __FILE__, __LINE__,
+ child);
+
+ /* write pid file */
+ if (pid_fd != -1) {
+ /* assume a 32bit pid_t */
+ char pidbuf[12];
+
+ snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child);
+
+ write(pid_fd, pidbuf, strlen(pidbuf));
+ close(pid_fd);
+ pid_fd = -1;
+ }
break;
- }
case -1:
- /* error */
break;
default:
- /* father */
-
- /* wait */
- select(0, NULL, NULL, NULL, &tv);
-
- switch (waitpid(child, &status, WNOHANG)) {
- case 0:
- fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n",
+ if (WIFEXITED(status)) {
+ fprintf(stderr, "%s.%d: child exited with: %d, %s\n",
+ __FILE__, __LINE__,
+ WEXITSTATUS(status), strerror(WEXITSTATUS(status)));
+ } else if (WIFSIGNALED(status)) {
+ fprintf(stderr, "%s.%d: child signaled: %d\n",
+ __FILE__, __LINE__,
+ WTERMSIG(status));
+ } else {
+ fprintf(stderr, "%s.%d: child died somehow: %d\n",
__FILE__, __LINE__,
- child);
-
- /* write pid file */
- if (pid_fd != -1) {
- /* assume a 32bit pid_t */
- char pidbuf[12];
-
- snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child);
-
- write(pid_fd, pidbuf, strlen(pidbuf));
- close(pid_fd);
- pid_fd = -1;
- }
-
- break;
- case -1:
- break;
- default:
- if (WIFEXITED(status)) {
- fprintf(stderr, "%s.%d: child exited with: %d, %s\n",
- __FILE__, __LINE__,
- WEXITSTATUS(status), strerror(WEXITSTATUS(status)));
- } else if (WIFSIGNALED(status)) {
- fprintf(stderr, "%s.%d: child signaled: %d\n",
- __FILE__, __LINE__,
- WTERMSIG(status));
- } else {
- fprintf(stderr, "%s.%d: child died somehow: %d\n",
- __FILE__, __LINE__,
- status);
- }
+ status);
}
-
- break;
}
- } else {
- fprintf(stderr, "%s.%d: socket is already used, can't spawn\n",
- __FILE__, __LINE__);
- return -1;
+
+ break;
}
close(fcgi_fd);
@@ -239,9 +245,12 @@ void show_version () {
}
void show_help () {
- char *b = "spawn-fcgi" "-" PACKAGE_VERSION \
-" - spawns fastcgi processes\n" \
-"usage:\n" \
+ char *b = \
+"Usage: spawn-fcgi [options] -- <fcgiapp> [fcgi app arguments]\n" \
+"\n" \
+"spawn-fcgi v" PACKAGE_VERSION " - spawns fastcgi processes\n" \
+"\n" \
+"Options:\n" \
" -f <fcgiapp> filename of the fcgi-application\n" \
" -a <addr> bind to ip address\n" \
" -p <port> bind to tcp-port\n" \
@@ -264,6 +273,7 @@ int main(int argc, char **argv) {
char *fcgi_app = NULL, *changeroot = NULL, *username = NULL,
*groupname = NULL, *unixsocket = NULL, *pid_file = NULL,
*addr = NULL;
+ char **fcgi_app_argv = { NULL };
unsigned short port = 0;
int child_count = 5;
int i_am_root, o;
@@ -274,10 +284,10 @@ int main(int argc, char **argv) {
i_am_root = (getuid() == 0);
- while(-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:s:P:"))) {
+ while(-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:s:P:"))) {
switch(o) {
case 'f': fcgi_app = optarg; break;
- case 'a': addr = optarg;/* ip addr */ break;
+ case 'a': addr = optarg;/* ip addr */ break;
case 'p': port = strtol(optarg, NULL, 10);/* port */ break;
case 'C': child_count = strtol(optarg, NULL, 10);/* */ break;
case 's': unixsocket = optarg; /* unix-domain socket */ break;
@@ -294,7 +304,11 @@ int main(int argc, char **argv) {
}
}
- if (fcgi_app == NULL || (port == 0 && unixsocket == NULL)) {
+ if (optind < argc) {
+ fcgi_app_argv = &argv[optind];
+ }
+
+ if ((fcgi_app == NULL && fcgi_app_argv == NULL) || (port == 0 && unixsocket == NULL)) {
show_help();
return -1;
}
@@ -404,6 +418,18 @@ int main(int argc, char **argv) {
}
}
+ /*
+ * Change group before chroot, when we have access
+ * to /etc/group
+ */
+ if (groupname) {
+ setgid(grp->gr_gid);
+ setgroups(0, NULL);
+ if (username) {
+ initgroups(username, grp->gr_gid);
+ }
+ }
+
if (changeroot) {
if (-1 == chroot(changeroot)) {
fprintf(stderr, "%s.%d: %s %s\n",
@@ -420,18 +446,12 @@ int main(int argc, char **argv) {
}
/* drop root privs */
- if (groupname) {
- setgid(grp->gr_gid);
- }
if (username) {
- if (groupname) {
- initgroups(username, grp->gr_gid);
- }
setuid(pwd->pw_uid);
}
}
- return fcgi_spawn_connection(fcgi_app, addr, port, unixsocket, child_count, pid_fd, nofork);
+ return fcgi_spawn_connection(fcgi_app, fcgi_app_argv, addr, port, unixsocket, child_count, pid_fd, nofork);
}
#else
int main() {
diff --git a/src/stream.c b/src/stream.c
index aac6cf7..d249647 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -64,6 +64,7 @@ int stream_open(stream *f, buffer *fn) {
NULL);
if (!mh) {
+/*
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
@@ -73,7 +74,7 @@ int stream_open(stream *f, buffer *fn) {
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
-
+*/
return -1;
}