summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am136
-rw-r--r--src/Makefile.in1431
-rw-r--r--src/SConscript192
-rw-r--r--src/array.c191
-rw-r--r--src/array.h71
-rw-r--r--src/base.h323
-rw-r--r--src/bitset.c6
-rw-r--r--src/buffer.c336
-rw-r--r--src/buffer.h26
-rw-r--r--src/chunk.c143
-rw-r--r--src/chunk.h16
-rw-r--r--src/configfile-glue.c328
-rw-r--r--src/configfile.c820
-rw-r--r--src/configfile.h6
-rw-r--r--src/configparser.c969
-rw-r--r--src/configparser.h23
-rw-r--r--src/configparser.y198
-rw-r--r--src/connections-glue.c9
-rw-r--r--src/connections.c1479
-rw-r--r--src/crc32.h6
-rw-r--r--src/data_array.c20
-rw-r--r--src/data_config.c56
-rw-r--r--src/data_count.c30
-rw-r--r--src/data_fastcgi.c28
-rw-r--r--src/data_integer.c24
-rw-r--r--src/data_string.c59
-rw-r--r--src/etag.c49
-rw-r--r--src/etag.h8
-rw-r--r--src/fastcgi.h4
-rw-r--r--src/fdevent.c139
-rw-r--r--src/fdevent.h144
-rw-r--r--src/fdevent_freebsd_kqueue.c123
-rw-r--r--src/fdevent_libev.c171
-rw-r--r--src/fdevent_linux_rtsig.c260
-rw-r--r--src/fdevent_linux_sysepoll.c94
-rw-r--r--src/fdevent_poll.c107
-rw-r--r--src/fdevent_select.c56
-rw-r--r--src/fdevent_solaris_devpoll.c106
-rw-r--r--src/fdevent_solaris_port.c172
-rw-r--r--src/http-header-glue.c216
-rw-r--r--src/http_auth.c957
-rw-r--r--src/http_auth.h35
-rw-r--r--src/http_auth_digest.c19
-rw-r--r--src/http_auth_digest.h24
-rw-r--r--src/http_chunk.c75
-rw-r--r--src/inet_ntop_cache.c29
-rw-r--r--src/joblist.c28
-rw-r--r--src/keyvalue.c127
-rw-r--r--src/keyvalue.h43
-rw-r--r--src/lemon.c118
-rw-r--r--src/lempar.c54
-rw-r--r--src/lighttpd-angel.c158
-rw-r--r--src/log.c302
-rw-r--r--src/log.h9
-rw-r--r--src/md5.c51
-rw-r--r--src/md5.h9
-rw-r--r--src/mod_access.c117
-rw-r--r--src/mod_accesslog.c670
-rw-r--r--src/mod_alias.c106
-rw-r--r--src/mod_auth.c523
-rw-r--r--src/mod_cgi.c992
-rw-r--r--src/mod_cml.c257
-rw-r--r--src/mod_cml.h16
-rw-r--r--src/mod_cml_funcs.c166
-rw-r--r--src/mod_cml_funcs.h2
-rw-r--r--src/mod_cml_lua.c256
-rw-r--r--src/mod_compress.c664
-rw-r--r--src/mod_dirlisting.c460
-rw-r--r--src/mod_evasive.c121
-rw-r--r--src/mod_evhost.c167
-rw-r--r--src/mod_expire.c219
-rw-r--r--src/mod_extforward.c517
-rw-r--r--src/mod_fastcgi.c3012
-rw-r--r--src/mod_flv_streaming.c277
-rw-r--r--src/mod_indexfile.c114
-rw-r--r--src/mod_magnet.c1110
-rw-r--r--src/mod_magnet_cache.c137
-rw-r--r--src/mod_magnet_cache.h33
-rw-r--r--src/mod_mysql_vhost.c172
-rw-r--r--src/mod_proxy.c838
-rw-r--r--src/mod_redirect.c183
-rw-r--r--src/mod_rewrite.c420
-rw-r--r--src/mod_rrdtool.c379
-rw-r--r--src/mod_scgi.c1852
-rw-r--r--src/mod_secure_download.c178
-rw-r--r--src/mod_setenv.c111
-rw-r--r--src/mod_simple_vhost.c127
-rw-r--r--src/mod_skeleton.c106
-rw-r--r--src/mod_ssi.c683
-rw-r--r--src/mod_ssi.h19
-rw-r--r--src/mod_ssi_expr.c198
-rw-r--r--src/mod_ssi_expr.h6
-rw-r--r--src/mod_ssi_exprparser.c167
-rw-r--r--src/mod_ssi_exprparser.y37
-rw-r--r--src/mod_staticfile.c356
-rw-r--r--src/mod_status.c646
-rw-r--r--src/mod_trigger_b4_dl.c269
-rw-r--r--src/mod_userdir.c153
-rw-r--r--src/mod_usertrack.c181
-rw-r--r--src/mod_webdav.c1353
-rw-r--r--src/network.c758
-rw-r--r--src/network.h2
-rw-r--r--src/network_backends.h24
-rw-r--r--src/network_freebsd_sendfile.c158
-rw-r--r--src/network_linux_sendfile.c173
-rw-r--r--src/network_openssl.c136
-rw-r--r--src/network_solaris_sendfilev.c118
-rw-r--r--src/network_write.c161
-rw-r--r--src/network_writev.c177
-rw-r--r--src/plugin.c176
-rw-r--r--src/plugin.h24
-rw-r--r--src/proc_open.c74
-rw-r--r--src/proc_open.h2
-rw-r--r--src/request.c742
-rw-r--r--src/response.c529
-rw-r--r--src/response.h5
-rw-r--r--src/server.c900
-rw-r--r--src/settings.h27
-rw-r--r--src/spawn-fcgi.c431
-rw-r--r--src/splaytree.c21
-rw-r--r--src/splaytree.h2
-rw-r--r--src/stat_cache.c343
-rw-r--r--src/stat_cache.h2
-rw-r--r--src/status_counter.c61
-rw-r--r--src/status_counter.h14
-rw-r--r--src/stream.c44
-rw-r--r--src/sys-socket.h1
-rw-r--r--src/version.h12
128 files changed, 20473 insertions, 13627 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 7e9fc9e..367f5d9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,31 +1,60 @@
+AM_CFLAGS = $(FAM_CFLAGS)
+
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
+sbin_PROGRAMS=lighttpd lighttpd-angel
+LEMON=$(top_builddir)/src/lemon$(EXEEXT)
lemon_SOURCES=lemon.c
-#simple_fcgi_SOURCES=simple-fcgi.c
-#simple_fcgi_LDADD=-lfcgi
+lighttpd_angel_SOURCES=lighttpd-angel.c
+
+.PHONY: versionstamp parsers
+
+versionstamp:
+ @test -f versionstamp.h || touch versionstamp.h; \
+ REVISION=""; \
+ if test -d "$(top_srcdir)/.svn" -a -x "`which svnversion`"; then \
+ REVISION="$$(LANG= LC_ALL=C svnversion "$(top_srcdir)" 2>/dev/null || echo exported)"; \
+ if test "$$REVISION" = "exported"; then \
+ REVISION=""; \
+ fi; \
+ fi; \
+ if test -z "$$REVISION" -a -d "$(top_srcdir)/.git" -a -x "`which git`"; then \
+ REVISION="$$(cd "$(top_srcdir)"; LANG= LC_ALL=C git describe --always 2>/dev/null || echo)"; \
+ fi; \
+ if test -n "$$REVISION"; then \
+ echo "#define REPO_VERSION \"-devel-$$REVISION\"" > versionstamp.h.tmp; \
+ else \
+ echo "#define REPO_VERSION \"\"" > versionstamp.h.tmp; \
+ fi; \
+ if ! diff versionstamp.h.tmp versionstamp.h >/dev/null 2>/dev/null; then \
+ mv versionstamp.h.tmp versionstamp.h; \
+ else \
+ rm versionstamp.h.tmp; \
+ fi
if CROSS_COMPILING
-configparser.c configparser.h:
-mod_ssi_exprparser.c mod_ssi_exprparser.h:
-else
-configparser.y: lemon
-mod_ssi_exprparser.y: lemon
+configparser.c configparser.h:
+mod_ssi_exprparser.c mod_ssi_exprparser.h:
-configparser.c configparser.h: configparser.y
+parsers:
+else
+configparser.h: configparser.c
+configparser.c: $(srcdir)/configparser.y $(srcdir)/lempar.c lemon$(EXEEXT)
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.h: mod_ssi_exprparser.c
+mod_ssi_exprparser.c: $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c lemon$(EXEEXT)
rm -f mod_ssi_exprparser.h
$(LEMON) -q $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c
+
+parsers: configparser.c mod_ssi_exprparser.c
endif
-configfile.c: configparser.h
-mod_ssi_expr.c: mod_ssi_exprparser.h
+BUILT_SOURCES = parsers versionstamp
+MAINTAINERCLEANFILES = configparser.c configparser.h mod_ssi_exprparser.c mod_ssi_exprparser.h
+CLEANFILES = versionstamp.h versionstamp.h.tmp
common_src=buffer.c log.c \
keyvalue.c chunk.c \
@@ -33,9 +62,10 @@ common_src=buffer.c log.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_select.c fdevent_libev.c \
fdevent_poll.c fdevent_linux_sysepoll.c \
- fdevent_solaris_devpoll.c fdevent_freebsd_kqueue.c \
+ fdevent_solaris_devpoll.c fdevent_solaris_port.c \
+ fdevent_freebsd_kqueue.c \
data_config.c bitset.c \
inet_ntop_cache.c crc32.c \
connections-glue.c \
@@ -44,14 +74,12 @@ common_src=buffer.c log.c \
network_write.c network_linux_sendfile.c \
network_freebsd_sendfile.c network_writev.c \
network_solaris_sendfilev.c network_openssl.c \
- splaytree.c
-
+ splaytree.c status_counter.c
+
src = server.c response.c connections.c network.c \
configfile.c configparser.c request.c proc_open.c
-spawn_fcgi_SOURCES=spawn-fcgi.c
-
-lib_LTLIBRARIES =
+lib_LTLIBRARIES =
if NO_RDYNAMIC
# if the linker doesn't allow referencing symbols of the binary
@@ -59,26 +87,36 @@ if NO_RDYNAMIC
# everything
lib_LTLIBRARIES += liblightcomp.la
liblightcomp_la_SOURCES=$(common_src)
-liblightcomp_la_CFLAGS=$(AM_CFLAGS) $(FAM_CFLAGS)
+liblightcomp_la_CFLAGS=$(AM_CFLAGS) $(LIBEV_CFLAGS)
liblightcomp_la_LDFLAGS = -avoid-version -no-undefined
-liblightcomp_la_LIBADD = $(PCRE_LIB) $(SSL_LIB) $(FAM_LIBS)
+liblightcomp_la_LIBADD = $(PCRE_LIB) $(SSL_LIB) $(FAM_LIBS) $(LIBEV_LIBS)
common_libadd = liblightcomp.la
else
src += $(common_src)
-common_libadd =
+common_libadd =
endif
+lib_LTLIBRARIES += mod_flv_streaming.la
+mod_flv_streaming_la_SOURCES = mod_flv_streaming.c
+mod_flv_streaming_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
+mod_flv_streaming_la_LIBADD = $(common_libadd)
+
lib_LTLIBRARIES += mod_evasive.la
mod_evasive_la_SOURCES = mod_evasive.c
mod_evasive_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_evasive_la_LIBADD = $(common_libadd)
-
lib_LTLIBRARIES += mod_webdav.la
mod_webdav_la_SOURCES = mod_webdav.c
-mod_webdav_la_CFLAGS = $(XML_CFLAGS)
+mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS)
mod_webdav_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS)
+mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS) $(UUID_LIBS)
+
+lib_LTLIBRARIES += mod_magnet.la
+mod_magnet_la_SOURCES = mod_magnet.c mod_magnet_cache.c
+mod_magnet_la_CFLAGS = $(AM_CFLAGS) $(LUA_CFLAGS)
+mod_magnet_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
+mod_magnet_la_LIBADD = $(common_libadd) $(LUA_LIBS) -lm
lib_LTLIBRARIES += mod_cml.la
mod_cml_la_SOURCES = mod_cml.c mod_cml_lua.c mod_cml_funcs.c
@@ -98,42 +136,42 @@ mod_mysql_vhost_la_LIBADD = $(MYSQL_LIBS) $(common_libadd)
mod_mysql_vhost_la_CPPFLAGS = $(MYSQL_INCLUDE)
lib_LTLIBRARIES += mod_cgi.la
-mod_cgi_la_SOURCES = mod_cgi.c
+mod_cgi_la_SOURCES = mod_cgi.c
mod_cgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_cgi_la_LIBADD = $(common_libadd)
lib_LTLIBRARIES += mod_scgi.la
-mod_scgi_la_SOURCES = mod_scgi.c
+mod_scgi_la_SOURCES = mod_scgi.c
mod_scgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_scgi_la_LIBADD = $(common_libadd)
lib_LTLIBRARIES += mod_staticfile.la
-mod_staticfile_la_SOURCES = mod_staticfile.c
+mod_staticfile_la_SOURCES = mod_staticfile.c
mod_staticfile_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_staticfile_la_LIBADD = $(common_libadd)
lib_LTLIBRARIES += mod_dirlisting.la
-mod_dirlisting_la_SOURCES = mod_dirlisting.c
+mod_dirlisting_la_SOURCES = mod_dirlisting.c
mod_dirlisting_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_dirlisting_la_LIBADD = $(common_libadd) $(PCRE_LIB)
lib_LTLIBRARIES += mod_indexfile.la
-mod_indexfile_la_SOURCES = mod_indexfile.c
+mod_indexfile_la_SOURCES = mod_indexfile.c
mod_indexfile_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_indexfile_la_LIBADD = $(common_libadd)
lib_LTLIBRARIES += mod_setenv.la
-mod_setenv_la_SOURCES = mod_setenv.c
+mod_setenv_la_SOURCES = mod_setenv.c
mod_setenv_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_setenv_la_LIBADD = $(common_libadd)
lib_LTLIBRARIES += mod_alias.la
-mod_alias_la_SOURCES = mod_alias.c
+mod_alias_la_SOURCES = mod_alias.c
mod_alias_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_alias_la_LIBADD = $(common_libadd)
lib_LTLIBRARIES += mod_userdir.la
-mod_userdir_la_SOURCES = mod_userdir.c
+mod_userdir_la_SOURCES = mod_userdir.c
mod_userdir_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_userdir_la_LIBADD = $(common_libadd)
@@ -153,7 +191,7 @@ mod_proxy_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_proxy_la_LIBADD = $(common_libadd)
lib_LTLIBRARIES += mod_ssi.la
-mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c
+mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c
mod_ssi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_ssi_la_LIBADD = $(common_libadd) $(PCRE_LIB)
@@ -181,24 +219,29 @@ lib_LTLIBRARIES += mod_simple_vhost.la
mod_simple_vhost_la_SOURCES = mod_simple_vhost.c
mod_simple_vhost_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_simple_vhost_la_LIBADD = $(common_libadd)
-
+
lib_LTLIBRARIES += mod_fastcgi.la
mod_fastcgi_la_SOURCES = mod_fastcgi.c
mod_fastcgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_fastcgi_la_LIBADD = $(common_libadd)
+lib_LTLIBRARIES += mod_extforward.la
+mod_extforward_la_SOURCES = mod_extforward.c
+mod_extforward_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
+mod_extforward_la_LIBADD = $(common_libadd)
+
lib_LTLIBRARIES += mod_access.la
mod_access_la_SOURCES = mod_access.c
mod_access_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_access_la_LIBADD = $(common_libadd)
lib_LTLIBRARIES += mod_compress.la
-mod_compress_la_SOURCES = mod_compress.c
+mod_compress_la_SOURCES = mod_compress.c
mod_compress_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_compress_la_LIBADD = $(Z_LIB) $(BZ_LIB) $(common_libadd)
lib_LTLIBRARIES += mod_auth.la
-mod_auth_la_SOURCES = mod_auth.c http_auth_digest.c http_auth.c
+mod_auth_la_SOURCES = mod_auth.c http_auth.c
mod_auth_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_auth_la_LIBADD = $(CRYPT_LIB) $(LDAP_LIB) $(LBER_LIB) $(common_libadd)
@@ -225,7 +268,7 @@ mod_accesslog_la_LIBADD = $(common_libadd)
hdr = server.h buffer.h network.h log.h keyvalue.h \
response.h request.h fastcgi.h chunk.h \
- settings.h http_chunk.h http_auth_digest.h \
+ settings.h http_chunk.h \
md5.h http_auth.h stream.h \
fdevent.h connections.h base.h stat_cache.h \
plugin.h mod_auth.h \
@@ -234,14 +277,16 @@ 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 proc_open.h
+ splaytree.h proc_open.h status_counter.h \
+ mod_magnet_cache.h \
+ version.h
-DEFS= @DEFS@ -DLIBRARY_DIR="\"$(libdir)\""
+DEFS= @DEFS@ -DHAVE_VERSION_H -DLIBRARY_DIR="\"$(libdir)\"" -DSBIN_DIR="\"$(sbindir)\""
lighttpd_SOURCES = $(src)
-lighttpd_LDADD = $(PCRE_LIB) $(DL_LIB) $(SENDFILE_LIB) $(ATTR_LIB) $(common_libadd) $(SSL_LIB) $(FAM_LIBS)
+lighttpd_LDADD = $(PCRE_LIB) $(DL_LIB) $(SENDFILE_LIB) $(ATTR_LIB) $(common_libadd) $(SSL_LIB) $(FAM_LIBS) $(LIBEV_LIBS)
lighttpd_LDFLAGS = -export-dynamic
-lighttpd_CCPFLAGS = $(FAM_CFLAGS)
+lighttpd_CCPFLAGS = $(FAM_CFLAGS) $(LIBEV_CFLAGS)
proc_open_SOURCES = proc_open.c buffer.c
proc_open_CPPFLAGS= -DDEBUG_PROC_OPEN
@@ -261,4 +306,5 @@ 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 cc6fab9..705e7ef 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,8 +1,9 @@
-# Makefile.in generated by automake 1.9.5 from Makefile.am.
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005 Free Software Foundation, Inc.
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -16,17 +17,29 @@
-SOURCES = $(liblightcomp_la_SOURCES) $(mod_access_la_SOURCES) $(mod_accesslog_la_SOURCES) $(mod_alias_la_SOURCES) $(mod_auth_la_SOURCES) $(mod_cgi_la_SOURCES) $(mod_cml_la_SOURCES) $(mod_compress_la_SOURCES) $(mod_dirlisting_la_SOURCES) $(mod_evasive_la_SOURCES) $(mod_evhost_la_SOURCES) $(mod_expire_la_SOURCES) $(mod_fastcgi_la_SOURCES) $(mod_indexfile_la_SOURCES) $(mod_mysql_vhost_la_SOURCES) $(mod_proxy_la_SOURCES) $(mod_redirect_la_SOURCES) $(mod_rewrite_la_SOURCES) $(mod_rrdtool_la_SOURCES) $(mod_scgi_la_SOURCES) $(mod_secdownload_la_SOURCES) $(mod_setenv_la_SOURCES) $(mod_simple_vhost_la_SOURCES) $(mod_ssi_la_SOURCES) $(mod_staticfile_la_SOURCES) $(mod_status_la_SOURCES) $(mod_trigger_b4_dl_la_SOURCES) $(mod_userdir_la_SOURCES) $(mod_usertrack_la_SOURCES) $(mod_webdav_la_SOURCES) $(lemon_SOURCES) $(lighttpd_SOURCES) $(proc_open_SOURCES) $(spawn_fcgi_SOURCES)
-
-srcdir = @srcdir@
-top_srcdir = @top_srcdir@
VPATH = @srcdir@
+am__make_dryrun = \
+ { \
+ am__dry=no; \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
+ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+ *) \
+ for am__flg in $$MAKEFLAGS; do \
+ case $$am__flg in \
+ *=*|--*) ;; \
+ *n*) am__dry=yes; break;; \
+ esac; \
+ done;; \
+ esac; \
+ test $$am__dry = yes; \
+ }
pkgdatadir = $(datadir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
-top_builddir = ..
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-INSTALL = @INSTALL@
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
@@ -42,8 +55,7 @@ build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
noinst_PROGRAMS = proc_open$(EXEEXT) lemon$(EXEEXT)
-sbin_PROGRAMS = lighttpd$(EXEEXT)
-bin_PROGRAMS = spawn-fcgi$(EXEEXT)
+sbin_PROGRAMS = lighttpd$(EXEEXT) lighttpd-angel$(EXEEXT)
# if the linker doesn't allow referencing symbols of the binary
# we have to put everything into a shared-lib and link it into
@@ -54,37 +66,61 @@ subdir = src
DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
-am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
-am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
- "$(DESTDIR)$(sbindir)"
-libLTLIBRARIES_INSTALL = $(INSTALL)
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(sbindir)"
LTLIBRARIES = $(lib_LTLIBRARIES)
am__DEPENDENCIES_1 =
@NO_RDYNAMIC_TRUE@liblightcomp_la_DEPENDENCIES = \
@NO_RDYNAMIC_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
-@NO_RDYNAMIC_TRUE@ $(am__DEPENDENCIES_1)
+@NO_RDYNAMIC_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
am__liblightcomp_la_SOURCES_DIST = 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_select.c fdevent_libev.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 network_write.c network_linux_sendfile.c \
- network_freebsd_sendfile.c network_writev.c \
- network_solaris_sendfilev.c network_openssl.c splaytree.c
+ fdevent_solaris_port.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 network_write.c \
+ network_linux_sendfile.c network_freebsd_sendfile.c \
+ network_writev.c network_solaris_sendfilev.c network_openssl.c \
+ splaytree.c status_counter.c
am__objects_1 = liblightcomp_la-buffer.lo liblightcomp_la-log.lo \
liblightcomp_la-keyvalue.lo liblightcomp_la-chunk.lo \
liblightcomp_la-http_chunk.lo liblightcomp_la-stream.lo \
@@ -95,10 +131,11 @@ am__objects_1 = liblightcomp_la-buffer.lo liblightcomp_la-log.lo \
liblightcomp_la-data_array.lo liblightcomp_la-data_integer.lo \
liblightcomp_la-md5.lo liblightcomp_la-data_fastcgi.lo \
liblightcomp_la-fdevent_select.lo \
- liblightcomp_la-fdevent_linux_rtsig.lo \
+ liblightcomp_la-fdevent_libev.lo \
liblightcomp_la-fdevent_poll.lo \
liblightcomp_la-fdevent_linux_sysepoll.lo \
liblightcomp_la-fdevent_solaris_devpoll.lo \
+ liblightcomp_la-fdevent_solaris_port.lo \
liblightcomp_la-fdevent_freebsd_kqueue.lo \
liblightcomp_la-data_config.lo liblightcomp_la-bitset.lo \
liblightcomp_la-inet_ntop_cache.lo liblightcomp_la-crc32.lo \
@@ -111,113 +148,244 @@ am__objects_1 = liblightcomp_la-buffer.lo liblightcomp_la-log.lo \
liblightcomp_la-network_writev.lo \
liblightcomp_la-network_solaris_sendfilev.lo \
liblightcomp_la-network_openssl.lo \
- liblightcomp_la-splaytree.lo
+ liblightcomp_la-splaytree.lo liblightcomp_la-status_counter.lo
@NO_RDYNAMIC_TRUE@am_liblightcomp_la_OBJECTS = $(am__objects_1)
liblightcomp_la_OBJECTS = $(am_liblightcomp_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+liblightcomp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(liblightcomp_la_CFLAGS) $(CFLAGS) $(liblightcomp_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
@NO_RDYNAMIC_TRUE@am_liblightcomp_la_rpath = -rpath $(libdir)
@NO_RDYNAMIC_TRUE@am__DEPENDENCIES_2 = liblightcomp.la
mod_access_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_access_la_OBJECTS = mod_access.lo
mod_access_la_OBJECTS = $(am_mod_access_la_OBJECTS)
+mod_access_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_access_la_LDFLAGS) $(LDFLAGS) -o $@
mod_accesslog_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_accesslog_la_OBJECTS = mod_accesslog.lo
mod_accesslog_la_OBJECTS = $(am_mod_accesslog_la_OBJECTS)
+mod_accesslog_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_accesslog_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
mod_alias_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_alias_la_OBJECTS = mod_alias.lo
mod_alias_la_OBJECTS = $(am_mod_alias_la_OBJECTS)
+mod_alias_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_alias_la_LDFLAGS) $(LDFLAGS) -o $@
mod_auth_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
-am_mod_auth_la_OBJECTS = mod_auth.lo http_auth_digest.lo http_auth.lo
+am_mod_auth_la_OBJECTS = mod_auth.lo http_auth.lo
mod_auth_la_OBJECTS = $(am_mod_auth_la_OBJECTS)
+mod_auth_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_auth_la_LDFLAGS) $(LDFLAGS) -o $@
mod_cgi_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_cgi_la_OBJECTS = mod_cgi.lo
mod_cgi_la_OBJECTS = $(am_mod_cgi_la_OBJECTS)
+mod_cgi_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_cgi_la_LDFLAGS) $(LDFLAGS) -o $@
mod_cml_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
$(am__DEPENDENCIES_1)
am_mod_cml_la_OBJECTS = mod_cml_la-mod_cml.lo \
mod_cml_la-mod_cml_lua.lo mod_cml_la-mod_cml_funcs.lo
mod_cml_la_OBJECTS = $(am_mod_cml_la_OBJECTS)
+mod_cml_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(mod_cml_la_CFLAGS) \
+ $(CFLAGS) $(mod_cml_la_LDFLAGS) $(LDFLAGS) -o $@
mod_compress_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
am_mod_compress_la_OBJECTS = mod_compress.lo
mod_compress_la_OBJECTS = $(am_mod_compress_la_OBJECTS)
+mod_compress_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_compress_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
mod_dirlisting_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
$(am__DEPENDENCIES_1)
am_mod_dirlisting_la_OBJECTS = mod_dirlisting.lo
mod_dirlisting_la_OBJECTS = $(am_mod_dirlisting_la_OBJECTS)
+mod_dirlisting_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_dirlisting_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
mod_evasive_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_evasive_la_OBJECTS = mod_evasive.lo
mod_evasive_la_OBJECTS = $(am_mod_evasive_la_OBJECTS)
+mod_evasive_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_evasive_la_LDFLAGS) $(LDFLAGS) -o \
+ $@
mod_evhost_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_evhost_la_OBJECTS = mod_evhost.lo
mod_evhost_la_OBJECTS = $(am_mod_evhost_la_OBJECTS)
+mod_evhost_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_evhost_la_LDFLAGS) $(LDFLAGS) -o $@
mod_expire_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_expire_la_OBJECTS = mod_expire.lo
mod_expire_la_OBJECTS = $(am_mod_expire_la_OBJECTS)
+mod_expire_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_expire_la_LDFLAGS) $(LDFLAGS) -o $@
+mod_extforward_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_extforward_la_OBJECTS = mod_extforward.lo
+mod_extforward_la_OBJECTS = $(am_mod_extforward_la_OBJECTS)
+mod_extforward_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_extforward_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
mod_fastcgi_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_fastcgi_la_OBJECTS = mod_fastcgi.lo
mod_fastcgi_la_OBJECTS = $(am_mod_fastcgi_la_OBJECTS)
+mod_fastcgi_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_fastcgi_la_LDFLAGS) $(LDFLAGS) -o \
+ $@
+mod_flv_streaming_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_flv_streaming_la_OBJECTS = mod_flv_streaming.lo
+mod_flv_streaming_la_OBJECTS = $(am_mod_flv_streaming_la_OBJECTS)
+mod_flv_streaming_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_flv_streaming_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
mod_indexfile_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_indexfile_la_OBJECTS = mod_indexfile.lo
mod_indexfile_la_OBJECTS = $(am_mod_indexfile_la_OBJECTS)
+mod_indexfile_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_indexfile_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+mod_magnet_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_1)
+am_mod_magnet_la_OBJECTS = mod_magnet_la-mod_magnet.lo \
+ mod_magnet_la-mod_magnet_cache.lo
+mod_magnet_la_OBJECTS = $(am_mod_magnet_la_OBJECTS)
+mod_magnet_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(mod_magnet_la_CFLAGS) \
+ $(CFLAGS) $(mod_magnet_la_LDFLAGS) $(LDFLAGS) -o $@
mod_mysql_vhost_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_2)
am_mod_mysql_vhost_la_OBJECTS = mod_mysql_vhost_la-mod_mysql_vhost.lo
mod_mysql_vhost_la_OBJECTS = $(am_mod_mysql_vhost_la_OBJECTS)
+mod_mysql_vhost_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_mysql_vhost_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
mod_proxy_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_proxy_la_OBJECTS = mod_proxy.lo
mod_proxy_la_OBJECTS = $(am_mod_proxy_la_OBJECTS)
+mod_proxy_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_proxy_la_LDFLAGS) $(LDFLAGS) -o $@
mod_redirect_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_2)
am_mod_redirect_la_OBJECTS = mod_redirect.lo
mod_redirect_la_OBJECTS = $(am_mod_redirect_la_OBJECTS)
+mod_redirect_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_redirect_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
mod_rewrite_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_2)
am_mod_rewrite_la_OBJECTS = mod_rewrite.lo
mod_rewrite_la_OBJECTS = $(am_mod_rewrite_la_OBJECTS)
+mod_rewrite_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_rewrite_la_LDFLAGS) $(LDFLAGS) -o \
+ $@
mod_rrdtool_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_rrdtool_la_OBJECTS = mod_rrdtool.lo
mod_rrdtool_la_OBJECTS = $(am_mod_rrdtool_la_OBJECTS)
+mod_rrdtool_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_rrdtool_la_LDFLAGS) $(LDFLAGS) -o \
+ $@
mod_scgi_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_scgi_la_OBJECTS = mod_scgi.lo
mod_scgi_la_OBJECTS = $(am_mod_scgi_la_OBJECTS)
+mod_scgi_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_scgi_la_LDFLAGS) $(LDFLAGS) -o $@
mod_secdownload_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_secdownload_la_OBJECTS = mod_secure_download.lo
mod_secdownload_la_OBJECTS = $(am_mod_secdownload_la_OBJECTS)
+mod_secdownload_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_secdownload_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
mod_setenv_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_setenv_la_OBJECTS = mod_setenv.lo
mod_setenv_la_OBJECTS = $(am_mod_setenv_la_OBJECTS)
+mod_setenv_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_setenv_la_LDFLAGS) $(LDFLAGS) -o $@
mod_simple_vhost_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_simple_vhost_la_OBJECTS = mod_simple_vhost.lo
mod_simple_vhost_la_OBJECTS = $(am_mod_simple_vhost_la_OBJECTS)
+mod_simple_vhost_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_simple_vhost_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
mod_ssi_la_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1)
am_mod_ssi_la_OBJECTS = mod_ssi_exprparser.lo mod_ssi_expr.lo \
mod_ssi.lo
mod_ssi_la_OBJECTS = $(am_mod_ssi_la_OBJECTS)
+mod_ssi_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_ssi_la_LDFLAGS) $(LDFLAGS) -o $@
mod_staticfile_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_staticfile_la_OBJECTS = mod_staticfile.lo
mod_staticfile_la_OBJECTS = $(am_mod_staticfile_la_OBJECTS)
+mod_staticfile_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_staticfile_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
mod_status_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_status_la_OBJECTS = mod_status.lo
mod_status_la_OBJECTS = $(am_mod_status_la_OBJECTS)
+mod_status_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(mod_status_la_LDFLAGS) $(LDFLAGS) -o $@
mod_trigger_b4_dl_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_2)
am_mod_trigger_b4_dl_la_OBJECTS = mod_trigger_b4_dl.lo
mod_trigger_b4_dl_la_OBJECTS = $(am_mod_trigger_b4_dl_la_OBJECTS)
+mod_trigger_b4_dl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_trigger_b4_dl_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
mod_userdir_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_userdir_la_OBJECTS = mod_userdir.lo
mod_userdir_la_OBJECTS = $(am_mod_userdir_la_OBJECTS)
+mod_userdir_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_userdir_la_LDFLAGS) $(LDFLAGS) -o \
+ $@
mod_usertrack_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_usertrack_la_OBJECTS = mod_usertrack.lo
mod_usertrack_la_OBJECTS = $(am_mod_usertrack_la_OBJECTS)
+mod_usertrack_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(mod_usertrack_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
mod_webdav_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
- $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
am_mod_webdav_la_OBJECTS = mod_webdav_la-mod_webdav.lo
mod_webdav_la_OBJECTS = $(am_mod_webdav_la_OBJECTS)
-binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
-sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
-PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) $(sbin_PROGRAMS)
+mod_webdav_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(mod_webdav_la_CFLAGS) \
+ $(CFLAGS) $(mod_webdav_la_LDFLAGS) $(LDFLAGS) -o $@
+PROGRAMS = $(noinst_PROGRAMS) $(sbin_PROGRAMS)
am_lemon_OBJECTS = lemon.$(OBJEXT)
lemon_OBJECTS = $(am_lemon_OBJECTS)
lemon_LDADD = $(LDADD)
@@ -226,14 +394,14 @@ am__lighttpd_SOURCES_DIST = server.c response.c connections.c \
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 \
- network_write.c network_linux_sendfile.c \
- network_freebsd_sendfile.c network_writev.c \
- network_solaris_sendfilev.c network_openssl.c splaytree.c
+ data_fastcgi.c fdevent_select.c fdevent_libev.c fdevent_poll.c \
+ fdevent_linux_sysepoll.c fdevent_solaris_devpoll.c \
+ fdevent_solaris_port.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 network_write.c \
+ network_linux_sendfile.c network_freebsd_sendfile.c \
+ network_writev.c network_solaris_sendfilev.c network_openssl.c \
+ splaytree.c status_counter.c
am__objects_2 = buffer.$(OBJEXT) log.$(OBJEXT) keyvalue.$(OBJEXT) \
chunk.$(OBJEXT) http_chunk.$(OBJEXT) stream.$(OBJEXT) \
fdevent.$(OBJEXT) stat_cache.$(OBJEXT) plugin.$(OBJEXT) \
@@ -241,9 +409,10 @@ am__objects_2 = buffer.$(OBJEXT) log.$(OBJEXT) keyvalue.$(OBJEXT) \
data_string.$(OBJEXT) data_count.$(OBJEXT) \
data_array.$(OBJEXT) data_integer.$(OBJEXT) md5.$(OBJEXT) \
data_fastcgi.$(OBJEXT) fdevent_select.$(OBJEXT) \
- fdevent_linux_rtsig.$(OBJEXT) fdevent_poll.$(OBJEXT) \
+ fdevent_libev.$(OBJEXT) fdevent_poll.$(OBJEXT) \
fdevent_linux_sysepoll.$(OBJEXT) \
fdevent_solaris_devpoll.$(OBJEXT) \
+ fdevent_solaris_port.$(OBJEXT) \
fdevent_freebsd_kqueue.$(OBJEXT) data_config.$(OBJEXT) \
bitset.$(OBJEXT) inet_ntop_cache.$(OBJEXT) crc32.$(OBJEXT) \
connections-glue.$(OBJEXT) configfile-glue.$(OBJEXT) \
@@ -251,7 +420,7 @@ am__objects_2 = buffer.$(OBJEXT) log.$(OBJEXT) keyvalue.$(OBJEXT) \
network_linux_sendfile.$(OBJEXT) \
network_freebsd_sendfile.$(OBJEXT) network_writev.$(OBJEXT) \
network_solaris_sendfilev.$(OBJEXT) network_openssl.$(OBJEXT) \
- splaytree.$(OBJEXT)
+ splaytree.$(OBJEXT) status_counter.$(OBJEXT)
@NO_RDYNAMIC_FALSE@am__objects_3 = $(am__objects_2)
am__objects_4 = server.$(OBJEXT) response.$(OBJEXT) \
connections.$(OBJEXT) network.$(OBJEXT) configfile.$(OBJEXT) \
@@ -262,32 +431,70 @@ lighttpd_OBJECTS = $(am_lighttpd_OBJECTS)
lighttpd_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+lighttpd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(lighttpd_LDFLAGS) $(LDFLAGS) -o $@
+am_lighttpd_angel_OBJECTS = lighttpd-angel.$(OBJEXT)
+lighttpd_angel_OBJECTS = $(am_lighttpd_angel_OBJECTS)
+lighttpd_angel_LDADD = $(LDADD)
am_proc_open_OBJECTS = proc_open-proc_open.$(OBJEXT) \
proc_open-buffer.$(OBJEXT)
proc_open_OBJECTS = $(am_proc_open_OBJECTS)
proc_open_LDADD = $(LDADD)
-am_spawn_fcgi_OBJECTS = spawn-fcgi.$(OBJEXT)
-spawn_fcgi_OBJECTS = $(am_spawn_fcgi_OBJECTS)
-spawn_fcgi_LDADD = $(LDADD)
-DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
+am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
CCLD = $(CC)
-LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
SOURCES = $(liblightcomp_la_SOURCES) $(mod_access_la_SOURCES) \
$(mod_accesslog_la_SOURCES) $(mod_alias_la_SOURCES) \
$(mod_auth_la_SOURCES) $(mod_cgi_la_SOURCES) \
$(mod_cml_la_SOURCES) $(mod_compress_la_SOURCES) \
$(mod_dirlisting_la_SOURCES) $(mod_evasive_la_SOURCES) \
$(mod_evhost_la_SOURCES) $(mod_expire_la_SOURCES) \
- $(mod_fastcgi_la_SOURCES) $(mod_indexfile_la_SOURCES) \
+ $(mod_extforward_la_SOURCES) $(mod_fastcgi_la_SOURCES) \
+ $(mod_flv_streaming_la_SOURCES) $(mod_indexfile_la_SOURCES) \
+ $(mod_magnet_la_SOURCES) $(mod_mysql_vhost_la_SOURCES) \
+ $(mod_proxy_la_SOURCES) $(mod_redirect_la_SOURCES) \
+ $(mod_rewrite_la_SOURCES) $(mod_rrdtool_la_SOURCES) \
+ $(mod_scgi_la_SOURCES) $(mod_secdownload_la_SOURCES) \
+ $(mod_setenv_la_SOURCES) $(mod_simple_vhost_la_SOURCES) \
+ $(mod_ssi_la_SOURCES) $(mod_staticfile_la_SOURCES) \
+ $(mod_status_la_SOURCES) $(mod_trigger_b4_dl_la_SOURCES) \
+ $(mod_userdir_la_SOURCES) $(mod_usertrack_la_SOURCES) \
+ $(mod_webdav_la_SOURCES) $(lemon_SOURCES) $(lighttpd_SOURCES) \
+ $(lighttpd_angel_SOURCES) $(proc_open_SOURCES)
+DIST_SOURCES = $(am__liblightcomp_la_SOURCES_DIST) \
+ $(mod_access_la_SOURCES) $(mod_accesslog_la_SOURCES) \
+ $(mod_alias_la_SOURCES) $(mod_auth_la_SOURCES) \
+ $(mod_cgi_la_SOURCES) $(mod_cml_la_SOURCES) \
+ $(mod_compress_la_SOURCES) $(mod_dirlisting_la_SOURCES) \
+ $(mod_evasive_la_SOURCES) $(mod_evhost_la_SOURCES) \
+ $(mod_expire_la_SOURCES) $(mod_extforward_la_SOURCES) \
+ $(mod_fastcgi_la_SOURCES) $(mod_flv_streaming_la_SOURCES) \
+ $(mod_indexfile_la_SOURCES) $(mod_magnet_la_SOURCES) \
$(mod_mysql_vhost_la_SOURCES) $(mod_proxy_la_SOURCES) \
$(mod_redirect_la_SOURCES) $(mod_rewrite_la_SOURCES) \
$(mod_rrdtool_la_SOURCES) $(mod_scgi_la_SOURCES) \
@@ -296,34 +503,20 @@ SOURCES = $(liblightcomp_la_SOURCES) $(mod_access_la_SOURCES) \
$(mod_staticfile_la_SOURCES) $(mod_status_la_SOURCES) \
$(mod_trigger_b4_dl_la_SOURCES) $(mod_userdir_la_SOURCES) \
$(mod_usertrack_la_SOURCES) $(mod_webdav_la_SOURCES) \
- $(lemon_SOURCES) $(lighttpd_SOURCES) $(proc_open_SOURCES) \
- $(spawn_fcgi_SOURCES)
-DIST_SOURCES = $(am__liblightcomp_la_SOURCES_DIST) \
- $(mod_access_la_SOURCES) $(mod_accesslog_la_SOURCES) \
- $(mod_alias_la_SOURCES) $(mod_auth_la_SOURCES) \
- $(mod_cgi_la_SOURCES) $(mod_cml_la_SOURCES) \
- $(mod_compress_la_SOURCES) $(mod_dirlisting_la_SOURCES) \
- $(mod_evasive_la_SOURCES) $(mod_evhost_la_SOURCES) \
- $(mod_expire_la_SOURCES) $(mod_fastcgi_la_SOURCES) \
- $(mod_indexfile_la_SOURCES) $(mod_mysql_vhost_la_SOURCES) \
- $(mod_proxy_la_SOURCES) $(mod_redirect_la_SOURCES) \
- $(mod_rewrite_la_SOURCES) $(mod_rrdtool_la_SOURCES) \
- $(mod_scgi_la_SOURCES) $(mod_secdownload_la_SOURCES) \
- $(mod_setenv_la_SOURCES) $(mod_simple_vhost_la_SOURCES) \
- $(mod_ssi_la_SOURCES) $(mod_staticfile_la_SOURCES) \
- $(mod_status_la_SOURCES) $(mod_trigger_b4_dl_la_SOURCES) \
- $(mod_userdir_la_SOURCES) $(mod_usertrack_la_SOURCES) \
- $(mod_webdav_la_SOURCES) $(lemon_SOURCES) \
- $(am__lighttpd_SOURCES_DIST) $(proc_open_SOURCES) \
- $(spawn_fcgi_SOURCES)
+ $(lemon_SOURCES) $(am__lighttpd_SOURCES_DIST) \
+ $(lighttpd_angel_SOURCES) $(proc_open_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
HEADERS = $(noinst_HEADERS)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
-AMDEP_FALSE = @AMDEP_FALSE@
-AMDEP_TRUE = @AMDEP_TRUE@
AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
ATTR_LIB = @ATTR_LIB@
AUTOCONF = @AUTOCONF@
@@ -334,69 +527,73 @@ BZ_LIB = @BZ_LIB@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
-CHECK_WITH_FASTCGI_FALSE = @CHECK_WITH_FASTCGI_FALSE@
-CHECK_WITH_FASTCGI_TRUE = @CHECK_WITH_FASTCGI_TRUE@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
-CROSS_COMPILING_FALSE = @CROSS_COMPILING_FALSE@
-CROSS_COMPILING_TRUE = @CROSS_COMPILING_TRUE@
CRYPT_LIB = @CRYPT_LIB@
-CXX = @CXX@
-CXXCPP = @CXXCPP@
-CXXDEPMODE = @CXXDEPMODE@
-CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
-DEFS = @DEFS@ -DLIBRARY_DIR="\"$(libdir)\""
+DEFS = @DEFS@ -DHAVE_VERSION_H -DLIBRARY_DIR="\"$(libdir)\"" -DSBIN_DIR="\"$(sbindir)\""
DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
DL_LIB = @DL_LIB@
-ECHO = @ECHO@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
-F77 = @F77@
FAM_CFLAGS = @FAM_CFLAGS@
FAM_LIBS = @FAM_LIBS@
-FFLAGS = @FFLAGS@
+FGREP = @FGREP@
GDBM_LIB = @GDBM_LIB@
+GREP = @GREP@
+INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LBER_LIB = @LBER_LIB@
+LD = @LD@
LDAP_LIB = @LDAP_LIB@
LDFLAGS = @LDFLAGS@
+LIBEV_CFLAGS = @LIBEV_CFLAGS@
+LIBEV_LIBS = @LIBEV_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
-LUACONFIG = @LUACONFIG@
LUA_CFLAGS = @LUA_CFLAGS@
LUA_LIBS = @LUA_LIBS@
-MAINT = @MAINT@
-MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
-MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
MEMCACHE_LIB = @MEMCACHE_LIB@
+MKDIR_P = @MKDIR_P@
MYSQL_CONFIG = @MYSQL_CONFIG@
MYSQL_INCLUDE = @MYSQL_INCLUDE@
MYSQL_LIBS = @MYSQL_LIBS@
-NO_RDYNAMIC_FALSE = @NO_RDYNAMIC_FALSE@
-NO_RDYNAMIC_TRUE = @NO_RDYNAMIC_TRUE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PCRECONFIG = @PCRECONFIG@
PCRE_LIB = @PCRE_LIB@
PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
RANLIB = @RANLIB@
+SED = @SED@
SENDFILE_LIB = @SENDFILE_LIB@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
@@ -404,21 +601,18 @@ SQLITE_CFLAGS = @SQLITE_CFLAGS@
SQLITE_LIBS = @SQLITE_LIBS@
SSL_LIB = @SSL_LIB@
STRIP = @STRIP@
-U = @U@
+UUID_LIBS = @UUID_LIBS@
VERSION = @VERSION@
XML_CFLAGS = @XML_CFLAGS@
XML_LIBS = @XML_LIBS@
Z_LIB = @Z_LIB@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
-ac_ct_CXX = @ac_ct_CXX@
-ac_ct_F77 = @ac_ct_F77@
-ac_ct_RANLIB = @ac_ct_RANLIB@
-ac_ct_STRIP = @ac_ct_STRIP@
-am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
-am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
-am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
-am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
@@ -430,43 +624,61 @@ build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
+builddir = @builddir@
datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
+htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
+localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
+psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
sysconfdir = @sysconfdir@
target = @target@
target_alias = @target_alias@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
-LEMON = $(top_builddir)/src/lemon
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CFLAGS = $(FAM_CFLAGS)
+LEMON = $(top_builddir)/src/lemon$(EXEEXT)
lemon_SOURCES = lemon.c
+lighttpd_angel_SOURCES = lighttpd-angel.c
+BUILT_SOURCES = parsers versionstamp
+MAINTAINERCLEANFILES = configparser.c configparser.h mod_ssi_exprparser.c mod_ssi_exprparser.h
+CLEANFILES = versionstamp.h versionstamp.h.tmp
common_src = 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_select.c fdevent_libev.c \
fdevent_poll.c fdevent_linux_sysepoll.c \
- fdevent_solaris_devpoll.c fdevent_freebsd_kqueue.c \
+ fdevent_solaris_devpoll.c fdevent_solaris_port.c \
+ fdevent_freebsd_kqueue.c \
data_config.c bitset.c \
inet_ntop_cache.c crc32.c \
connections-glue.c \
@@ -475,38 +687,44 @@ common_src = buffer.c log.c \
network_write.c network_linux_sendfile.c \
network_freebsd_sendfile.c network_writev.c \
network_solaris_sendfilev.c network_openssl.c \
- splaytree.c
+ splaytree.c status_counter.c
src = server.c response.c connections.c network.c configfile.c \
configparser.c request.c proc_open.c $(am__append_2)
-spawn_fcgi_SOURCES = spawn-fcgi.c
#lib_LTLIBRARIES += mod_httptls.la
#mod_httptls_la_SOURCES = mod_httptls.c
#mod_httptls_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
#mod_httptls_la_LIBADD = $(common_libadd)
-lib_LTLIBRARIES = $(am__append_1) mod_evasive.la mod_webdav.la \
- mod_cml.la mod_trigger_b4_dl.la mod_mysql_vhost.la mod_cgi.la \
- mod_scgi.la mod_staticfile.la mod_dirlisting.la \
- mod_indexfile.la mod_setenv.la mod_alias.la mod_userdir.la \
- mod_rrdtool.la mod_usertrack.la mod_proxy.la mod_ssi.la \
- mod_secdownload.la mod_expire.la mod_evhost.la \
- mod_simple_vhost.la mod_fastcgi.la mod_access.la \
- mod_compress.la mod_auth.la mod_rewrite.la mod_redirect.la \
- mod_status.la mod_accesslog.la
+lib_LTLIBRARIES = $(am__append_1) mod_flv_streaming.la mod_evasive.la \
+ mod_webdav.la mod_magnet.la mod_cml.la mod_trigger_b4_dl.la \
+ mod_mysql_vhost.la mod_cgi.la mod_scgi.la mod_staticfile.la \
+ mod_dirlisting.la mod_indexfile.la mod_setenv.la mod_alias.la \
+ mod_userdir.la mod_rrdtool.la mod_usertrack.la mod_proxy.la \
+ mod_ssi.la mod_secdownload.la mod_expire.la mod_evhost.la \
+ mod_simple_vhost.la mod_fastcgi.la mod_extforward.la \
+ mod_access.la mod_compress.la mod_auth.la mod_rewrite.la \
+ mod_redirect.la mod_status.la mod_accesslog.la
@NO_RDYNAMIC_TRUE@liblightcomp_la_SOURCES = $(common_src)
-@NO_RDYNAMIC_TRUE@liblightcomp_la_CFLAGS = $(AM_CFLAGS) $(FAM_CFLAGS)
+@NO_RDYNAMIC_TRUE@liblightcomp_la_CFLAGS = $(AM_CFLAGS) $(LIBEV_CFLAGS)
@NO_RDYNAMIC_TRUE@liblightcomp_la_LDFLAGS = -avoid-version -no-undefined
-@NO_RDYNAMIC_TRUE@liblightcomp_la_LIBADD = $(PCRE_LIB) $(SSL_LIB) $(FAM_LIBS)
+@NO_RDYNAMIC_TRUE@liblightcomp_la_LIBADD = $(PCRE_LIB) $(SSL_LIB) $(FAM_LIBS) $(LIBEV_LIBS)
@NO_RDYNAMIC_FALSE@common_libadd =
@NO_RDYNAMIC_TRUE@common_libadd = liblightcomp.la
+mod_flv_streaming_la_SOURCES = mod_flv_streaming.c
+mod_flv_streaming_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
+mod_flv_streaming_la_LIBADD = $(common_libadd)
mod_evasive_la_SOURCES = mod_evasive.c
mod_evasive_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_evasive_la_LIBADD = $(common_libadd)
mod_webdav_la_SOURCES = mod_webdav.c
-mod_webdav_la_CFLAGS = $(XML_CFLAGS)
+mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS)
mod_webdav_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
-mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS)
+mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS) $(UUID_LIBS)
+mod_magnet_la_SOURCES = mod_magnet.c mod_magnet_cache.c
+mod_magnet_la_CFLAGS = $(AM_CFLAGS) $(LUA_CFLAGS)
+mod_magnet_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
+mod_magnet_la_LIBADD = $(common_libadd) $(LUA_LIBS) -lm
mod_cml_la_SOURCES = mod_cml.c mod_cml_lua.c mod_cml_funcs.c
mod_cml_la_CFLAGS = $(AM_CFLAGS) $(LUA_CFLAGS)
mod_cml_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
@@ -518,28 +736,28 @@ mod_mysql_vhost_la_SOURCES = mod_mysql_vhost.c
mod_mysql_vhost_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_mysql_vhost_la_LIBADD = $(MYSQL_LIBS) $(common_libadd)
mod_mysql_vhost_la_CPPFLAGS = $(MYSQL_INCLUDE)
-mod_cgi_la_SOURCES = mod_cgi.c
+mod_cgi_la_SOURCES = mod_cgi.c
mod_cgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_cgi_la_LIBADD = $(common_libadd)
-mod_scgi_la_SOURCES = mod_scgi.c
+mod_scgi_la_SOURCES = mod_scgi.c
mod_scgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_scgi_la_LIBADD = $(common_libadd)
-mod_staticfile_la_SOURCES = mod_staticfile.c
+mod_staticfile_la_SOURCES = mod_staticfile.c
mod_staticfile_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_staticfile_la_LIBADD = $(common_libadd)
-mod_dirlisting_la_SOURCES = mod_dirlisting.c
+mod_dirlisting_la_SOURCES = mod_dirlisting.c
mod_dirlisting_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_dirlisting_la_LIBADD = $(common_libadd) $(PCRE_LIB)
-mod_indexfile_la_SOURCES = mod_indexfile.c
+mod_indexfile_la_SOURCES = mod_indexfile.c
mod_indexfile_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_indexfile_la_LIBADD = $(common_libadd)
-mod_setenv_la_SOURCES = mod_setenv.c
+mod_setenv_la_SOURCES = mod_setenv.c
mod_setenv_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_setenv_la_LIBADD = $(common_libadd)
-mod_alias_la_SOURCES = mod_alias.c
+mod_alias_la_SOURCES = mod_alias.c
mod_alias_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_alias_la_LIBADD = $(common_libadd)
-mod_userdir_la_SOURCES = mod_userdir.c
+mod_userdir_la_SOURCES = mod_userdir.c
mod_userdir_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_userdir_la_LIBADD = $(common_libadd)
mod_rrdtool_la_SOURCES = mod_rrdtool.c
@@ -551,7 +769,7 @@ mod_usertrack_la_LIBADD = $(common_libadd)
mod_proxy_la_SOURCES = mod_proxy.c
mod_proxy_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_proxy_la_LIBADD = $(common_libadd)
-mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c
+mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c
mod_ssi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_ssi_la_LIBADD = $(common_libadd) $(PCRE_LIB)
mod_secdownload_la_SOURCES = mod_secure_download.c
@@ -569,13 +787,16 @@ mod_simple_vhost_la_LIBADD = $(common_libadd)
mod_fastcgi_la_SOURCES = mod_fastcgi.c
mod_fastcgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_fastcgi_la_LIBADD = $(common_libadd)
+mod_extforward_la_SOURCES = mod_extforward.c
+mod_extforward_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
+mod_extforward_la_LIBADD = $(common_libadd)
mod_access_la_SOURCES = mod_access.c
mod_access_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_access_la_LIBADD = $(common_libadd)
-mod_compress_la_SOURCES = mod_compress.c
+mod_compress_la_SOURCES = mod_compress.c
mod_compress_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_compress_la_LIBADD = $(Z_LIB) $(BZ_LIB) $(common_libadd)
-mod_auth_la_SOURCES = mod_auth.c http_auth_digest.c http_auth.c
+mod_auth_la_SOURCES = mod_auth.c http_auth.c
mod_auth_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_auth_la_LIBADD = $(CRYPT_LIB) $(LDAP_LIB) $(LBER_LIB) $(common_libadd)
mod_rewrite_la_SOURCES = mod_rewrite.c
@@ -592,7 +813,7 @@ mod_accesslog_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_accesslog_la_LIBADD = $(common_libadd)
hdr = server.h buffer.h network.h log.h keyvalue.h \
response.h request.h fastcgi.h chunk.h \
- settings.h http_chunk.h http_auth_digest.h \
+ settings.h http_chunk.h \
md5.h http_auth.h stream.h \
fdevent.h connections.h base.h stat_cache.h \
plugin.h mod_auth.h \
@@ -601,12 +822,14 @@ 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 proc_open.h
+ splaytree.h proc_open.h status_counter.h \
+ mod_magnet_cache.h \
+ version.h
lighttpd_SOURCES = $(src)
-lighttpd_LDADD = $(PCRE_LIB) $(DL_LIB) $(SENDFILE_LIB) $(ATTR_LIB) $(common_libadd) $(SSL_LIB) $(FAM_LIBS)
+lighttpd_LDADD = $(PCRE_LIB) $(DL_LIB) $(SENDFILE_LIB) $(ATTR_LIB) $(common_libadd) $(SSL_LIB) $(FAM_LIBS) $(LIBEV_LIBS)
lighttpd_LDFLAGS = -export-dynamic
-lighttpd_CCPFLAGS = $(FAM_CFLAGS)
+lighttpd_CCPFLAGS = $(FAM_CFLAGS) $(LIBEV_CFLAGS)
proc_open_SOURCES = proc_open.c buffer.c
proc_open_CPPFLAGS = -DDEBUG_PROC_OPEN
@@ -623,23 +846,24 @@ 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
-all: all-am
+EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c SConscript
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
- && exit 0; \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
- echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
- cd $(top_srcdir) && \
- $(AUTOMAKE) --gnu src/Makefile
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
@@ -653,27 +877,33 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+$(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
@$(NORMAL_INSTALL)
- test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)"
- @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
if test -f $$p; then \
- f=$(am__strip_dir) \
- echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
- $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+ list2="$$list2 $$p"; \
else :; fi; \
- done
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
uninstall-libLTLIBRARIES:
@$(NORMAL_UNINSTALL)
- @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \
- p=$(am__strip_dir) \
- echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
- $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
done
clean-libLTLIBRARIES:
@@ -684,141 +914,139 @@ clean-libLTLIBRARIES:
echo "rm -f \"$${dir}/so_locations\""; \
rm -f "$${dir}/so_locations"; \
done
-liblightcomp.la: $(liblightcomp_la_OBJECTS) $(liblightcomp_la_DEPENDENCIES)
- $(LINK) $(am_liblightcomp_la_rpath) $(liblightcomp_la_LDFLAGS) $(liblightcomp_la_OBJECTS) $(liblightcomp_la_LIBADD) $(LIBS)
-mod_access.la: $(mod_access_la_OBJECTS) $(mod_access_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_access_la_LDFLAGS) $(mod_access_la_OBJECTS) $(mod_access_la_LIBADD) $(LIBS)
-mod_accesslog.la: $(mod_accesslog_la_OBJECTS) $(mod_accesslog_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_accesslog_la_LDFLAGS) $(mod_accesslog_la_OBJECTS) $(mod_accesslog_la_LIBADD) $(LIBS)
-mod_alias.la: $(mod_alias_la_OBJECTS) $(mod_alias_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_alias_la_LDFLAGS) $(mod_alias_la_OBJECTS) $(mod_alias_la_LIBADD) $(LIBS)
-mod_auth.la: $(mod_auth_la_OBJECTS) $(mod_auth_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_auth_la_LDFLAGS) $(mod_auth_la_OBJECTS) $(mod_auth_la_LIBADD) $(LIBS)
-mod_cgi.la: $(mod_cgi_la_OBJECTS) $(mod_cgi_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_cgi_la_LDFLAGS) $(mod_cgi_la_OBJECTS) $(mod_cgi_la_LIBADD) $(LIBS)
-mod_cml.la: $(mod_cml_la_OBJECTS) $(mod_cml_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_cml_la_LDFLAGS) $(mod_cml_la_OBJECTS) $(mod_cml_la_LIBADD) $(LIBS)
-mod_compress.la: $(mod_compress_la_OBJECTS) $(mod_compress_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_compress_la_LDFLAGS) $(mod_compress_la_OBJECTS) $(mod_compress_la_LIBADD) $(LIBS)
-mod_dirlisting.la: $(mod_dirlisting_la_OBJECTS) $(mod_dirlisting_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_dirlisting_la_LDFLAGS) $(mod_dirlisting_la_OBJECTS) $(mod_dirlisting_la_LIBADD) $(LIBS)
-mod_evasive.la: $(mod_evasive_la_OBJECTS) $(mod_evasive_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_evasive_la_LDFLAGS) $(mod_evasive_la_OBJECTS) $(mod_evasive_la_LIBADD) $(LIBS)
-mod_evhost.la: $(mod_evhost_la_OBJECTS) $(mod_evhost_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_evhost_la_LDFLAGS) $(mod_evhost_la_OBJECTS) $(mod_evhost_la_LIBADD) $(LIBS)
-mod_expire.la: $(mod_expire_la_OBJECTS) $(mod_expire_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_expire_la_LDFLAGS) $(mod_expire_la_OBJECTS) $(mod_expire_la_LIBADD) $(LIBS)
-mod_fastcgi.la: $(mod_fastcgi_la_OBJECTS) $(mod_fastcgi_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_fastcgi_la_LDFLAGS) $(mod_fastcgi_la_OBJECTS) $(mod_fastcgi_la_LIBADD) $(LIBS)
-mod_indexfile.la: $(mod_indexfile_la_OBJECTS) $(mod_indexfile_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_indexfile_la_LDFLAGS) $(mod_indexfile_la_OBJECTS) $(mod_indexfile_la_LIBADD) $(LIBS)
-mod_mysql_vhost.la: $(mod_mysql_vhost_la_OBJECTS) $(mod_mysql_vhost_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_mysql_vhost_la_LDFLAGS) $(mod_mysql_vhost_la_OBJECTS) $(mod_mysql_vhost_la_LIBADD) $(LIBS)
-mod_proxy.la: $(mod_proxy_la_OBJECTS) $(mod_proxy_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_proxy_la_LDFLAGS) $(mod_proxy_la_OBJECTS) $(mod_proxy_la_LIBADD) $(LIBS)
-mod_redirect.la: $(mod_redirect_la_OBJECTS) $(mod_redirect_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_redirect_la_LDFLAGS) $(mod_redirect_la_OBJECTS) $(mod_redirect_la_LIBADD) $(LIBS)
-mod_rewrite.la: $(mod_rewrite_la_OBJECTS) $(mod_rewrite_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_rewrite_la_LDFLAGS) $(mod_rewrite_la_OBJECTS) $(mod_rewrite_la_LIBADD) $(LIBS)
-mod_rrdtool.la: $(mod_rrdtool_la_OBJECTS) $(mod_rrdtool_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_rrdtool_la_LDFLAGS) $(mod_rrdtool_la_OBJECTS) $(mod_rrdtool_la_LIBADD) $(LIBS)
-mod_scgi.la: $(mod_scgi_la_OBJECTS) $(mod_scgi_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_scgi_la_LDFLAGS) $(mod_scgi_la_OBJECTS) $(mod_scgi_la_LIBADD) $(LIBS)
-mod_secdownload.la: $(mod_secdownload_la_OBJECTS) $(mod_secdownload_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_secdownload_la_LDFLAGS) $(mod_secdownload_la_OBJECTS) $(mod_secdownload_la_LIBADD) $(LIBS)
-mod_setenv.la: $(mod_setenv_la_OBJECTS) $(mod_setenv_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_setenv_la_LDFLAGS) $(mod_setenv_la_OBJECTS) $(mod_setenv_la_LIBADD) $(LIBS)
-mod_simple_vhost.la: $(mod_simple_vhost_la_OBJECTS) $(mod_simple_vhost_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_simple_vhost_la_LDFLAGS) $(mod_simple_vhost_la_OBJECTS) $(mod_simple_vhost_la_LIBADD) $(LIBS)
-mod_ssi.la: $(mod_ssi_la_OBJECTS) $(mod_ssi_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_ssi_la_LDFLAGS) $(mod_ssi_la_OBJECTS) $(mod_ssi_la_LIBADD) $(LIBS)
-mod_staticfile.la: $(mod_staticfile_la_OBJECTS) $(mod_staticfile_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_staticfile_la_LDFLAGS) $(mod_staticfile_la_OBJECTS) $(mod_staticfile_la_LIBADD) $(LIBS)
-mod_status.la: $(mod_status_la_OBJECTS) $(mod_status_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_status_la_LDFLAGS) $(mod_status_la_OBJECTS) $(mod_status_la_LIBADD) $(LIBS)
-mod_trigger_b4_dl.la: $(mod_trigger_b4_dl_la_OBJECTS) $(mod_trigger_b4_dl_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_trigger_b4_dl_la_LDFLAGS) $(mod_trigger_b4_dl_la_OBJECTS) $(mod_trigger_b4_dl_la_LIBADD) $(LIBS)
-mod_userdir.la: $(mod_userdir_la_OBJECTS) $(mod_userdir_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_userdir_la_LDFLAGS) $(mod_userdir_la_OBJECTS) $(mod_userdir_la_LIBADD) $(LIBS)
-mod_usertrack.la: $(mod_usertrack_la_OBJECTS) $(mod_usertrack_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_usertrack_la_LDFLAGS) $(mod_usertrack_la_OBJECTS) $(mod_usertrack_la_LIBADD) $(LIBS)
-mod_webdav.la: $(mod_webdav_la_OBJECTS) $(mod_webdav_la_DEPENDENCIES)
- $(LINK) -rpath $(libdir) $(mod_webdav_la_LDFLAGS) $(mod_webdav_la_OBJECTS) $(mod_webdav_la_LIBADD) $(LIBS)
-install-binPROGRAMS: $(bin_PROGRAMS)
- @$(NORMAL_INSTALL)
- test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
- @list='$(bin_PROGRAMS)'; for p in $$list; do \
- p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
- if test -f $$p \
- || test -f $$p1 \
- ; then \
- f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
- echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
- $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
- else :; fi; \
- done
-
-uninstall-binPROGRAMS:
- @$(NORMAL_UNINSTALL)
- @list='$(bin_PROGRAMS)'; for p in $$list; do \
- f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
- echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
- rm -f "$(DESTDIR)$(bindir)/$$f"; \
- done
-
-clean-binPROGRAMS:
- @list='$(bin_PROGRAMS)'; for p in $$list; do \
- f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
- echo " rm -f $$p $$f"; \
- rm -f $$p $$f ; \
- done
+liblightcomp.la: $(liblightcomp_la_OBJECTS) $(liblightcomp_la_DEPENDENCIES) $(EXTRA_liblightcomp_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(liblightcomp_la_LINK) $(am_liblightcomp_la_rpath) $(liblightcomp_la_OBJECTS) $(liblightcomp_la_LIBADD) $(LIBS)
+mod_access.la: $(mod_access_la_OBJECTS) $(mod_access_la_DEPENDENCIES) $(EXTRA_mod_access_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_access_la_LINK) -rpath $(libdir) $(mod_access_la_OBJECTS) $(mod_access_la_LIBADD) $(LIBS)
+mod_accesslog.la: $(mod_accesslog_la_OBJECTS) $(mod_accesslog_la_DEPENDENCIES) $(EXTRA_mod_accesslog_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_accesslog_la_LINK) -rpath $(libdir) $(mod_accesslog_la_OBJECTS) $(mod_accesslog_la_LIBADD) $(LIBS)
+mod_alias.la: $(mod_alias_la_OBJECTS) $(mod_alias_la_DEPENDENCIES) $(EXTRA_mod_alias_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_alias_la_LINK) -rpath $(libdir) $(mod_alias_la_OBJECTS) $(mod_alias_la_LIBADD) $(LIBS)
+mod_auth.la: $(mod_auth_la_OBJECTS) $(mod_auth_la_DEPENDENCIES) $(EXTRA_mod_auth_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_auth_la_LINK) -rpath $(libdir) $(mod_auth_la_OBJECTS) $(mod_auth_la_LIBADD) $(LIBS)
+mod_cgi.la: $(mod_cgi_la_OBJECTS) $(mod_cgi_la_DEPENDENCIES) $(EXTRA_mod_cgi_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_cgi_la_LINK) -rpath $(libdir) $(mod_cgi_la_OBJECTS) $(mod_cgi_la_LIBADD) $(LIBS)
+mod_cml.la: $(mod_cml_la_OBJECTS) $(mod_cml_la_DEPENDENCIES) $(EXTRA_mod_cml_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_cml_la_LINK) -rpath $(libdir) $(mod_cml_la_OBJECTS) $(mod_cml_la_LIBADD) $(LIBS)
+mod_compress.la: $(mod_compress_la_OBJECTS) $(mod_compress_la_DEPENDENCIES) $(EXTRA_mod_compress_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_compress_la_LINK) -rpath $(libdir) $(mod_compress_la_OBJECTS) $(mod_compress_la_LIBADD) $(LIBS)
+mod_dirlisting.la: $(mod_dirlisting_la_OBJECTS) $(mod_dirlisting_la_DEPENDENCIES) $(EXTRA_mod_dirlisting_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_dirlisting_la_LINK) -rpath $(libdir) $(mod_dirlisting_la_OBJECTS) $(mod_dirlisting_la_LIBADD) $(LIBS)
+mod_evasive.la: $(mod_evasive_la_OBJECTS) $(mod_evasive_la_DEPENDENCIES) $(EXTRA_mod_evasive_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_evasive_la_LINK) -rpath $(libdir) $(mod_evasive_la_OBJECTS) $(mod_evasive_la_LIBADD) $(LIBS)
+mod_evhost.la: $(mod_evhost_la_OBJECTS) $(mod_evhost_la_DEPENDENCIES) $(EXTRA_mod_evhost_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_evhost_la_LINK) -rpath $(libdir) $(mod_evhost_la_OBJECTS) $(mod_evhost_la_LIBADD) $(LIBS)
+mod_expire.la: $(mod_expire_la_OBJECTS) $(mod_expire_la_DEPENDENCIES) $(EXTRA_mod_expire_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_expire_la_LINK) -rpath $(libdir) $(mod_expire_la_OBJECTS) $(mod_expire_la_LIBADD) $(LIBS)
+mod_extforward.la: $(mod_extforward_la_OBJECTS) $(mod_extforward_la_DEPENDENCIES) $(EXTRA_mod_extforward_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_extforward_la_LINK) -rpath $(libdir) $(mod_extforward_la_OBJECTS) $(mod_extforward_la_LIBADD) $(LIBS)
+mod_fastcgi.la: $(mod_fastcgi_la_OBJECTS) $(mod_fastcgi_la_DEPENDENCIES) $(EXTRA_mod_fastcgi_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_fastcgi_la_LINK) -rpath $(libdir) $(mod_fastcgi_la_OBJECTS) $(mod_fastcgi_la_LIBADD) $(LIBS)
+mod_flv_streaming.la: $(mod_flv_streaming_la_OBJECTS) $(mod_flv_streaming_la_DEPENDENCIES) $(EXTRA_mod_flv_streaming_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_flv_streaming_la_LINK) -rpath $(libdir) $(mod_flv_streaming_la_OBJECTS) $(mod_flv_streaming_la_LIBADD) $(LIBS)
+mod_indexfile.la: $(mod_indexfile_la_OBJECTS) $(mod_indexfile_la_DEPENDENCIES) $(EXTRA_mod_indexfile_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_indexfile_la_LINK) -rpath $(libdir) $(mod_indexfile_la_OBJECTS) $(mod_indexfile_la_LIBADD) $(LIBS)
+mod_magnet.la: $(mod_magnet_la_OBJECTS) $(mod_magnet_la_DEPENDENCIES) $(EXTRA_mod_magnet_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_magnet_la_LINK) -rpath $(libdir) $(mod_magnet_la_OBJECTS) $(mod_magnet_la_LIBADD) $(LIBS)
+mod_mysql_vhost.la: $(mod_mysql_vhost_la_OBJECTS) $(mod_mysql_vhost_la_DEPENDENCIES) $(EXTRA_mod_mysql_vhost_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_mysql_vhost_la_LINK) -rpath $(libdir) $(mod_mysql_vhost_la_OBJECTS) $(mod_mysql_vhost_la_LIBADD) $(LIBS)
+mod_proxy.la: $(mod_proxy_la_OBJECTS) $(mod_proxy_la_DEPENDENCIES) $(EXTRA_mod_proxy_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_proxy_la_LINK) -rpath $(libdir) $(mod_proxy_la_OBJECTS) $(mod_proxy_la_LIBADD) $(LIBS)
+mod_redirect.la: $(mod_redirect_la_OBJECTS) $(mod_redirect_la_DEPENDENCIES) $(EXTRA_mod_redirect_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_redirect_la_LINK) -rpath $(libdir) $(mod_redirect_la_OBJECTS) $(mod_redirect_la_LIBADD) $(LIBS)
+mod_rewrite.la: $(mod_rewrite_la_OBJECTS) $(mod_rewrite_la_DEPENDENCIES) $(EXTRA_mod_rewrite_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_rewrite_la_LINK) -rpath $(libdir) $(mod_rewrite_la_OBJECTS) $(mod_rewrite_la_LIBADD) $(LIBS)
+mod_rrdtool.la: $(mod_rrdtool_la_OBJECTS) $(mod_rrdtool_la_DEPENDENCIES) $(EXTRA_mod_rrdtool_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_rrdtool_la_LINK) -rpath $(libdir) $(mod_rrdtool_la_OBJECTS) $(mod_rrdtool_la_LIBADD) $(LIBS)
+mod_scgi.la: $(mod_scgi_la_OBJECTS) $(mod_scgi_la_DEPENDENCIES) $(EXTRA_mod_scgi_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_scgi_la_LINK) -rpath $(libdir) $(mod_scgi_la_OBJECTS) $(mod_scgi_la_LIBADD) $(LIBS)
+mod_secdownload.la: $(mod_secdownload_la_OBJECTS) $(mod_secdownload_la_DEPENDENCIES) $(EXTRA_mod_secdownload_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_secdownload_la_LINK) -rpath $(libdir) $(mod_secdownload_la_OBJECTS) $(mod_secdownload_la_LIBADD) $(LIBS)
+mod_setenv.la: $(mod_setenv_la_OBJECTS) $(mod_setenv_la_DEPENDENCIES) $(EXTRA_mod_setenv_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_setenv_la_LINK) -rpath $(libdir) $(mod_setenv_la_OBJECTS) $(mod_setenv_la_LIBADD) $(LIBS)
+mod_simple_vhost.la: $(mod_simple_vhost_la_OBJECTS) $(mod_simple_vhost_la_DEPENDENCIES) $(EXTRA_mod_simple_vhost_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_simple_vhost_la_LINK) -rpath $(libdir) $(mod_simple_vhost_la_OBJECTS) $(mod_simple_vhost_la_LIBADD) $(LIBS)
+mod_ssi.la: $(mod_ssi_la_OBJECTS) $(mod_ssi_la_DEPENDENCIES) $(EXTRA_mod_ssi_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_ssi_la_LINK) -rpath $(libdir) $(mod_ssi_la_OBJECTS) $(mod_ssi_la_LIBADD) $(LIBS)
+mod_staticfile.la: $(mod_staticfile_la_OBJECTS) $(mod_staticfile_la_DEPENDENCIES) $(EXTRA_mod_staticfile_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_staticfile_la_LINK) -rpath $(libdir) $(mod_staticfile_la_OBJECTS) $(mod_staticfile_la_LIBADD) $(LIBS)
+mod_status.la: $(mod_status_la_OBJECTS) $(mod_status_la_DEPENDENCIES) $(EXTRA_mod_status_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_status_la_LINK) -rpath $(libdir) $(mod_status_la_OBJECTS) $(mod_status_la_LIBADD) $(LIBS)
+mod_trigger_b4_dl.la: $(mod_trigger_b4_dl_la_OBJECTS) $(mod_trigger_b4_dl_la_DEPENDENCIES) $(EXTRA_mod_trigger_b4_dl_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_trigger_b4_dl_la_LINK) -rpath $(libdir) $(mod_trigger_b4_dl_la_OBJECTS) $(mod_trigger_b4_dl_la_LIBADD) $(LIBS)
+mod_userdir.la: $(mod_userdir_la_OBJECTS) $(mod_userdir_la_DEPENDENCIES) $(EXTRA_mod_userdir_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_userdir_la_LINK) -rpath $(libdir) $(mod_userdir_la_OBJECTS) $(mod_userdir_la_LIBADD) $(LIBS)
+mod_usertrack.la: $(mod_usertrack_la_OBJECTS) $(mod_usertrack_la_DEPENDENCIES) $(EXTRA_mod_usertrack_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_usertrack_la_LINK) -rpath $(libdir) $(mod_usertrack_la_OBJECTS) $(mod_usertrack_la_LIBADD) $(LIBS)
+mod_webdav.la: $(mod_webdav_la_OBJECTS) $(mod_webdav_la_DEPENDENCIES) $(EXTRA_mod_webdav_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(mod_webdav_la_LINK) -rpath $(libdir) $(mod_webdav_la_OBJECTS) $(mod_webdav_la_LIBADD) $(LIBS)
clean-noinstPROGRAMS:
- @list='$(noinst_PROGRAMS)'; for p in $$list; do \
- f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
- echo " rm -f $$p $$f"; \
- rm -f $$p $$f ; \
- done
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
install-sbinPROGRAMS: $(sbin_PROGRAMS)
@$(NORMAL_INSTALL)
- test -z "$(sbindir)" || $(mkdir_p) "$(DESTDIR)$(sbindir)"
- @list='$(sbin_PROGRAMS)'; for p in $$list; do \
- p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
- if test -f $$p \
- || test -f $$p1 \
- ; then \
- f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
- echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(sbinPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(sbindir)/$$f'"; \
- $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(sbinPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(sbindir)/$$f" || exit 1; \
- else :; fi; \
- done
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p || test -f $$p1; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \
+ } \
+ ; done
uninstall-sbinPROGRAMS:
@$(NORMAL_UNINSTALL)
- @list='$(sbin_PROGRAMS)'; for p in $$list; do \
- f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
- echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \
- rm -f "$(DESTDIR)$(sbindir)/$$f"; \
- done
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(sbindir)" && rm -f $$files
clean-sbinPROGRAMS:
- @list='$(sbin_PROGRAMS)'; for p in $$list; do \
- f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
- echo " rm -f $$p $$f"; \
- rm -f $$p $$f ; \
- done
-lemon$(EXEEXT): $(lemon_OBJECTS) $(lemon_DEPENDENCIES)
+ @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+lemon$(EXEEXT): $(lemon_OBJECTS) $(lemon_DEPENDENCIES) $(EXTRA_lemon_DEPENDENCIES)
@rm -f lemon$(EXEEXT)
- $(LINK) $(lemon_LDFLAGS) $(lemon_OBJECTS) $(lemon_LDADD) $(LIBS)
-lighttpd$(EXEEXT): $(lighttpd_OBJECTS) $(lighttpd_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(lemon_OBJECTS) $(lemon_LDADD) $(LIBS)
+lighttpd$(EXEEXT): $(lighttpd_OBJECTS) $(lighttpd_DEPENDENCIES) $(EXTRA_lighttpd_DEPENDENCIES)
@rm -f lighttpd$(EXEEXT)
- $(LINK) $(lighttpd_LDFLAGS) $(lighttpd_OBJECTS) $(lighttpd_LDADD) $(LIBS)
-proc_open$(EXEEXT): $(proc_open_OBJECTS) $(proc_open_DEPENDENCIES)
+ $(AM_V_CCLD)$(lighttpd_LINK) $(lighttpd_OBJECTS) $(lighttpd_LDADD) $(LIBS)
+lighttpd-angel$(EXEEXT): $(lighttpd_angel_OBJECTS) $(lighttpd_angel_DEPENDENCIES) $(EXTRA_lighttpd_angel_DEPENDENCIES)
+ @rm -f lighttpd-angel$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lighttpd_angel_OBJECTS) $(lighttpd_angel_LDADD) $(LIBS)
+proc_open$(EXEEXT): $(proc_open_OBJECTS) $(proc_open_DEPENDENCIES) $(EXTRA_proc_open_DEPENDENCIES)
@rm -f proc_open$(EXEEXT)
- $(LINK) $(proc_open_LDFLAGS) $(proc_open_OBJECTS) $(proc_open_LDADD) $(LIBS)
-spawn-fcgi$(EXEEXT): $(spawn_fcgi_OBJECTS) $(spawn_fcgi_DEPENDENCIES)
- @rm -f spawn-fcgi$(EXEEXT)
- $(LINK) $(spawn_fcgi_LDFLAGS) $(spawn_fcgi_OBJECTS) $(spawn_fcgi_LDADD) $(LIBS)
+ $(AM_V_CCLD)$(LINK) $(proc_open_OBJECTS) $(proc_open_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -845,14 +1073,14 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/etag.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdevent.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdevent_freebsd_kqueue.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdevent_linux_rtsig.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdevent_libev.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdevent_linux_sysepoll.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdevent_poll.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdevent_select.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdevent_solaris_devpoll.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdevent_solaris_port.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http-header-glue.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http_auth.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http_auth_digest.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http_chunk.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inet_ntop_cache.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/joblist.Po@am__quote@
@@ -874,11 +1102,12 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-etag.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-fdevent.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-fdevent_freebsd_kqueue.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-fdevent_linux_rtsig.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-fdevent_libev.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-fdevent_linux_sysepoll.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-fdevent_poll.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-fdevent_select.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-fdevent_solaris_devpoll.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-fdevent_solaris_port.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-http-header-glue.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-http_chunk.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-inet_ntop_cache.Plo@am__quote@
@@ -895,7 +1124,9 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-plugin.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-splaytree.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-stat_cache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-status_counter.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-stream.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lighttpd-angel.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_access.Plo@am__quote@
@@ -911,8 +1142,12 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_evasive.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_evhost.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_expire.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_extforward.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_fastcgi.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_flv_streaming.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_indexfile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_magnet_la-mod_magnet.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_magnet_la-mod_magnet_cache.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_proxy.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_redirect.Plo@am__quote@
@@ -945,360 +1180,388 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/request.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/response.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spawn-fcgi.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/splaytree.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stat_cache.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/status_counter.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream.Po@am__quote@
.c.o:
-@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
.c.obj:
-@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
.c.lo:
-@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
liblightcomp_la-buffer.lo: buffer.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-buffer.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-buffer.Tpo" -c -o liblightcomp_la-buffer.lo `test -f 'buffer.c' || echo '$(srcdir)/'`buffer.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-buffer.Tpo" "$(DEPDIR)/liblightcomp_la-buffer.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-buffer.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='buffer.c' object='liblightcomp_la-buffer.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-buffer.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-buffer.Tpo -c -o liblightcomp_la-buffer.lo `test -f 'buffer.c' || echo '$(srcdir)/'`buffer.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-buffer.Tpo $(DEPDIR)/liblightcomp_la-buffer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='buffer.c' object='liblightcomp_la-buffer.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-buffer.lo `test -f 'buffer.c' || echo '$(srcdir)/'`buffer.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-buffer.lo `test -f 'buffer.c' || echo '$(srcdir)/'`buffer.c
liblightcomp_la-log.lo: log.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-log.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-log.Tpo" -c -o liblightcomp_la-log.lo `test -f 'log.c' || echo '$(srcdir)/'`log.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-log.Tpo" "$(DEPDIR)/liblightcomp_la-log.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-log.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='log.c' object='liblightcomp_la-log.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-log.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-log.Tpo -c -o liblightcomp_la-log.lo `test -f 'log.c' || echo '$(srcdir)/'`log.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-log.Tpo $(DEPDIR)/liblightcomp_la-log.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='log.c' object='liblightcomp_la-log.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-log.lo `test -f 'log.c' || echo '$(srcdir)/'`log.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-log.lo `test -f 'log.c' || echo '$(srcdir)/'`log.c
liblightcomp_la-keyvalue.lo: keyvalue.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-keyvalue.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-keyvalue.Tpo" -c -o liblightcomp_la-keyvalue.lo `test -f 'keyvalue.c' || echo '$(srcdir)/'`keyvalue.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-keyvalue.Tpo" "$(DEPDIR)/liblightcomp_la-keyvalue.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-keyvalue.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='keyvalue.c' object='liblightcomp_la-keyvalue.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-keyvalue.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-keyvalue.Tpo -c -o liblightcomp_la-keyvalue.lo `test -f 'keyvalue.c' || echo '$(srcdir)/'`keyvalue.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-keyvalue.Tpo $(DEPDIR)/liblightcomp_la-keyvalue.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='keyvalue.c' object='liblightcomp_la-keyvalue.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-keyvalue.lo `test -f 'keyvalue.c' || echo '$(srcdir)/'`keyvalue.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-keyvalue.lo `test -f 'keyvalue.c' || echo '$(srcdir)/'`keyvalue.c
liblightcomp_la-chunk.lo: chunk.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-chunk.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-chunk.Tpo" -c -o liblightcomp_la-chunk.lo `test -f 'chunk.c' || echo '$(srcdir)/'`chunk.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-chunk.Tpo" "$(DEPDIR)/liblightcomp_la-chunk.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-chunk.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='chunk.c' object='liblightcomp_la-chunk.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-chunk.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-chunk.Tpo -c -o liblightcomp_la-chunk.lo `test -f 'chunk.c' || echo '$(srcdir)/'`chunk.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-chunk.Tpo $(DEPDIR)/liblightcomp_la-chunk.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='chunk.c' object='liblightcomp_la-chunk.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-chunk.lo `test -f 'chunk.c' || echo '$(srcdir)/'`chunk.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-chunk.lo `test -f 'chunk.c' || echo '$(srcdir)/'`chunk.c
liblightcomp_la-http_chunk.lo: http_chunk.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-http_chunk.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-http_chunk.Tpo" -c -o liblightcomp_la-http_chunk.lo `test -f 'http_chunk.c' || echo '$(srcdir)/'`http_chunk.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-http_chunk.Tpo" "$(DEPDIR)/liblightcomp_la-http_chunk.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-http_chunk.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='http_chunk.c' object='liblightcomp_la-http_chunk.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-http_chunk.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-http_chunk.Tpo -c -o liblightcomp_la-http_chunk.lo `test -f 'http_chunk.c' || echo '$(srcdir)/'`http_chunk.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-http_chunk.Tpo $(DEPDIR)/liblightcomp_la-http_chunk.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http_chunk.c' object='liblightcomp_la-http_chunk.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-http_chunk.lo `test -f 'http_chunk.c' || echo '$(srcdir)/'`http_chunk.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-http_chunk.lo `test -f 'http_chunk.c' || echo '$(srcdir)/'`http_chunk.c
liblightcomp_la-stream.lo: stream.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-stream.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-stream.Tpo" -c -o liblightcomp_la-stream.lo `test -f 'stream.c' || echo '$(srcdir)/'`stream.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-stream.Tpo" "$(DEPDIR)/liblightcomp_la-stream.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-stream.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='stream.c' object='liblightcomp_la-stream.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-stream.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-stream.Tpo -c -o liblightcomp_la-stream.lo `test -f 'stream.c' || echo '$(srcdir)/'`stream.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-stream.Tpo $(DEPDIR)/liblightcomp_la-stream.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='stream.c' object='liblightcomp_la-stream.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-stream.lo `test -f 'stream.c' || echo '$(srcdir)/'`stream.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-stream.lo `test -f 'stream.c' || echo '$(srcdir)/'`stream.c
liblightcomp_la-fdevent.lo: fdevent.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-fdevent.Tpo" -c -o liblightcomp_la-fdevent.lo `test -f 'fdevent.c' || echo '$(srcdir)/'`fdevent.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-fdevent.Tpo" "$(DEPDIR)/liblightcomp_la-fdevent.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-fdevent.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fdevent.c' object='liblightcomp_la-fdevent.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-fdevent.Tpo -c -o liblightcomp_la-fdevent.lo `test -f 'fdevent.c' || echo '$(srcdir)/'`fdevent.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-fdevent.Tpo $(DEPDIR)/liblightcomp_la-fdevent.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent.c' object='liblightcomp_la-fdevent.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent.lo `test -f 'fdevent.c' || echo '$(srcdir)/'`fdevent.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent.lo `test -f 'fdevent.c' || echo '$(srcdir)/'`fdevent.c
liblightcomp_la-stat_cache.lo: stat_cache.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-stat_cache.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-stat_cache.Tpo" -c -o liblightcomp_la-stat_cache.lo `test -f 'stat_cache.c' || echo '$(srcdir)/'`stat_cache.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-stat_cache.Tpo" "$(DEPDIR)/liblightcomp_la-stat_cache.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-stat_cache.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='stat_cache.c' object='liblightcomp_la-stat_cache.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-stat_cache.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-stat_cache.Tpo -c -o liblightcomp_la-stat_cache.lo `test -f 'stat_cache.c' || echo '$(srcdir)/'`stat_cache.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-stat_cache.Tpo $(DEPDIR)/liblightcomp_la-stat_cache.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='stat_cache.c' object='liblightcomp_la-stat_cache.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-stat_cache.lo `test -f 'stat_cache.c' || echo '$(srcdir)/'`stat_cache.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-stat_cache.lo `test -f 'stat_cache.c' || echo '$(srcdir)/'`stat_cache.c
liblightcomp_la-plugin.lo: plugin.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-plugin.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-plugin.Tpo" -c -o liblightcomp_la-plugin.lo `test -f 'plugin.c' || echo '$(srcdir)/'`plugin.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-plugin.Tpo" "$(DEPDIR)/liblightcomp_la-plugin.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-plugin.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin.c' object='liblightcomp_la-plugin.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-plugin.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-plugin.Tpo -c -o liblightcomp_la-plugin.lo `test -f 'plugin.c' || echo '$(srcdir)/'`plugin.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-plugin.Tpo $(DEPDIR)/liblightcomp_la-plugin.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugin.c' object='liblightcomp_la-plugin.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-plugin.lo `test -f 'plugin.c' || echo '$(srcdir)/'`plugin.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-plugin.lo `test -f 'plugin.c' || echo '$(srcdir)/'`plugin.c
liblightcomp_la-joblist.lo: joblist.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-joblist.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-joblist.Tpo" -c -o liblightcomp_la-joblist.lo `test -f 'joblist.c' || echo '$(srcdir)/'`joblist.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-joblist.Tpo" "$(DEPDIR)/liblightcomp_la-joblist.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-joblist.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='joblist.c' object='liblightcomp_la-joblist.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-joblist.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-joblist.Tpo -c -o liblightcomp_la-joblist.lo `test -f 'joblist.c' || echo '$(srcdir)/'`joblist.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-joblist.Tpo $(DEPDIR)/liblightcomp_la-joblist.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='joblist.c' object='liblightcomp_la-joblist.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-joblist.lo `test -f 'joblist.c' || echo '$(srcdir)/'`joblist.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-joblist.lo `test -f 'joblist.c' || echo '$(srcdir)/'`joblist.c
liblightcomp_la-etag.lo: etag.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-etag.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-etag.Tpo" -c -o liblightcomp_la-etag.lo `test -f 'etag.c' || echo '$(srcdir)/'`etag.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-etag.Tpo" "$(DEPDIR)/liblightcomp_la-etag.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-etag.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='etag.c' object='liblightcomp_la-etag.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-etag.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-etag.Tpo -c -o liblightcomp_la-etag.lo `test -f 'etag.c' || echo '$(srcdir)/'`etag.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-etag.Tpo $(DEPDIR)/liblightcomp_la-etag.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='etag.c' object='liblightcomp_la-etag.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-etag.lo `test -f 'etag.c' || echo '$(srcdir)/'`etag.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-etag.lo `test -f 'etag.c' || echo '$(srcdir)/'`etag.c
liblightcomp_la-array.lo: array.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-array.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-array.Tpo" -c -o liblightcomp_la-array.lo `test -f 'array.c' || echo '$(srcdir)/'`array.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-array.Tpo" "$(DEPDIR)/liblightcomp_la-array.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-array.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='array.c' object='liblightcomp_la-array.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-array.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-array.Tpo -c -o liblightcomp_la-array.lo `test -f 'array.c' || echo '$(srcdir)/'`array.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-array.Tpo $(DEPDIR)/liblightcomp_la-array.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='array.c' object='liblightcomp_la-array.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-array.lo `test -f 'array.c' || echo '$(srcdir)/'`array.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-array.lo `test -f 'array.c' || echo '$(srcdir)/'`array.c
liblightcomp_la-data_string.lo: data_string.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-data_string.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-data_string.Tpo" -c -o liblightcomp_la-data_string.lo `test -f 'data_string.c' || echo '$(srcdir)/'`data_string.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-data_string.Tpo" "$(DEPDIR)/liblightcomp_la-data_string.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-data_string.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='data_string.c' object='liblightcomp_la-data_string.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-data_string.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-data_string.Tpo -c -o liblightcomp_la-data_string.lo `test -f 'data_string.c' || echo '$(srcdir)/'`data_string.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-data_string.Tpo $(DEPDIR)/liblightcomp_la-data_string.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='data_string.c' object='liblightcomp_la-data_string.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-data_string.lo `test -f 'data_string.c' || echo '$(srcdir)/'`data_string.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-data_string.lo `test -f 'data_string.c' || echo '$(srcdir)/'`data_string.c
liblightcomp_la-data_count.lo: data_count.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-data_count.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-data_count.Tpo" -c -o liblightcomp_la-data_count.lo `test -f 'data_count.c' || echo '$(srcdir)/'`data_count.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-data_count.Tpo" "$(DEPDIR)/liblightcomp_la-data_count.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-data_count.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='data_count.c' object='liblightcomp_la-data_count.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-data_count.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-data_count.Tpo -c -o liblightcomp_la-data_count.lo `test -f 'data_count.c' || echo '$(srcdir)/'`data_count.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-data_count.Tpo $(DEPDIR)/liblightcomp_la-data_count.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='data_count.c' object='liblightcomp_la-data_count.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-data_count.lo `test -f 'data_count.c' || echo '$(srcdir)/'`data_count.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-data_count.lo `test -f 'data_count.c' || echo '$(srcdir)/'`data_count.c
liblightcomp_la-data_array.lo: data_array.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-data_array.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-data_array.Tpo" -c -o liblightcomp_la-data_array.lo `test -f 'data_array.c' || echo '$(srcdir)/'`data_array.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-data_array.Tpo" "$(DEPDIR)/liblightcomp_la-data_array.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-data_array.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='data_array.c' object='liblightcomp_la-data_array.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-data_array.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-data_array.Tpo -c -o liblightcomp_la-data_array.lo `test -f 'data_array.c' || echo '$(srcdir)/'`data_array.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-data_array.Tpo $(DEPDIR)/liblightcomp_la-data_array.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='data_array.c' object='liblightcomp_la-data_array.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-data_array.lo `test -f 'data_array.c' || echo '$(srcdir)/'`data_array.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-data_array.lo `test -f 'data_array.c' || echo '$(srcdir)/'`data_array.c
liblightcomp_la-data_integer.lo: data_integer.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-data_integer.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-data_integer.Tpo" -c -o liblightcomp_la-data_integer.lo `test -f 'data_integer.c' || echo '$(srcdir)/'`data_integer.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-data_integer.Tpo" "$(DEPDIR)/liblightcomp_la-data_integer.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-data_integer.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='data_integer.c' object='liblightcomp_la-data_integer.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-data_integer.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-data_integer.Tpo -c -o liblightcomp_la-data_integer.lo `test -f 'data_integer.c' || echo '$(srcdir)/'`data_integer.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-data_integer.Tpo $(DEPDIR)/liblightcomp_la-data_integer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='data_integer.c' object='liblightcomp_la-data_integer.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-data_integer.lo `test -f 'data_integer.c' || echo '$(srcdir)/'`data_integer.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-data_integer.lo `test -f 'data_integer.c' || echo '$(srcdir)/'`data_integer.c
liblightcomp_la-md5.lo: md5.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-md5.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-md5.Tpo" -c -o liblightcomp_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-md5.Tpo" "$(DEPDIR)/liblightcomp_la-md5.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-md5.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='md5.c' object='liblightcomp_la-md5.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-md5.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-md5.Tpo -c -o liblightcomp_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-md5.Tpo $(DEPDIR)/liblightcomp_la-md5.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='md5.c' object='liblightcomp_la-md5.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c
liblightcomp_la-data_fastcgi.lo: data_fastcgi.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-data_fastcgi.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-data_fastcgi.Tpo" -c -o liblightcomp_la-data_fastcgi.lo `test -f 'data_fastcgi.c' || echo '$(srcdir)/'`data_fastcgi.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-data_fastcgi.Tpo" "$(DEPDIR)/liblightcomp_la-data_fastcgi.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-data_fastcgi.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='data_fastcgi.c' object='liblightcomp_la-data_fastcgi.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-data_fastcgi.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-data_fastcgi.Tpo -c -o liblightcomp_la-data_fastcgi.lo `test -f 'data_fastcgi.c' || echo '$(srcdir)/'`data_fastcgi.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-data_fastcgi.Tpo $(DEPDIR)/liblightcomp_la-data_fastcgi.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='data_fastcgi.c' object='liblightcomp_la-data_fastcgi.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-data_fastcgi.lo `test -f 'data_fastcgi.c' || echo '$(srcdir)/'`data_fastcgi.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-data_fastcgi.lo `test -f 'data_fastcgi.c' || echo '$(srcdir)/'`data_fastcgi.c
liblightcomp_la-fdevent_select.lo: fdevent_select.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_select.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-fdevent_select.Tpo" -c -o liblightcomp_la-fdevent_select.lo `test -f 'fdevent_select.c' || echo '$(srcdir)/'`fdevent_select.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-fdevent_select.Tpo" "$(DEPDIR)/liblightcomp_la-fdevent_select.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-fdevent_select.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fdevent_select.c' object='liblightcomp_la-fdevent_select.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_select.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-fdevent_select.Tpo -c -o liblightcomp_la-fdevent_select.lo `test -f 'fdevent_select.c' || echo '$(srcdir)/'`fdevent_select.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-fdevent_select.Tpo $(DEPDIR)/liblightcomp_la-fdevent_select.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_select.c' object='liblightcomp_la-fdevent_select.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_select.lo `test -f 'fdevent_select.c' || echo '$(srcdir)/'`fdevent_select.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_select.lo `test -f 'fdevent_select.c' || echo '$(srcdir)/'`fdevent_select.c
-liblightcomp_la-fdevent_linux_rtsig.lo: fdevent_linux_rtsig.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_linux_rtsig.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-fdevent_linux_rtsig.Tpo" -c -o liblightcomp_la-fdevent_linux_rtsig.lo `test -f 'fdevent_linux_rtsig.c' || echo '$(srcdir)/'`fdevent_linux_rtsig.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-fdevent_linux_rtsig.Tpo" "$(DEPDIR)/liblightcomp_la-fdevent_linux_rtsig.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-fdevent_linux_rtsig.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fdevent_linux_rtsig.c' object='liblightcomp_la-fdevent_linux_rtsig.lo' libtool=yes @AMDEPBACKSLASH@
+liblightcomp_la-fdevent_libev.lo: fdevent_libev.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_libev.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-fdevent_libev.Tpo -c -o liblightcomp_la-fdevent_libev.lo `test -f 'fdevent_libev.c' || echo '$(srcdir)/'`fdevent_libev.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-fdevent_libev.Tpo $(DEPDIR)/liblightcomp_la-fdevent_libev.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_libev.c' object='liblightcomp_la-fdevent_libev.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_linux_rtsig.lo `test -f 'fdevent_linux_rtsig.c' || echo '$(srcdir)/'`fdevent_linux_rtsig.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_libev.lo `test -f 'fdevent_libev.c' || echo '$(srcdir)/'`fdevent_libev.c
liblightcomp_la-fdevent_poll.lo: fdevent_poll.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_poll.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-fdevent_poll.Tpo" -c -o liblightcomp_la-fdevent_poll.lo `test -f 'fdevent_poll.c' || echo '$(srcdir)/'`fdevent_poll.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-fdevent_poll.Tpo" "$(DEPDIR)/liblightcomp_la-fdevent_poll.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-fdevent_poll.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fdevent_poll.c' object='liblightcomp_la-fdevent_poll.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_poll.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-fdevent_poll.Tpo -c -o liblightcomp_la-fdevent_poll.lo `test -f 'fdevent_poll.c' || echo '$(srcdir)/'`fdevent_poll.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-fdevent_poll.Tpo $(DEPDIR)/liblightcomp_la-fdevent_poll.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_poll.c' object='liblightcomp_la-fdevent_poll.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_poll.lo `test -f 'fdevent_poll.c' || echo '$(srcdir)/'`fdevent_poll.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_poll.lo `test -f 'fdevent_poll.c' || echo '$(srcdir)/'`fdevent_poll.c
liblightcomp_la-fdevent_linux_sysepoll.lo: fdevent_linux_sysepoll.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_linux_sysepoll.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-fdevent_linux_sysepoll.Tpo" -c -o liblightcomp_la-fdevent_linux_sysepoll.lo `test -f 'fdevent_linux_sysepoll.c' || echo '$(srcdir)/'`fdevent_linux_sysepoll.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-fdevent_linux_sysepoll.Tpo" "$(DEPDIR)/liblightcomp_la-fdevent_linux_sysepoll.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-fdevent_linux_sysepoll.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fdevent_linux_sysepoll.c' object='liblightcomp_la-fdevent_linux_sysepoll.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_linux_sysepoll.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-fdevent_linux_sysepoll.Tpo -c -o liblightcomp_la-fdevent_linux_sysepoll.lo `test -f 'fdevent_linux_sysepoll.c' || echo '$(srcdir)/'`fdevent_linux_sysepoll.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-fdevent_linux_sysepoll.Tpo $(DEPDIR)/liblightcomp_la-fdevent_linux_sysepoll.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_linux_sysepoll.c' object='liblightcomp_la-fdevent_linux_sysepoll.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_linux_sysepoll.lo `test -f 'fdevent_linux_sysepoll.c' || echo '$(srcdir)/'`fdevent_linux_sysepoll.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_linux_sysepoll.lo `test -f 'fdevent_linux_sysepoll.c' || echo '$(srcdir)/'`fdevent_linux_sysepoll.c
liblightcomp_la-fdevent_solaris_devpoll.lo: fdevent_solaris_devpoll.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_solaris_devpoll.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-fdevent_solaris_devpoll.Tpo" -c -o liblightcomp_la-fdevent_solaris_devpoll.lo `test -f 'fdevent_solaris_devpoll.c' || echo '$(srcdir)/'`fdevent_solaris_devpoll.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-fdevent_solaris_devpoll.Tpo" "$(DEPDIR)/liblightcomp_la-fdevent_solaris_devpoll.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-fdevent_solaris_devpoll.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fdevent_solaris_devpoll.c' object='liblightcomp_la-fdevent_solaris_devpoll.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_solaris_devpoll.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-fdevent_solaris_devpoll.Tpo -c -o liblightcomp_la-fdevent_solaris_devpoll.lo `test -f 'fdevent_solaris_devpoll.c' || echo '$(srcdir)/'`fdevent_solaris_devpoll.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-fdevent_solaris_devpoll.Tpo $(DEPDIR)/liblightcomp_la-fdevent_solaris_devpoll.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_solaris_devpoll.c' object='liblightcomp_la-fdevent_solaris_devpoll.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_solaris_devpoll.lo `test -f 'fdevent_solaris_devpoll.c' || echo '$(srcdir)/'`fdevent_solaris_devpoll.c
+
+liblightcomp_la-fdevent_solaris_port.lo: fdevent_solaris_port.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_solaris_port.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-fdevent_solaris_port.Tpo -c -o liblightcomp_la-fdevent_solaris_port.lo `test -f 'fdevent_solaris_port.c' || echo '$(srcdir)/'`fdevent_solaris_port.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-fdevent_solaris_port.Tpo $(DEPDIR)/liblightcomp_la-fdevent_solaris_port.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_solaris_port.c' object='liblightcomp_la-fdevent_solaris_port.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_solaris_devpoll.lo `test -f 'fdevent_solaris_devpoll.c' || echo '$(srcdir)/'`fdevent_solaris_devpoll.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_solaris_port.lo `test -f 'fdevent_solaris_port.c' || echo '$(srcdir)/'`fdevent_solaris_port.c
liblightcomp_la-fdevent_freebsd_kqueue.lo: fdevent_freebsd_kqueue.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_freebsd_kqueue.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-fdevent_freebsd_kqueue.Tpo" -c -o liblightcomp_la-fdevent_freebsd_kqueue.lo `test -f 'fdevent_freebsd_kqueue.c' || echo '$(srcdir)/'`fdevent_freebsd_kqueue.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-fdevent_freebsd_kqueue.Tpo" "$(DEPDIR)/liblightcomp_la-fdevent_freebsd_kqueue.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-fdevent_freebsd_kqueue.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fdevent_freebsd_kqueue.c' object='liblightcomp_la-fdevent_freebsd_kqueue.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-fdevent_freebsd_kqueue.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-fdevent_freebsd_kqueue.Tpo -c -o liblightcomp_la-fdevent_freebsd_kqueue.lo `test -f 'fdevent_freebsd_kqueue.c' || echo '$(srcdir)/'`fdevent_freebsd_kqueue.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-fdevent_freebsd_kqueue.Tpo $(DEPDIR)/liblightcomp_la-fdevent_freebsd_kqueue.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdevent_freebsd_kqueue.c' object='liblightcomp_la-fdevent_freebsd_kqueue.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_freebsd_kqueue.lo `test -f 'fdevent_freebsd_kqueue.c' || echo '$(srcdir)/'`fdevent_freebsd_kqueue.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-fdevent_freebsd_kqueue.lo `test -f 'fdevent_freebsd_kqueue.c' || echo '$(srcdir)/'`fdevent_freebsd_kqueue.c
liblightcomp_la-data_config.lo: data_config.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-data_config.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-data_config.Tpo" -c -o liblightcomp_la-data_config.lo `test -f 'data_config.c' || echo '$(srcdir)/'`data_config.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-data_config.Tpo" "$(DEPDIR)/liblightcomp_la-data_config.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-data_config.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='data_config.c' object='liblightcomp_la-data_config.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-data_config.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-data_config.Tpo -c -o liblightcomp_la-data_config.lo `test -f 'data_config.c' || echo '$(srcdir)/'`data_config.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-data_config.Tpo $(DEPDIR)/liblightcomp_la-data_config.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='data_config.c' object='liblightcomp_la-data_config.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-data_config.lo `test -f 'data_config.c' || echo '$(srcdir)/'`data_config.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-data_config.lo `test -f 'data_config.c' || echo '$(srcdir)/'`data_config.c
liblightcomp_la-bitset.lo: bitset.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-bitset.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-bitset.Tpo" -c -o liblightcomp_la-bitset.lo `test -f 'bitset.c' || echo '$(srcdir)/'`bitset.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-bitset.Tpo" "$(DEPDIR)/liblightcomp_la-bitset.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-bitset.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bitset.c' object='liblightcomp_la-bitset.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-bitset.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-bitset.Tpo -c -o liblightcomp_la-bitset.lo `test -f 'bitset.c' || echo '$(srcdir)/'`bitset.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-bitset.Tpo $(DEPDIR)/liblightcomp_la-bitset.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bitset.c' object='liblightcomp_la-bitset.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-bitset.lo `test -f 'bitset.c' || echo '$(srcdir)/'`bitset.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-bitset.lo `test -f 'bitset.c' || echo '$(srcdir)/'`bitset.c
liblightcomp_la-inet_ntop_cache.lo: inet_ntop_cache.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-inet_ntop_cache.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-inet_ntop_cache.Tpo" -c -o liblightcomp_la-inet_ntop_cache.lo `test -f 'inet_ntop_cache.c' || echo '$(srcdir)/'`inet_ntop_cache.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-inet_ntop_cache.Tpo" "$(DEPDIR)/liblightcomp_la-inet_ntop_cache.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-inet_ntop_cache.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='inet_ntop_cache.c' object='liblightcomp_la-inet_ntop_cache.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-inet_ntop_cache.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-inet_ntop_cache.Tpo -c -o liblightcomp_la-inet_ntop_cache.lo `test -f 'inet_ntop_cache.c' || echo '$(srcdir)/'`inet_ntop_cache.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-inet_ntop_cache.Tpo $(DEPDIR)/liblightcomp_la-inet_ntop_cache.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='inet_ntop_cache.c' object='liblightcomp_la-inet_ntop_cache.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-inet_ntop_cache.lo `test -f 'inet_ntop_cache.c' || echo '$(srcdir)/'`inet_ntop_cache.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-inet_ntop_cache.lo `test -f 'inet_ntop_cache.c' || echo '$(srcdir)/'`inet_ntop_cache.c
liblightcomp_la-crc32.lo: crc32.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-crc32.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-crc32.Tpo" -c -o liblightcomp_la-crc32.lo `test -f 'crc32.c' || echo '$(srcdir)/'`crc32.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-crc32.Tpo" "$(DEPDIR)/liblightcomp_la-crc32.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-crc32.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crc32.c' object='liblightcomp_la-crc32.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-crc32.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-crc32.Tpo -c -o liblightcomp_la-crc32.lo `test -f 'crc32.c' || echo '$(srcdir)/'`crc32.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-crc32.Tpo $(DEPDIR)/liblightcomp_la-crc32.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='crc32.c' object='liblightcomp_la-crc32.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-crc32.lo `test -f 'crc32.c' || echo '$(srcdir)/'`crc32.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-crc32.lo `test -f 'crc32.c' || echo '$(srcdir)/'`crc32.c
liblightcomp_la-connections-glue.lo: connections-glue.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-connections-glue.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-connections-glue.Tpo" -c -o liblightcomp_la-connections-glue.lo `test -f 'connections-glue.c' || echo '$(srcdir)/'`connections-glue.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-connections-glue.Tpo" "$(DEPDIR)/liblightcomp_la-connections-glue.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-connections-glue.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='connections-glue.c' object='liblightcomp_la-connections-glue.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-connections-glue.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-connections-glue.Tpo -c -o liblightcomp_la-connections-glue.lo `test -f 'connections-glue.c' || echo '$(srcdir)/'`connections-glue.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-connections-glue.Tpo $(DEPDIR)/liblightcomp_la-connections-glue.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='connections-glue.c' object='liblightcomp_la-connections-glue.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-connections-glue.lo `test -f 'connections-glue.c' || echo '$(srcdir)/'`connections-glue.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-connections-glue.lo `test -f 'connections-glue.c' || echo '$(srcdir)/'`connections-glue.c
liblightcomp_la-configfile-glue.lo: configfile-glue.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-configfile-glue.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-configfile-glue.Tpo" -c -o liblightcomp_la-configfile-glue.lo `test -f 'configfile-glue.c' || echo '$(srcdir)/'`configfile-glue.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-configfile-glue.Tpo" "$(DEPDIR)/liblightcomp_la-configfile-glue.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-configfile-glue.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='configfile-glue.c' object='liblightcomp_la-configfile-glue.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-configfile-glue.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-configfile-glue.Tpo -c -o liblightcomp_la-configfile-glue.lo `test -f 'configfile-glue.c' || echo '$(srcdir)/'`configfile-glue.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-configfile-glue.Tpo $(DEPDIR)/liblightcomp_la-configfile-glue.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='configfile-glue.c' object='liblightcomp_la-configfile-glue.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-configfile-glue.lo `test -f 'configfile-glue.c' || echo '$(srcdir)/'`configfile-glue.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-configfile-glue.lo `test -f 'configfile-glue.c' || echo '$(srcdir)/'`configfile-glue.c
liblightcomp_la-http-header-glue.lo: http-header-glue.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-http-header-glue.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-http-header-glue.Tpo" -c -o liblightcomp_la-http-header-glue.lo `test -f 'http-header-glue.c' || echo '$(srcdir)/'`http-header-glue.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-http-header-glue.Tpo" "$(DEPDIR)/liblightcomp_la-http-header-glue.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-http-header-glue.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='http-header-glue.c' object='liblightcomp_la-http-header-glue.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-http-header-glue.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-http-header-glue.Tpo -c -o liblightcomp_la-http-header-glue.lo `test -f 'http-header-glue.c' || echo '$(srcdir)/'`http-header-glue.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-http-header-glue.Tpo $(DEPDIR)/liblightcomp_la-http-header-glue.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='http-header-glue.c' object='liblightcomp_la-http-header-glue.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-http-header-glue.lo `test -f 'http-header-glue.c' || echo '$(srcdir)/'`http-header-glue.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-http-header-glue.lo `test -f 'http-header-glue.c' || echo '$(srcdir)/'`http-header-glue.c
liblightcomp_la-network_write.lo: network_write.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-network_write.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-network_write.Tpo" -c -o liblightcomp_la-network_write.lo `test -f 'network_write.c' || echo '$(srcdir)/'`network_write.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-network_write.Tpo" "$(DEPDIR)/liblightcomp_la-network_write.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-network_write.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network_write.c' object='liblightcomp_la-network_write.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-network_write.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-network_write.Tpo -c -o liblightcomp_la-network_write.lo `test -f 'network_write.c' || echo '$(srcdir)/'`network_write.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-network_write.Tpo $(DEPDIR)/liblightcomp_la-network_write.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network_write.c' object='liblightcomp_la-network_write.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-network_write.lo `test -f 'network_write.c' || echo '$(srcdir)/'`network_write.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-network_write.lo `test -f 'network_write.c' || echo '$(srcdir)/'`network_write.c
liblightcomp_la-network_linux_sendfile.lo: network_linux_sendfile.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-network_linux_sendfile.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-network_linux_sendfile.Tpo" -c -o liblightcomp_la-network_linux_sendfile.lo `test -f 'network_linux_sendfile.c' || echo '$(srcdir)/'`network_linux_sendfile.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-network_linux_sendfile.Tpo" "$(DEPDIR)/liblightcomp_la-network_linux_sendfile.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-network_linux_sendfile.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network_linux_sendfile.c' object='liblightcomp_la-network_linux_sendfile.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-network_linux_sendfile.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-network_linux_sendfile.Tpo -c -o liblightcomp_la-network_linux_sendfile.lo `test -f 'network_linux_sendfile.c' || echo '$(srcdir)/'`network_linux_sendfile.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-network_linux_sendfile.Tpo $(DEPDIR)/liblightcomp_la-network_linux_sendfile.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network_linux_sendfile.c' object='liblightcomp_la-network_linux_sendfile.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-network_linux_sendfile.lo `test -f 'network_linux_sendfile.c' || echo '$(srcdir)/'`network_linux_sendfile.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-network_linux_sendfile.lo `test -f 'network_linux_sendfile.c' || echo '$(srcdir)/'`network_linux_sendfile.c
liblightcomp_la-network_freebsd_sendfile.lo: network_freebsd_sendfile.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-network_freebsd_sendfile.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-network_freebsd_sendfile.Tpo" -c -o liblightcomp_la-network_freebsd_sendfile.lo `test -f 'network_freebsd_sendfile.c' || echo '$(srcdir)/'`network_freebsd_sendfile.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-network_freebsd_sendfile.Tpo" "$(DEPDIR)/liblightcomp_la-network_freebsd_sendfile.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-network_freebsd_sendfile.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network_freebsd_sendfile.c' object='liblightcomp_la-network_freebsd_sendfile.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-network_freebsd_sendfile.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-network_freebsd_sendfile.Tpo -c -o liblightcomp_la-network_freebsd_sendfile.lo `test -f 'network_freebsd_sendfile.c' || echo '$(srcdir)/'`network_freebsd_sendfile.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-network_freebsd_sendfile.Tpo $(DEPDIR)/liblightcomp_la-network_freebsd_sendfile.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network_freebsd_sendfile.c' object='liblightcomp_la-network_freebsd_sendfile.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-network_freebsd_sendfile.lo `test -f 'network_freebsd_sendfile.c' || echo '$(srcdir)/'`network_freebsd_sendfile.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-network_freebsd_sendfile.lo `test -f 'network_freebsd_sendfile.c' || echo '$(srcdir)/'`network_freebsd_sendfile.c
liblightcomp_la-network_writev.lo: network_writev.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-network_writev.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-network_writev.Tpo" -c -o liblightcomp_la-network_writev.lo `test -f 'network_writev.c' || echo '$(srcdir)/'`network_writev.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-network_writev.Tpo" "$(DEPDIR)/liblightcomp_la-network_writev.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-network_writev.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network_writev.c' object='liblightcomp_la-network_writev.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-network_writev.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-network_writev.Tpo -c -o liblightcomp_la-network_writev.lo `test -f 'network_writev.c' || echo '$(srcdir)/'`network_writev.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-network_writev.Tpo $(DEPDIR)/liblightcomp_la-network_writev.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network_writev.c' object='liblightcomp_la-network_writev.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-network_writev.lo `test -f 'network_writev.c' || echo '$(srcdir)/'`network_writev.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-network_writev.lo `test -f 'network_writev.c' || echo '$(srcdir)/'`network_writev.c
liblightcomp_la-network_solaris_sendfilev.lo: network_solaris_sendfilev.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-network_solaris_sendfilev.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-network_solaris_sendfilev.Tpo" -c -o liblightcomp_la-network_solaris_sendfilev.lo `test -f 'network_solaris_sendfilev.c' || echo '$(srcdir)/'`network_solaris_sendfilev.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-network_solaris_sendfilev.Tpo" "$(DEPDIR)/liblightcomp_la-network_solaris_sendfilev.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-network_solaris_sendfilev.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network_solaris_sendfilev.c' object='liblightcomp_la-network_solaris_sendfilev.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-network_solaris_sendfilev.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-network_solaris_sendfilev.Tpo -c -o liblightcomp_la-network_solaris_sendfilev.lo `test -f 'network_solaris_sendfilev.c' || echo '$(srcdir)/'`network_solaris_sendfilev.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-network_solaris_sendfilev.Tpo $(DEPDIR)/liblightcomp_la-network_solaris_sendfilev.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network_solaris_sendfilev.c' object='liblightcomp_la-network_solaris_sendfilev.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-network_solaris_sendfilev.lo `test -f 'network_solaris_sendfilev.c' || echo '$(srcdir)/'`network_solaris_sendfilev.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-network_solaris_sendfilev.lo `test -f 'network_solaris_sendfilev.c' || echo '$(srcdir)/'`network_solaris_sendfilev.c
liblightcomp_la-network_openssl.lo: network_openssl.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-network_openssl.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-network_openssl.Tpo" -c -o liblightcomp_la-network_openssl.lo `test -f 'network_openssl.c' || echo '$(srcdir)/'`network_openssl.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-network_openssl.Tpo" "$(DEPDIR)/liblightcomp_la-network_openssl.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-network_openssl.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network_openssl.c' object='liblightcomp_la-network_openssl.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-network_openssl.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-network_openssl.Tpo -c -o liblightcomp_la-network_openssl.lo `test -f 'network_openssl.c' || echo '$(srcdir)/'`network_openssl.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-network_openssl.Tpo $(DEPDIR)/liblightcomp_la-network_openssl.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network_openssl.c' object='liblightcomp_la-network_openssl.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-network_openssl.lo `test -f 'network_openssl.c' || echo '$(srcdir)/'`network_openssl.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-network_openssl.lo `test -f 'network_openssl.c' || echo '$(srcdir)/'`network_openssl.c
liblightcomp_la-splaytree.lo: splaytree.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-splaytree.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-splaytree.Tpo" -c -o liblightcomp_la-splaytree.lo `test -f 'splaytree.c' || echo '$(srcdir)/'`splaytree.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-splaytree.Tpo" "$(DEPDIR)/liblightcomp_la-splaytree.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-splaytree.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='splaytree.c' object='liblightcomp_la-splaytree.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-splaytree.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-splaytree.Tpo -c -o liblightcomp_la-splaytree.lo `test -f 'splaytree.c' || echo '$(srcdir)/'`splaytree.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-splaytree.Tpo $(DEPDIR)/liblightcomp_la-splaytree.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='splaytree.c' object='liblightcomp_la-splaytree.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-splaytree.lo `test -f 'splaytree.c' || echo '$(srcdir)/'`splaytree.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-splaytree.lo `test -f 'splaytree.c' || echo '$(srcdir)/'`splaytree.c
+
+liblightcomp_la-status_counter.lo: status_counter.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-status_counter.lo -MD -MP -MF $(DEPDIR)/liblightcomp_la-status_counter.Tpo -c -o liblightcomp_la-status_counter.lo `test -f 'status_counter.c' || echo '$(srcdir)/'`status_counter.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightcomp_la-status_counter.Tpo $(DEPDIR)/liblightcomp_la-status_counter.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='status_counter.c' object='liblightcomp_la-status_counter.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-status_counter.lo `test -f 'status_counter.c' || echo '$(srcdir)/'`status_counter.c
mod_cml_la-mod_cml.lo: mod_cml.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -MT mod_cml_la-mod_cml.lo -MD -MP -MF "$(DEPDIR)/mod_cml_la-mod_cml.Tpo" -c -o mod_cml_la-mod_cml.lo `test -f 'mod_cml.c' || echo '$(srcdir)/'`mod_cml.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/mod_cml_la-mod_cml.Tpo" "$(DEPDIR)/mod_cml_la-mod_cml.Plo"; else rm -f "$(DEPDIR)/mod_cml_la-mod_cml.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mod_cml.c' object='mod_cml_la-mod_cml.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -MT mod_cml_la-mod_cml.lo -MD -MP -MF $(DEPDIR)/mod_cml_la-mod_cml.Tpo -c -o mod_cml_la-mod_cml.lo `test -f 'mod_cml.c' || echo '$(srcdir)/'`mod_cml.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_cml_la-mod_cml.Tpo $(DEPDIR)/mod_cml_la-mod_cml.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_cml.c' object='mod_cml_la-mod_cml.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -c -o mod_cml_la-mod_cml.lo `test -f 'mod_cml.c' || echo '$(srcdir)/'`mod_cml.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -c -o mod_cml_la-mod_cml.lo `test -f 'mod_cml.c' || echo '$(srcdir)/'`mod_cml.c
mod_cml_la-mod_cml_lua.lo: mod_cml_lua.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -MT mod_cml_la-mod_cml_lua.lo -MD -MP -MF "$(DEPDIR)/mod_cml_la-mod_cml_lua.Tpo" -c -o mod_cml_la-mod_cml_lua.lo `test -f 'mod_cml_lua.c' || echo '$(srcdir)/'`mod_cml_lua.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/mod_cml_la-mod_cml_lua.Tpo" "$(DEPDIR)/mod_cml_la-mod_cml_lua.Plo"; else rm -f "$(DEPDIR)/mod_cml_la-mod_cml_lua.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mod_cml_lua.c' object='mod_cml_la-mod_cml_lua.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -MT mod_cml_la-mod_cml_lua.lo -MD -MP -MF $(DEPDIR)/mod_cml_la-mod_cml_lua.Tpo -c -o mod_cml_la-mod_cml_lua.lo `test -f 'mod_cml_lua.c' || echo '$(srcdir)/'`mod_cml_lua.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_cml_la-mod_cml_lua.Tpo $(DEPDIR)/mod_cml_la-mod_cml_lua.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_cml_lua.c' object='mod_cml_la-mod_cml_lua.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -c -o mod_cml_la-mod_cml_lua.lo `test -f 'mod_cml_lua.c' || echo '$(srcdir)/'`mod_cml_lua.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -c -o mod_cml_la-mod_cml_lua.lo `test -f 'mod_cml_lua.c' || echo '$(srcdir)/'`mod_cml_lua.c
mod_cml_la-mod_cml_funcs.lo: mod_cml_funcs.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -MT mod_cml_la-mod_cml_funcs.lo -MD -MP -MF "$(DEPDIR)/mod_cml_la-mod_cml_funcs.Tpo" -c -o mod_cml_la-mod_cml_funcs.lo `test -f 'mod_cml_funcs.c' || echo '$(srcdir)/'`mod_cml_funcs.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/mod_cml_la-mod_cml_funcs.Tpo" "$(DEPDIR)/mod_cml_la-mod_cml_funcs.Plo"; else rm -f "$(DEPDIR)/mod_cml_la-mod_cml_funcs.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mod_cml_funcs.c' object='mod_cml_la-mod_cml_funcs.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -MT mod_cml_la-mod_cml_funcs.lo -MD -MP -MF $(DEPDIR)/mod_cml_la-mod_cml_funcs.Tpo -c -o mod_cml_la-mod_cml_funcs.lo `test -f 'mod_cml_funcs.c' || echo '$(srcdir)/'`mod_cml_funcs.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_cml_la-mod_cml_funcs.Tpo $(DEPDIR)/mod_cml_la-mod_cml_funcs.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_cml_funcs.c' object='mod_cml_la-mod_cml_funcs.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -c -o mod_cml_la-mod_cml_funcs.lo `test -f 'mod_cml_funcs.c' || echo '$(srcdir)/'`mod_cml_funcs.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -c -o mod_cml_la-mod_cml_funcs.lo `test -f 'mod_cml_funcs.c' || echo '$(srcdir)/'`mod_cml_funcs.c
+
+mod_magnet_la-mod_magnet.lo: mod_magnet.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_magnet_la_CFLAGS) $(CFLAGS) -MT mod_magnet_la-mod_magnet.lo -MD -MP -MF $(DEPDIR)/mod_magnet_la-mod_magnet.Tpo -c -o mod_magnet_la-mod_magnet.lo `test -f 'mod_magnet.c' || echo '$(srcdir)/'`mod_magnet.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_magnet_la-mod_magnet.Tpo $(DEPDIR)/mod_magnet_la-mod_magnet.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_magnet.c' object='mod_magnet_la-mod_magnet.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_magnet_la_CFLAGS) $(CFLAGS) -c -o mod_magnet_la-mod_magnet.lo `test -f 'mod_magnet.c' || echo '$(srcdir)/'`mod_magnet.c
+
+mod_magnet_la-mod_magnet_cache.lo: mod_magnet_cache.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_magnet_la_CFLAGS) $(CFLAGS) -MT mod_magnet_la-mod_magnet_cache.lo -MD -MP -MF $(DEPDIR)/mod_magnet_la-mod_magnet_cache.Tpo -c -o mod_magnet_la-mod_magnet_cache.lo `test -f 'mod_magnet_cache.c' || echo '$(srcdir)/'`mod_magnet_cache.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_magnet_la-mod_magnet_cache.Tpo $(DEPDIR)/mod_magnet_la-mod_magnet_cache.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_magnet_cache.c' object='mod_magnet_la-mod_magnet_cache.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_magnet_la_CFLAGS) $(CFLAGS) -c -o mod_magnet_la-mod_magnet_cache.lo `test -f 'mod_magnet_cache.c' || echo '$(srcdir)/'`mod_magnet_cache.c
mod_mysql_vhost_la-mod_mysql_vhost.lo: mod_mysql_vhost.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_mysql_vhost_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mod_mysql_vhost_la-mod_mysql_vhost.lo -MD -MP -MF "$(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Tpo" -c -o mod_mysql_vhost_la-mod_mysql_vhost.lo `test -f 'mod_mysql_vhost.c' || echo '$(srcdir)/'`mod_mysql_vhost.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Tpo" "$(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Plo"; else rm -f "$(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mod_mysql_vhost.c' object='mod_mysql_vhost_la-mod_mysql_vhost.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_mysql_vhost_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mod_mysql_vhost_la-mod_mysql_vhost.lo -MD -MP -MF $(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Tpo -c -o mod_mysql_vhost_la-mod_mysql_vhost.lo `test -f 'mod_mysql_vhost.c' || echo '$(srcdir)/'`mod_mysql_vhost.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Tpo $(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_mysql_vhost.c' object='mod_mysql_vhost_la-mod_mysql_vhost.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_mysql_vhost_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mod_mysql_vhost_la-mod_mysql_vhost.lo `test -f 'mod_mysql_vhost.c' || echo '$(srcdir)/'`mod_mysql_vhost.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_mysql_vhost_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mod_mysql_vhost_la-mod_mysql_vhost.lo `test -f 'mod_mysql_vhost.c' || echo '$(srcdir)/'`mod_mysql_vhost.c
mod_webdav_la-mod_webdav.lo: mod_webdav.c
-@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_webdav_la_CFLAGS) $(CFLAGS) -MT mod_webdav_la-mod_webdav.lo -MD -MP -MF "$(DEPDIR)/mod_webdav_la-mod_webdav.Tpo" -c -o mod_webdav_la-mod_webdav.lo `test -f 'mod_webdav.c' || echo '$(srcdir)/'`mod_webdav.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/mod_webdav_la-mod_webdav.Tpo" "$(DEPDIR)/mod_webdav_la-mod_webdav.Plo"; else rm -f "$(DEPDIR)/mod_webdav_la-mod_webdav.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mod_webdav.c' object='mod_webdav_la-mod_webdav.lo' libtool=yes @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_webdav_la_CFLAGS) $(CFLAGS) -MT mod_webdav_la-mod_webdav.lo -MD -MP -MF $(DEPDIR)/mod_webdav_la-mod_webdav.Tpo -c -o mod_webdav_la-mod_webdav.lo `test -f 'mod_webdav.c' || echo '$(srcdir)/'`mod_webdav.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_webdav_la-mod_webdav.Tpo $(DEPDIR)/mod_webdav_la-mod_webdav.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_webdav.c' object='mod_webdav_la-mod_webdav.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_webdav_la_CFLAGS) $(CFLAGS) -c -o mod_webdav_la-mod_webdav.lo `test -f 'mod_webdav.c' || echo '$(srcdir)/'`mod_webdav.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_webdav_la_CFLAGS) $(CFLAGS) -c -o mod_webdav_la-mod_webdav.lo `test -f 'mod_webdav.c' || echo '$(srcdir)/'`mod_webdav.c
proc_open-proc_open.o: proc_open.c
-@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proc_open_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT proc_open-proc_open.o -MD -MP -MF "$(DEPDIR)/proc_open-proc_open.Tpo" -c -o proc_open-proc_open.o `test -f 'proc_open.c' || echo '$(srcdir)/'`proc_open.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/proc_open-proc_open.Tpo" "$(DEPDIR)/proc_open-proc_open.Po"; else rm -f "$(DEPDIR)/proc_open-proc_open.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='proc_open.c' object='proc_open-proc_open.o' libtool=no @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proc_open_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT proc_open-proc_open.o -MD -MP -MF $(DEPDIR)/proc_open-proc_open.Tpo -c -o proc_open-proc_open.o `test -f 'proc_open.c' || echo '$(srcdir)/'`proc_open.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/proc_open-proc_open.Tpo $(DEPDIR)/proc_open-proc_open.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='proc_open.c' object='proc_open-proc_open.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proc_open_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o proc_open-proc_open.o `test -f 'proc_open.c' || echo '$(srcdir)/'`proc_open.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proc_open_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o proc_open-proc_open.o `test -f 'proc_open.c' || echo '$(srcdir)/'`proc_open.c
proc_open-proc_open.obj: proc_open.c
-@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proc_open_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT proc_open-proc_open.obj -MD -MP -MF "$(DEPDIR)/proc_open-proc_open.Tpo" -c -o proc_open-proc_open.obj `if test -f 'proc_open.c'; then $(CYGPATH_W) 'proc_open.c'; else $(CYGPATH_W) '$(srcdir)/proc_open.c'; fi`; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/proc_open-proc_open.Tpo" "$(DEPDIR)/proc_open-proc_open.Po"; else rm -f "$(DEPDIR)/proc_open-proc_open.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='proc_open.c' object='proc_open-proc_open.obj' libtool=no @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proc_open_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT proc_open-proc_open.obj -MD -MP -MF $(DEPDIR)/proc_open-proc_open.Tpo -c -o proc_open-proc_open.obj `if test -f 'proc_open.c'; then $(CYGPATH_W) 'proc_open.c'; else $(CYGPATH_W) '$(srcdir)/proc_open.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/proc_open-proc_open.Tpo $(DEPDIR)/proc_open-proc_open.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='proc_open.c' object='proc_open-proc_open.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proc_open_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o proc_open-proc_open.obj `if test -f 'proc_open.c'; then $(CYGPATH_W) 'proc_open.c'; else $(CYGPATH_W) '$(srcdir)/proc_open.c'; fi`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proc_open_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o proc_open-proc_open.obj `if test -f 'proc_open.c'; then $(CYGPATH_W) 'proc_open.c'; else $(CYGPATH_W) '$(srcdir)/proc_open.c'; fi`
proc_open-buffer.o: buffer.c
-@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proc_open_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT proc_open-buffer.o -MD -MP -MF "$(DEPDIR)/proc_open-buffer.Tpo" -c -o proc_open-buffer.o `test -f 'buffer.c' || echo '$(srcdir)/'`buffer.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/proc_open-buffer.Tpo" "$(DEPDIR)/proc_open-buffer.Po"; else rm -f "$(DEPDIR)/proc_open-buffer.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='buffer.c' object='proc_open-buffer.o' libtool=no @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proc_open_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT proc_open-buffer.o -MD -MP -MF $(DEPDIR)/proc_open-buffer.Tpo -c -o proc_open-buffer.o `test -f 'buffer.c' || echo '$(srcdir)/'`buffer.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/proc_open-buffer.Tpo $(DEPDIR)/proc_open-buffer.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='buffer.c' object='proc_open-buffer.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proc_open_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o proc_open-buffer.o `test -f 'buffer.c' || echo '$(srcdir)/'`buffer.c
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proc_open_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o proc_open-buffer.o `test -f 'buffer.c' || echo '$(srcdir)/'`buffer.c
proc_open-buffer.obj: buffer.c
-@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proc_open_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT proc_open-buffer.obj -MD -MP -MF "$(DEPDIR)/proc_open-buffer.Tpo" -c -o proc_open-buffer.obj `if test -f 'buffer.c'; then $(CYGPATH_W) 'buffer.c'; else $(CYGPATH_W) '$(srcdir)/buffer.c'; fi`; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/proc_open-buffer.Tpo" "$(DEPDIR)/proc_open-buffer.Po"; else rm -f "$(DEPDIR)/proc_open-buffer.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='buffer.c' object='proc_open-buffer.obj' libtool=no @AMDEPBACKSLASH@
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proc_open_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT proc_open-buffer.obj -MD -MP -MF $(DEPDIR)/proc_open-buffer.Tpo -c -o proc_open-buffer.obj `if test -f 'buffer.c'; then $(CYGPATH_W) 'buffer.c'; else $(CYGPATH_W) '$(srcdir)/buffer.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/proc_open-buffer.Tpo $(DEPDIR)/proc_open-buffer.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='buffer.c' object='proc_open-buffer.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proc_open_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o proc_open-buffer.obj `if test -f 'buffer.c'; then $(CYGPATH_W) 'buffer.c'; else $(CYGPATH_W) '$(srcdir)/buffer.c'; fi`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(proc_open_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o proc_open-buffer.obj `if test -f 'buffer.c'; then $(CYGPATH_W) 'buffer.c'; else $(CYGPATH_W) '$(srcdir)/buffer.c'; fi`
mostlyclean-libtool:
-rm -f *.lo
@@ -1306,95 +1569,98 @@ mostlyclean-libtool:
clean-libtool:
-rm -rf .libs _libs
-distclean-libtool:
- -rm -f libtool
-uninstall-info-am:
-
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
- $(AWK) ' { files[$$0] = 1; } \
- END { for (i in files) print i; }'`; \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
mkid -fID $$unique
tags: TAGS
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
- tags=; \
+ set x; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
- $(AWK) ' { files[$$0] = 1; } \
- END { for (i in files) print i; }'`; \
- if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
- $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
- $$tags $$unique; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
fi
ctags: CTAGS
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
- tags=; \
- here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
- $(AWK) ' { files[$$0] = 1; } \
- END { for (i in files) print i; }'`; \
- test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
- $$tags $$unique
+ $$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
- && cd $(top_srcdir) \
- && gtags -i $(GTAGS_ARGS) $$here
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
- @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
- topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
- list='$(DISTFILES)'; for file in $$list; do \
- case $$file in \
- $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
- $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
- esac; \
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
- dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
- if test "$$dir" != "$$file" && test "$$dir" != "."; then \
- dir="/$$dir"; \
- $(mkdir_p) "$(distdir)$$dir"; \
- else \
- dir=''; \
- fi; \
if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
- cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
- cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
- test -f $(distdir)/$$file \
- || cp -p $$d/$$file $(distdir)/$$file \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
-check: check-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS)
-install-binPROGRAMS: install-libLTLIBRARIES
-
installdirs:
- for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)"; do \
- test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(sbindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
-install: install-am
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
@@ -1404,31 +1670,39 @@ install-am: all-am
installcheck: installcheck-am
install-strip:
- $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
- install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
- `test -z '$(STRIP)' || \
- echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
mostlyclean-generic:
clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
clean: clean-am
-clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
- clean-libtool clean-noinstPROGRAMS clean-sbinPROGRAMS \
- mostlyclean-am
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ clean-noinstPROGRAMS clean-sbinPROGRAMS mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
- distclean-libtool distclean-tags
+ distclean-tags
dvi: dvi-am
@@ -1436,19 +1710,38 @@ dvi-am:
html: html-am
+html-am:
+
info: info-am
info-am:
install-data-am:
-install-exec-am: install-binPROGRAMS install-libLTLIBRARIES \
- install-sbinPROGRAMS
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES install-sbinPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
install-info: install-info-am
+install-info-am:
+
install-man:
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
installcheck-am:
maintainer-clean: maintainer-clean-am
@@ -1469,44 +1762,68 @@ ps: ps-am
ps-am:
-uninstall-am: uninstall-binPROGRAMS uninstall-info-am \
- uninstall-libLTLIBRARIES uninstall-sbinPROGRAMS
-
-.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
- clean-generic clean-libLTLIBRARIES clean-libtool \
- clean-noinstPROGRAMS clean-sbinPROGRAMS ctags distclean \
- distclean-compile distclean-generic distclean-libtool \
- distclean-tags distdir dvi dvi-am html html-am info info-am \
- install install-am install-binPROGRAMS install-data \
- install-data-am install-exec install-exec-am install-info \
- install-info-am install-libLTLIBRARIES install-man \
- install-sbinPROGRAMS install-strip installcheck \
+uninstall-am: uninstall-libLTLIBRARIES uninstall-sbinPROGRAMS
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool clean-noinstPROGRAMS \
+ clean-sbinPROGRAMS ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-libLTLIBRARIES \
+ install-man install-pdf install-pdf-am install-ps \
+ install-ps-am install-sbinPROGRAMS install-strip installcheck \
installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
- tags uninstall uninstall-am uninstall-binPROGRAMS \
- uninstall-info-am uninstall-libLTLIBRARIES \
+ tags uninstall uninstall-am uninstall-libLTLIBRARIES \
uninstall-sbinPROGRAMS
-#simple_fcgi_SOURCES=simple-fcgi.c
-#simple_fcgi_LDADD=-lfcgi
+.PHONY: versionstamp parsers
+
+versionstamp:
+ @test -f versionstamp.h || touch versionstamp.h; \
+ REVISION=""; \
+ if test -d "$(top_srcdir)/.svn" -a -x "`which svnversion`"; then \
+ REVISION="$$(LANG= LC_ALL=C svnversion "$(top_srcdir)" 2>/dev/null || echo exported)"; \
+ if test "$$REVISION" = "exported"; then \
+ REVISION=""; \
+ fi; \
+ fi; \
+ if test -z "$$REVISION" -a -d "$(top_srcdir)/.git" -a -x "`which git`"; then \
+ REVISION="$$(cd "$(top_srcdir)"; LANG= LC_ALL=C git describe --always 2>/dev/null || echo)"; \
+ fi; \
+ if test -n "$$REVISION"; then \
+ echo "#define REPO_VERSION \"-devel-$$REVISION\"" > versionstamp.h.tmp; \
+ else \
+ echo "#define REPO_VERSION \"\"" > versionstamp.h.tmp; \
+ fi; \
+ if ! diff versionstamp.h.tmp versionstamp.h >/dev/null 2>/dev/null; then \
+ mv versionstamp.h.tmp versionstamp.h; \
+ else \
+ rm versionstamp.h.tmp; \
+ fi
-@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_TRUE@configparser.c configparser.h:
+@CROSS_COMPILING_TRUE@mod_ssi_exprparser.c mod_ssi_exprparser.h:
-@CROSS_COMPILING_FALSE@configparser.c configparser.h: configparser.y
+@CROSS_COMPILING_TRUE@parsers:
+@CROSS_COMPILING_FALSE@configparser.h: configparser.c
+@CROSS_COMPILING_FALSE@configparser.c: $(srcdir)/configparser.y $(srcdir)/lempar.c lemon$(EXEEXT)
@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.h: mod_ssi_exprparser.c
+@CROSS_COMPILING_FALSE@mod_ssi_exprparser.c: $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c lemon$(EXEEXT)
@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
+@CROSS_COMPILING_FALSE@parsers: configparser.c mod_ssi_exprparser.c
+
# 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..7565094
--- /dev/null
+++ b/src/SConscript
@@ -0,0 +1,192 @@
+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_libev.c \
+ fdevent_poll.c fdevent_linux_sysepoll.c \
+ fdevent_solaris_devpoll.c fdevent_solaris_port.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_extforward' : { 'src' : [ 'mod_extforward.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.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)
+
+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 = []
+
+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.c b/src/array.c
index 14afa28..05568b3 100644
--- a/src/array.c
+++ b/src/array.c
@@ -1,3 +1,6 @@
+#include "array.h"
+#include "buffer.h"
+
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
@@ -6,17 +9,14 @@
#include <errno.h>
#include <assert.h>
-#include "array.h"
-#include "buffer.h"
-
array *array_init(void) {
array *a;
-
+
a = calloc(1, sizeof(*a));
assert(a);
-
+
a->next_power_of_2 = 1;
-
+
return a;
}
@@ -43,29 +43,29 @@ array *array_init_array(array *src) {
void array_free(array *a) {
size_t i;
if (!a) return;
-
+
if (!a->is_weakref) {
for (i = 0; i < a->size; i++) {
if (a->data[i]) a->data[i]->free(a->data[i]);
}
}
-
+
if (a->data) free(a->data);
if (a->sorted) free(a->sorted);
-
+
free(a);
}
void array_reset(array *a) {
size_t i;
if (!a) return;
-
+
if (!a->is_weakref) {
for (i = 0; i < a->used; i++) {
a->data[i]->reset(a->data[i]);
}
}
-
+
a->used = 0;
}
@@ -84,20 +84,20 @@ data_unset *array_pop(array *a) {
static int array_get_index(array *a, const char *key, size_t keylen, int *rndx) {
int ndx = -1;
int i, pos = 0;
-
+
if (key == NULL) return -1;
-
+
/* try to find the string */
for (i = pos = a->next_power_of_2 / 2; ; i >>= 1) {
int cmp;
-
+
if (pos < 0) {
pos += i;
} else if (pos >= (int)a->used) {
pos -= i;
} else {
cmp = buffer_caseless_compare(key, keylen, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used);
-
+
if (cmp == 0) {
/* found */
ndx = a->sorted[pos];
@@ -110,46 +110,64 @@ static int array_get_index(array *a, const char *key, size_t keylen, int *rndx)
}
if (i == 0) break;
}
-
+
if (rndx) *rndx = pos;
-
+
return ndx;
}
data_unset *array_get_element(array *a, const char *key) {
int ndx;
-
+
if (-1 != (ndx = array_get_index(a, key, strlen(key) + 1, NULL))) {
/* found, leave here */
-
+
return a->data[ndx];
- }
-
+ }
+
return NULL;
}
data_unset *array_get_unused_element(array *a, data_type_t t) {
data_unset *ds = NULL;
-
- UNUSED(t);
+ unsigned int i;
- if (a->size == 0) return NULL;
-
- if (a->used == a->size) return NULL;
+ for (i = a->used; i < a->size; i++) {
+ if (a->data[i] && a->data[i]->type == t) {
+ ds = a->data[i];
- if (a->data[a->used]) {
- ds = a->data[a->used];
-
- a->data[a->used] = NULL;
+ /* make empty slot at a->used for next insert */
+ a->data[i] = a->data[a->used];
+ a->data[a->used] = NULL;
+
+ return ds;
+ }
}
-
- return ds;
+
+ return NULL;
+}
+
+void array_set_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
+ data_string *ds_dst;
+
+ if (NULL != (ds_dst = (data_string *)array_get_element(hdrs, key))) {
+ buffer_copy_string_len(ds_dst->value, value, val_len);
+ return;
+ }
+
+ if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
+ ds_dst = data_string_init();
+ }
+
+ buffer_copy_string_len(ds_dst->key, key, key_len);
+ buffer_copy_string_len(ds_dst->value, value, val_len);
+ array_insert_unique(hdrs, (data_unset *)ds_dst);
}
/* replace or insert data, return the old one with the same key */
data_unset *array_replace(array *a, data_unset *du) {
int ndx;
-
+
if (-1 == (ndx = array_get_index(a, du->key->ptr, du->key->used, NULL))) {
array_insert_unique(a, du);
return NULL;
@@ -164,31 +182,31 @@ int array_insert_unique(array *a, data_unset *str) {
int ndx = -1;
int pos = 0;
size_t j;
-
+
/* generate unique index if neccesary */
if (str->key->used == 0 || str->is_index_key) {
buffer_copy_long(str->key, a->unique_ndx++);
str->is_index_key = 1;
}
-
+
/* try to find the string */
if (-1 != (ndx = array_get_index(a, str->key->ptr, str->key->used, &pos))) {
/* found, leave here */
if (a->data[ndx]->type == str->type) {
str->insert_dup(a->data[ndx], str);
} else {
- fprintf(stderr, "a\n");
+ SEGFAULT();
}
return 0;
}
-
+
/* insert */
-
+
if (a->used+1 > INT_MAX) {
/* we can't handle more then INT_MAX entries: see array_get_index() */
return -1;
}
-
+
if (a->size == 0) {
a->size = 16;
a->data = malloc(sizeof(*a->data) * a->size);
@@ -204,34 +222,37 @@ int array_insert_unique(array *a, data_unset *str) {
assert(a->sorted);
for (j = a->used; j < a->size; j++) a->data[j] = NULL;
}
-
+
ndx = (int) a->used;
-
+
+ /* make sure there is nothing here */
+ if (a->data[ndx]) a->data[ndx]->free(a->data[ndx]);
+
a->data[a->used++] = str;
-
+
if (pos != ndx &&
- ((pos < 0) ||
+ ((pos < 0) ||
buffer_caseless_compare(str->key->ptr, str->key->used, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used) > 0)) {
pos++;
- }
-
+ }
+
/* move everything on step to the right */
if (pos != ndx) {
memmove(a->sorted + (pos + 1), a->sorted + (pos), (ndx - pos) * sizeof(*a->sorted));
}
-
+
/* insert */
a->sorted[pos] = ndx;
-
+
if (a->next_power_of_2 == (size_t)ndx) a->next_power_of_2 <<= 1;
-
+
return 0;
}
void array_print_indent(int depth) {
int i;
for (i = 0; i < depth; i ++) {
- fprintf(stderr, " ");
+ fprintf(stdout, " ");
}
}
@@ -254,7 +275,7 @@ int array_print(array *a, int depth) {
size_t i;
size_t maxlen;
int oneline = 1;
-
+
if (a->used > 5) {
oneline = 0;
}
@@ -275,20 +296,20 @@ int array_print(array *a, int depth) {
}
}
if (oneline) {
- fprintf(stderr, "(");
+ fprintf(stdout, "(");
for (i = 0; i < a->used; i++) {
data_unset *du = a->data[i];
if (i != 0) {
- fprintf(stderr, ", ");
+ fprintf(stdout, ", ");
}
du->print(du, depth + 1);
}
- fprintf(stderr, ")");
+ fprintf(stdout, ")");
return 0;
}
maxlen = array_get_max_key_length(a);
- fprintf(stderr, "(\n");
+ fprintf(stdout, "(\n");
for (i = 0; i < a->used; i++) {
data_unset *du = a->data[i];
array_print_indent(depth + 1);
@@ -296,25 +317,25 @@ int array_print(array *a, int depth) {
int j;
if (i && (i % 5) == 0) {
- fprintf(stderr, "# %zd\n", i);
+ fprintf(stdout, "# %zd\n", i);
array_print_indent(depth + 1);
}
- fprintf(stderr, "\"%s\"", du->key->ptr);
+ fprintf(stdout, "\"%s\"", du->key->ptr);
for (j = maxlen - strlen(du->key->ptr); j > 0; j --) {
- fprintf(stderr, " ");
+ fprintf(stdout, " ");
}
- fprintf(stderr, " => ");
+ fprintf(stdout, " => ");
}
du->print(du, depth + 1);
- fprintf(stderr, ",\n");
+ fprintf(stdout, ",\n");
}
if (!(i && (i - 1 % 5) == 0)) {
array_print_indent(depth + 1);
- fprintf(stderr, "# %zd\n", i);
+ fprintf(stdout, "# %zd\n", i);
}
array_print_indent(depth);
- fprintf(stderr, ")");
-
+ fprintf(stdout, ")");
+
return 0;
}
@@ -323,47 +344,47 @@ int main (int argc, char **argv) {
array *a;
data_string *ds;
data_count *dc;
-
+
UNUSED(argc);
UNUSED(argv);
a = array_init();
-
+
ds = data_string_init();
- buffer_copy_string(ds->key, "abc");
- buffer_copy_string(ds->value, "alfrag");
-
+ buffer_copy_string_len(ds->key, CONST_STR_LEN("abc"));
+ buffer_copy_string_len(ds->value, CONST_STR_LEN("alfrag"));
+
array_insert_unique(a, (data_unset *)ds);
-
+
ds = data_string_init();
- buffer_copy_string(ds->key, "abc");
- buffer_copy_string(ds->value, "hameplman");
-
+ buffer_copy_string_len(ds->key, CONST_STR_LEN("abc"));
+ buffer_copy_string_len(ds->value, CONST_STR_LEN("hameplman"));
+
array_insert_unique(a, (data_unset *)ds);
-
+
ds = data_string_init();
- buffer_copy_string(ds->key, "123");
- buffer_copy_string(ds->value, "alfrag");
-
+ buffer_copy_string_len(ds->key, CONST_STR_LEN("123"));
+ buffer_copy_string_len(ds->value, CONST_STR_LEN("alfrag"));
+
array_insert_unique(a, (data_unset *)ds);
-
+
dc = data_count_init();
- buffer_copy_string(dc->key, "def");
-
+ buffer_copy_string_len(dc->key, CONST_STR_LEN("def"));
+
array_insert_unique(a, (data_unset *)dc);
-
+
dc = data_count_init();
- buffer_copy_string(dc->key, "def");
-
+ buffer_copy_string_len(dc->key, CONST_STR_LEN("def"));
+
array_insert_unique(a, (data_unset *)dc);
-
+
array_print(a, 0);
-
+
array_free(a);
-
+
fprintf(stderr, "%d\n",
buffer_caseless_compare(CONST_STR_LEN("Content-Type"), CONST_STR_LEN("Content-type")));
-
+
return 0;
}
#endif
diff --git a/src/array.h b/src/array.h
index 27f27a4..84245c7 100644
--- a/src/array.h
+++ b/src/array.h
@@ -1,15 +1,18 @@
#ifndef ARRAY_H
#define ARRAY_H
-#include <stdlib.h>
#ifdef HAVE_CONFIG_H
-#include "config.h"
+# include "config.h"
#endif
+
#ifdef HAVE_PCRE_H
# include <pcre.h>
#endif
+
#include "buffer.h"
+#include <stdlib.h>
+
#define DATA_IS_STRING(x) (x->type == TYPE_STRING)
typedef enum { TYPE_UNSET, TYPE_STRING, TYPE_COUNT, TYPE_ARRAY, TYPE_INTEGER, TYPE_FASTCGI, TYPE_CONFIG } data_type_t;
@@ -29,21 +32,21 @@ typedef struct data_unset {
typedef struct {
data_unset **data;
-
+
size_t *sorted;
-
+
size_t used;
size_t size;
-
+
size_t unique_ndx;
-
+
size_t next_power_of_2;
int is_weakref; /* data is weakref, don't bother the data */
} array;
typedef struct {
DATA_UNSET;
-
+
int count;
} data_count;
@@ -51,7 +54,7 @@ data_count *data_count_init(void);
typedef struct {
DATA_UNSET;
-
+
buffer *value;
} data_string;
@@ -60,21 +63,44 @@ data_string *data_response_init(void);
typedef struct {
DATA_UNSET;
-
+
array *value;
} data_array;
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;
-
-#define PATCHES NULL, "SERVERsocket", "HTTPurl", "HTTPhost", "HTTPreferer", "HTTPuseragent", "HTTPcookie", "HTTPremoteip"
+/**
+ * possible compare ops in the configfile parser
+ */
+typedef enum {
+ CONFIG_COND_UNSET,
+ CONFIG_COND_EQ, /** == */
+ CONFIG_COND_MATCH, /** =~ */
+ CONFIG_COND_NE, /** != */
+ CONFIG_COND_NOMATCH /** !~ */
+} config_cond_t;
+
+/**
+ * possible fields to match against
+ */
typedef enum {
COMP_UNSET,
- COMP_SERVER_SOCKET, COMP_HTTP_URL, COMP_HTTP_HOST, COMP_HTTP_REFERER, COMP_HTTP_USERAGENT, COMP_HTTP_COOKIE, COMP_HTTP_REMOTEIP
+ COMP_SERVER_SOCKET,
+ COMP_HTTP_URL,
+ COMP_HTTP_HOST,
+ COMP_HTTP_REFERER,
+ COMP_HTTP_USER_AGENT,
+ COMP_HTTP_LANGUAGE,
+ COMP_HTTP_COOKIE,
+ COMP_HTTP_REMOTE_IP,
+ COMP_HTTP_QUERY_STRING,
+ COMP_HTTP_SCHEME,
+ COMP_HTTP_REQUEST_METHOD,
+
+ COMP_LAST_ELEMENT
} comp_key_t;
-/* $HTTP["host"] == "incremental.home.kneschke.de" { ... }
+/* $HTTP["host"] == "incremental.home.kneschke.de" { ... }
* for print: comp_key op string
* for compare: comp cond string/regex
*/
@@ -82,15 +108,15 @@ typedef enum {
typedef struct _data_config data_config;
struct _data_config {
DATA_UNSET;
-
+
array *value;
-
+
buffer *comp_key;
comp_key_t comp;
-
+
config_cond_t cond;
buffer *op;
-
+
int context_ndx; /* more or less like an id */
array *childs;
/* nested */
@@ -98,7 +124,7 @@ struct _data_config {
/* for chaining only */
data_config *prev;
data_config *next;
-
+
buffer *string;
#ifdef HAVE_PCRE_H
pcre *regex;
@@ -110,7 +136,7 @@ data_config *data_config_init(void);
typedef struct {
DATA_UNSET;
-
+
int value;
} data_integer;
@@ -120,13 +146,13 @@ typedef struct {
DATA_UNSET;
buffer *host;
-
+
unsigned short port;
time_t disable_ts;
int is_disabled;
size_t balance;
-
+
int usage; /* fair-balancing needs the no. of connections active on this host */
int last_used_ndx; /* round robin */
} data_fastcgi;
@@ -142,6 +168,7 @@ data_unset *array_pop(array *a);
int array_print(array *a, int depth);
data_unset *array_get_unused_element(array *a, data_type_t t);
data_unset *array_get_element(array *a, const char *key);
+void array_set_key_value(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len);
data_unset *array_replace(array *a, data_unset *du);
int array_strcasecmp(const char *a, size_t a_len, const char *b, size_t b_len);
void array_print_indent(int depth);
diff --git a/src/base.h b/src/base.h
index 98e23b8..9c75cc9 100644
--- a/src/base.h
+++ b/src/base.h
@@ -1,18 +1,21 @@
#ifndef _BASE_H_
#define _BASE_H_
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include "settings.h"
+
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
#include <limits.h>
+
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
+
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#endif
@@ -21,15 +24,18 @@
#include "array.h"
#include "chunk.h"
#include "keyvalue.h"
-#include "settings.h"
#include "fdevent.h"
#include "sys-socket.h"
#include "splaytree.h"
+#include "etag.h"
#if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
# define USE_OPENSSL
-# include <openssl/ssl.h>
+# include <openssl/ssl.h>
+# if ! defined OPENSSL_NO_TLSEXT && ! defined SSL_CTRL_SET_TLSEXT_HOSTNAME
+# define OPENSSL_NO_TLSEXT
+# endif
#endif
#ifdef HAVE_FAM_H
@@ -78,26 +84,26 @@ typedef int socklen_t;
# define SHUT_WR 1
#endif
-#include "settings.h"
-
-typedef enum { T_CONFIG_UNSET,
- T_CONFIG_STRING,
- T_CONFIG_SHORT,
- T_CONFIG_BOOLEAN,
- T_CONFIG_ARRAY,
- T_CONFIG_LOCAL,
- T_CONFIG_DEPRECATED
+typedef enum { T_CONFIG_UNSET,
+ T_CONFIG_STRING,
+ T_CONFIG_SHORT,
+ T_CONFIG_INT,
+ T_CONFIG_BOOLEAN,
+ T_CONFIG_ARRAY,
+ T_CONFIG_LOCAL,
+ T_CONFIG_DEPRECATED,
+ T_CONFIG_UNSUPPORTED
} config_values_type_t;
-typedef enum { T_CONFIG_SCOPE_UNSET,
- T_CONFIG_SCOPE_SERVER,
+typedef enum { T_CONFIG_SCOPE_UNSET,
+ T_CONFIG_SCOPE_SERVER,
T_CONFIG_SCOPE_CONNECTION
} config_scope_type_t;
typedef struct {
const char *key;
void *destination;
-
+
config_values_type_t type;
config_scope_type_t scope;
} config_values_t;
@@ -142,29 +148,29 @@ typedef struct {
/* the request-line */
buffer *request;
buffer *uri;
-
+
buffer *orig_uri;
-
+
http_method_t http_method;
http_version_t http_version;
-
+
buffer *request_line;
-
+
/* strings to the header */
buffer *http_host; /* not alloced */
const char *http_range;
const char *http_content_type;
const char *http_if_modified_since;
const char *http_if_none_match;
-
+
array *headers;
-
+
/* CONTENT */
size_t content_length; /* returned by strtoul() */
-
+
/* internal representation */
int accept_encoding;
-
+
/* internal */
buffer *pathinfo;
} request;
@@ -172,40 +178,48 @@ typedef struct {
typedef struct {
off_t content_length;
int keep_alive; /* used by the subrequests in proxy, cgi and fcgi to say the subrequest was keep-alive or not */
-
+
array *headers;
-
- enum {
+
+ enum {
HTTP_TRANSFER_ENCODING_IDENTITY, HTTP_TRANSFER_ENCODING_CHUNKED
} transfer_encoding;
} response;
typedef struct {
- buffer *scheme;
+ buffer *scheme; /* scheme without colon or slashes ( "http" or "https" ) */
+
+ /* authority with optional portnumber ("site.name" or "site.name:8080" ) NOTE: without "username:password@" */
buffer *authority;
+
+ /* path including leading slash ("/" or "/index.html") - urldecoded, and sanitized ( buffer_path_simplify() && buffer_urldecode_path() ) */
buffer *path;
- buffer *path_raw;
- buffer *query;
+ buffer *path_raw; /* raw path, as sent from client. no urldecoding or path simplifying */
+ buffer *query; /* querystring ( everything after "?", ie: in "/index.php?foo=1", query is "foo=1" ) */
} request_uri;
typedef struct {
buffer *path;
buffer *basedir; /* path = "(basedir)(.*)" */
-
+
buffer *doc_root; /* path = doc_root + rel_path */
buffer *rel_path;
-
+
buffer *etag;
} physical;
typedef struct {
buffer *name;
buffer *etag;
-
+
struct stat st;
-
+
time_t stat_ts;
-
+
+#ifdef HAVE_LSTAT
+ char is_symlink;
+#endif
+
#ifdef HAVE_FAM_H
int dir_version;
int dir_ndx;
@@ -216,7 +230,7 @@ typedef struct {
typedef struct {
splay_tree *files; /* the nodes of the tree are stat_cache_entry's */
-
+
buffer *dir_name; /* for building the dirname from the filename */
#ifdef HAVE_FAM_H
splay_tree *dirs; /* the nodes of the tree are fam_dir_entry */
@@ -224,11 +238,12 @@ typedef struct {
FAMConnection *fam;
int fam_fcce_ndx;
#endif
+ buffer *hash_key; /* temp-store for the hash-key */
} stat_cache;
typedef struct {
array *mimetypes;
-
+
/* virtual-servers */
buffer *document_root;
buffer *server_name;
@@ -236,7 +251,7 @@ typedef struct {
buffer *server_tag;
buffer *dirlist_encoding;
buffer *errorfile_prefix;
-
+
unsigned short max_keep_alive_requests;
unsigned short max_keep_alive_idle;
unsigned short max_read_idle;
@@ -244,33 +259,52 @@ typedef struct {
unsigned short use_xattr;
unsigned short follow_symlink;
unsigned short range_requests;
-
+
/* debug */
-
+
unsigned short log_file_not_found;
unsigned short log_request_header;
unsigned short log_request_handling;
unsigned short log_response_header;
unsigned short log_condition_handling;
-
-
+ unsigned short log_ssl_noise;
+ unsigned short log_timeouts;
+
+
/* server wide */
buffer *ssl_pemfile;
buffer *ssl_ca_file;
- unsigned short use_ipv6;
+ buffer *ssl_cipher_list;
+ buffer *ssl_dh_file;
+ buffer *ssl_ec_curve;
+ unsigned short ssl_honor_cipher_order; /* determine SSL cipher in server-preferred order, not client-order */
+ unsigned short ssl_use_sslv2;
+ unsigned short ssl_use_sslv3;
+ unsigned short ssl_verifyclient;
+ unsigned short ssl_verifyclient_enforce;
+ unsigned short ssl_verifyclient_depth;
+ buffer *ssl_verifyclient_username;
+ unsigned short ssl_verifyclient_export_cert;
+ unsigned short ssl_disable_client_renegotiation;
+
+ unsigned short use_ipv6, set_v6only; /* set_v6only is only a temporary option */
+ unsigned short defer_accept;
unsigned short is_ssl;
unsigned short allow_http11;
+ unsigned short etag_use_inode;
+ unsigned short etag_use_mtime;
+ unsigned short etag_use_size;
unsigned short force_lowercase_filenames; /* if the FS is case-insensitive, force all files to lower-case */
- unsigned short max_request_size;
+ unsigned int max_request_size;
unsigned short kbytes_per_second; /* connection kb/s limit */
/* configside */
unsigned short global_kbytes_per_second; /* */
- off_t global_bytes_per_second_cnt;
+ off_t global_bytes_per_second_cnt;
/* server-wide traffic-shaper
- *
+ *
* each context has the counter which is inited once
* a second by the global_kbytes_per_second config-var
*
@@ -278,12 +312,12 @@ typedef struct {
* the connected conns are "offline" a little bit
*
* the problem:
- * we somehow have to loose our "we are writable" signal
+ * we somehow have to loose our "we are writable" signal
* on the way.
- *
+ *
*/
off_t *global_bytes_per_second_cnt_ptr; /* */
-
+
#ifdef USE_OPENSSL
SSL_CTX *ssl_ctx;
#endif
@@ -291,18 +325,18 @@ typedef struct {
/* the order of the items should be the same as they are processed
* read before write as we use this later */
-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
+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;
@@ -311,95 +345,106 @@ typedef struct {
int patterncount;
int matches[3 * 10];
buffer *comp_value; /* just a pointer */
+
+ comp_key_t comp_type;
} cond_cache_t;
typedef struct {
connection_state_t state;
-
+
/* timestamps */
time_t read_idle_ts;
time_t close_timeout_ts;
time_t write_request_ts;
-
+
time_t connection_start;
time_t request_start;
-
+
struct timeval start_tv;
-
+
size_t request_count; /* number of requests handled in this connection */
size_t loops_per_request; /* to catch endless loops in a single request
- *
+ *
* used by mod_rewrite, mod_fastcgi, ... and others
* this is self-protection
*/
-
+
int fd; /* the FD for this connection */
int fde_ndx; /* index for the fdevent-handler */
int ndx; /* reverse mapping to server->connection[ndx] */
-
+
/* fd states */
int is_readable;
int is_writable;
-
- int keep_alive; /* only request.c can enable it, all other just disable */
-
+
+ int keep_alive; /* only request.c can enable it, all other just disable */
+ int keep_alive_idle; /* remember max_keep_alive_idle from config */
+
int file_started;
int file_finished;
-
+
chunkqueue *write_queue; /* a large queue for low-level write ( HTTP response ) [ file, mem ] */
chunkqueue *read_queue; /* a small queue for low-level read ( HTTP request ) [ mem ] */
chunkqueue *request_content_queue; /* takes request-content into tempfile if necessary [ tempfile, mem ]*/
-
+
int traffic_limit_reached;
-
+
off_t bytes_written; /* used by mod_accesslog, mod_rrd */
off_t bytes_written_cur_second; /* used by mod_accesslog, mod_rrd */
off_t bytes_read; /* used by mod_accesslog, mod_rrd */
off_t bytes_header;
-
+
int http_status;
-
+
sock_addr dst_addr;
buffer *dst_addr_buf;
/* request */
buffer *parse_request;
unsigned int parsed_response; /* bitfield which contains the important header-fields of the parsed response header */
-
+
request request;
request_uri uri;
- physical physical;
+ physical physical;
response response;
-
+
size_t header_len;
-
+
buffer *authed_user;
array *environment; /* used to pass lighttpd internal stuff to the FastCGI/CGI apps, setenv does that */
-
+
/* response */
int got_response;
-
+
int in_joblist;
-
+
connection_type mode;
-
+
void **plugin_ctx; /* plugin connection specific config */
-
+
specific_config conf; /* global connection specific config */
cond_cache_t *cond_cache;
-
+
buffer *server_name;
-
+
/* error-handler */
buffer *error_handler;
int error_handler_saved_status;
int in_error_handler;
-
+
void *srv_socket; /* reference to the server-socket (typecast to server_socket) */
-
+
#ifdef USE_OPENSSL
SSL *ssl;
+# ifndef OPENSSL_NO_TLSEXT
+ buffer *tlsext_server_name;
+# endif
+ unsigned int renegotiations; /* count of SSL_CB_HANDSHAKE_START */
#endif
+ /* etag handling */
+ etag_flags_t etag_flags;
+
+ int conditional_is_valid[COMP_LAST_ELEMENT];
} connection;
typedef struct {
@@ -442,90 +487,100 @@ typedef struct {
typedef struct {
unsigned short port;
buffer *bindhost;
-
+
buffer *errorlog_file;
unsigned short errorlog_use_syslog;
-
+ buffer *breakagelog_file;
+
unsigned short dont_daemonize;
buffer *changeroot;
buffer *username;
buffer *groupname;
-
+
buffer *pid_file;
-
+
buffer *event_handler;
-
+
buffer *modules_dir;
buffer *network_backend;
array *modules;
array *upload_tempdirs;
-
+
unsigned short max_worker;
unsigned short max_fds;
unsigned short max_conns;
- unsigned short max_request_size;
-
+ unsigned int max_request_size;
+
unsigned short log_request_header_on_error;
unsigned short log_state_handling;
-
- enum { STAT_CACHE_ENGINE_UNSET,
- STAT_CACHE_ENGINE_NONE,
- STAT_CACHE_ENGINE_SIMPLE,
- STAT_CACHE_ENGINE_FAM
+
+ enum { STAT_CACHE_ENGINE_UNSET,
+ STAT_CACHE_ENGINE_NONE,
+ STAT_CACHE_ENGINE_SIMPLE
+#ifdef HAVE_FAM_H
+ , STAT_CACHE_ENGINE_FAM
+#endif
} stat_cache_engine;
unsigned short enable_cores;
+ unsigned short reject_expect_100_with_417;
} server_config;
typedef struct {
sock_addr addr;
int fd;
int fde_ndx;
-
+
buffer *ssl_pemfile;
buffer *ssl_ca_file;
+ buffer *ssl_cipher_list;
+ buffer *ssl_dh_file;
+ buffer *ssl_ec_curve;
+ unsigned short ssl_use_sslv2;
+ unsigned short ssl_use_sslv3;
unsigned short use_ipv6;
unsigned short is_ssl;
-
+
buffer *srv_token;
-
+
#ifdef USE_OPENSSL
SSL_CTX *ssl_ctx;
#endif
+ unsigned short is_proxy_ssl;
} server_socket;
typedef struct {
server_socket **ptr;
-
+
size_t size;
size_t used;
} server_socket_array;
typedef struct server {
server_socket_array srv_sockets;
-
+
/* the errorlog */
int errorlog_fd;
- enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } errorlog_mode;
+ enum { ERRORLOG_FILE, ERRORLOG_FD, ERRORLOG_SYSLOG, ERRORLOG_PIPE } errorlog_mode;
buffer *errorlog_buf;
-
+
fdevents *ev, *ev_ins;
-
+
buffer_plugin plugins;
void *plugin_slots;
-
+
/* counters */
int con_opened;
int con_read;
int con_written;
int con_closed;
-
+
int ssl_is_init;
-
+
int max_fds; /* max possible fds */
int cur_fds; /* currently used fds */
int want_fds; /* waiting fds */
int sockets_disabled;
-
+
size_t max_conns;
/* buffers */
@@ -533,13 +588,13 @@ typedef struct server {
buffer *response_header;
buffer *response_range;
buffer *tmp_buf;
-
+
buffer *tmp_chunk_len;
-
+
buffer *empty_string; /* is necessary for cond_match */
buffer *cond_check_buf;
-
+
/* caches */
#ifdef HAVE_IPV6
inet_ntop_cache_type inet_ntop_cache[INET_NTOP_CACHE_MAX];
@@ -547,31 +602,35 @@ typedef struct server {
mtime_cache_type mtime_cache[FILE_CACHE_MAX];
array *split_vals;
-
+
/* Timestamps */
time_t cur_ts;
time_t last_generated_date_ts;
time_t last_generated_debug_ts;
time_t startup_ts;
-
+
+ char entropy[8]; /* from /dev/[u]random if possible, otherwise rand() */
+ char is_real_entropy; /* whether entropy is from /dev/[u]random */
+
buffer *ts_debug_str;
buffer *ts_date_str;
-
+
/* config-file */
array *config;
array *config_touched;
-
+
array *config_context;
specific_config **config_storage;
-
+
server_config srvconf;
-
- int config_deprecated;
-
+
+ short int config_deprecated;
+ short int config_unsupported;
+
connections *conns;
connections *joblist;
connections *fdwaitqueue;
-
+
stat_cache *stat_cache;
/**
@@ -588,14 +647,12 @@ typedef struct server {
* fastcgi.backend.<key>.disconnects = ...
*/
array *status;
-
+
fdevent_handler_t event_handler;
- int (* network_backend_write)(struct server *srv, connection *con, int fd, chunkqueue *cq);
- int (* network_backend_read)(struct server *srv, connection *con, int fd, chunkqueue *cq);
+ int (* network_backend_write)(struct server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes);
#ifdef USE_OPENSSL
- int (* network_ssl_backend_write)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
- int (* network_ssl_backend_read)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
+ int (* network_ssl_backend_write)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq, off_t max_bytes);
#endif
uid_t uid;
diff --git a/src/bitset.c b/src/bitset.c
index 7fe5662..555f244 100644
--- a/src/bitset.c
+++ b/src/bitset.c
@@ -1,12 +1,12 @@
+#include "buffer.h"
+#include "bitset.h"
+
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
-#include "bitset.h"
-#include "buffer.h"
-
#define BITSET_BITS \
( CHAR_BIT * sizeof(size_t) )
diff --git a/src/buffer.c b/src/buffer.c
index 40b8cb9..cff44fe 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1,3 +1,5 @@
+#include "buffer.h"
+
#include <stdlib.h>
#include <string.h>
@@ -5,27 +7,25 @@
#include <assert.h>
#include <ctype.h>
-#include "buffer.h"
-
static const char hex_chars[] = "0123456789abcdef";
/**
- * init the buffer
- *
+ * init the buffer
+ *
*/
buffer* buffer_init(void) {
buffer *b;
-
+
b = malloc(sizeof(*b));
assert(b);
-
+
b->ptr = NULL;
b->size = 0;
b->used = 0;
-
+
return b;
}
@@ -36,8 +36,8 @@ buffer *buffer_init_buffer(buffer *src) {
}
/**
- * free the buffer
- *
+ * free the buffer
+ *
*/
void buffer_free(buffer *b) {
@@ -49,39 +49,41 @@ void buffer_free(buffer *b) {
void buffer_reset(buffer *b) {
if (!b) return;
-
+
/* limit don't reuse buffer larger than ... bytes */
if (b->size > BUFFER_MAX_REUSE_SIZE) {
free(b->ptr);
b->ptr = NULL;
b->size = 0;
+ } else if (b->size) {
+ b->ptr[0] = '\0';
}
-
+
b->used = 0;
}
/**
- *
- * allocate (if neccessary) enough space for 'size' bytes and
+ *
+ * allocate (if neccessary) enough space for 'size' bytes and
* set the 'used' counter to 0
- *
+ *
*/
#define BUFFER_PIECE_SIZE 64
int buffer_prepare_copy(buffer *b, size_t size) {
if (!b) return -1;
-
- if ((0 == b->size) ||
+
+ if ((0 == b->size) ||
(size > b->size)) {
if (b->size) free(b->ptr);
-
+
b->size = size;
-
+
/* always allocate a multiply of BUFFER_PIECE_SIZE */
b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
-
+
b->ptr = malloc(b->size);
assert(b->ptr);
}
@@ -90,30 +92,30 @@ int buffer_prepare_copy(buffer *b, size_t size) {
}
/**
- *
+ *
* increase the internal buffer (if neccessary) to append another 'size' byte
* ->used isn't changed
- *
+ *
*/
int buffer_prepare_append(buffer *b, size_t size) {
if (!b) return -1;
-
+
if (0 == b->size) {
b->size = size;
-
+
/* always allocate a multiply of BUFFER_PIECE_SIZE */
b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
-
+
b->ptr = malloc(b->size);
b->used = 0;
assert(b->ptr);
} else if (b->used + size > b->size) {
b->size += size;
-
+
/* always allocate a multiply of BUFFER_PIECE_SIZE */
b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
-
+
b->ptr = realloc(b->ptr, b->size);
assert(b->ptr);
}
@@ -122,7 +124,7 @@ int buffer_prepare_append(buffer *b, size_t size) {
int buffer_copy_string(buffer *b, const char *s) {
size_t s_len;
-
+
if (!s || !b) return -1;
s_len = strlen(s) + 1;
@@ -136,28 +138,28 @@ int buffer_copy_string(buffer *b, const char *s) {
int buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
if (!s || !b) return -1;
-#if 0
- /* removed optimization as we have to keep the empty string
+#if 0
+ /* removed optimization as we have to keep the empty string
* in some cases for the config handling
- *
+ *
* url.access-deny = ( "" )
*/
if (s_len == 0) return 0;
-#endif
+#endif
buffer_prepare_copy(b, s_len + 1);
-
+
memcpy(b->ptr, s, s_len);
b->ptr[s_len] = '\0';
b->used = s_len + 1;
-
+
return 0;
}
int buffer_copy_string_buffer(buffer *b, const buffer *src) {
if (!src) return -1;
-
+
if (src->used == 0) {
- b->used = 0;
+ buffer_reset(b);
return 0;
}
return buffer_copy_string_len(b, src->ptr, src->used - 1);
@@ -185,6 +187,7 @@ int buffer_append_string_rfill(buffer *b, const char *s, size_t maxlen) {
if (!s || !b) return -1;
s_len = strlen(s);
+ if (s_len > maxlen) s_len = maxlen;
buffer_prepare_append(b, maxlen + 1);
if (b->used == 0)
b->used++;
@@ -201,10 +204,10 @@ int buffer_append_string_rfill(buffer *b, const char *s, size_t maxlen) {
/**
* append a string to the end of the buffer
- *
- * the resulting buffer is terminated with a '\0'
+ *
+ * the resulting buffer is terminated with a '\0'
* s is treated as a un-terminated string (a \0 is handled a normal character)
- *
+ *
* @param b a buffer
* @param s the string
* @param s_len size of the string (without the terminating \0)
@@ -228,7 +231,7 @@ int buffer_append_string_len(buffer *b, const char *s, size_t s_len) {
int buffer_append_string_buffer(buffer *b, const buffer *src) {
if (!src) return -1;
if (src->used == 0) return 0;
-
+
return buffer_append_string_len(b, src->ptr, src->used - 1);
}
@@ -245,9 +248,9 @@ int buffer_append_memory(buffer *b, const char *s, size_t s_len) {
int buffer_copy_memory(buffer *b, const char *s, size_t s_len) {
if (!s || !b) return -1;
-
+
b->used = 0;
-
+
return buffer_append_memory(b, s, s_len);
}
@@ -281,7 +284,7 @@ int buffer_append_long_hex(buffer *b, unsigned long value) {
return 0;
}
-int ltostr(char *buf, long val) {
+int LI_ltostr(char *buf, long val) {
char swap;
char *end;
int len = 1;
@@ -320,7 +323,7 @@ int buffer_append_long(buffer *b, long val) {
if (b->used == 0)
b->used++;
- b->used += ltostr(b->ptr + (b->used - 1), val);
+ b->used += LI_ltostr(b->ptr + (b->used - 1), val);
return 0;
}
@@ -402,46 +405,46 @@ char hex2int(unsigned char hex) {
/**
- * init the buffer
- *
+ * init the buffer
+ *
*/
buffer_array* buffer_array_init(void) {
buffer_array *b;
-
+
b = malloc(sizeof(*b));
-
+
assert(b);
b->ptr = NULL;
b->size = 0;
b->used = 0;
-
+
return b;
}
void buffer_array_reset(buffer_array *b) {
size_t i;
-
+
if (!b) return;
-
+
/* if they are too large, reduce them */
for (i = 0; i < b->used; i++) {
buffer_reset(b->ptr[i]);
}
-
+
b->used = 0;
}
/**
- * free the buffer_array
- *
+ * free the buffer_array
+ *
*/
void buffer_array_free(buffer_array *b) {
size_t i;
if (!b) return;
-
+
for (i = 0; i < b->size; i++) {
if (b->ptr[i]) buffer_free(b->ptr[i]);
}
@@ -451,7 +454,7 @@ void buffer_array_free(buffer_array *b) {
buffer *buffer_array_append_get_buffer(buffer_array *b) {
size_t i;
-
+
if (b->size == 0) {
b->size = 16;
b->ptr = malloc(sizeof(*b->ptr) * b->size);
@@ -467,13 +470,13 @@ buffer *buffer_array_append_get_buffer(buffer_array *b) {
b->ptr[i] = NULL;
}
}
-
+
if (b->ptr[b->used] == NULL) {
b->ptr[b->used] = buffer_init();
}
-
+
b->ptr[b->used]->used = 0;
-
+
return b->ptr[b->used++];
}
@@ -482,33 +485,34 @@ char * buffer_search_string_len(buffer *b, const char *needle, size_t len) {
size_t i;
if (len == 0) return NULL;
if (needle == NULL) return NULL;
-
+
if (b->used < len) return NULL;
-
+
for(i = 0; i < b->used - len; i++) {
if (0 == memcmp(b->ptr + i, needle, len)) {
return b->ptr + i;
}
}
-
+
return NULL;
}
buffer *buffer_init_string(const char *str) {
buffer *b = buffer_init();
-
+
buffer_copy_string(b, str);
-
+
return b;
}
int buffer_is_empty(buffer *b) {
+ if (!b) return 1;
return (b->used == 0);
}
/**
* check if two buffer contain the same data
- *
+ *
* HISTORY: this function was pretty much optimized, but didn't handled
* alignment properly.
*/
@@ -522,115 +526,121 @@ int buffer_is_equal(buffer *a, buffer *b) {
int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) {
buffer b;
-
+
b.ptr = (char *)s;
b.used = b_len + 1;
-
+
return buffer_is_equal(a, &b);
}
/* simple-assumption:
- *
+ *
* most parts are equal and doing a case conversion needs time
- *
+ *
*/
int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len) {
size_t ndx = 0, max_ndx;
size_t *al, *bl;
size_t mask = sizeof(*al) - 1;
-
+
al = (size_t *)a;
bl = (size_t *)b;
-
+
/* is the alignment correct ? */
if ( ((size_t)al & mask) == 0 &&
((size_t)bl & mask) == 0 ) {
-
+
max_ndx = ((a_len < b_len) ? a_len : b_len) & ~mask;
-
+
for (; ndx < max_ndx; ndx += sizeof(*al)) {
if (*al != *bl) break;
al++; bl++;
-
+
}
-
+
}
-
+
a = (char *)al;
b = (char *)bl;
-
+
max_ndx = ((a_len < b_len) ? a_len : b_len);
-
+
for (; ndx < max_ndx; ndx++) {
- char a1 = *a++, b1 = *b++;
-
+ int a1 = *a++, b1 = *b++;
+
if (a1 != b1) {
- if ((a1 >= 'A' && a1 <= 'Z') && (b1 >= 'a' && b1 <= 'z'))
- a1 |= 32;
- else if ((a1 >= 'a' && a1 <= 'z') && (b1 >= 'A' && b1 <= 'Z'))
- b1 |= 32;
+ /* always lowercase for transitive results */
+ if (a1 >= 'A' && a1 <= 'Z') a1 |= 32;
+ if (b1 >= 'A' && b1 <= 'Z') b1 |= 32;
+
if ((a1 - b1) != 0) return (a1 - b1);
-
}
}
-
- return 0;
+
+ /* all chars are the same, and the length match too
+ *
+ * they are the same */
+ if (a_len == b_len) return 0;
+
+ /* if a is shorter then b, then b is larger */
+ return (a_len - b_len);
}
/**
* check if the rightmost bytes of the string are equal.
- *
- *
+ *
+ *
*/
int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) {
/* no, len -> equal */
if (len == 0) return 1;
-
+
/* len > 0, but empty buffers -> not equal */
if (b1->used == 0 || b2->used == 0) return 0;
-
+
/* buffers too small -> not equal */
if (b1->used - 1 < len || b1->used - 1 < len) return 0;
-
- if (0 == strncmp(b1->ptr + b1->used - 1 - len,
+
+ if (0 == strncmp(b1->ptr + b1->used - 1 - len,
b2->ptr + b2->used - 1 - len, len)) {
return 1;
}
-
+
return 0;
}
int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
size_t i;
-
+
/* BO protection */
if (in_len * 2 < in_len) return -1;
-
+
buffer_prepare_copy(b, in_len * 2 + 1);
-
+
for (i = 0; i < in_len; i++) {
b->ptr[b->used++] = hex_chars[(in[i] >> 4) & 0x0F];
b->ptr[b->used++] = hex_chars[in[i] & 0x0F];
}
b->ptr[b->used++] = '\0';
-
+
return 0;
}
-const char encoded_chars_rel_uri_part[] = {
+/* everything except: ! ( ) * - . 0-9 A-Z _ a-z */
+static const char encoded_chars_rel_uri_part[] = {
/*
0 1 2 3 4 5 6 7 8 9 A B C D E F
*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, /* 20 - 2F space " # $ % & ' + , / */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 30 - 3F : ; = ? @ < > */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50 - 5F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 70 - 7F DEL */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 30 - 3F : ; < = > ? */
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F @ */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* 50 - 5F [ \ ] ^ */
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F ` */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, /* 70 - 7F { | } ~ DEL */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 - 8F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 - 9F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* A0 - AF */
@@ -641,18 +651,19 @@ const char encoded_chars_rel_uri_part[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* F0 - FF */
};
-const char encoded_chars_rel_uri[] = {
+/* everything except: ! ( ) * - . / 0-9 A-Z _ a-z */
+static const char encoded_chars_rel_uri[] = {
/*
0 1 2 3 4 5 6 7 8 9 A B C D E F
*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
- 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, /* 20 - 2F space " # $ % & ' + , / */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 30 - 3F : ; = ? @ < > */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50 - 5F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 70 - 7F DEL */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
+ 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, /* 20 - 2F space " # $ % & ' + , */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 30 - 3F : ; < = > ? */
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F @ */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, /* 50 - 5F [ \ ] ^ */
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F ` */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, /* 70 - 7F { | } ~ DEL */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 - 8F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 - 9F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* A0 - AF */
@@ -663,12 +674,12 @@ const char encoded_chars_rel_uri[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* F0 - FF */
};
-const char encoded_chars_html[] = {
+static const char encoded_chars_html[] = {
/*
0 1 2 3 4 5 6 7 8 9 A B C D E F
*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 2F & */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 30 - 3F < > */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
@@ -685,12 +696,12 @@ const char encoded_chars_html[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* F0 - FF */
};
-const char encoded_chars_minimal_xml[] = {
+static const char encoded_chars_minimal_xml[] = {
/*
0 1 2 3 4 5 6 7 8 9 A B C D E F
*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 2F & */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 30 - 3F < > */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
@@ -707,17 +718,17 @@ const char encoded_chars_minimal_xml[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
};
-const char encoded_chars_hex[] = {
+static const char encoded_chars_hex[] = {
/*
0 1 2 3 4 5 6 7 8 9 A B C D E F
*/
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 70 - 7F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 - 8F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 - 9F */
@@ -729,18 +740,41 @@ const char encoded_chars_hex[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* F0 - FF */
};
+static const char encoded_chars_http_header[] = {
+ /*
+ 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* 00 - 0F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 2F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 30 - 3F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50 - 5F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70 - 7F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
+};
+
+
int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_encoding_t encoding) {
unsigned char *ds, *d;
size_t d_len, ndx;
const char *map = NULL;
-
+
if (!s || !b) return -1;
-
+
if (b->ptr[b->used - 1] != '\0') {
SEGFAULT();
}
-
+
if (s_len == 0) return 0;
switch(encoding) {
@@ -759,12 +793,15 @@ int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_
case ENCODING_HEX:
map = encoded_chars_hex;
break;
+ case ENCODING_HTTP_HEADER:
+ map = encoded_chars_http_header;
+ break;
case ENCODING_UNSET:
break;
}
assert(map != NULL);
-
+
/* count to-be-encoded-characters */
for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
if (map[*ds]) {
@@ -777,6 +814,7 @@ int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_
case ENCODING_MINIMAL_XML:
d_len += 6;
break;
+ case ENCODING_HTTP_HEADER:
case ENCODING_HEX:
d_len += 2;
break;
@@ -787,9 +825,9 @@ int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_
d_len ++;
}
}
-
+
buffer_prepare_append(b, d_len);
-
+
for (ds = (unsigned char *)s, d = (unsigned char *)b->ptr + b->used - 1, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
if (map[*ds]) {
switch(encoding) {
@@ -812,6 +850,10 @@ int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_
d[d_len++] = hex_chars[((*ds) >> 4) & 0x0F];
d[d_len++] = hex_chars[(*ds) & 0x0F];
break;
+ case ENCODING_HTTP_HEADER:
+ d[d_len++] = *ds;
+ d[d_len++] = '\t';
+ break;
case ENCODING_UNSET:
break;
}
@@ -820,9 +862,9 @@ int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_
}
}
- /* terminate buffer and calculate new length */
+ /* terminate buffer and calculate new length */
b->ptr[b->used + d_len - 1] = '\0';
-
+
b->used += d_len;
return 0;
@@ -854,10 +896,10 @@ static int buffer_urldecode_internal(buffer *url, int is_query) {
low = hex2int(*(src + 2));
if (low != 0xFF) {
high = (high << 4) | low;
-
- /* map control-characters out */
+
+ /* map control-characters out */
if (high < 32 || high == 127) high = '_';
-
+
*dst = high;
src += 2;
}
@@ -914,6 +956,18 @@ int buffer_path_simplify(buffer *dest, buffer *src)
start = dest->ptr;
out = dest->ptr;
slash = dest->ptr;
+
+
+#if defined(__WIN32) || defined(__CYGWIN__)
+ /* cygwin is treating \ and / the same, so we have to that too
+ */
+
+ for (walk = src->ptr; *walk; walk++) {
+ if (*walk == '\\') *walk = '/';
+ }
+ walk = src->ptr;
+#endif
+
while (*walk == ' ') {
walk++;
}
@@ -979,7 +1033,7 @@ int light_isdigit(int c) {
int light_isxdigit(int c) {
if (light_isdigit(c)) return 1;
-
+
c |= 32;
return (c >= 'a' && c <= 'f');
}
@@ -995,29 +1049,29 @@ int light_isalnum(int c) {
int buffer_to_lower(buffer *b) {
char *c;
-
+
if (b->used == 0) return 0;
-
+
for (c = b->ptr; *c; c++) {
if (*c >= 'A' && *c <= 'Z') {
*c |= 32;
}
}
-
+
return 0;
}
int buffer_to_upper(buffer *b) {
char *c;
-
+
if (b->used == 0) return 0;
-
+
for (c = b->ptr; *c; c++) {
if (*c >= 'a' && *c <= 'z') {
*c &= ~32;
}
}
-
+
return 0;
}
diff --git a/src/buffer.h b/src/buffer.h
index 3ca22e5..bda0424 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -1,34 +1,35 @@
#ifndef _BUFFER_H_
#define _BUFFER_H_
-#include <stdlib.h>
-#include <sys/types.h>
-
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "settings.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <stdio.h>
+
typedef struct {
char *ptr;
-
+
size_t used;
size_t size;
} buffer;
typedef struct {
buffer **ptr;
-
+
size_t used;
size_t size;
} buffer_array;
typedef struct {
char *ptr;
-
+
size_t offset; /* input-pointer */
-
+
size_t used; /* output-pointer */
size_t size;
} read_buffer;
@@ -43,7 +44,7 @@ buffer* buffer_init_buffer(buffer *b);
buffer* buffer_init_string(const char *str);
void buffer_free(buffer *b);
void buffer_reset(buffer *b);
-
+
int buffer_prepare_copy(buffer *b, size_t size);
int buffer_prepare_append(buffer *b, size_t size);
@@ -87,9 +88,10 @@ typedef enum {
ENCODING_UNSET,
ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of a href */
ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus coding / too as %2F */
- ENCODING_HTML, /* & becomes &amp; and so on */
- ENCODING_MINIMAL_XML, /* minimal encoding for xml */
- ENCODING_HEX /* encode string as hex */
+ ENCODING_HTML, /* & becomes &amp; and so on */
+ ENCODING_MINIMAL_XML, /* minimal encoding for xml */
+ ENCODING_HEX, /* encode string as hex */
+ ENCODING_HTTP_HEADER /* encode \n with \t\n */
} buffer_encoding_t;
int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_encoding_t encoding);
@@ -102,7 +104,7 @@ int buffer_to_lower(buffer *b);
int buffer_to_upper(buffer *b);
/** deprecated */
-int ltostr(char *buf, long val);
+int LI_ltostr(char *buf, long val);
char hex2int(unsigned char c);
char int2hex(char i);
diff --git a/src/chunk.c b/src/chunk.c
index 3903428..7583db6 100644
--- a/src/chunk.c
+++ b/src/chunk.c
@@ -1,9 +1,11 @@
/**
* the network chunk-API
- *
- *
+ *
+ *
*/
+#include "chunk.h"
+
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
@@ -16,38 +18,36 @@
#include <errno.h>
#include <string.h>
-#include "chunk.h"
-
chunkqueue *chunkqueue_init(void) {
chunkqueue *cq;
-
+
cq = calloc(1, sizeof(*cq));
-
+
cq->first = NULL;
cq->last = NULL;
-
+
cq->unused = NULL;
-
+
return cq;
}
static chunk *chunk_init(void) {
chunk *c;
-
+
c = calloc(1, sizeof(*c));
-
+
c->mem = buffer_init();
c->file.name = buffer_init();
c->file.fd = -1;
c->file.mmap.start = MAP_FAILED;
c->next = NULL;
-
+
return c;
}
static void chunk_free(chunk *c) {
if (!c) return;
-
+
buffer_free(c->mem);
buffer_free(c->file.name);
@@ -56,13 +56,13 @@ static void chunk_free(chunk *c) {
static void chunk_reset(chunk *c) {
if (!c) return;
-
+
buffer_reset(c->mem);
if (c->file.is_temp && !buffer_is_empty(c->file.name)) {
unlink(c->file.name->ptr);
}
-
+
buffer_reset(c->file.name);
if (c->file.fd != -1) {
@@ -78,27 +78,27 @@ static void chunk_reset(chunk *c) {
void chunkqueue_free(chunkqueue *cq) {
chunk *c, *pc;
-
+
if (!cq) return;
-
+
for (c = cq->first; c; ) {
pc = c;
c = c->next;
chunk_free(pc);
}
-
+
for (c = cq->unused; c; ) {
pc = c;
c = c->next;
chunk_free(pc);
}
-
+
free(cq);
}
static chunk *chunkqueue_get_unused_chunk(chunkqueue *cq) {
chunk *c;
-
+
/* check if we have a unused chunk */
if (!cq->unused) {
c = chunk_init();
@@ -109,18 +109,18 @@ static chunk *chunkqueue_get_unused_chunk(chunkqueue *cq) {
c->next = NULL;
cq->unused_chunks--;
}
-
+
return c;
}
static int chunkqueue_prepend_chunk(chunkqueue *cq, chunk *c) {
c->next = cq->first;
cq->first = c;
-
+
if (cq->last == NULL) {
cq->last = c;
}
-
+
return 0;
}
@@ -129,19 +129,19 @@ static int chunkqueue_append_chunk(chunkqueue *cq, chunk *c) {
cq->last->next = c;
}
cq->last = c;
-
+
if (cq->first == NULL) {
cq->first = c;
}
-
+
return 0;
}
void chunkqueue_reset(chunkqueue *cq) {
chunk *c;
/* move everything to the unused queue */
-
- /* mark all read written */
+
+ /* mark all read written */
for (c = cq->first; c; c = c->next) {
switch(c->type) {
case MEM_CHUNK:
@@ -150,7 +150,7 @@ void chunkqueue_reset(chunkqueue *cq) {
case FILE_CHUNK:
c->offset = c->file.length;
break;
- default:
+ default:
break;
}
}
@@ -162,93 +162,108 @@ void chunkqueue_reset(chunkqueue *cq) {
int chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
chunk *c;
-
+
if (len == 0) return 0;
-
+
c = chunkqueue_get_unused_chunk(cq);
-
+
c->type = FILE_CHUNK;
-
+
buffer_copy_string_buffer(c->file.name, fn);
c->file.start = offset;
c->file.length = len;
c->offset = 0;
-
+
chunkqueue_append_chunk(cq, c);
-
+
return 0;
}
int chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) {
chunk *c;
-
+
if (mem->used == 0) return 0;
-
+
c = chunkqueue_get_unused_chunk(cq);
c->type = MEM_CHUNK;
c->offset = 0;
buffer_copy_string_buffer(c->mem, mem);
-
+
+ chunkqueue_append_chunk(cq, c);
+
+ return 0;
+}
+
+int chunkqueue_append_buffer_weak(chunkqueue *cq, buffer *mem) {
+ chunk *c;
+
+ c = chunkqueue_get_unused_chunk(cq);
+ c->type = MEM_CHUNK;
+ c->offset = 0;
+ if (c->mem) buffer_free(c->mem);
+ c->mem = mem;
+
chunkqueue_append_chunk(cq, c);
-
+
return 0;
}
int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) {
chunk *c;
-
+
if (mem->used == 0) return 0;
-
+
c = chunkqueue_get_unused_chunk(cq);
c->type = MEM_CHUNK;
c->offset = 0;
buffer_copy_string_buffer(c->mem, mem);
-
+
chunkqueue_prepend_chunk(cq, c);
-
+
return 0;
}
+
int chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) {
chunk *c;
-
+
if (len == 0) return 0;
-
+
c = chunkqueue_get_unused_chunk(cq);
c->type = MEM_CHUNK;
c->offset = 0;
buffer_copy_string_len(c->mem, mem, len - 1);
-
+
chunkqueue_append_chunk(cq, c);
-
+
return 0;
}
buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
chunk *c;
-
+
c = chunkqueue_get_unused_chunk(cq);
-
+
c->type = MEM_CHUNK;
c->offset = 0;
buffer_reset(c->mem);
-
+
chunkqueue_prepend_chunk(cq, c);
-
+
return c->mem;
}
buffer *chunkqueue_get_append_buffer(chunkqueue *cq) {
chunk *c;
-
+
c = chunkqueue_get_unused_chunk(cq);
-
+
c->type = MEM_CHUNK;
c->offset = 0;
buffer_reset(c->mem);
-
+
chunkqueue_append_chunk(cq, c);
-
+
return c->mem;
}
@@ -263,7 +278,7 @@ int chunkqueue_set_tempdirs(chunkqueue *cq, array *tempdirs) {
chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
chunk *c;
buffer *template = buffer_init_string("/var/tmp/lighttpd-upload-XXXXXX");
-
+
c = chunkqueue_get_unused_chunk(cq);
c->type = FILE_CHUNK;
@@ -273,13 +288,13 @@ chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
size_t i;
/* we have several tempdirs, only if all of them fail we jump out */
-
+
for (i = 0; i < cq->tempdirs->used; i++) {
data_string *ds = (data_string *)cq->tempdirs->data[i];
buffer_copy_string_buffer(template, ds->value);
BUFFER_APPEND_SLASH(template);
- BUFFER_APPEND_STRING_CONST(template, "lighttpd-upload-XXXXXX");
+ buffer_append_string_len(template, CONST_STR_LEN("lighttpd-upload-XXXXXX"));
if (-1 != (c->file.fd = mkstemp(template->ptr))) {
/* only trigger the unlink if we created the temp-file successfully */
@@ -300,7 +315,7 @@ chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
chunkqueue_append_chunk(cq, c);
buffer_free(template);
-
+
return c;
}
@@ -308,7 +323,7 @@ chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
off_t chunkqueue_length(chunkqueue *cq) {
off_t len = 0;
chunk *c;
-
+
for (c = cq->first; c; c = c->next) {
switch (c->type) {
case MEM_CHUNK:
@@ -321,14 +336,14 @@ off_t chunkqueue_length(chunkqueue *cq) {
break;
}
}
-
+
return len;
}
off_t chunkqueue_written(chunkqueue *cq) {
off_t len = 0;
chunk *c;
-
+
for (c = cq->first; c; c = c->next) {
switch (c->type) {
case MEM_CHUNK:
@@ -339,7 +354,7 @@ off_t chunkqueue_written(chunkqueue *cq) {
break;
}
}
-
+
return len;
}
@@ -355,12 +370,12 @@ int chunkqueue_remove_finished_chunks(chunkqueue *cq) {
switch (c->type) {
case MEM_CHUNK:
- if (c->offset == (off_t)c->mem->used - 1) is_finished = 1;
+ if (c->mem->used == 0 || (c->offset == (off_t)c->mem->used - 1)) is_finished = 1;
break;
case FILE_CHUNK:
- if (c->offset == c->file.length) is_finished = 1;
+ if (c->offset == c->file.length) is_finished = 1;
break;
- default:
+ default:
break;
}
diff --git a/src/chunk.h b/src/chunk.h
index ddc8617..e43d3eb 100644
--- a/src/chunk.h
+++ b/src/chunk.h
@@ -3,10 +3,11 @@
#include "buffer.h"
#include "array.h"
+#include "sys-mmap.h"
typedef struct chunk {
enum { UNUSED_CHUNK, MEM_CHUNK, FILE_CHUNK } type;
-
+
buffer *mem; /* either the storage of the mem-chunk or the read-ahead buffer */
struct {
@@ -16,7 +17,7 @@ typedef struct chunk {
off_t length; /* octets to send from the starting offset */
int fd;
- struct {
+ struct {
char *start; /* the start pointer of the mmap'ed area */
size_t length; /* size of the mmap'ed area */
off_t offset; /* start is <n> octet away from the start of the file */
@@ -24,20 +25,20 @@ typedef struct chunk {
int is_temp; /* file is temporary and will be deleted if on cleanup */
} file;
-
- off_t offset; /* octets sent from this chunk
- the size of the chunk is either
+
+ off_t offset; /* octets sent from this chunk
+ the size of the chunk is either
- mem-chunk: mem->used - 1
- file-chunk: file.length
*/
-
+
struct chunk *next;
} chunk;
typedef struct {
chunk *first;
chunk *last;
-
+
chunk *unused;
size_t unused_chunks;
@@ -51,6 +52,7 @@ int chunkqueue_set_tempdirs(chunkqueue *c, array *tempdirs);
int chunkqueue_append_file(chunkqueue *c, buffer *fn, off_t offset, off_t len);
int chunkqueue_append_mem(chunkqueue *c, const char *mem, size_t len);
int chunkqueue_append_buffer(chunkqueue *c, buffer *mem);
+int chunkqueue_append_buffer_weak(chunkqueue *c, buffer *mem);
int chunkqueue_prepend_buffer(chunkqueue *c, buffer *mem);
buffer * chunkqueue_get_append_buffer(chunkqueue *c);
diff --git a/src/configfile-glue.c b/src/configfile-glue.c
index 5c3c68b..3efa46a 100644
--- a/src/configfile-glue.c
+++ b/src/configfile-glue.c
@@ -1,20 +1,23 @@
-#include <string.h>
-
#include "base.h"
#include "buffer.h"
#include "array.h"
#include "log.h"
#include "plugin.h"
+#include "configfile.h"
+
+#include <string.h>
+#include <stdlib.h>
+
/**
* like all glue code this file contains functions which
* are the external interface of lighttpd. The functions
* are used by the server itself and the plugins.
*
- * The main-goal is to have a small library in the end
- * which is linked against both and which will define
+ * The main-goal is to have a small library in the end
+ * which is linked against both and which will define
* the interface itself in the end.
- *
+ *
*/
@@ -24,56 +27,56 @@
int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[]) {
size_t i;
data_unset *du;
-
+
for (i = 0; cv[i].key; i++) {
-
+
if (NULL == (du = array_get_element(ca, cv[i].key))) {
/* no found */
-
+
continue;
}
-
+
switch (cv[i].type) {
case T_CONFIG_ARRAY:
if (du->type == TYPE_ARRAY) {
size_t j;
data_array *da = (data_array *)du;
-
+
for (j = 0; j < da->value->used; j++) {
if (da->value->data[j]->type == TYPE_STRING) {
data_string *ds = data_string_init();
-
+
buffer_copy_string_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
if (!da->is_index_key) {
/* the id's were generated automaticly, as we copy now we might have to renumber them
- * this is used to prepend server.modules by mod_indexfiles as it has to be loaded
+ * this is used to prepend server.modules by mod_indexfile as it has to be loaded
* before mod_fastcgi and friends */
buffer_copy_string_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
}
-
+
array_insert_unique(cv[i].destination, (data_unset *)ds);
} else {
- log_error_write(srv, __FILE__, __LINE__, "sssd",
- "the key of and array can only be a string or a integer, variable:",
- cv[i].key, "type:", da->value->data[j]->type);
-
+ log_error_write(srv, __FILE__, __LINE__, "sssd",
+ "the key of an array can only be a string or a integer, variable:",
+ cv[i].key, "type:", da->value->data[j]->type);
+
return -1;
}
}
} else {
- log_error_write(srv, __FILE__, __LINE__, "sss", "unexpected type for key: ", cv[i].key, "array of strings");
-
+ log_error_write(srv, __FILE__, __LINE__, "ss", cv[i].key, "should have been a array of strings like ... = ( \"...\" )");
+
return -1;
}
break;
case T_CONFIG_STRING:
if (du->type == TYPE_STRING) {
data_string *ds = (data_string *)du;
-
+
buffer_copy_string_buffer(cv[i].destination, ds->value);
} else {
- log_error_write(srv, __FILE__, __LINE__, "ssss", "unexpected type for key: ", cv[i].key, "(string)", "\"...\"");
-
+ log_error_write(srv, __FILE__, __LINE__, "ssss", cv[i].key, "should have been a string like ... = \"...\"");
+
return -1;
}
break;
@@ -81,81 +84,133 @@ int config_insert_values_internal(server *srv, array *ca, const config_values_t
switch(du->type) {
case TYPE_INTEGER: {
data_integer *di = (data_integer *)du;
-
+
*((unsigned short *)(cv[i].destination)) = di->value;
break;
}
case TYPE_STRING: {
data_string *ds = (data_string *)du;
-
- log_error_write(srv, __FILE__, __LINE__, "ssb", "get a string but expected a short:", cv[i].key, ds->value);
-
+
+ /* If the value came from an environment variable, then it is a
+ * data_string, although it may contain a number in ASCII
+ * decimal format. We try to interpret the string as a decimal
+ * short before giving up, in order to support setting numeric
+ * values with environment variables (eg, port number).
+ */
+ if (ds->value->ptr && *ds->value->ptr) {
+ char *e;
+ long l = strtol(ds->value->ptr, &e, 10);
+ if (e != ds->value->ptr && !*e && l >=0 && l <= 65535) {
+ *((unsigned short *)(cv[i].destination)) = l;
+ break;
+ }
+ }
+
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected a short:", cv[i].key, ds->value);
+
return -1;
}
default:
- log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected a integer, range 0 ... 65535");
+ log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected a short integer, range 0 ... 65535");
+ return -1;
+ }
+ break;
+ case T_CONFIG_INT:
+ switch(du->type) {
+ case TYPE_INTEGER: {
+ data_integer *di = (data_integer *)du;
+
+ *((unsigned int *)(cv[i].destination)) = di->value;
+ break;
+ }
+ case TYPE_STRING: {
+ data_string *ds = (data_string *)du;
+
+ if (ds->value->ptr && *ds->value->ptr) {
+ char *e;
+ long l = strtol(ds->value->ptr, &e, 10);
+ if (e != ds->value->ptr && !*e && l >= 0) {
+ *((unsigned int *)(cv[i].destination)) = l;
+ break;
+ }
+ }
+
+
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected an integer:", cv[i].key, ds->value);
+
+ return -1;
+ }
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected an integer, range 0 ... 4294967295");
return -1;
}
break;
case T_CONFIG_BOOLEAN:
if (du->type == TYPE_STRING) {
data_string *ds = (data_string *)du;
-
+
if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
*((unsigned short *)(cv[i].destination)) = 1;
} else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
*((unsigned short *)(cv[i].destination)) = 0;
} else {
log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)");
-
+
return -1;
}
} else {
log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");
-
+
return -1;
}
break;
case T_CONFIG_LOCAL:
case T_CONFIG_UNSET:
break;
+ case T_CONFIG_UNSUPPORTED:
+ log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found unsupported key:", cv[i].key, "-", (char *)(cv[i].destination));
+
+ srv->config_unsupported = 1;
+
+ break;
case T_CONFIG_DEPRECATED:
log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));
-
+
srv->config_deprecated = 1;
-
+
break;
}
}
+
return 0;
}
int config_insert_values_global(server *srv, array *ca, const config_values_t cv[]) {
size_t i;
data_unset *du;
-
+
for (i = 0; cv[i].key; i++) {
data_string *touched;
-
+
if (NULL == (du = array_get_element(ca, cv[i].key))) {
/* no found */
-
+
continue;
}
-
+
/* touched */
touched = data_string_init();
-
- buffer_copy_string(touched->value, "");
+
+ buffer_copy_string_len(touched->value, CONST_STR_LEN(""));
buffer_copy_string_buffer(touched->key, du->key);
-
+
array_insert_unique(srv->config_touched, (data_unset *)touched);
}
-
+
return config_insert_values_internal(srv, ca, cv);
}
-unsigned short sock_addr_get_port(sock_addr *addr) {
+static unsigned short sock_addr_get_port(sock_addr *addr) {
#ifdef HAVE_IPV6
return ntohs(addr->plain.sa_family ? addr->ipv6.sin6_port : addr->ipv4.sin_port);
#else
@@ -168,59 +223,89 @@ static cond_result_t config_check_cond_cached(server *srv, connection *con, data
static cond_result_t config_check_cond_nocache(server *srv, connection *con, data_config *dc) {
buffer *l;
server_socket *srv_sock = con->srv_socket;
+
/* check parent first */
if (dc->parent && dc->parent->context_ndx) {
+ /**
+ * a nested conditional
+ *
+ * if the parent is not decided yet or false, we can't be true either
+ */
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "sb", "go parent", dc->parent->key);
}
- if (config_check_cond_cached(srv, con, dc->parent) == COND_RESULT_FALSE) {
+
+ switch (config_check_cond_cached(srv, con, dc->parent)) {
+ case COND_RESULT_FALSE:
return COND_RESULT_FALSE;
+ case COND_RESULT_UNSET:
+ return COND_RESULT_UNSET;
+ default:
+ break;
}
}
if (dc->prev) {
+ /**
+ * a else branch
+ *
+ * we can only be executed, if all of our previous brothers
+ * are false
+ */
if (con->conf.log_condition_handling) {
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 (COND_RESULT_FALSE == con->cond_cache[dc->context_ndx].result) {
- return COND_RESULT_FALSE;
+ switch (con->cond_cache[dc->context_ndx].result) {
+ case COND_RESULT_FALSE:
+ return con->cond_cache[dc->context_ndx].result;
+ default:
+ break;
}
}
+ if (!con->conditional_is_valid[dc->comp]) {
+ if (con->conf.log_condition_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "dss",
+ dc->comp,
+ dc->key->ptr,
+ con->conditional_is_valid[dc->comp] ? "yeah" : "nej");
+ }
+
+ return COND_RESULT_UNSET;
+ }
+
/* pass the rules */
-
+
switch (dc->comp) {
case COMP_HTTP_HOST: {
char *ck_colon = NULL, *val_colon = NULL;
-
+
if (!buffer_is_empty(con->uri.authority)) {
-
- /*
+
+ /*
* append server-port to the HTTP_POST if necessary
*/
-
+
l = con->uri.authority;
-
+
switch(dc->cond) {
case CONFIG_COND_NE:
case CONFIG_COND_EQ:
ck_colon = strchr(dc->string->ptr, ':');
val_colon = strchr(l->ptr, ':');
-
- if (ck_colon == val_colon) {
- /* nothing to do with it */
- break;
- }
- if (ck_colon) {
+
+ if (NULL != ck_colon && NULL == val_colon) {
/* condition "host:port" but client send "host" */
buffer_copy_string_buffer(srv->cond_check_buf, l);
- BUFFER_APPEND_STRING_CONST(srv->cond_check_buf, ":");
+ buffer_append_string_len(srv->cond_check_buf, CONST_STR_LEN(":"));
buffer_append_long(srv->cond_check_buf, sock_addr_get_port(&(srv_sock->addr)));
l = srv->cond_check_buf;
- } else if (!ck_colon) {
+ } else if (NULL != val_colon && NULL == ck_colon) {
/* condition "host" but client send "host:port" */
buffer_copy_string_len(srv->cond_check_buf, l->ptr, val_colon - l->ptr);
l = srv->cond_check_buf;
@@ -229,22 +314,26 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
default:
break;
}
+#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
+ } else if (!buffer_is_empty(con->tlsext_server_name)) {
+ l = con->tlsext_server_name;
+#endif
} else {
- l = NULL;
+ l = srv->empty_string;
}
break;
}
- case COMP_HTTP_REMOTEIP: {
+ case COMP_HTTP_REMOTE_IP: {
char *nm_slash;
- /* handle remoteip limitations
- *
+ /* handle remoteip limitations
+ *
* "10.0.0.1" is provided for all comparisions
- *
+ *
* only for == and != we support
- *
+ *
* "10.0.0.1/24"
*/
-
+
if ((dc->cond == CONFIG_COND_EQ ||
dc->cond == CONFIG_COND_NE) &&
(con->dst_addr.plain.sa_family == AF_INET) &&
@@ -253,41 +342,41 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
long nm;
char *err;
struct in_addr val_inp;
-
+
if (*(nm_slash+1) == '\0') {
log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string);
-
+
return COND_RESULT_FALSE;
}
-
+
nm_bits = strtol(nm_slash + 1, &err, 10);
-
+
if (*err) {
- log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, *err);
-
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, err);
+
return COND_RESULT_FALSE;
}
-
+
/* take IP convert to the native */
buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr);
-#ifdef __WIN32
+#ifdef __WIN32
if (INADDR_NONE == (val_inp.s_addr = inet_addr(srv->cond_check_buf->ptr))) {
log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
-
+
return COND_RESULT_FALSE;
}
#else
if (0 == inet_aton(srv->cond_check_buf->ptr, &val_inp)) {
log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
-
+
return COND_RESULT_FALSE;
}
#endif
-
+
/* build netmask */
nm = htonl(~((1 << (32 - nm_bits)) - 1));
-
+
if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) {
return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
} else {
@@ -298,17 +387,25 @@ 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_QUERY_STRING:
+ l = con->uri.query;
+ break;
+
case COMP_SERVER_SOCKET:
l = srv_sock->srv_token;
break;
case COMP_HTTP_REFERER: {
data_string *ds;
-
+
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
l = ds->value;
} else {
@@ -325,7 +422,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;
@@ -334,11 +431,30 @@ 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;
+ }
+ case COMP_HTTP_LANGUAGE: {
+ data_string *ds;
+ if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Accept-Language"))) {
+ l = ds->value;
+ } else {
+ l = srv->empty_string;
+ }
+ break;
+ }
default:
return COND_RESULT_FALSE;
}
-
+
if (NULL == l) {
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "bsbs", dc->comp_key,
@@ -346,7 +462,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
}
return COND_RESULT_FALSE;
}
-
+
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key,
"(", l, ") compare to ", dc->string);
@@ -365,16 +481,17 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
case CONFIG_COND_MATCH: {
cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
int n;
-
+
#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));
-
+
+ cache->patterncount = n;
if (n > 0) {
- cache->patterncount = n;
cache->comp_value = l;
+ cache->comp_type = dc->comp;
return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
} else {
/* cache is already cleared */
@@ -387,7 +504,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
/* no way */
break;
}
-
+
return COND_RESULT_FALSE;
}
@@ -407,21 +524,56 @@ static cond_result_t config_check_cond_cached(server *srv, connection *con, data
}
}
}
+ caches[dc->context_ndx].comp_type = dc->comp;
+
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
"(uncached) result:",
- caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
+ caches[dc->context_ndx].result == COND_RESULT_UNSET ? "unknown" :
+ (caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false"));
}
} else {
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
"(cached) result:",
- caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
+ caches[dc->context_ndx].result == COND_RESULT_UNSET ? "unknown" :
+ (caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false"));
}
}
return caches[dc->context_ndx].result;
}
+/**
+ * reset the config-cache for a named item
+ *
+ * if the item is COND_LAST_ELEMENT we reset all items
+ */
+void config_cond_cache_reset_item(server *srv, connection *con, comp_key_t item) {
+ size_t i;
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ if (item == COMP_LAST_ELEMENT ||
+ con->cond_cache[i].comp_type == item) {
+ con->cond_cache[i].result = COND_RESULT_UNSET;
+ con->cond_cache[i].patterncount = 0;
+ con->cond_cache[i].comp_value = NULL;
+ }
+ }
+}
+
+/**
+ * reset the config cache to its initial state at connection start
+ */
+void config_cond_cache_reset(server *srv, connection *con) {
+ size_t i;
+
+ config_cond_cache_reset_all_items(srv, con);
+
+ for (i = 0; i < COMP_LAST_ELEMENT; i++) {
+ con->conditional_is_valid[i] = 0;
+ }
+}
+
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 ===");
@@ -432,7 +584,7 @@ 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)
{
cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
- if (n > cache->patterncount) {
+ if (n >= cache->patterncount) {
return 0;
}
diff --git a/src/configfile.c b/src/configfile.c
index 6f13cd6..bb71b95 100644
--- a/src/configfile.c
+++ b/src/configfile.c
@@ -1,3 +1,12 @@
+#include "server.h"
+#include "log.h"
+#include "stream.h"
+#include "plugin.h"
+
+#include "configparser.h"
+#include "configfile.h"
+#include "proc_open.h"
+
#include <sys/stat.h>
#include <stdlib.h>
@@ -7,27 +16,16 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
+#include <limits.h>
#include <assert.h>
-#include "server.h"
-#include "log.h"
-#include "stream.h"
-#include "plugin.h"
-#ifdef USE_LICENSE
-#include "license.h"
-#endif
-
-#include "configparser.h"
-#include "configfile.h"
-#include "proc_open.h"
-
static int config_insert(server *srv) {
size_t i;
int ret = 0;
buffer *stat_cache_string;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "server.bind", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 0 */
{ "server.errorlog", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 1 */
{ "server.errorfile-prefix", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 2 */
@@ -38,49 +36,78 @@ static int config_insert(server *srv) {
{ "server.tag", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
{ "server.use-ipv6", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
{ "server.modules", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_SERVER }, /* 9 */
-
+
{ "server.event-handler", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 10 */
{ "server.pid-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 11 */
- { "server.max-request-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
+ { "server.max-request-size", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
{ "server.max-worker", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 13 */
{ "server.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
- { "server.force-lowercase-filenames", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 15 */
+ { "server.force-lowercase-filenames", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },/* 15 */
{ "debug.log-condition-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 16 */
- { "server.max-keep-alive-requests", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 17 */
+ { "server.max-keep-alive-requests", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },/* 17 */
{ "server.name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 18 */
{ "server.max-keep-alive-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 19 */
-
+
{ "server.max-read-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 20 */
{ "server.max-write-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 21 */
{ "server.error-handler-404", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 22 */
{ "server.max-fds", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 23 */
+#ifdef HAVE_LSTAT
{ "server.follow-symlink", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 24 */
+#else
+ { "server.follow-symlink",
+ "Your system lacks lstat(). We can not differ symlinks from files."
+ "Please remove server.follow-symlinks from your config.",
+ T_CONFIG_UNSUPPORTED, T_CONFIG_SCOPE_UNSET }, /* 24 */
+#endif
{ "server.kbytes-per-second", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 25 */
{ "connection.kbytes-per-second", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 26 */
{ "mimetype.use-xattr", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 27 */
{ "mimetype.assign", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 28 */
{ "ssl.pemfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 29 */
-
+
{ "ssl.engine", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 30 */
-
+
{ "debug.log-file-not-found", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 31 */
{ "debug.log-request-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 32 */
{ "debug.log-response-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 33 */
{ "debug.log-request-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 34 */
-
- { "server.protocol-http11", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 35 */
- { "debug.log-request-header-on-error", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 36 */
- { "debug.log-state-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 37 */
- { "ssl.ca-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 38 */
-
- { "server.errorlog-use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 39 */
- { "server.range-requests", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 40 */
- { "server.stat-cache-engine", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 41 */
- { "server.max-connections", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 42 */
- { "server.network-backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 43 */
- { "server.upload-dirs", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 44 */
- { "server.core-files", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 45 */
-
+ { "debug.log-ssl-noise", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 35 */
+
+ { "server.protocol-http11", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 36 */
+ { "debug.log-request-header-on-error", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 37 */
+ { "debug.log-state-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 38 */
+ { "ssl.ca-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 39 */
+
+ { "server.errorlog-use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 40 */
+ { "server.range-requests", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 41 */
+ { "server.stat-cache-engine", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 42 */
+ { "server.max-connections", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 43 */
+ { "server.network-backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 44 */
+ { "server.upload-dirs", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 45 */
+ { "server.core-files", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 46 */
+ { "ssl.cipher-list", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 47 */
+ { "ssl.use-sslv2", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 48 */
+ { "etag.use-inode", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 49 */
+ { "etag.use-mtime", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 50 */
+ { "etag.use-size", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 51 */
+ { "server.reject-expect-100-with-417", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 52 */
+ { "debug.log-timeouts", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 53 */
+ { "server.defer-accept", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 54 */
+ { "server.breakagelog", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 55 */
+ { "ssl.verifyclient.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 56 */
+ { "ssl.verifyclient.enforce", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 57 */
+ { "ssl.verifyclient.depth", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 58 */
+ { "ssl.verifyclient.username", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 59 */
+ { "ssl.verifyclient.exportcert", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 60 */
+
+ { "server.set-v6only", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 61 */
+ { "ssl.use-sslv3", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 62 */
+ { "ssl.dh-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 63 */
+ { "ssl.ec-curve", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 64 */
+ { "ssl.disable-client-renegotiation", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER },/* 65 */
+ { "ssl.honor-cipher-order", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 66 */
+
{ "server.host", "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
{ "server.docroot", "use server.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
{ "server.virtual-root", "load mod_simple_vhost and use simple-vhost.server-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
@@ -90,11 +117,11 @@ static int config_insert(server *srv) {
{ "server.groupid", "use server.groupname instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
{ "server.use-keep-alive", "use server.max-keep-alive-requests = 0 instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
{ "server.force-lower-case-files", "use server.force-lowercase-filenames instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
-
+
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
/* 0 */
cv[0].destination = srv->srvconf.bindhost;
cv[1].destination = srv->srvconf.errorlog_file;
@@ -102,33 +129,36 @@ static int config_insert(server *srv) {
cv[4].destination = srv->srvconf.username;
cv[5].destination = srv->srvconf.groupname;
cv[6].destination = &(srv->srvconf.port);
-
+
cv[9].destination = srv->srvconf.modules;
cv[10].destination = srv->srvconf.event_handler;
cv[11].destination = srv->srvconf.pid_file;
-
+
cv[13].destination = &(srv->srvconf.max_worker);
cv[23].destination = &(srv->srvconf.max_fds);
- cv[36].destination = &(srv->srvconf.log_request_header_on_error);
- cv[37].destination = &(srv->srvconf.log_state_handling);
-
- cv[39].destination = &(srv->srvconf.errorlog_use_syslog);
-
+ cv[37].destination = &(srv->srvconf.log_request_header_on_error);
+ cv[38].destination = &(srv->srvconf.log_state_handling);
+
+ cv[40].destination = &(srv->srvconf.errorlog_use_syslog);
+
stat_cache_string = buffer_init();
- cv[41].destination = stat_cache_string;
- cv[43].destination = srv->srvconf.network_backend;
- cv[44].destination = srv->srvconf.upload_tempdirs;
- cv[45].destination = &(srv->srvconf.enable_cores);
-
- cv[42].destination = &(srv->srvconf.max_conns);
+ cv[42].destination = stat_cache_string;
+ cv[44].destination = srv->srvconf.network_backend;
+ cv[45].destination = srv->srvconf.upload_tempdirs;
+ cv[46].destination = &(srv->srvconf.enable_cores);
+
+ cv[43].destination = &(srv->srvconf.max_conns);
cv[12].destination = &(srv->srvconf.max_request_size);
+ cv[52].destination = &(srv->srvconf.reject_expect_100_with_417);
+ cv[55].destination = srv->srvconf.breakagelog_file;
+
srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
assert(srv->config_storage);
-
+
for (i = 0; i < srv->config_context->used; i++) {
specific_config *s;
-
+
s = calloc(1, sizeof(specific_config));
assert(s);
s->document_root = buffer_init();
@@ -138,6 +168,9 @@ static int config_insert(server *srv) {
s->ssl_ca_file = buffer_init();
s->error_handler = buffer_init();
s->server_tag = buffer_init();
+ s->ssl_cipher_list = buffer_init();
+ s->ssl_dh_file = buffer_init();
+ s->ssl_ec_curve = buffer_init();
s->errorfile_prefix = buffer_init();
s->max_keep_alive_requests = 16;
s->max_keep_alive_idle = 5;
@@ -145,22 +178,40 @@ static int config_insert(server *srv) {
s->max_write_idle = 360;
s->use_xattr = 0;
s->is_ssl = 0;
+ s->ssl_honor_cipher_order = 1;
+ s->ssl_use_sslv2 = 0;
+ s->ssl_use_sslv3 = 1;
s->use_ipv6 = 0;
+ s->set_v6only = 1;
+ s->defer_accept = 0;
+#ifdef HAVE_LSTAT
s->follow_symlink = 1;
+#endif
s->kbytes_per_second = 0;
s->allow_http11 = 1;
+ s->etag_use_inode = 1;
+ s->etag_use_mtime = 1;
+ s->etag_use_size = 1;
s->range_requests = 1;
- s->force_lowercase_filenames = 0;
+ s->force_lowercase_filenames = (i == 0) ? 2 : 0; /* we wan't to detect later if user changed this for global section */
s->global_kbytes_per_second = 0;
s->global_bytes_per_second_cnt = 0;
s->global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
-
+ s->ssl_verifyclient = 0;
+ s->ssl_verifyclient_enforce = 1;
+ s->ssl_verifyclient_username = buffer_init();
+ s->ssl_verifyclient_depth = 9;
+ s->ssl_verifyclient_export_cert = 0;
+ s->ssl_disable_client_renegotiation = 1;
+
cv[2].destination = s->errorfile_prefix;
-
+
cv[7].destination = s->server_tag;
cv[8].destination = &(s->use_ipv6);
-
-
+ cv[61].destination = &(s->set_v6only);
+ cv[54].destination = &(s->defer_accept);
+
+
/* 13 max-worker */
cv[14].destination = s->document_root;
cv[15].destination = &(s->force_lowercase_filenames);
@@ -171,7 +222,9 @@ static int config_insert(server *srv) {
cv[20].destination = &(s->max_read_idle);
cv[21].destination = &(s->max_write_idle);
cv[22].destination = s->error_handler;
+#ifdef HAVE_LSTAT
cv[24].destination = &(s->follow_symlink);
+#endif
/* 23 -> max-fds */
cv[25].destination = &(s->global_kbytes_per_second);
cv[26].destination = &(s->kbytes_per_second);
@@ -179,48 +232,75 @@ static int config_insert(server *srv) {
cv[28].destination = s->mimetypes;
cv[29].destination = s->ssl_pemfile;
cv[30].destination = &(s->is_ssl);
-
+
cv[31].destination = &(s->log_file_not_found);
cv[32].destination = &(s->log_request_handling);
cv[33].destination = &(s->log_response_header);
cv[34].destination = &(s->log_request_header);
-
- cv[35].destination = &(s->allow_http11);
- cv[38].destination = s->ssl_ca_file;
- cv[40].destination = &(s->range_requests);
-
+ cv[35].destination = &(s->log_ssl_noise);
+ cv[53].destination = &(s->log_timeouts);
+
+ cv[36].destination = &(s->allow_http11);
+ cv[39].destination = s->ssl_ca_file;
+ cv[41].destination = &(s->range_requests);
+
+ cv[47].destination = s->ssl_cipher_list;
+ cv[48].destination = &(s->ssl_use_sslv2);
+ cv[62].destination = &(s->ssl_use_sslv3);
+ cv[63].destination = s->ssl_dh_file;
+ cv[64].destination = s->ssl_ec_curve;
+ cv[66].destination = &(s->ssl_honor_cipher_order);
+
+ cv[49].destination = &(s->etag_use_inode);
+ cv[50].destination = &(s->etag_use_mtime);
+ cv[51].destination = &(s->etag_use_size);
+
+ /* ssl.verify */
+ cv[56].destination = &(s->ssl_verifyclient);
+ cv[57].destination = &(s->ssl_verifyclient_enforce);
+ cv[58].destination = &(s->ssl_verifyclient_depth);
+ cv[59].destination = s->ssl_verifyclient_username;
+ cv[60].destination = &(s->ssl_verifyclient_export_cert);
+ cv[65].destination = &(s->ssl_disable_client_renegotiation);
+
srv->config_storage[i] = s;
-
+
if (0 != (ret = config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv))) {
break;
}
}
-
+
if (buffer_is_empty(stat_cache_string)) {
srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
} else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("simple"))) {
srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
+#ifdef HAVE_FAM_H
} else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("fam"))) {
srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_FAM;
+#endif
} else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("disable"))) {
srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_NONE;
} else {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "server.stat-cache-engine can be one of \"disable\", \"simple\", \"fam\", but not:", stat_cache_string);
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "server.stat-cache-engine can be one of \"disable\", \"simple\","
+#ifdef HAVE_FAM_H
+ " \"fam\","
+#endif
+ " but not:", stat_cache_string);
ret = HANDLER_ERROR;
}
-
+
buffer_free(stat_cache_string);
-
+
return ret;
-
+
}
#define PATCH(x) con->conf.x = s->x
int config_setup_connection(server *srv, connection *con) {
specific_config *s = srv->config_storage[0];
-
+
PATCH(allow_http11);
PATCH(mimetypes);
PATCH(document_root);
@@ -231,48 +311,71 @@ int config_setup_connection(server *srv, connection *con) {
PATCH(use_xattr);
PATCH(error_handler);
PATCH(errorfile_prefix);
+#ifdef HAVE_LSTAT
PATCH(follow_symlink);
+#endif
PATCH(server_tag);
PATCH(kbytes_per_second);
PATCH(global_kbytes_per_second);
PATCH(global_bytes_per_second_cnt);
-
+
con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
buffer_copy_string_buffer(con->server_name, s->server_name);
-
+
PATCH(log_request_header);
PATCH(log_response_header);
PATCH(log_request_handling);
PATCH(log_condition_handling);
PATCH(log_file_not_found);
-
+ PATCH(log_ssl_noise);
+ PATCH(log_timeouts);
+
PATCH(range_requests);
PATCH(force_lowercase_filenames);
PATCH(is_ssl);
-
+
PATCH(ssl_pemfile);
+#ifdef USE_OPENSSL
+ PATCH(ssl_ctx);
+#endif
PATCH(ssl_ca_file);
+ PATCH(ssl_cipher_list);
+ PATCH(ssl_dh_file);
+ PATCH(ssl_ec_curve);
+ PATCH(ssl_honor_cipher_order);
+ PATCH(ssl_use_sslv2);
+ PATCH(ssl_use_sslv3);
+ PATCH(etag_use_inode);
+ PATCH(etag_use_mtime);
+ PATCH(etag_use_size);
+
+ PATCH(ssl_verifyclient);
+ PATCH(ssl_verifyclient_enforce);
+ PATCH(ssl_verifyclient_depth);
+ PATCH(ssl_verifyclient_username);
+ PATCH(ssl_verifyclient_export_cert);
+ PATCH(ssl_disable_client_renegotiation);
+
return 0;
}
int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
size_t i, j;
-
+
+ con->conditional_is_valid[comp] = 1;
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
specific_config *s = srv->config_storage[i];
-
- /* not our stage */
- if (comp != dc->comp) continue;
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.document-root"))) {
PATCH(document_root);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.range-requests"))) {
@@ -293,14 +396,37 @@ int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
PATCH(max_read_idle);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("mimetype.use-xattr"))) {
PATCH(use_xattr);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("etag.use-inode"))) {
+ PATCH(etag_use_inode);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("etag.use-mtime"))) {
+ PATCH(etag_use_mtime);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("etag.use-size"))) {
+ PATCH(etag_use_size);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.pemfile"))) {
PATCH(ssl_pemfile);
+#ifdef USE_OPENSSL
+ PATCH(ssl_ctx);
+#endif
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.ca-file"))) {
PATCH(ssl_ca_file);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.honor-cipher-order"))) {
+ PATCH(ssl_honor_cipher_order);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.use-sslv2"))) {
+ PATCH(ssl_use_sslv2);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.use-sslv3"))) {
+ PATCH(ssl_use_sslv3);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.cipher-list"))) {
+ PATCH(ssl_cipher_list);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.engine"))) {
PATCH(is_ssl);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.dh-file"))) {
+ PATCH(ssl_dh_file);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.ec-curve"))) {
+ PATCH(ssl_ec_curve);
+#ifdef HAVE_LSTAT
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.follow-symlink"))) {
PATCH(follow_symlink);
+#endif
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.name"))) {
buffer_copy_string_buffer(con->server_name, s->server_name);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.tag"))) {
@@ -317,18 +443,38 @@ int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
PATCH(log_condition_handling);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-file-not-found"))) {
PATCH(log_file_not_found);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-ssl-noise"))) {
+ PATCH(log_ssl_noise);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-timeouts"))) {
+ PATCH(log_timeouts);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.protocol-http11"))) {
PATCH(allow_http11);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
PATCH(force_lowercase_filenames);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.kbytes-per-second"))) {
PATCH(global_kbytes_per_second);
PATCH(global_bytes_per_second_cnt);
con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.activate"))) {
+ PATCH(ssl_verifyclient);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.enforce"))) {
+ PATCH(ssl_verifyclient_enforce);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.depth"))) {
+ PATCH(ssl_verifyclient_depth);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.username"))) {
+ PATCH(ssl_verifyclient_username);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.verifyclient.exportcert"))) {
+ PATCH(ssl_verifyclient_export_cert);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.disable-client-renegotiation"))) {
+ PATCH(ssl_disable_client_renegotiation);
}
}
}
-
+
+ con->etag_flags = (con->conf.etag_use_mtime ? ETAG_USE_MTIME : 0) |
+ (con->conf.etag_use_inode ? ETAG_USE_INODE : 0) |
+ (con->conf.etag_use_size ? ETAG_USE_SIZE : 0);
+
return 0;
}
#undef PATCH
@@ -336,15 +482,15 @@ int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
typedef struct {
int foo;
int bar;
-
+
const buffer *source;
const char *input;
size_t offset;
size_t size;
-
+
int line_pos;
int line;
-
+
int in_key;
int in_brace;
int in_cond;
@@ -352,8 +498,8 @@ typedef struct {
#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] == '\\') &&
+ if (buffer_is_empty(basedir) ||
+ (fn[0] == '/' || fn[0] == '\\') ||
(fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\'))) {
t->file = buffer_init_string(fn);
} else {
@@ -362,7 +508,7 @@ static int tokenizer_open(server *srv, tokenizer_t *t, buffer *basedir, const ch
}
if (0 != stream_open(&(t->s), t->file)) {
- log_error_write(srv, __FILE__, __LINE__, "sbss",
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
"opening configfile ", t->file, "failed:", strerror(errno));
buffer_free(t->file);
return -1;
@@ -373,7 +519,7 @@ static int tokenizer_open(server *srv, tokenizer_t *t, buffer *basedir, const ch
t->size = t->s.size;
t->line = 1;
t->line_pos = 1;
-
+
t->in_key = 1;
t->in_brace = 0;
t->in_cond = 0;
@@ -401,7 +547,7 @@ static int config_skip_newline(tokenizer_t *t) {
static int config_skip_comment(tokenizer_t *t) {
int i;
assert(t->input[t->offset] == '#');
- for (i = 1; t->input[t->offset + i] &&
+ for (i = 1; t->input[t->offset + i] &&
(t->input[t->offset + i] != '\n' && t->input[t->offset + i] != '\r');
i++);
t->offset += i;
@@ -411,96 +557,96 @@ static int config_skip_comment(tokenizer_t *t) {
static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *token) {
int tid = 0;
size_t i;
-
+
for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
char c = t->input[t->offset];
const char *start = NULL;
-
+
switch (c) {
- case '=':
+ case '=':
if (t->in_brace) {
if (t->input[t->offset + 1] == '>') {
t->offset += 2;
-
- buffer_copy_string(token, "=>");
-
+
+ buffer_copy_string_len(token, CONST_STR_LEN("=>"));
+
tid = TK_ARRAY_ASSIGN;
} else {
- log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
"source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
+ "line:", t->line, "pos:", t->line_pos,
"use => for assignments in arrays");
return -1;
}
} else if (t->in_cond) {
if (t->input[t->offset + 1] == '=') {
t->offset += 2;
-
- buffer_copy_string(token, "==");
-
+
+ buffer_copy_string_len(token, CONST_STR_LEN("=="));
+
tid = TK_EQ;
} else if (t->input[t->offset + 1] == '~') {
t->offset += 2;
-
- buffer_copy_string(token, "=~");
-
+
+ buffer_copy_string_len(token, CONST_STR_LEN("=~"));
+
tid = TK_MATCH;
} else {
- log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
"source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
- "only =~ and == are allow in the condition");
+ "line:", t->line, "pos:", t->line_pos,
+ "only =~ and == are allowed in the condition");
return -1;
}
t->in_key = 1;
t->in_cond = 0;
} else if (t->in_key) {
tid = TK_ASSIGN;
-
+
buffer_copy_string_len(token, t->input + t->offset, 1);
-
+
t->offset++;
t->line_pos++;
} else {
- log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
"source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
+ "line:", t->line, "pos:", t->line_pos,
"unexpected equal-sign: =");
return -1;
}
-
+
break;
- case '!':
+ case '!':
if (t->in_cond) {
if (t->input[t->offset + 1] == '=') {
t->offset += 2;
-
- buffer_copy_string(token, "!=");
-
+
+ buffer_copy_string_len(token, CONST_STR_LEN("!="));
+
tid = TK_NE;
} else if (t->input[t->offset + 1] == '~') {
t->offset += 2;
-
- buffer_copy_string(token, "!~");
-
+
+ buffer_copy_string_len(token, CONST_STR_LEN("!~"));
+
tid = TK_NOMATCH;
} else {
- log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
"source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
- "only !~ and != are allow in the condition");
+ "line:", t->line, "pos:", t->line_pos,
+ "only !~ and != are allowed in the condition");
return -1;
}
t->in_key = 1;
t->in_cond = 0;
} else {
- log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
"source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
+ "line:", t->line, "pos:", t->line_pos,
"unexpected exclamation-marks: !");
return -1;
}
-
+
break;
case '\t':
case ' ':
@@ -536,214 +682,208 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
}
t->in_key = 1;
tid = TK_EOL;
- buffer_copy_string(token, "(EOL)");
+ buffer_copy_string_len(token, CONST_STR_LEN("(EOL)"));
} else {
config_skip_newline(t);
t->line_pos = 1;
- t->line++;
+ t->line++;
}
break;
case ',':
if (t->in_brace > 0) {
tid = TK_COMMA;
-
- buffer_copy_string(token, "(COMMA)");
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(COMMA)"));
}
-
+
t->offset++;
t->line_pos++;
break;
case '"':
/* search for the terminating " */
start = t->input + t->offset + 1;
- buffer_copy_string(token, "");
-
+ buffer_copy_string_len(token, CONST_STR_LEN(""));
+
for (i = 1; t->input[t->offset + i]; i++) {
if (t->input[t->offset + i] == '\\' &&
t->input[t->offset + i + 1] == '"') {
-
+
buffer_append_string_len(token, start, t->input + t->offset + i - start);
-
+
start = t->input + t->offset + i + 1;
-
+
/* skip the " */
i++;
continue;
}
-
-
+
+
if (t->input[t->offset + i] == '"') {
tid = TK_STRING;
-
+
buffer_append_string_len(token, start, t->input + t->offset + i - start);
-
+
break;
}
}
if (t->input[t->offset + i] == '\0') {
/* ERROR */
-
- log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
+
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
"source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
+ "line:", t->line, "pos:", t->line_pos,
"missing closing quote");
-
+
return -1;
}
-
+
t->offset += i + 1;
t->line_pos += i + 1;
-
+
break;
case '(':
t->offset++;
t->in_brace++;
-
+
tid = TK_LPARAN;
-
- buffer_copy_string(token, "(");
+
+ buffer_copy_string_len(token, CONST_STR_LEN("("));
break;
case ')':
t->offset++;
t->in_brace--;
-
+
tid = TK_RPARAN;
-
- buffer_copy_string(token, ")");
+
+ buffer_copy_string_len(token, CONST_STR_LEN(")"));
break;
case '$':
t->offset++;
-
+
tid = TK_DOLLAR;
t->in_cond = 1;
t->in_key = 0;
-
- buffer_copy_string(token, "$");
-
+
+ buffer_copy_string_len(token, CONST_STR_LEN("$"));
+
break;
case '+':
if (t->input[t->offset + 1] == '=') {
t->offset += 2;
- buffer_copy_string(token, "+=");
+ buffer_copy_string_len(token, CONST_STR_LEN("+="));
tid = TK_APPEND;
} else {
t->offset++;
tid = TK_PLUS;
- buffer_copy_string(token, "+");
+ buffer_copy_string_len(token, CONST_STR_LEN("+"));
}
break;
case '{':
t->offset++;
-
+
tid = TK_LCURLY;
-
- buffer_copy_string(token, "{");
-
+
+ buffer_copy_string_len(token, CONST_STR_LEN("{"));
+
break;
-
+
case '}':
t->offset++;
-
+
tid = TK_RCURLY;
-
- buffer_copy_string(token, "}");
-
+
+ buffer_copy_string_len(token, CONST_STR_LEN("}"));
+
break;
case '[':
t->offset++;
-
+
tid = TK_LBRACKET;
-
- buffer_copy_string(token, "[");
-
+
+ buffer_copy_string_len(token, CONST_STR_LEN("["));
+
break;
-
+
case ']':
t->offset++;
-
+
tid = TK_RBRACKET;
-
- buffer_copy_string(token, "]");
-
+
+ buffer_copy_string_len(token, CONST_STR_LEN("]"));
+
break;
case '#':
t->line_pos += config_skip_comment(t);
-
+
break;
default:
if (t->in_cond) {
- for (i = 0; t->input[t->offset + i] &&
+ for (i = 0; t->input[t->offset + i] &&
(isalpha((unsigned char)t->input[t->offset + i])
); i++);
-
+
if (i && t->input[t->offset + i]) {
tid = TK_SRVVARNAME;
buffer_copy_string_len(token, t->input + t->offset, i);
-
+
t->offset += i;
t->line_pos += i;
} else {
/* ERROR */
- log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
"source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
+ "line:", t->line, "pos:", t->line_pos,
"invalid character in condition");
return -1;
}
} else if (isdigit((unsigned char)c)) {
/* take all digits */
for (i = 0; t->input[t->offset + i] && isdigit((unsigned char)t->input[t->offset + i]); i++);
-
+
/* was there it least a digit ? */
- if (i && t->input[t->offset + i]) {
+ if (i) {
tid = TK_INTEGER;
-
+
buffer_copy_string_len(token, t->input + t->offset, i);
-
+
t->offset += i;
t->line_pos += i;
- } else {
- /* ERROR */
- log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
- "source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
- "unexpected EOF");
-
- return -1;
}
} else {
/* the key might consist of [-.0-9a-z] */
- for (i = 0; t->input[t->offset + i] &&
- (isalnum((unsigned char)t->input[t->offset + i]) ||
+ for (i = 0; t->input[t->offset + i] &&
+ (isalnum((unsigned char)t->input[t->offset + i]) ||
t->input[t->offset + i] == '.' ||
t->input[t->offset + i] == '_' || /* for env.* */
t->input[t->offset + i] == '-'
); i++);
-
+
if (i && t->input[t->offset + i]) {
buffer_copy_string_len(token, t->input + t->offset, i);
-
+
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, "global") == 0) {
+ tid = TK_GLOBAL;
} else if (strcmp(token->ptr, "else") == 0) {
tid = TK_ELSE;
} else {
tid = TK_LKEY;
}
-
+
t->offset += i;
t->line_pos += i;
} else {
/* ERROR */
- log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
"source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
+ "line:", t->line, "pos:", t->line_pos,
"invalid character in variable name");
return -1;
}
@@ -751,16 +891,16 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
break;
}
}
-
+
if (tid) {
*token_id = tid;
#if 0
- log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
"source:", t->source,
"line:", t->line, "pos:", t->line_pos,
token, token->used - 1, tid);
#endif
-
+
return 1;
} else if (t->offset < t->size) {
fprintf(stderr, "%s.%d: %d, %s\n",
@@ -782,7 +922,7 @@ static int config_parse(server *srv, config_t *context, tokenizer_t *t) {
while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) {
buffer_copy_string_buffer(lasttoken, token);
configparser(pParser, token_id, token, context);
-
+
token = buffer_init();
}
buffer_free(token);
@@ -795,14 +935,14 @@ static int config_parse(server *srv, config_t *context, tokenizer_t *t) {
}
}
configparserFree(pParser, free);
-
+
if (ret == -1) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "configfile parser failed:", lasttoken);
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "configfile parser failed at:", lasttoken);
} else if (context->ok == 0) {
- log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
+ log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
"source:", t->source,
- "line:", t->line, "pos:", t->line_pos,
+ "line:", t->line, "pos:", t->line_pos,
"parser failed somehow near here:", lasttoken);
ret = -1;
}
@@ -819,7 +959,7 @@ static int tokenizer_init(tokenizer_t *t, const buffer *source, const char *inpu
t->offset = 0;
t->line = 1;
t->line_pos = 1;
-
+
t->in_key = 1;
t->in_brace = 0;
t->in_cond = 0;
@@ -832,8 +972,8 @@ int config_parse_file(server *srv, config_t *context, const char *fn) {
int ret;
buffer *filename;
- if (buffer_is_empty(context->basedir) &&
- (fn[0] == '/' || fn[0] == '\\') &&
+ if (buffer_is_empty(context->basedir) ||
+ (fn[0] == '/' || fn[0] == '\\') ||
(fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\'))) {
filename = buffer_init_string(fn);
} else {
@@ -842,9 +982,14 @@ int config_parse_file(server *srv, config_t *context, const char *fn) {
}
if (0 != stream_open(&s, filename)) {
- log_error_write(srv, __FILE__, __LINE__, "sbss",
- "opening configfile ", filename, "failed:", strerror(errno));
- ret = -1;
+ if (s.size == 0) {
+ /* the file was empty, nothing to parse */
+ ret = 0;
+ } else {
+ 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);
@@ -855,16 +1000,39 @@ int config_parse_file(server *srv, config_t *context, const char *fn) {
return ret;
}
+static char* getCWD(void) {
+ char *s, *s1;
+ size_t len;
+#ifdef PATH_MAX
+ len = PATH_MAX;
+#else
+ len = 4096;
+#endif
+
+ s = malloc(len);
+ if (!s) return NULL;
+ while (NULL == getcwd(s, len)) {
+ if (errno != ERANGE || SSIZE_MAX - len < len) return NULL;
+ len *= 2;
+ s1 = realloc(s, len);
+ if (!s1) {
+ free(s);
+ return NULL;
+ }
+ s = s1;
+ }
+ return s;
+}
+
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];
+ char *oldpwd;
- if (NULL == getcwd(oldpwd, sizeof(oldpwd))) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ if (NULL == (oldpwd = getCWD())) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
"cannot get cwd", strerror(errno));
return -1;
}
@@ -876,8 +1044,8 @@ int config_parse_cmd(server *srv, config_t *context, const char *cmd) {
chdir(context->basedir->ptr);
}
- if (0 != proc_open_buffer(&proc, cmd, NULL, out, NULL)) {
- log_error_write(srv, __FILE__, __LINE__, "sbss",
+ if (0 != proc_open_buffer(cmd, NULL, out, NULL)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
"opening", source, "failed:", strerror(errno));
ret = -1;
} else {
@@ -888,6 +1056,7 @@ int config_parse_cmd(server *srv, config_t *context, const char *cmd) {
buffer_free(source);
buffer_free(out);
chdir(oldpwd);
+ free(oldpwd);
return ret;
}
@@ -908,6 +1077,7 @@ int config_read(server *srv, const char *fn) {
config_t context;
data_config *dc;
data_integer *dpid;
+ data_string *dcwd;
int ret;
char *pos;
data_array *modules;
@@ -915,20 +1085,18 @@ int config_read(server *srv, const char *fn) {
context_init(srv, &context);
context.all_configs = srv->config_context;
- pos = strrchr(fn,
#ifdef __WIN32
- '\\'
+ pos = strrchr(fn, '\\');
#else
- '/'
+ pos = strrchr(fn, '/');
#endif
- );
if (pos) {
buffer_copy_string_len(context.basedir, fn, pos - fn + 1);
fn = pos + 1;
}
-
+
dc = data_config_init();
- buffer_copy_string(dc->key, "global");
+ buffer_copy_string_len(dc->key, CONST_STR_LEN("global"));
assert(context.all_configs->used == 0);
dc->context_ndx = context.all_configs->used;
@@ -939,9 +1107,17 @@ int config_read(server *srv, const char *fn) {
srv->config = dc->value;
dpid = data_integer_init();
dpid->value = getpid();
- buffer_copy_string(dpid->key, "var.PID");
+ buffer_copy_string_len(dpid->key, CONST_STR_LEN("var.PID"));
array_insert_unique(srv->config, (data_unset *)dpid);
-
+
+ dcwd = data_string_init();
+ buffer_prepare_copy(dcwd->value, 1024);
+ if (NULL != getcwd(dcwd->value->ptr, dcwd->value->size - 1)) {
+ dcwd->value->used = strlen(dcwd->value->ptr) + 1;
+ buffer_copy_string_len(dcwd->key, CONST_STR_LEN("var.CWD"));
+ array_insert_unique(srv->config, (data_unset *)dcwd);
+ }
+
ret = config_parse_file(srv, &context, fn);
/* remains nothing if parser is ok */
@@ -957,7 +1133,7 @@ int config_read(server *srv, const char *fn) {
} else {
return -1;
}
-
+
if (NULL != (modules = (data_array *)array_get_element(srv->config, "server.modules"))) {
data_string *ds;
data_array *prepends;
@@ -972,7 +1148,7 @@ int config_read(server *srv, const char *fn) {
/* prepend default modules */
if (NULL == array_get_element(modules->value, "mod_indexfile")) {
ds = data_string_init();
- buffer_copy_string(ds->value, "mod_indexfile");
+ buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_indexfile"));
array_insert_unique(prepends->value, (data_unset *)ds);
}
@@ -985,22 +1161,42 @@ int config_read(server *srv, const char *fn) {
/* append default modules */
if (NULL == array_get_element(modules->value, "mod_dirlisting")) {
ds = data_string_init();
- buffer_copy_string(ds->value, "mod_dirlisting");
+ buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_dirlisting"));
array_insert_unique(modules->value, (data_unset *)ds);
}
if (NULL == array_get_element(modules->value, "mod_staticfile")) {
ds = data_string_init();
- buffer_copy_string(ds->value, "mod_staticfile");
+ buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_staticfile"));
array_insert_unique(modules->value, (data_unset *)ds);
}
+ } else {
+ data_string *ds;
+
+ modules = data_array_init();
+
+ /* server.modules is not set */
+ ds = data_string_init();
+ buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_indexfile"));
+ array_insert_unique(modules->value, (data_unset *)ds);
+
+ ds = data_string_init();
+ buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_dirlisting"));
+ array_insert_unique(modules->value, (data_unset *)ds);
+
+ ds = data_string_init();
+ buffer_copy_string_len(ds->value, CONST_STR_LEN("mod_staticfile"));
+ array_insert_unique(modules->value, (data_unset *)ds);
+
+ buffer_copy_string_len(modules->key, CONST_STR_LEN("server.modules"));
+ array_insert_unique(srv->config, (data_unset *)modules);
}
-
+
if (0 != config_insert(srv)) {
return -1;
}
-
+
return 0;
}
@@ -1008,48 +1204,50 @@ int config_set_defaults(server *srv) {
size_t i;
specific_config *s = srv->config_storage[0];
struct stat st1, st2;
-
- struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
- {
- /* - poll is most reliable
+
+ struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
+ {
+ /* - epoll is most reliable
* - select works everywhere
- * - linux-* are experimental
*/
+#ifdef USE_LINUX_EPOLL
+ { FDEVENT_HANDLER_LINUX_SYSEPOLL, "linux-sysepoll" },
+#endif
#ifdef USE_POLL
{ FDEVENT_HANDLER_POLL, "poll" },
#endif
#ifdef USE_SELECT
{ FDEVENT_HANDLER_SELECT, "select" },
#endif
-#ifdef USE_LINUX_EPOLL
- { FDEVENT_HANDLER_LINUX_SYSEPOLL, "linux-sysepoll" },
-#endif
-#ifdef USE_LINUX_SIGIO
- { FDEVENT_HANDLER_LINUX_RTSIG, "linux-rtsig" },
+#ifdef USE_LIBEV
+ { FDEVENT_HANDLER_LIBEV, "libev" },
#endif
#ifdef USE_SOLARIS_DEVPOLL
{ FDEVENT_HANDLER_SOLARIS_DEVPOLL,"solaris-devpoll" },
#endif
+#ifdef USE_SOLARIS_PORT
+ { FDEVENT_HANDLER_SOLARIS_PORT, "solaris-eventports" },
+#endif
#ifdef USE_FREEBSD_KQUEUE
{ FDEVENT_HANDLER_FREEBSD_KQUEUE, "freebsd-kqueue" },
{ FDEVENT_HANDLER_FREEBSD_KQUEUE, "kqueue" },
#endif
{ FDEVENT_HANDLER_UNSET, NULL }
};
-
-
- if (buffer_is_empty(s->document_root)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "a default document-root has to be set");
-
- return -1;
- }
-
+
+
+ if (buffer_is_empty(s->document_root)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "a default document-root has to be set");
+
+ return -1;
+ }
+
if (buffer_is_empty(srv->srvconf.changeroot)) {
- if (-1 == stat(s->document_root->ptr, &st1)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
+ if (-1 == stat(s->document_root->ptr, &st1)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
"base-docroot doesn't exist:",
- s->document_root);
+ s->document_root);
return -1;
}
@@ -1057,87 +1255,91 @@ int config_set_defaults(server *srv) {
buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.changeroot);
buffer_append_string_buffer(srv->tmp_buf, s->document_root);
- if (-1 == stat(srv->tmp_buf->ptr, &st1)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
+ if (-1 == stat(srv->tmp_buf->ptr, &st1)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
"base-docroot doesn't exist:",
- srv->tmp_buf);
+ srv->tmp_buf);
return -1;
}
-
+
}
-
- buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
- buffer_to_lower(srv->tmp_buf);
+ buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
+
+ buffer_to_lower(srv->tmp_buf);
+
+ if (2 == s->force_lowercase_filenames) { /* user didn't configure it in global section? */
+ s->force_lowercase_filenames = 0; /* default to 0 */
- if (0 == stat(srv->tmp_buf->ptr, &st1)) {
- int is_lower = 0;
+ if (0 == stat(srv->tmp_buf->ptr, &st1)) {
+ int is_lower = 0;
- is_lower = buffer_is_equal(srv->tmp_buf, s->document_root);
+ is_lower = buffer_is_equal(srv->tmp_buf, s->document_root);
- /* lower-case existed, check upper-case */
- buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
+ /* lower-case existed, check upper-case */
+ buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
- buffer_to_upper(srv->tmp_buf);
+ buffer_to_upper(srv->tmp_buf);
- /* we have to handle the special case that upper and lower-casing results in the same filename
- * as in server.document-root = "/" or "/12345/" */
+ /* we have to handle the special case that upper and lower-casing results in the same filename
+ * as in server.document-root = "/" or "/12345/" */
- if (is_lower && buffer_is_equal(srv->tmp_buf, s->document_root)) {
- /* lower-casing and upper-casing didn't result in
- * an other filename, no need to stat(),
- * just assume it is case-sensitive. */
+ if (is_lower && buffer_is_equal(srv->tmp_buf, s->document_root)) {
+ /* lower-casing and upper-casing didn't result in
+ * an other filename, no need to stat(),
+ * just assume it is case-sensitive. */
- s->force_lowercase_filenames = 0;
- } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
+ s->force_lowercase_filenames = 0;
+ } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
+
+ /* upper case exists too, doesn't the FS handle this ? */
+
+ /* upper and lower have the same inode -> case-insensitve FS */
+
+ if (st1.st_ino == st2.st_ino) {
+ /* upper and lower have the same inode -> case-insensitve FS */
+
+ s->force_lowercase_filenames = 1;
+ }
+ }
+ }
+ }
- /* upper case exists too, doesn't the FS handle this ? */
-
- /* upper and lower have the same inode -> case-insensitve FS */
-
- if (st1.st_ino == st2.st_ino) {
- /* upper and lower have the same inode -> case-insensitve FS */
-
- s->force_lowercase_filenames = 1;
- }
- }
- }
-
if (srv->srvconf.port == 0) {
srv->srvconf.port = s->is_ssl ? 443 : 80;
}
-
+
if (srv->srvconf.event_handler->used == 0) {
/* choose a good default
- *
- * the event_handler list is sorted by 'goodness'
+ *
+ * the event_handler list is sorted by 'goodness'
* taking the first available should be the best solution
*/
srv->event_handler = event_handlers[0].et;
-
+
if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"sorry, there is no event handler for this system");
-
+
return -1;
}
} else {
/*
* User override
*/
-
+
for (i = 0; event_handlers[i].name; i++) {
if (0 == strcmp(event_handlers[i].name, srv->srvconf.event_handler->ptr)) {
srv->event_handler = event_handlers[i].et;
break;
}
}
-
+
if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "the selected event-handler in unknown or not supported:",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "the selected event-handler in unknown or not supported:",
srv->srvconf.event_handler );
-
+
return -1;
}
}
@@ -1145,19 +1347,19 @@ int config_set_defaults(server *srv) {
if (s->is_ssl) {
if (buffer_is_empty(s->ssl_pemfile)) {
/* PEM file is require */
-
- log_error_write(srv, __FILE__, __LINE__, "s",
+
+ log_error_write(srv, __FILE__, __LINE__, "s",
"ssl.pemfile has to be set");
return -1;
}
-
+
#ifndef USE_OPENSSL
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"ssl support is missing, recompile with --with-openssl");
-
+
return -1;
#endif
}
-
+
return 0;
}
diff --git a/src/configfile.h b/src/configfile.h
index 600297f..f46e869 100644
--- a/src/configfile.h
+++ b/src/configfile.h
@@ -21,4 +21,10 @@ int config_parse_file(server *srv, config_t *context, const char *fn);
int config_parse_cmd(server *srv, config_t *context, const char *cmd);
data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2);
+void config_cond_cache_reset(server *srv, connection *con);
+void config_cond_cache_reset_item(server *srv, connection *con, comp_key_t item);
+
+#define config_cond_cache_reset_all_items(srv, con) \
+ config_cond_cache_reset_item(srv, con, COMP_LAST_ELEMENT);
+
#endif
diff --git a/src/configparser.c b/src/configparser.c
index 2ce169a..a13d729 100644
--- a/src/configparser.c
+++ b/src/configparser.c
@@ -4,18 +4,16 @@
/* First off, code is include which follows the "include" declaration
** in the input file. */
#include <stdio.h>
-#line 5 "./configparser.y"
+#line 5 "../../src/configparser.y"
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
#include "configfile.h"
#include "buffer.h"
#include "array.h"
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
static void configparser_push(config_t *ctx, data_config *dc, int isnew) {
if (isnew) {
dc->context_ndx = ctx->all_configs->used;
@@ -24,6 +22,10 @@ static void configparser_push(config_t *ctx, data_config *dc, int isnew) {
dc->parent = ctx->current;
array_insert_unique(dc->parent->childs, (data_unset *)dc);
}
+ if (ctx->configs_stack->used > 0 && ctx->current->context_ndx == 0) {
+ fprintf(stderr, "Cannot use conditionals inside a global { ... } block\n");
+ exit(-1);
+ }
array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
ctx->current = dc;
}
@@ -36,43 +38,25 @@ static data_config *configparser_pop(config_t *ctx) {
/* return a copied variable */
static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
- if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
- char *env;
-
- if (NULL != (env = getenv(key->ptr + 4))) {
- data_string *ds;
- ds = data_string_init();
- buffer_append_string(ds->value, env);
- return (data_unset *)ds;
- }
-
- fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
- ctx->ok = 0;
-
- return NULL;
- } else {
- data_unset *du;
- data_config *dc;
+ data_unset *du;
+ data_config *dc;
#if 0
- fprintf(stderr, "get var %s\n", key->ptr);
+ fprintf(stderr, "get var %s\n", key->ptr);
#endif
- for (dc = ctx->current; dc; dc = dc->parent) {
+ for (dc = ctx->current; dc; dc = dc->parent) {
#if 0
- fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
- array_print(dc->value, 0);
+ fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
+ array_print(dc->value, 0);
#endif
- if (NULL != (du = array_get_element(dc->value, key->ptr))) {
- return du->copy(du);
- }
+ if (NULL != (du = array_get_element(dc->value, key->ptr))) {
+ return du->copy(du);
}
- fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
- ctx->ok = 0;
- return NULL;
}
+ 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) {
@@ -89,8 +73,7 @@ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
op1->free(op1);
return (data_unset *)ds;
} else {
- fprintf(stderr, "data type mismatch, cannot be merge\n");
- op1->free(op1);
+ fprintf(stderr, "data type mismatch, cannot merge\n");
return NULL;
}
}
@@ -124,14 +107,14 @@ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
}
-#line 128 "configparser.c"
+#line 111 "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.
*/
-/*
+/*
** These constants (all generated automatically by the parser generator)
** specify the various kinds of tokens (terminals) that the parser
-** understands.
+** understands.
**
** Each symbol here is a terminal symbol in the grammar.
*/
@@ -148,7 +131,7 @@ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
** and nonterminals. "int" is used otherwise.
** YYNOCODE is a number of type YYCODETYPE which corresponds
** to no legal terminal or nonterminal number. This
-** number is used to fill in empty slots of the hash
+** number is used to fill in empty slots of the hash
** table.
** YYFALLBACK If defined, this indicates that one or more tokens
** have fall-back values which should be used if the
@@ -157,7 +140,7 @@ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
** and nonterminal numbers. "unsigned char" is
** used if there are fewer than 250 rules and
** states combined. "int" is used otherwise.
-** configparserTOKENTYPE is the data type used for minor tokens given
+** configparserTOKENTYPE is the data type used for minor tokens given
** directly to the parser from the tokenizer.
** YYMINORTYPE is the data type used for all minor tokens.
** This is typically a union of many types, one of
@@ -175,27 +158,27 @@ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
*/
/*  */
#define YYCODETYPE unsigned char
-#define YYNOCODE 45
+#define YYNOCODE 48
#define YYACTIONTYPE unsigned char
#define configparserTOKENTYPE buffer *
typedef union {
configparserTOKENTYPE yy0;
- buffer * yy1;
- config_cond_t yy29;
- data_unset * yy43;
- data_config * yy74;
- array * yy78;
- int yy89;
+ config_cond_t yy27;
+ array * yy40;
+ data_unset * yy41;
+ buffer * yy43;
+ data_config * yy78;
+ int yy95;
} YYMINORTYPE;
#define YYSTACKDEPTH 100
#define configparserARG_SDECL config_t *ctx;
#define configparserARG_PDECL ,config_t *ctx
#define configparserARG_FETCH config_t *ctx = yypParser->ctx
#define configparserARG_STORE yypParser->ctx = ctx
-#define YYNSTATE 56
-#define YYNRULE 36
-#define YYERRORSYMBOL 25
-#define YYERRSYMDT yy89
+#define YYNSTATE 63
+#define YYNRULE 40
+#define YYERRORSYMBOL 26
+#define YYERRSYMDT yy95
#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
@@ -203,7 +186,7 @@ typedef union {
/* Next are that tables used to determine what action to take based on the
** current state and lookahead token. These tables are used to implement
** functions that take a state number and lookahead value and return an
-** action integer.
+** action integer.
**
** Suppose the action integer is N. Then the action is determined as
** follows
@@ -228,7 +211,7 @@ typedef union {
** If the index value yy_shift_ofst[S]+X is out of range or if the value
** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
-** and that yy_default[S] should be used instead.
+** and that yy_default[S] should be used instead.
**
** The formula above is for computing the action when the lookahead is
** a terminal symbol. If the lookahead is a non-terminal (as occurs after
@@ -248,62 +231,69 @@ typedef union {
** yy_default[] Default action for each state.
*/
static YYACTIONTYPE yy_action[] = {
- /* 0 */ 2, 3, 4, 12, 13, 56, 14, 6, 38, 19,
- /* 10 */ 79, 15, 27, 26, 35, 9, 28, 24, 21, 32,
- /* 20 */ 40, 14, 93, 1, 19, 27, 26, 31, 52, 54,
- /* 30 */ 24, 21, 32, 7, 39, 40, 48, 49, 50, 51,
- /* 40 */ 27, 43, 18, 52, 54, 24, 21, 44, 27, 43,
- /* 50 */ 84, 27, 43, 24, 21, 53, 24, 21, 55, 19,
- /* 60 */ 40, 22, 23, 25, 27, 17, 27, 34, 33, 24,
- /* 70 */ 21, 24, 21, 5, 27, 37, 10, 27, 47, 24,
- /* 80 */ 21, 20, 24, 21, 80, 8, 24, 21, 16, 36,
- /* 90 */ 18, 11, 9, 29, 30, 18, 89, 41, 45, 42,
- /* 100 */ 46,
+ /* 0 */ 2, 3, 4, 5, 13, 14, 63, 15, 7, 45,
+ /* 10 */ 20, 88, 16, 46, 28, 49, 41, 10, 40, 25,
+ /* 20 */ 22, 50, 46, 8, 15, 104, 1, 20, 28, 18,
+ /* 30 */ 58, 60, 6, 25, 22, 40, 47, 62, 11, 46,
+ /* 40 */ 20, 9, 23, 24, 26, 29, 89, 58, 60, 10,
+ /* 50 */ 17, 38, 28, 27, 37, 19, 30, 25, 22, 34,
+ /* 60 */ 15, 100, 20, 20, 23, 24, 26, 12, 19, 31,
+ /* 70 */ 32, 40, 19, 44, 43, 46, 95, 35, 90, 89,
+ /* 80 */ 28, 49, 42, 58, 60, 25, 22, 59, 28, 27,
+ /* 90 */ 33, 48, 52, 25, 22, 34, 28, 49, 51, 28,
+ /* 100 */ 36, 25, 22, 61, 25, 22, 89, 28, 39, 89,
+ /* 110 */ 89, 89, 25, 22, 54, 55, 56, 57, 89, 28,
+ /* 120 */ 53, 21, 89, 89, 25, 22, 25, 22,
};
static YYCODETYPE yy_lookahead[] = {
- /* 0 */ 28, 29, 30, 31, 32, 0, 1, 42, 36, 4,
- /* 10 */ 12, 39, 33, 34, 35, 43, 37, 38, 39, 40,
- /* 20 */ 15, 1, 26, 27, 4, 33, 34, 35, 23, 24,
- /* 30 */ 38, 39, 40, 12, 14, 15, 19, 20, 21, 22,
- /* 40 */ 33, 34, 5, 23, 24, 38, 39, 40, 33, 34,
- /* 50 */ 13, 33, 34, 38, 39, 40, 38, 39, 40, 4,
- /* 60 */ 15, 6, 7, 8, 33, 34, 33, 34, 11, 38,
- /* 70 */ 39, 38, 39, 1, 33, 34, 13, 33, 34, 38,
- /* 80 */ 39, 33, 38, 39, 12, 36, 38, 39, 2, 3,
- /* 90 */ 5, 27, 43, 9, 10, 5, 11, 16, 18, 17,
- /* 100 */ 41,
+ /* 0 */ 29, 30, 31, 32, 33, 34, 0, 1, 44, 38,
+ /* 10 */ 4, 15, 41, 16, 35, 36, 45, 46, 12, 40,
+ /* 20 */ 41, 42, 16, 15, 1, 27, 28, 4, 35, 36,
+ /* 30 */ 24, 25, 1, 40, 41, 12, 17, 14, 13, 16,
+ /* 40 */ 4, 38, 6, 7, 8, 9, 15, 24, 25, 46,
+ /* 50 */ 2, 3, 35, 36, 37, 5, 39, 40, 41, 42,
+ /* 60 */ 1, 11, 4, 4, 6, 7, 8, 28, 5, 9,
+ /* 70 */ 10, 12, 5, 14, 28, 16, 13, 11, 13, 47,
+ /* 80 */ 35, 36, 13, 24, 25, 40, 41, 42, 35, 36,
+ /* 90 */ 37, 18, 43, 40, 41, 42, 35, 36, 19, 35,
+ /* 100 */ 36, 40, 41, 42, 40, 41, 47, 35, 36, 47,
+ /* 110 */ 47, 47, 40, 41, 20, 21, 22, 23, 47, 35,
+ /* 120 */ 36, 35, 47, 47, 40, 41, 40, 41,
};
-#define YY_SHIFT_USE_DFLT (-3)
+#define YY_SHIFT_USE_DFLT (-5)
static signed char yy_shift_ofst[] = {
- /* 0 */ -3, 5, -3, -3, 72, -2, 21, 45, -3, 63,
- /* 10 */ -3, 20, -3, -3, -3, 86, 55, 90, 55, -3,
- /* 20 */ -3, -3, -3, -3, -3, 55, 85, -3, 84, -3,
- /* 30 */ 55, -3, 57, 55, 90, -3, 55, 90, -3, -3,
- /* 40 */ 81, 82, 55, 90, 80, 17, 55, 37, -3, -3,
- /* 50 */ -3, -3, 55, -3, 55, -3,
+ /* 0 */ -5, 6, -5, -5, -5, 31, -4, 8, -3, -5,
+ /* 10 */ 25, -5, 23, -5, -5, -5, 48, 58, 67, 58,
+ /* 20 */ -5, -5, -5, -5, -5, -5, 36, 50, -5, -5,
+ /* 30 */ 60, -5, 58, -5, 66, 58, 67, -5, 58, 67,
+ /* 40 */ 65, 69, -5, 59, -5, -5, 19, 73, 58, 67,
+ /* 50 */ 79, 94, 58, 63, -5, -5, -5, -5, 58, -5,
+ /* 60 */ 58, -5, -5,
};
-#define YY_REDUCE_USE_DFLT (-36)
+#define YY_REDUCE_USE_DFLT (-37)
static signed char yy_reduce_ofst[] = {
- /* 0 */ -4, -28, -36, -36, -35, -36, -36, 49, -36, -36,
- /* 10 */ 64, -28, -36, -36, -36, -36, 31, -36, 48, -36,
- /* 20 */ -36, -36, -36, -36, -36, -21, -36, -36, -36, -36,
- /* 30 */ -8, -36, -36, 33, -36, -36, 41, -36, -36, -36,
- /* 40 */ -36, -36, 7, -36, -36, 59, 44, -36, -36, -36,
- /* 50 */ -36, -36, 15, -36, 18, -36,
+ /* 0 */ -2, -29, -37, -37, -37, -36, -37, -37, 3, -37,
+ /* 10 */ -37, 39, -29, -37, -37, -37, -37, -7, -37, 86,
+ /* 20 */ -37, -37, -37, -37, -37, -37, 17, -37, -37, -37,
+ /* 30 */ -37, -37, 53, -37, -37, 64, -37, -37, 72, -37,
+ /* 40 */ -37, -37, 46, -29, -37, -37, -37, -37, -21, -37,
+ /* 50 */ -37, 49, 84, -37, -37, -37, -37, -37, 45, -37,
+ /* 60 */ 61, -37, -37,
};
static YYACTIONTYPE yy_default[] = {
- /* 0 */ 58, 92, 57, 59, 92, 60, 92, 92, 81, 92,
- /* 10 */ 58, 92, 61, 62, 63, 92, 92, 64, 92, 66,
- /* 20 */ 67, 69, 70, 71, 72, 92, 77, 68, 92, 73,
- /* 30 */ 75, 74, 92, 92, 78, 76, 92, 65, 82, 83,
- /* 40 */ 92, 92, 92, 89, 92, 92, 92, 92, 85, 86,
- /* 50 */ 87, 88, 92, 90, 92, 91,
+ /* 0 */ 65, 103, 64, 66, 67, 103, 68, 103, 103, 92,
+ /* 10 */ 103, 65, 103, 69, 70, 71, 103, 103, 72, 103,
+ /* 20 */ 74, 75, 77, 78, 79, 80, 103, 86, 76, 81,
+ /* 30 */ 103, 82, 84, 83, 103, 103, 87, 85, 103, 73,
+ /* 40 */ 103, 103, 65, 103, 91, 93, 103, 103, 103, 100,
+ /* 50 */ 103, 103, 103, 103, 96, 97, 98, 99, 103, 101,
+ /* 60 */ 103, 102, 94,
};
#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
/* The next table maps tokens into fallback tokens. If a construct
** like the following:
-**
+**
** %fallback ID X Y Z.
**
** appears in the grammer, then ID becomes a fallback token for X, Y,
@@ -349,15 +339,15 @@ typedef struct yyParser yyParser;
#ifndef NDEBUG
#include <stdio.h>
-static FILE *yyTraceFILE = 0;
-static char *yyTracePrompt = 0;
+static FILE *yyTraceFILE = NULL;
+static char *yyTracePrompt = NULL;
#endif /* NDEBUG */
#ifndef NDEBUG
-/*
+/*
** Turn parser tracing on by giving a stream to which to write the trace
** and a prompt to preface each trace message. Tracing is turned off
-** by making either argument NULL
+** by making either argument NULL
**
** Inputs:
** <ul>
@@ -371,29 +361,32 @@ static char *yyTracePrompt = 0;
** Outputs:
** None.
*/
+#if 0
void configparserTrace(FILE *TraceFILE, char *zTracePrompt){
yyTraceFILE = TraceFILE;
yyTracePrompt = zTracePrompt;
if( yyTraceFILE==0 ) yyTracePrompt = 0;
else if( yyTracePrompt==0 ) yyTraceFILE = 0;
}
+#endif
#endif /* NDEBUG */
#ifndef NDEBUG
/* For tracing shifts, the names of all terminals and nonterminals
** are required. The following table supplies these names */
-static const char *yyTokenName[] = {
+static const char *yyTokenName[] = {
"$", "EOL", "ASSIGN", "APPEND",
"LKEY", "PLUS", "STRING", "INTEGER",
"LPARAN", "RPARAN", "COMMA", "ARRAY_ASSIGN",
- "ELSE", "LCURLY", "RCURLY", "DOLLAR",
- "SRVVARNAME", "LBRACKET", "RBRACKET", "EQ",
- "MATCH", "NE", "NOMATCH", "INCLUDE",
- "INCLUDE_SHELL", "error", "input", "metalines",
- "metaline", "varline", "condlines", "include",
- "include_shell", "value", "expression", "aelement",
- "condline", "aelements", "array", "key",
- "stringop", "cond", "eols", "context",
+ "GLOBAL", "LCURLY", "RCURLY", "ELSE",
+ "DOLLAR", "SRVVARNAME", "LBRACKET", "RBRACKET",
+ "EQ", "MATCH", "NE", "NOMATCH",
+ "INCLUDE", "INCLUDE_SHELL", "error", "input",
+ "metalines", "metaline", "varline", "global",
+ "condlines", "include", "include_shell", "value",
+ "expression", "aelement", "condline", "aelements",
+ "array", "key", "stringop", "cond",
+ "eols", "globalstart", "context",
};
#endif /* NDEBUG */
@@ -405,38 +398,42 @@ static const char *yyRuleName[] = {
/* 1 */ "metalines ::= metalines metaline",
/* 2 */ "metalines ::=",
/* 3 */ "metaline ::= varline",
- /* 4 */ "metaline ::= condlines EOL",
- /* 5 */ "metaline ::= include",
- /* 6 */ "metaline ::= include_shell",
- /* 7 */ "metaline ::= EOL",
- /* 8 */ "varline ::= key ASSIGN expression",
- /* 9 */ "varline ::= key APPEND expression",
- /* 10 */ "key ::= LKEY",
- /* 11 */ "expression ::= expression PLUS value",
- /* 12 */ "expression ::= value",
- /* 13 */ "value ::= key",
- /* 14 */ "value ::= STRING",
- /* 15 */ "value ::= INTEGER",
- /* 16 */ "value ::= array",
- /* 17 */ "array ::= LPARAN aelements RPARAN",
- /* 18 */ "aelements ::= aelements COMMA aelement",
- /* 19 */ "aelements ::= aelements COMMA",
- /* 20 */ "aelements ::= aelement",
- /* 21 */ "aelement ::= expression",
- /* 22 */ "aelement ::= stringop ARRAY_ASSIGN expression",
- /* 23 */ "eols ::= EOL",
- /* 24 */ "eols ::=",
- /* 25 */ "condlines ::= condlines eols ELSE condline",
- /* 26 */ "condlines ::= condline",
- /* 27 */ "condline ::= context LCURLY metalines RCURLY",
- /* 28 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
- /* 29 */ "cond ::= EQ",
- /* 30 */ "cond ::= MATCH",
- /* 31 */ "cond ::= NE",
- /* 32 */ "cond ::= NOMATCH",
- /* 33 */ "stringop ::= expression",
- /* 34 */ "include ::= INCLUDE stringop",
- /* 35 */ "include_shell ::= INCLUDE_SHELL stringop",
+ /* 4 */ "metaline ::= global",
+ /* 5 */ "metaline ::= condlines EOL",
+ /* 6 */ "metaline ::= include",
+ /* 7 */ "metaline ::= include_shell",
+ /* 8 */ "metaline ::= EOL",
+ /* 9 */ "varline ::= key ASSIGN expression",
+ /* 10 */ "varline ::= key APPEND expression",
+ /* 11 */ "key ::= LKEY",
+ /* 12 */ "expression ::= expression PLUS value",
+ /* 13 */ "expression ::= value",
+ /* 14 */ "value ::= key",
+ /* 15 */ "value ::= STRING",
+ /* 16 */ "value ::= INTEGER",
+ /* 17 */ "value ::= array",
+ /* 18 */ "array ::= LPARAN RPARAN",
+ /* 19 */ "array ::= LPARAN aelements RPARAN",
+ /* 20 */ "aelements ::= aelements COMMA aelement",
+ /* 21 */ "aelements ::= aelements COMMA",
+ /* 22 */ "aelements ::= aelement",
+ /* 23 */ "aelement ::= expression",
+ /* 24 */ "aelement ::= stringop ARRAY_ASSIGN expression",
+ /* 25 */ "eols ::= EOL",
+ /* 26 */ "eols ::=",
+ /* 27 */ "globalstart ::= GLOBAL",
+ /* 28 */ "global ::= globalstart LCURLY metalines RCURLY",
+ /* 29 */ "condlines ::= condlines eols ELSE condline",
+ /* 30 */ "condlines ::= condline",
+ /* 31 */ "condline ::= context LCURLY metalines RCURLY",
+ /* 32 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
+ /* 33 */ "cond ::= EQ",
+ /* 34 */ "cond ::= MATCH",
+ /* 35 */ "cond ::= NE",
+ /* 36 */ "cond ::= NOMATCH",
+ /* 37 */ "stringop ::= expression",
+ /* 38 */ "include ::= INCLUDE stringop",
+ /* 39 */ "include_shell ::= INCLUDE_SHELL stringop",
};
#endif /* NDEBUG */
@@ -444,9 +441,10 @@ static const char *yyRuleName[] = {
** This function returns the symbolic name associated with a token
** value.
*/
+#if 0
const char *configparserTokenName(int tokenType){
#ifndef NDEBUG
- if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
+ if( tokenType>0 && (size_t)tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
return yyTokenName[tokenType];
}else{
return "Unknown";
@@ -455,8 +453,9 @@ const char *configparserTokenName(int tokenType){
return "";
#endif
}
+#endif
-/*
+/*
** This function allocates a new parser.
** The only argument is a pointer to a function which works like
** malloc.
@@ -487,7 +486,7 @@ static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
/* Here is inserted the actions which take place when a
** terminal or non-terminal is destroyed. This can happen
** when the symbol is popped from the stack during a
- ** reduce or during error processing or when a parser is
+ ** reduce or during error processing or when a parser is
** being destroyed before it is finished parsing.
**
** Note: during a reduce, the only symbols destroyed are those
@@ -518,43 +517,44 @@ static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
case 22:
case 23:
case 24:
-#line 159 "./configparser.y"
+ case 25:
+#line 144 "../../src/configparser.y"
{ buffer_free((yypminor->yy0)); }
#line 523 "configparser.c"
break;
- case 33:
-#line 150 "./configparser.y"
-{ (yypminor->yy43)->free((yypminor->yy43)); }
+ case 35:
+#line 135 "../../src/configparser.y"
+{ (yypminor->yy41)->free((yypminor->yy41)); }
#line 528 "configparser.c"
break;
- case 34:
-#line 151 "./configparser.y"
-{ (yypminor->yy43)->free((yypminor->yy43)); }
+ case 36:
+#line 136 "../../src/configparser.y"
+{ (yypminor->yy41)->free((yypminor->yy41)); }
#line 533 "configparser.c"
break;
- case 35:
-#line 152 "./configparser.y"
-{ (yypminor->yy43)->free((yypminor->yy43)); }
+ case 37:
+#line 137 "../../src/configparser.y"
+{ (yypminor->yy41)->free((yypminor->yy41)); }
#line 538 "configparser.c"
break;
- case 37:
-#line 153 "./configparser.y"
-{ array_free((yypminor->yy78)); }
+ case 39:
+#line 138 "../../src/configparser.y"
+{ array_free((yypminor->yy40)); }
#line 543 "configparser.c"
break;
- case 38:
-#line 154 "./configparser.y"
-{ array_free((yypminor->yy78)); }
+ case 40:
+#line 139 "../../src/configparser.y"
+{ array_free((yypminor->yy40)); }
#line 548 "configparser.c"
break;
- case 39:
-#line 155 "./configparser.y"
-{ buffer_free((yypminor->yy1)); }
+ case 41:
+#line 140 "../../src/configparser.y"
+{ buffer_free((yypminor->yy43)); }
#line 553 "configparser.c"
break;
- case 40:
-#line 156 "./configparser.y"
-{ buffer_free((yypminor->yy1)); }
+ case 42:
+#line 141 "../../src/configparser.y"
+{ buffer_free((yypminor->yy43)); }
#line 558 "configparser.c"
break;
default: break; /* If no destructor action specified: do nothing */
@@ -587,7 +587,7 @@ static int yy_pop_parser_stack(yyParser *pParser){
return yymajor;
}
-/*
+/*
** Deallocate and destroy a parser. Destructors are all called for
** all stack elements before shutting the parser down.
**
@@ -604,7 +604,7 @@ void configparserFree(
void (*freeProc)(void*) /* Function used to reclaim memory */
){
yyParser *pParser = (yyParser*)p;
- if( pParser==0 ) return;
+ if( pParser==NULL ) return;
while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
(*freeProc)((void*)pParser);
}
@@ -623,7 +623,7 @@ static int yy_find_shift_action(
){
int i;
int stateno = pParser->yystack[pParser->yyidx].stateno;
-
+
/* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
i = yy_shift_ofst[stateno];
if( i==YY_SHIFT_USE_DFLT ){
@@ -633,7 +633,7 @@ static int yy_find_shift_action(
return YY_NO_ACTION;
}
i += iLookAhead;
- if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
+ if( i<0 || (size_t)i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
#ifdef YYFALLBACK
int iFallback; /* Fallback token */
if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
@@ -667,7 +667,7 @@ static int yy_find_reduce_action(
){
int i;
int stateno = pParser->yystack[pParser->yyidx].stateno;
-
+
i = yy_reduce_ofst[stateno];
if( i==YY_REDUCE_USE_DFLT ){
return yy_default[stateno];
@@ -676,7 +676,7 @@ static int yy_find_reduce_action(
return YY_NO_ACTION;
}
i += iLookAhead;
- if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
+ if( i<0 || (size_t)i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
return yy_default[stateno];
}else{
return yy_action[i];
@@ -731,42 +731,46 @@ static struct {
YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
unsigned char nrhs; /* Number of right-hand side symbols in the rule */
} yyRuleInfo[] = {
- { 26, 1 },
- { 27, 2 },
- { 27, 0 },
- { 28, 1 },
+ { 27, 1 },
{ 28, 2 },
- { 28, 1 },
- { 28, 1 },
- { 28, 1 },
- { 29, 3 },
- { 29, 3 },
+ { 28, 0 },
+ { 29, 1 },
+ { 29, 1 },
+ { 29, 2 },
+ { 29, 1 },
+ { 29, 1 },
+ { 29, 1 },
+ { 30, 3 },
+ { 30, 3 },
+ { 41, 1 },
+ { 36, 3 },
+ { 36, 1 },
+ { 35, 1 },
+ { 35, 1 },
+ { 35, 1 },
+ { 35, 1 },
+ { 40, 2 },
+ { 40, 3 },
+ { 39, 3 },
+ { 39, 2 },
{ 39, 1 },
- { 34, 3 },
- { 34, 1 },
- { 33, 1 },
- { 33, 1 },
- { 33, 1 },
- { 33, 1 },
- { 38, 3 },
- { 37, 3 },
- { 37, 2 },
{ 37, 1 },
- { 35, 1 },
- { 35, 3 },
+ { 37, 3 },
+ { 44, 1 },
+ { 44, 0 },
+ { 45, 1 },
+ { 31, 4 },
+ { 32, 4 },
+ { 32, 1 },
+ { 38, 4 },
+ { 46, 7 },
+ { 43, 1 },
+ { 43, 1 },
+ { 43, 1 },
+ { 43, 1 },
{ 42, 1 },
- { 42, 0 },
- { 30, 4 },
- { 30, 1 },
- { 36, 4 },
- { 43, 7 },
- { 41, 1 },
- { 41, 1 },
- { 41, 1 },
- { 41, 1 },
- { 40, 1 },
- { 31, 2 },
- { 32, 2 },
+ { 33, 2 },
+ { 34, 2 },
};
static void yy_accept(yyParser*); /* Forward Declaration */
@@ -787,8 +791,8 @@ static void yy_reduce(
configparserARG_FETCH;
yymsp = &yypParser->yystack[yypParser->yyidx];
#ifndef NDEBUG
- if( yyTraceFILE && yyruleno>=0
- && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
+ if( yyTraceFILE && yyruleno>=0
+ && (size_t)yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
yyRuleName[yyruleno]);
}
@@ -816,287 +820,359 @@ static void yy_reduce(
/* No destructor defined for varline */
break;
case 4:
-#line 133 "./configparser.y"
-{ yymsp[-1].minor.yy74 = NULL; }
-#line 821 "configparser.c"
- yy_destructor(1,&yymsp[0].minor);
+ /* No destructor defined for global */
break;
case 5:
- /* No destructor defined for include */
+#line 117 "../../src/configparser.y"
+{ yymsp[-1].minor.yy78 = NULL; }
+#line 828 "configparser.c"
+ yy_destructor(1,&yymsp[0].minor);
break;
case 6:
- /* No destructor defined for include_shell */
+ /* No destructor defined for include */
break;
case 7:
- yy_destructor(1,&yymsp[0].minor);
+ /* No destructor defined for include_shell */
break;
case 8:
-#line 161 "./configparser.y"
+ yy_destructor(1,&yymsp[0].minor);
+ break;
+ case 9:
+#line 146 "../../src/configparser.y"
{
- buffer_copy_string_buffer(yymsp[0].minor.yy43->key, yymsp[-2].minor.yy1);
- if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy43->key->ptr)) {
- array_insert_unique(ctx->current->value, yymsp[0].minor.yy43);
- yymsp[0].minor.yy43 = NULL;
- } else {
- fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n",
- ctx->current->context_ndx,
- ctx->current->key->ptr, yymsp[0].minor.yy43->key->ptr);
- ctx->ok = 0;
- yymsp[0].minor.yy43->free(yymsp[0].minor.yy43);
- yymsp[0].minor.yy43 = 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.yy1);
- yymsp[-2].minor.yy1 = NULL;
+ buffer_free(yymsp[-2].minor.yy43);
+ yymsp[-2].minor.yy43 = NULL;
}
-#line 851 "configparser.c"
+#line 865 "configparser.c"
yy_destructor(2,&yymsp[-1].minor);
break;
- case 9:
-#line 178 "./configparser.y"
+ case 10:
+#line 170 "../../src/configparser.y"
{
array *vars = ctx->current->value;
data_unset *du;
- if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy1->ptr))) {
+ if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
+ fprintf(stderr, "Appending 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 != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
/* exists in current block */
- du = configparser_merge_data(du, yymsp[0].minor.yy43);
+ du = configparser_merge_data(du, yymsp[0].minor.yy41);
if (NULL == du) {
ctx->ok = 0;
}
else {
- buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy1);
+ buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
array_replace(vars, du);
}
- } else if (NULL != (du = configparser_get_variable(ctx, yymsp[-2].minor.yy1))) {
- du = configparser_merge_data(du, yymsp[0].minor.yy43);
+ yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
+ } else if (NULL != (du = configparser_get_variable(ctx, yymsp[-2].minor.yy43))) {
+ du = configparser_merge_data(du, yymsp[0].minor.yy41);
if (NULL == du) {
ctx->ok = 0;
}
else {
- buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy1);
+ buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
array_insert_unique(ctx->current->value, du);
}
+ yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
} else {
- fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n",
- ctx->current->context_ndx,
- ctx->current->key->ptr, yymsp[-2].minor.yy1->ptr);
- ctx->ok = 0;
+ buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
+ array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
}
- buffer_free(yymsp[-2].minor.yy1);
- yymsp[-2].minor.yy1 = NULL;
- yymsp[0].minor.yy43->free(yymsp[0].minor.yy43);
- yymsp[0].minor.yy43 = NULL;
+ buffer_free(yymsp[-2].minor.yy43);
+ yymsp[-2].minor.yy43 = NULL;
+ yymsp[0].minor.yy41 = NULL;
}
-#line 890 "configparser.c"
+#line 908 "configparser.c"
yy_destructor(3,&yymsp[-1].minor);
break;
- case 10:
-#line 213 "./configparser.y"
+ case 11:
+#line 209 "../../src/configparser.y"
{
if (strchr(yymsp[0].minor.yy0->ptr, '.') == NULL) {
- yygotominor.yy1 = buffer_init_string("var.");
- buffer_append_string_buffer(yygotominor.yy1, yymsp[0].minor.yy0);
+ yygotominor.yy43 = buffer_init_string("var.");
+ buffer_append_string_buffer(yygotominor.yy43, yymsp[0].minor.yy0);
buffer_free(yymsp[0].minor.yy0);
yymsp[0].minor.yy0 = NULL;
} else {
- yygotominor.yy1 = yymsp[0].minor.yy0;
+ yygotominor.yy43 = yymsp[0].minor.yy0;
yymsp[0].minor.yy0 = NULL;
}
}
-#line 906 "configparser.c"
+#line 924 "configparser.c"
break;
- case 11:
-#line 225 "./configparser.y"
+ case 12:
+#line 221 "../../src/configparser.y"
{
- yygotominor.yy43 = configparser_merge_data(yymsp[-2].minor.yy43, yymsp[0].minor.yy43);
- if (NULL == yygotominor.yy43) {
+ yygotominor.yy41 = configparser_merge_data(yymsp[-2].minor.yy41, yymsp[0].minor.yy41);
+ if (NULL == yygotominor.yy41) {
ctx->ok = 0;
}
- yymsp[-2].minor.yy43 = NULL;
- yymsp[0].minor.yy43->free(yymsp[0].minor.yy43);
- yymsp[0].minor.yy43 = NULL;
+ yymsp[-2].minor.yy41 = NULL;
+ yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
+ yymsp[0].minor.yy41 = NULL;
}
-#line 919 "configparser.c"
+#line 937 "configparser.c"
yy_destructor(5,&yymsp[-1].minor);
break;
- case 12:
-#line 235 "./configparser.y"
+ case 13:
+#line 231 "../../src/configparser.y"
{
- yygotominor.yy43 = yymsp[0].minor.yy43;
- yymsp[0].minor.yy43 = NULL;
+ yygotominor.yy41 = yymsp[0].minor.yy41;
+ yymsp[0].minor.yy41 = NULL;
}
-#line 928 "configparser.c"
+#line 946 "configparser.c"
break;
- case 13:
-#line 240 "./configparser.y"
+ case 14:
+#line 236 "../../src/configparser.y"
{
- yygotominor.yy43 = configparser_get_variable(ctx, yymsp[0].minor.yy1);
- if (!yygotominor.yy43) {
+ yygotominor.yy41 = NULL;
+ if (strncmp(yymsp[0].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
+ char *env;
+
+ if (NULL != (env = getenv(yymsp[0].minor.yy43->ptr + 4))) {
+ data_string *ds;
+ ds = data_string_init();
+ buffer_append_string(ds->value, env);
+ yygotominor.yy41 = (data_unset *)ds;
+ }
+ else {
+ fprintf(stderr, "Undefined env variable: %s\n", yymsp[0].minor.yy43->ptr + 4);
+ ctx->ok = 0;
+ }
+ } else if (NULL == (yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43))) {
+ fprintf(stderr, "Undefined config variable: %s\n", yymsp[0].minor.yy43->ptr);
+ ctx->ok = 0;
+ }
+ if (!yygotominor.yy41) {
/* make a dummy so it won't crash */
- yygotominor.yy43 = (data_unset *)data_string_init();
+ yygotominor.yy41 = (data_unset *)data_string_init();
}
- buffer_free(yymsp[0].minor.yy1);
- yymsp[0].minor.yy1 = NULL;
+ buffer_free(yymsp[0].minor.yy43);
+ yymsp[0].minor.yy43 = NULL;
}
-#line 941 "configparser.c"
+#line 976 "configparser.c"
break;
- case 14:
-#line 250 "./configparser.y"
+ case 15:
+#line 263 "../../src/configparser.y"
{
- yygotominor.yy43 = (data_unset *)data_string_init();
- buffer_copy_string_buffer(((data_string *)(yygotominor.yy43))->value, yymsp[0].minor.yy0);
+ 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 951 "configparser.c"
+#line 986 "configparser.c"
break;
- case 15:
-#line 257 "./configparser.y"
+ case 16:
+#line 270 "../../src/configparser.y"
{
- yygotominor.yy43 = (data_unset *)data_integer_init();
- ((data_integer *)(yygotominor.yy43))->value = strtol(yymsp[0].minor.yy0->ptr, NULL, 10);
+ 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 961 "configparser.c"
+#line 996 "configparser.c"
break;
- case 16:
-#line 263 "./configparser.y"
+ case 17:
+#line 276 "../../src/configparser.y"
{
- yygotominor.yy43 = (data_unset *)data_array_init();
- array_free(((data_array *)(yygotominor.yy43))->value);
- ((data_array *)(yygotominor.yy43))->value = yymsp[0].minor.yy78;
- yymsp[0].minor.yy78 = NULL;
+ 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 971 "configparser.c"
+#line 1006 "configparser.c"
break;
- case 17:
-#line 269 "./configparser.y"
+ case 18:
+#line 282 "../../src/configparser.y"
{
- yygotominor.yy78 = yymsp[-1].minor.yy78;
- yymsp[-1].minor.yy78 = NULL;
+ yygotominor.yy40 = array_init();
}
-#line 979 "configparser.c"
+#line 1013 "configparser.c"
+ yy_destructor(8,&yymsp[-1].minor);
+ yy_destructor(9,&yymsp[0].minor);
+ break;
+ case 19:
+#line 285 "../../src/configparser.y"
+{
+ yygotominor.yy40 = yymsp[-1].minor.yy40;
+ yymsp[-1].minor.yy40 = NULL;
+}
+#line 1023 "configparser.c"
yy_destructor(8,&yymsp[-2].minor);
yy_destructor(9,&yymsp[0].minor);
break;
- case 18:
-#line 274 "./configparser.y"
+ case 20:
+#line 290 "../../src/configparser.y"
{
- if (buffer_is_empty(yymsp[0].minor.yy43->key) ||
- NULL == array_get_element(yymsp[-2].minor.yy78, yymsp[0].minor.yy43->key->ptr)) {
- array_insert_unique(yymsp[-2].minor.yy78, yymsp[0].minor.yy43);
- yymsp[0].minor.yy43 = NULL;
+ if (buffer_is_empty(yymsp[0].minor.yy41->key) ||
+ NULL == array_get_element(yymsp[-2].minor.yy40, yymsp[0].minor.yy41->key->ptr)) {
+ array_insert_unique(yymsp[-2].minor.yy40, yymsp[0].minor.yy41);
+ yymsp[0].minor.yy41 = NULL;
} else {
- fprintf(stderr, "Duplicate array-key: %s\n",
- yymsp[0].minor.yy43->key->ptr);
+ fprintf(stderr, "Duplicate array-key: %s\n",
+ yymsp[0].minor.yy41->key->ptr);
ctx->ok = 0;
- yymsp[0].minor.yy43->free(yymsp[0].minor.yy43);
- yymsp[0].minor.yy43 = NULL;
+ yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
+ yymsp[0].minor.yy41 = NULL;
}
-
- yygotominor.yy78 = yymsp[-2].minor.yy78;
- yymsp[-2].minor.yy78 = NULL;
+
+ yygotominor.yy40 = yymsp[-2].minor.yy40;
+ yymsp[-2].minor.yy40 = NULL;
}
-#line 1001 "configparser.c"
+#line 1045 "configparser.c"
yy_destructor(10,&yymsp[-1].minor);
break;
- case 19:
-#line 291 "./configparser.y"
+ case 21:
+#line 307 "../../src/configparser.y"
{
- yygotominor.yy78 = yymsp[-1].minor.yy78;
- yymsp[-1].minor.yy78 = NULL;
+ yygotominor.yy40 = yymsp[-1].minor.yy40;
+ yymsp[-1].minor.yy40 = NULL;
}
-#line 1010 "configparser.c"
+#line 1054 "configparser.c"
yy_destructor(10,&yymsp[0].minor);
break;
- case 20:
-#line 296 "./configparser.y"
+ case 22:
+#line 312 "../../src/configparser.y"
{
- yygotominor.yy78 = array_init();
- array_insert_unique(yygotominor.yy78, yymsp[0].minor.yy43);
- yymsp[0].minor.yy43 = NULL;
+ yygotominor.yy40 = array_init();
+ array_insert_unique(yygotominor.yy40, yymsp[0].minor.yy41);
+ yymsp[0].minor.yy41 = NULL;
}
-#line 1020 "configparser.c"
+#line 1064 "configparser.c"
break;
- case 21:
-#line 302 "./configparser.y"
+ case 23:
+#line 318 "../../src/configparser.y"
{
- yygotominor.yy43 = yymsp[0].minor.yy43;
- yymsp[0].minor.yy43 = NULL;
+ yygotominor.yy41 = yymsp[0].minor.yy41;
+ yymsp[0].minor.yy41 = NULL;
}
-#line 1028 "configparser.c"
+#line 1072 "configparser.c"
break;
- case 22:
-#line 306 "./configparser.y"
+ case 24:
+#line 322 "../../src/configparser.y"
{
- buffer_copy_string_buffer(yymsp[0].minor.yy43->key, yymsp[-2].minor.yy1);
- buffer_free(yymsp[-2].minor.yy1);
- yymsp[-2].minor.yy1 = NULL;
-
- yygotominor.yy43 = yymsp[0].minor.yy43;
- yymsp[0].minor.yy43 = NULL;
+ buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
+ buffer_free(yymsp[-2].minor.yy43);
+ yymsp[-2].minor.yy43 = NULL;
+
+ yygotominor.yy41 = yymsp[0].minor.yy41;
+ yymsp[0].minor.yy41 = NULL;
}
-#line 1040 "configparser.c"
+#line 1084 "configparser.c"
yy_destructor(11,&yymsp[-1].minor);
break;
- case 23:
+ case 25:
yy_destructor(1,&yymsp[0].minor);
break;
- case 24:
+ case 26:
break;
- case 25:
-#line 318 "./configparser.y"
+ case 27:
+#line 334 "../../src/configparser.y"
{
- assert(yymsp[-3].minor.yy74->context_ndx < yymsp[0].minor.yy74->context_ndx);
- yymsp[0].minor.yy74->prev = yymsp[-3].minor.yy74;
- yymsp[-3].minor.yy74->next = yymsp[0].minor.yy74;
- yygotominor.yy74 = yymsp[0].minor.yy74;
- yymsp[-3].minor.yy74 = NULL;
- yymsp[0].minor.yy74 = NULL;
+ data_config *dc;
+ dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
+ assert(dc);
+ configparser_push(ctx, dc, 0);
}
-#line 1058 "configparser.c"
+#line 1100 "configparser.c"
+ yy_destructor(12,&yymsp[0].minor);
+ break;
+ case 28:
+#line 341 "../../src/configparser.y"
+{
+ data_config *cur;
+
+ cur = ctx->current;
+ configparser_pop(ctx);
+
+ assert(cur && ctx->current);
+
+ yygotominor.yy78 = cur;
+}
+#line 1115 "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 352 "../../src/configparser.y"
+{
+ if (yymsp[-3].minor.yy78->context_ndx >= yymsp[0].minor.yy78->context_ndx) {
+ fprintf(stderr, "unreachable else condition\n");
+ ctx->ok = 0;
+ }
+ yymsp[0].minor.yy78->prev = yymsp[-3].minor.yy78;
+ yymsp[-3].minor.yy78->next = yymsp[0].minor.yy78;
+ yygotominor.yy78 = yymsp[0].minor.yy78;
+ yymsp[-3].minor.yy78 = NULL;
+ yymsp[0].minor.yy78 = NULL;
+}
+#line 1134 "configparser.c"
/* No destructor defined for eols */
- yy_destructor(12,&yymsp[-1].minor);
+ yy_destructor(15,&yymsp[-1].minor);
break;
- case 26:
-#line 327 "./configparser.y"
+ case 30:
+#line 364 "../../src/configparser.y"
{
- yygotominor.yy74 = yymsp[0].minor.yy74;
- yymsp[0].minor.yy74 = NULL;
+ yygotominor.yy78 = yymsp[0].minor.yy78;
+ yymsp[0].minor.yy78 = NULL;
}
-#line 1068 "configparser.c"
+#line 1144 "configparser.c"
break;
- case 27:
-#line 332 "./configparser.y"
+ case 31:
+#line 369 "../../src/configparser.y"
{
data_config *cur;
-
+
cur = ctx->current;
configparser_pop(ctx);
assert(cur && ctx->current);
- yygotominor.yy74 = cur;
+ yygotominor.yy78 = cur;
}
-#line 1082 "configparser.c"
+#line 1158 "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 28:
-#line 343 "./configparser.y"
+ case 32:
+#line 380 "../../src/configparser.y"
{
data_config *dc;
buffer *b, *rvalue, *op;
- if (ctx->ok && yymsp[0].minor.yy43->type != TYPE_STRING) {
+ if (ctx->ok && yymsp[0].minor.yy41->type != TYPE_STRING) {
fprintf(stderr, "rvalue must be string");
ctx->ok = 0;
}
- switch(yymsp[-1].minor.yy29) {
+ switch(yymsp[-1].minor.yy27) {
case CONFIG_COND_NE:
op = buffer_init_string("!=");
break;
@@ -1118,11 +1194,11 @@ static void yy_reduce(
buffer_copy_string_buffer(b, ctx->current->key);
buffer_append_string(b, "/");
buffer_append_string_buffer(b, yymsp[-5].minor.yy0);
- buffer_append_string_buffer(b, yymsp[-3].minor.yy1);
+ buffer_append_string_buffer(b, yymsp[-3].minor.yy43);
buffer_append_string_buffer(b, op);
- rvalue = ((data_string*)yymsp[0].minor.yy43)->value;
+ rvalue = ((data_string*)yymsp[0].minor.yy41)->value;
buffer_append_string_buffer(b, rvalue);
-
+
if (NULL != (dc = (data_config *)array_get_element(ctx->all_configs, b->ptr))) {
configparser_push(ctx, dc, 0);
} else {
@@ -1135,23 +1211,30 @@ 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_LANGUAGE, CONST_STR_LEN("HTTP[\"language\"]" ) },
{ COMP_HTTP_COOKIE, CONST_STR_LEN("HTTP[\"cookie\"]" ) },
- { COMP_HTTP_REMOTEIP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) },
+ { 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;
dc = data_config_init();
-
+
buffer_copy_string_buffer(dc->key, b);
buffer_copy_string_buffer(dc->op, op);
buffer_copy_string_buffer(dc->comp_key, yymsp[-5].minor.yy0);
buffer_append_string_len(dc->comp_key, CONST_STR_LEN("[\""));
- buffer_append_string_buffer(dc->comp_key, yymsp[-3].minor.yy1);
+ buffer_append_string_buffer(dc->comp_key, yymsp[-3].minor.yy43);
buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]"));
- dc->cond = yymsp[-1].minor.yy29;
-
+ dc->cond = yymsp[-1].minor.yy27;
+
for (i = 0; comps[i].comp_key; i ++) {
if (buffer_is_equal_string(
dc->comp_key, comps[i].comp_key, comps[i].len)) {
@@ -1164,7 +1247,7 @@ static void yy_reduce(
ctx->ok = 0;
}
- switch(yymsp[-1].minor.yy29) {
+ switch(yymsp[-1].minor.yy27) {
case CONFIG_COND_NE:
case CONFIG_COND_EQ:
dc->string = buffer_init_buffer(rvalue);
@@ -1173,42 +1256,50 @@ static void yy_reduce(
case CONFIG_COND_MATCH: {
#ifdef HAVE_PCRE_H
const char *errptr;
- int erroff;
-
- if (NULL == (dc->regex =
+ int erroff, captures;
+
+ if (NULL == (dc->regex =
pcre_compile(rvalue->ptr, 0, &errptr, &erroff, NULL))) {
dc->string = buffer_init_string(errptr);
dc->cond = CONFIG_COND_UNSET;
- fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n",
+ fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n",
rvalue->ptr, errptr, erroff);
ctx->ok = 0;
} else if (NULL == (dc->regex_study =
- pcre_study(dc->regex, 0, &errptr)) &&
+ pcre_study(dc->regex, 0, &errptr)) &&
errptr != NULL) {
- fprintf(stderr, "studying regex failed: %s -> %s\n",
+ fprintf(stderr, "studying regex failed: %s -> %s\n",
rvalue->ptr, errptr);
ctx->ok = 0;
+ } else if (0 != (pcre_fullinfo(dc->regex, dc->regex_study, PCRE_INFO_CAPTURECOUNT, &captures))) {
+ fprintf(stderr, "getting capture count for regex failed: %s\n",
+ rvalue->ptr);
+ ctx->ok = 0;
+ } else if (captures > 9) {
+ fprintf(stderr, "Too many captures in regex, use (?:...) instead of (...): %s\n",
+ rvalue->ptr);
+ ctx->ok = 0;
} else {
dc->string = buffer_init_buffer(rvalue);
}
#else
fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n"
- "(perhaps just a missing pcre-devel package ?) \n",
- yymsp[-5].minor.yy0->ptr, yymsp[-3].minor.yy1->ptr);
+ "(perhaps just a missing pcre-devel package ?) \n",
+ yymsp[-5].minor.yy0->ptr, yymsp[-3].minor.yy43->ptr);
ctx->ok = 0;
#endif
break;
}
default:
- fprintf(stderr, "unknown condition for $%s[%s]\n",
- yymsp[-5].minor.yy0->ptr, yymsp[-3].minor.yy1->ptr);
+ fprintf(stderr, "unknown condition for $%s[%s]\n",
+ yymsp[-5].minor.yy0->ptr, yymsp[-3].minor.yy43->ptr);
ctx->ok = 0;
break;
}
-
+
configparser_push(ctx, dc, 1);
}
@@ -1216,95 +1307,95 @@ static void yy_reduce(
buffer_free(op);
buffer_free(yymsp[-5].minor.yy0);
yymsp[-5].minor.yy0 = NULL;
- buffer_free(yymsp[-3].minor.yy1);
- yymsp[-3].minor.yy1 = NULL;
- yymsp[0].minor.yy43->free(yymsp[0].minor.yy43);
- yymsp[0].minor.yy43 = NULL;
+ buffer_free(yymsp[-3].minor.yy43);
+ yymsp[-3].minor.yy43 = NULL;
+ yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
+ yymsp[0].minor.yy41 = NULL;
}
-#line 1224 "configparser.c"
- yy_destructor(15,&yymsp[-6].minor);
- yy_destructor(17,&yymsp[-4].minor);
- yy_destructor(18,&yymsp[-2].minor);
+#line 1315 "configparser.c"
+ yy_destructor(16,&yymsp[-6].minor);
+ yy_destructor(18,&yymsp[-4].minor);
+ yy_destructor(19,&yymsp[-2].minor);
break;
- case 29:
-#line 477 "./configparser.y"
-{
- yygotominor.yy29 = CONFIG_COND_EQ;
-}
-#line 1234 "configparser.c"
- yy_destructor(19,&yymsp[0].minor);
- break;
- case 30:
-#line 480 "./configparser.y"
+ case 33:
+#line 529 "../../src/configparser.y"
{
- yygotominor.yy29 = CONFIG_COND_MATCH;
+ yygotominor.yy27 = CONFIG_COND_EQ;
}
-#line 1242 "configparser.c"
+#line 1325 "configparser.c"
yy_destructor(20,&yymsp[0].minor);
break;
- case 31:
-#line 483 "./configparser.y"
+ case 34:
+#line 532 "../../src/configparser.y"
{
- yygotominor.yy29 = CONFIG_COND_NE;
+ yygotominor.yy27 = CONFIG_COND_MATCH;
}
-#line 1250 "configparser.c"
+#line 1333 "configparser.c"
yy_destructor(21,&yymsp[0].minor);
break;
- case 32:
-#line 486 "./configparser.y"
+ case 35:
+#line 535 "../../src/configparser.y"
{
- yygotominor.yy29 = CONFIG_COND_NOMATCH;
+ yygotominor.yy27 = CONFIG_COND_NE;
}
-#line 1258 "configparser.c"
+#line 1341 "configparser.c"
yy_destructor(22,&yymsp[0].minor);
break;
- case 33:
-#line 490 "./configparser.y"
+ case 36:
+#line 538 "../../src/configparser.y"
+{
+ yygotominor.yy27 = CONFIG_COND_NOMATCH;
+}
+#line 1349 "configparser.c"
+ yy_destructor(23,&yymsp[0].minor);
+ break;
+ case 37:
+#line 542 "../../src/configparser.y"
{
- yygotominor.yy1 = NULL;
+ yygotominor.yy43 = NULL;
if (ctx->ok) {
- if (yymsp[0].minor.yy43->type == TYPE_STRING) {
- yygotominor.yy1 = buffer_init_buffer(((data_string*)yymsp[0].minor.yy43)->value);
- } else if (yymsp[0].minor.yy43->type == TYPE_INTEGER) {
- yygotominor.yy1 = buffer_init();
- buffer_copy_long(yygotominor.yy1, ((data_integer *)yymsp[0].minor.yy43)->value);
+ if (yymsp[0].minor.yy41->type == TYPE_STRING) {
+ yygotominor.yy43 = buffer_init_buffer(((data_string*)yymsp[0].minor.yy41)->value);
+ } else if (yymsp[0].minor.yy41->type == TYPE_INTEGER) {
+ yygotominor.yy43 = buffer_init();
+ buffer_copy_long(yygotominor.yy43, ((data_integer *)yymsp[0].minor.yy41)->value);
} else {
fprintf(stderr, "operand must be string");
ctx->ok = 0;
}
}
- yymsp[0].minor.yy43->free(yymsp[0].minor.yy43);
- yymsp[0].minor.yy43 = NULL;
+ yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
+ yymsp[0].minor.yy41 = NULL;
}
-#line 1279 "configparser.c"
+#line 1370 "configparser.c"
break;
- case 34:
-#line 507 "./configparser.y"
+ case 38:
+#line 559 "../../src/configparser.y"
{
if (ctx->ok) {
- if (0 != config_parse_file(ctx->srv, ctx, yymsp[0].minor.yy1->ptr)) {
+ if (0 != config_parse_file(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
ctx->ok = 0;
}
- buffer_free(yymsp[0].minor.yy1);
- yymsp[0].minor.yy1 = NULL;
+ buffer_free(yymsp[0].minor.yy43);
+ yymsp[0].minor.yy43 = NULL;
}
}
-#line 1292 "configparser.c"
- yy_destructor(23,&yymsp[-1].minor);
+#line 1383 "configparser.c"
+ yy_destructor(24,&yymsp[-1].minor);
break;
- case 35:
-#line 517 "./configparser.y"
+ case 39:
+#line 569 "../../src/configparser.y"
{
if (ctx->ok) {
- if (0 != config_parse_cmd(ctx->srv, ctx, yymsp[0].minor.yy1->ptr)) {
+ if (0 != config_parse_cmd(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
ctx->ok = 0;
}
- buffer_free(yymsp[0].minor.yy1);
- yymsp[0].minor.yy1 = NULL;
+ buffer_free(yymsp[0].minor.yy43);
+ yymsp[0].minor.yy43 = NULL;
}
}
-#line 1306 "configparser.c"
- yy_destructor(24,&yymsp[-1].minor);
+#line 1397 "configparser.c"
+ yy_destructor(25,&yymsp[-1].minor);
break;
};
yygoto = yyRuleInfo[yyruleno].lhs;
@@ -1333,11 +1424,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 125 "./configparser.y"
+#line 108 "../../src/configparser.y"
ctx->ok = 0;
-#line 1340 "configparser.c"
+#line 1431 "configparser.c"
configparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
@@ -1350,6 +1441,8 @@ static void yy_syntax_error(
YYMINORTYPE yyminor /* The minor type of the error token */
){
configparserARG_FETCH;
+ UNUSED(yymajor);
+ UNUSED(yyminor);
#define TOKEN (yyminor.yy0)
configparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
@@ -1444,7 +1537,7 @@ void configparser(
#ifdef YYERRORSYMBOL
/* A syntax error has occurred.
** The response to an error depends upon whether or not the
- ** grammar defines an error token "ERROR".
+ ** grammar defines an error token "ERROR".
**
** This is what we do if the grammar does define ERROR:
**
diff --git a/src/configparser.h b/src/configparser.h
index 9490e58..1610621 100644
--- a/src/configparser.h
+++ b/src/configparser.h
@@ -9,16 +9,17 @@
#define TK_RPARAN 9
#define TK_COMMA 10
#define TK_ARRAY_ASSIGN 11
-#define TK_ELSE 12
+#define TK_GLOBAL 12
#define TK_LCURLY 13
#define TK_RCURLY 14
-#define TK_DOLLAR 15
-#define TK_SRVVARNAME 16
-#define TK_LBRACKET 17
-#define TK_RBRACKET 18
-#define TK_EQ 19
-#define TK_MATCH 20
-#define TK_NE 21
-#define TK_NOMATCH 22
-#define TK_INCLUDE 23
-#define TK_INCLUDE_SHELL 24
+#define TK_ELSE 15
+#define TK_DOLLAR 16
+#define TK_SRVVARNAME 17
+#define TK_LBRACKET 18
+#define TK_RBRACKET 19
+#define TK_EQ 20
+#define TK_MATCH 21
+#define TK_NE 22
+#define TK_NOMATCH 23
+#define TK_INCLUDE 24
+#define TK_INCLUDE_SHELL 25
diff --git a/src/configparser.y b/src/configparser.y
index 767024f..aa6fe98 100644
--- a/src/configparser.y
+++ b/src/configparser.y
@@ -3,16 +3,14 @@
%name configparser
%include {
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
#include "configfile.h"
#include "buffer.h"
#include "array.h"
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
static void configparser_push(config_t *ctx, data_config *dc, int isnew) {
if (isnew) {
dc->context_ndx = ctx->all_configs->used;
@@ -21,6 +19,10 @@ static void configparser_push(config_t *ctx, data_config *dc, int isnew) {
dc->parent = ctx->current;
array_insert_unique(dc->parent->childs, (data_unset *)dc);
}
+ if (ctx->configs_stack->used > 0 && ctx->current->context_ndx == 0) {
+ fprintf(stderr, "Cannot use conditionals inside a global { ... } block\n");
+ exit(-1);
+ }
array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
ctx->current = dc;
}
@@ -33,43 +35,25 @@ static data_config *configparser_pop(config_t *ctx) {
/* return a copied variable */
static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
- if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
- char *env;
-
- if (NULL != (env = getenv(key->ptr + 4))) {
- data_string *ds;
- ds = data_string_init();
- buffer_append_string(ds->value, env);
- return (data_unset *)ds;
- }
-
- fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
- ctx->ok = 0;
-
- return NULL;
- } else {
- data_unset *du;
- data_config *dc;
+ data_unset *du;
+ data_config *dc;
#if 0
- fprintf(stderr, "get var %s\n", key->ptr);
+ fprintf(stderr, "get var %s\n", key->ptr);
#endif
- for (dc = ctx->current; dc; dc = dc->parent) {
+ for (dc = ctx->current; dc; dc = dc->parent) {
#if 0
- fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
- array_print(dc->value, 0);
+ fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
+ array_print(dc->value, 0);
#endif
- if (NULL != (du = array_get_element(dc->value, key->ptr))) {
- return du->copy(du);
- }
+ if (NULL != (du = array_get_element(dc->value, key->ptr))) {
+ return du->copy(du);
}
- fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
- ctx->ok = 0;
- return NULL;
}
+ 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) {
@@ -86,8 +70,7 @@ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
op1->free(op1);
return (data_unset *)ds;
} else {
- fprintf(stderr, "data type mismatch, cannot be merge\n");
- op1->free(op1);
+ fprintf(stderr, "data type mismatch, cannot merge\n");
return NULL;
}
}
@@ -130,6 +113,7 @@ input ::= metalines.
metalines ::= metalines metaline.
metalines ::= .
metaline ::= varline.
+metaline ::= global.
metaline ::= condlines(A) EOL. { A = NULL; }
metaline ::= include.
metaline ::= include_shell.
@@ -140,6 +124,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 *}
@@ -159,17 +144,24 @@ metaline ::= EOL.
%token_destructor { buffer_free($$); }
varline ::= key(A) ASSIGN expression(B). {
- buffer_copy_string_buffer(B->key, A);
- 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;
@@ -179,7 +171,12 @@ varline ::= key(A) APPEND expression(B). {
array *vars = ctx->current->value;
data_unset *du;
- if (NULL != (du = array_get_element(vars, A->ptr))) {
+ if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
+ fprintf(stderr, "Appending 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 != (du = array_get_element(vars, A->ptr))) {
/* exists in current block */
du = configparser_merge_data(du, B);
if (NULL == du) {
@@ -189,6 +186,7 @@ varline ::= key(A) APPEND expression(B). {
buffer_copy_string_buffer(du->key, A);
array_replace(vars, du);
}
+ B->free(B);
} else if (NULL != (du = configparser_get_variable(ctx, A))) {
du = configparser_merge_data(du, B);
if (NULL == du) {
@@ -198,15 +196,13 @@ varline ::= key(A) APPEND expression(B). {
buffer_copy_string_buffer(du->key, A);
array_insert_unique(ctx->current->value, du);
}
+ B->free(B);
} else {
- fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n",
- ctx->current->context_ndx,
- ctx->current->key->ptr, A->ptr);
- ctx->ok = 0;
+ buffer_copy_string_buffer(B->key, A);
+ array_insert_unique(ctx->current->value, B);
}
buffer_free(A);
A = NULL;
- B->free(B);
B = NULL;
}
@@ -238,7 +234,24 @@ expression(A) ::= value(B). {
}
value(A) ::= key(B). {
- A = configparser_get_variable(ctx, B);
+ A = NULL;
+ if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) {
+ char *env;
+
+ if (NULL != (env = getenv(B->ptr + 4))) {
+ data_string *ds;
+ ds = data_string_init();
+ buffer_append_string(ds->value, env);
+ A = (data_unset *)ds;
+ }
+ else {
+ fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4);
+ ctx->ok = 0;
+ }
+ } else if (NULL == (A = configparser_get_variable(ctx, B))) {
+ fprintf(stderr, "Undefined config variable: %s\n", B->ptr);
+ ctx->ok = 0;
+ }
if (!A) {
/* make a dummy so it won't crash */
A = (data_unset *)data_string_init();
@@ -266,6 +279,9 @@ value(A) ::= array(B). {
((data_array *)(A))->value = B;
B = NULL;
}
+array(A) ::= LPARAN RPARAN. {
+ A = array_init();
+}
array(A) ::= LPARAN aelements(B) RPARAN. {
A = B;
B = NULL;
@@ -277,13 +293,13 @@ aelements(A) ::= aelements(C) COMMA aelement(B). {
array_insert_unique(C, B);
B = NULL;
} else {
- fprintf(stderr, "Duplicate array-key: %s\n",
+ fprintf(stderr, "Duplicate array-key: %s\n",
B->key->ptr);
ctx->ok = 0;
B->free(B);
B = NULL;
}
-
+
A = C;
C = NULL;
}
@@ -307,7 +323,7 @@ aelement(A) ::= stringop(B) ARRAY_ASSIGN expression(C). {
buffer_copy_string_buffer(C->key, B);
buffer_free(B);
B = NULL;
-
+
A = C;
C = NULL;
}
@@ -315,8 +331,29 @@ aelement(A) ::= stringop(B) ARRAY_ASSIGN expression(C). {
eols ::= EOL.
eols ::= .
+globalstart ::= GLOBAL. {
+ data_config *dc;
+ dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
+ assert(dc);
+ configparser_push(ctx, dc, 0);
+}
+
+global(A) ::= globalstart LCURLY metalines RCURLY. {
+ data_config *cur;
+
+ cur = ctx->current;
+ configparser_pop(ctx);
+
+ assert(cur && ctx->current);
+
+ A = cur;
+}
+
condlines(A) ::= condlines(B) eols ELSE condline(C). {
- assert(B->context_ndx < C->context_ndx);
+ if (B->context_ndx >= C->context_ndx) {
+ fprintf(stderr, "unreachable else condition\n");
+ ctx->ok = 0;
+ }
C->prev = B;
B->next = C;
A = C;
@@ -331,7 +368,7 @@ condlines(A) ::= condline(B). {
condline(A) ::= context LCURLY metalines RCURLY. {
data_config *cur;
-
+
cur = ctx->current;
configparser_pop(ctx);
@@ -375,7 +412,7 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio
buffer_append_string_buffer(b, op);
rvalue = ((data_string*)D)->value;
buffer_append_string_buffer(b, rvalue);
-
+
if (NULL != (dc = (data_config *)array_get_element(ctx->all_configs, b->ptr))) {
configparser_push(ctx, dc, 0);
} else {
@@ -388,15 +425,22 @@ 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_LANGUAGE, CONST_STR_LEN("HTTP[\"language\"]" ) },
{ COMP_HTTP_COOKIE, CONST_STR_LEN("HTTP[\"cookie\"]" ) },
- { COMP_HTTP_REMOTEIP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) },
+ { 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;
dc = data_config_init();
-
+
buffer_copy_string_buffer(dc->key, b);
buffer_copy_string_buffer(dc->op, op);
buffer_copy_string_buffer(dc->comp_key, B);
@@ -404,7 +448,7 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio
buffer_append_string_buffer(dc->comp_key, C);
buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]"));
dc->cond = E;
-
+
for (i = 0; comps[i].comp_key; i ++) {
if (buffer_is_equal_string(
dc->comp_key, comps[i].comp_key, comps[i].len)) {
@@ -426,29 +470,37 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio
case CONFIG_COND_MATCH: {
#ifdef HAVE_PCRE_H
const char *errptr;
- int erroff;
-
- if (NULL == (dc->regex =
+ int erroff, captures;
+
+ if (NULL == (dc->regex =
pcre_compile(rvalue->ptr, 0, &errptr, &erroff, NULL))) {
dc->string = buffer_init_string(errptr);
dc->cond = CONFIG_COND_UNSET;
- fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n",
+ fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n",
rvalue->ptr, errptr, erroff);
ctx->ok = 0;
} else if (NULL == (dc->regex_study =
- pcre_study(dc->regex, 0, &errptr)) &&
+ pcre_study(dc->regex, 0, &errptr)) &&
errptr != NULL) {
- fprintf(stderr, "studying regex failed: %s -> %s\n",
+ fprintf(stderr, "studying regex failed: %s -> %s\n",
rvalue->ptr, errptr);
ctx->ok = 0;
+ } else if (0 != (pcre_fullinfo(dc->regex, dc->regex_study, PCRE_INFO_CAPTURECOUNT, &captures))) {
+ fprintf(stderr, "getting capture count for regex failed: %s\n",
+ rvalue->ptr);
+ ctx->ok = 0;
+ } else if (captures > 9) {
+ fprintf(stderr, "Too many captures in regex, use (?:...) instead of (...): %s\n",
+ rvalue->ptr);
+ ctx->ok = 0;
} else {
dc->string = buffer_init_buffer(rvalue);
}
#else
fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n"
- "(perhaps just a missing pcre-devel package ?) \n",
+ "(perhaps just a missing pcre-devel package ?) \n",
B->ptr, C->ptr);
ctx->ok = 0;
#endif
@@ -456,12 +508,12 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio
}
default:
- fprintf(stderr, "unknown condition for $%s[%s]\n",
+ fprintf(stderr, "unknown condition for $%s[%s]\n",
B->ptr, C->ptr);
ctx->ok = 0;
break;
}
-
+
configparser_push(ctx, dc, 1);
}
diff --git a/src/connections-glue.c b/src/connections-glue.c
index ac6d267..5ef7a1e 100644
--- a/src/connections-glue.c
+++ b/src/connections-glue.c
@@ -1,4 +1,5 @@
#include "base.h"
+#include "connections.h"
const char *connection_get_state(connection_state_t state) {
switch (state) {
@@ -13,7 +14,7 @@ const char *connection_get_state(connection_state_t state) {
case CON_STATE_REQUEST_END: return "req-end";
case CON_STATE_RESPONSE_START: return "resp-start";
case CON_STATE_RESPONSE_END: return "resp-end";
- default: return "(unknown)";
+ default: return "(unknown)";
}
}
@@ -30,15 +31,15 @@ const char *connection_get_short_state(connection_state_t state) {
case CON_STATE_REQUEST_END: return "Q";
case CON_STATE_RESPONSE_START: return "s";
case CON_STATE_RESPONSE_END: return "S";
- default: return "x";
+ default: return "x";
}
}
int connection_set_state(server *srv, connection *con, connection_state_t state) {
UNUSED(srv);
-
+
con->state = state;
-
+
return 0;
}
diff --git a/src/connections.c b/src/connections.c
index ea3a66c..48ca60f 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -1,13 +1,3 @@
-#include <sys/stat.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <fcntl.h>
-#include <assert.h>
-
#include "buffer.h"
#include "server.h"
#include "log.h"
@@ -25,9 +15,19 @@
#include "inet_ntop_cache.h"
+#include <sys/stat.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <assert.h>
+
#ifdef USE_OPENSSL
-# include <openssl/ssl.h>
-# include <openssl/err.h>
+# include <openssl/ssl.h>
+# include <openssl/err.h>
#endif
#ifdef HAVE_SYS_FILIO_H
@@ -43,7 +43,7 @@ typedef struct {
static connection *connections_get_new_connection(server *srv) {
connections *conns = srv->conns;
size_t i;
-
+
if (conns->size == 0) {
conns->size = 128;
conns->ptr = NULL;
@@ -54,21 +54,21 @@ static connection *connections_get_new_connection(server *srv) {
} else if (conns->size == conns->used) {
conns->size += 128;
conns->ptr = realloc(conns->ptr, sizeof(*conns->ptr) * conns->size);
-
+
for (i = conns->used; i < conns->size; i++) {
conns->ptr[i] = connection_init(srv);
}
}
connection_reset(srv, conns->ptr[conns->used]);
-#if 0
+#if 0
fprintf(stderr, "%s.%d: add: ", __FILE__, __LINE__);
for (i = 0; i < conns->used + 1; i++) {
fprintf(stderr, "%d ", conns->ptr[i]->fd);
}
fprintf(stderr, "\n");
-#endif
-
+#endif
+
conns->ptr[conns->used]->ndx = conns->used;
return conns->ptr[conns->used++];
}
@@ -77,26 +77,31 @@ static int connection_del(server *srv, connection *con) {
size_t i;
connections *conns = srv->conns;
connection *temp;
-
+
if (con == NULL) return -1;
-
+
if (-1 == con->ndx) return -1;
-
+
+ buffer_reset(con->uri.authority);
+ buffer_reset(con->uri.path);
+ buffer_reset(con->uri.query);
+ buffer_reset(con->request.orig_uri);
+
i = con->ndx;
-
+
/* not last element */
-
+
if (i != conns->used - 1) {
temp = conns->ptr[i];
conns->ptr[i] = conns->ptr[conns->used - 1];
conns->ptr[conns->used - 1] = temp;
-
+
conns->ptr[i]->ndx = i;
conns->ptr[conns->used - 1]->ndx = -1;
}
-
+
conns->used--;
-
+
con->ndx = -1;
#if 0
fprintf(stderr, "%s.%d: del: (%d)", __FILE__, __LINE__, conns->used);
@@ -104,7 +109,7 @@ static int connection_del(server *srv, connection *con) {
fprintf(stderr, "%d ", conns->ptr[i]->fd);
}
fprintf(stderr, "\n");
-#endif
+#endif
return 0;
}
@@ -112,14 +117,14 @@ int connection_close(server *srv, connection *con) {
#ifdef USE_OPENSSL
server_socket *srv_sock = con->srv_socket;
#endif
-
+
#ifdef USE_OPENSSL
if (srv_sock->is_ssl) {
if (con->ssl) SSL_free(con->ssl);
con->ssl = NULL;
}
#endif
-
+
fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
fdevent_unregister(srv->ev, con->fd);
#ifdef __WIN32
@@ -133,184 +138,254 @@ int connection_close(server *srv, connection *con) {
"(warning) close:", con->fd, strerror(errno));
}
#endif
-
+
srv->cur_fds--;
#if 0
log_error_write(srv, __FILE__, __LINE__, "sd",
"closed()", con->fd);
#endif
-
+
connection_del(srv, con);
connection_set_state(srv, con, CON_STATE_CONNECT);
-
+
return 0;
}
#if 0
static void dump_packet(const unsigned char *data, size_t len) {
size_t i, j;
-
+
if (len == 0) return;
-
+
for (i = 0; i < len; i++) {
if (i % 16 == 0) fprintf(stderr, " ");
-
+
fprintf(stderr, "%02x ", data[i]);
-
+
if ((i + 1) % 16 == 0) {
fprintf(stderr, " ");
for (j = 0; j <= i % 16; j++) {
unsigned char c;
-
+
if (i-15+j >= len) break;
-
+
c = data[i-15+j];
-
+
fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
}
-
+
fprintf(stderr, "\n");
}
}
-
+
if (len % 16 != 0) {
for (j = i % 16; j < 16; j++) {
fprintf(stderr, " ");
}
-
+
fprintf(stderr, " ");
for (j = i & ~0xf; j < len; j++) {
unsigned char c;
-
+
c = data[j];
fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
}
fprintf(stderr, "\n");
}
}
-#endif
+#endif
-static int connection_handle_read(server *srv, connection *con) {
- int len;
- buffer *b;
- int toread;
+static int connection_handle_read_ssl(server *srv, connection *con) {
#ifdef USE_OPENSSL
- server_socket *srv_sock = con->srv_socket;
-#endif
+ int r, ssl_err, len, count = 0, read_offset, toread;
+ buffer *b = NULL;
- b = chunkqueue_get_append_buffer(con->read_queue);
- buffer_prepare_copy(b, 4096);
+ if (!con->conf.is_ssl) return -1;
-#ifdef USE_OPENSSL
- if (srv_sock->is_ssl) {
- len = SSL_read(con->ssl, b->ptr, b->size - 1);
- } else {
- if (ioctl(con->fd, FIONREAD, &toread)) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "unexpected end-of-file:",
- con->fd);
+ ERR_clear_error();
+ do {
+ if (NULL != con->read_queue->last) {
+ b = con->read_queue->last->mem;
+ }
+
+ if (NULL == b || b->size - b->used < 1024) {
+ b = chunkqueue_get_append_buffer(con->read_queue);
+ len = SSL_pending(con->ssl);
+ if (len < 4*1024) len = 4*1024; /* always alloc >= 4k buffer */
+ buffer_prepare_copy(b, len + 1);
+
+ /* overwrite everything with 0 */
+ memset(b->ptr, 0, b->size);
+ }
+
+ read_offset = (b->used > 0) ? b->used - 1 : 0;
+ toread = b->size - 1 - read_offset;
+
+ len = SSL_read(con->ssl, b->ptr + read_offset, toread);
+
+ if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) {
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client");
return -1;
}
- buffer_prepare_copy(b, toread);
- len = read(con->fd, b->ptr, b->size - 1);
- }
-#elif defined(__WIN32)
- len = recv(con->fd, b->ptr, b->size - 1, 0);
-#else
- if (ioctl(con->fd, FIONREAD, &toread)) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "unexpected end-of-file:",
- con->fd);
- return -1;
- }
- buffer_prepare_copy(b, toread);
+ if (len > 0) {
+ if (b->used > 0) b->used--;
+ b->used += len;
+ b->ptr[b->used++] = '\0';
+
+ con->bytes_read += len;
+
+ count += len;
+ }
+ } while (len == toread && count < MAX_READ_LIMIT);
+
- len = read(con->fd, b->ptr, b->size - 1);
-#endif
-
if (len < 0) {
- con->is_readable = 0;
-
-#ifdef USE_OPENSSL
- if (srv_sock->is_ssl) {
- int r, ssl_err;
-
- switch ((r = SSL_get_error(con->ssl, len))) {
- case SSL_ERROR_WANT_READ:
- return 0;
- case SSL_ERROR_SYSCALL:
- /**
- * man SSL_get_error()
- *
- * SSL_ERROR_SYSCALL
- * Some I/O error occurred. The OpenSSL error queue may contain more
- * information on the error. If the error queue is empty (i.e.
- * ERR_get_error() returns 0), ret can be used to find out more about
- * the error: If ret == 0, an EOF was observed that violates the
- * protocol. If ret == -1, the underlying BIO reported an I/O error
- * (for socket I/O on Unix systems, consult errno for details).
- *
- */
- while((ssl_err = ERR_get_error())) {
- /* get all errors from the error-queue */
- log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
- r, ERR_error_string(ssl_err, NULL));
- }
+ int oerrno = errno;
+ switch ((r = SSL_get_error(con->ssl, len))) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ con->is_readable = 0;
+
+ /* the manual says we have to call SSL_read with the same arguments next time.
+ * we ignore this restriction; no one has complained about it in 1.5 yet, so it probably works anyway.
+ */
- switch(errno) {
- default:
- log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
- len, r, errno,
- strerror(errno));
- break;
- }
-
- break;
- case SSL_ERROR_ZERO_RETURN:
- /* clean shutdown on the remote side */
-
- if (r == 0) {
- /* FIXME: later */
- }
-
- /* fall thourgh */
+ return 0;
+ case SSL_ERROR_SYSCALL:
+ /**
+ * man SSL_get_error()
+ *
+ * SSL_ERROR_SYSCALL
+ * Some I/O error occurred. The OpenSSL error queue may contain more
+ * information on the error. If the error queue is empty (i.e.
+ * ERR_get_error() returns 0), ret can be used to find out more about
+ * the error: If ret == 0, an EOF was observed that violates the
+ * protocol. If ret == -1, the underlying BIO reported an I/O error
+ * (for socket I/O on Unix systems, consult errno for details).
+ *
+ */
+ while((ssl_err = ERR_get_error())) {
+ /* get all errors from the error-queue */
+ log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
+ r, ERR_error_string(ssl_err, NULL));
+ }
+
+ switch(oerrno) {
default:
- while((ssl_err = ERR_get_error())) {
- /* get all errors from the error-queue */
- log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
- r, ERR_error_string(ssl_err, NULL));
- }
+ log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
+ len, r, oerrno,
+ strerror(oerrno));
break;
}
- } else {
- if (errno == EAGAIN) return 0;
- if (errno == EINTR) {
- /* we have been interrupted before we could read */
- con->is_readable = 1;
- return 0;
+
+ break;
+ case SSL_ERROR_ZERO_RETURN:
+ /* clean shutdown on the remote side */
+
+ if (r == 0) {
+ /* FIXME: later */
}
-
- if (errno != ECONNRESET) {
- /* expected for keep-alive */
- log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
+
+ /* fall thourgh */
+ default:
+ while((ssl_err = ERR_get_error())) {
+ switch (ERR_GET_REASON(ssl_err)) {
+ case SSL_R_SSL_HANDSHAKE_FAILURE:
+ case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
+ case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:
+ case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
+ if (!con->conf.log_ssl_noise) continue;
+ break;
+ default:
+ break;
+ }
+ /* get all errors from the error-queue */
+ log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
+ r, ERR_error_string(ssl_err, NULL));
}
+ break;
}
+
+ connection_set_state(srv, con, CON_STATE_ERROR);
+
+ return -1;
+ } else if (len == 0) {
+ con->is_readable = 0;
+ /* the other end close the connection -> KEEP-ALIVE */
+
+ return -2;
+ } else {
+ joblist_append(srv, con);
+ }
+
+ return 0;
#else
+ UNUSED(srv);
+ UNUSED(con);
+ return -1;
+#endif
+}
+
+/* 0: everything ok, -1: error, -2: con closed */
+static int connection_handle_read(server *srv, connection *con) {
+ int len;
+ buffer *b;
+ int toread, read_offset;
+
+ if (con->conf.is_ssl) {
+ return connection_handle_read_ssl(srv, con);
+ }
+
+ b = (NULL != con->read_queue->last) ? con->read_queue->last->mem : NULL;
+
+ /* default size for chunks is 4kb; only use bigger chunks if FIONREAD tells
+ * us more than 4kb is available
+ * if FIONREAD doesn't signal a big chunk we fill the previous buffer
+ * if it has >= 1kb free
+ */
+#if defined(__WIN32)
+ if (NULL == b || b->size - b->used < 1024) {
+ b = chunkqueue_get_append_buffer(con->read_queue);
+ buffer_prepare_copy(b, 4 * 1024);
+ }
+
+ read_offset = (b->used == 0) ? 0 : b->used - 1;
+ len = recv(con->fd, b->ptr + read_offset, b->size - 1 - read_offset, 0);
+#else
+ if (ioctl(con->fd, FIONREAD, &toread) || toread == 0 || toread <= 4*1024) {
+ if (NULL == b || b->size - b->used < 1024) {
+ b = chunkqueue_get_append_buffer(con->read_queue);
+ buffer_prepare_copy(b, 4 * 1024);
+ }
+ } else {
+ if (toread > MAX_READ_LIMIT) toread = MAX_READ_LIMIT;
+ b = chunkqueue_get_append_buffer(con->read_queue);
+ buffer_prepare_copy(b, toread + 1);
+ }
+
+ read_offset = (b->used == 0) ? 0 : b->used - 1;
+ len = read(con->fd, b->ptr + read_offset, b->size - 1 - read_offset);
+#endif
+
+ if (len < 0) {
+ con->is_readable = 0;
+
if (errno == EAGAIN) return 0;
if (errno == EINTR) {
/* we have been interrupted before we could read */
con->is_readable = 1;
return 0;
}
-
+
if (errno != ECONNRESET) {
/* expected for keep-alive */
log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
}
-#endif
+
connection_set_state(srv, con, CON_STATE_ERROR);
-
+
return -1;
} else if (len == 0) {
con->is_readable = 0;
@@ -321,18 +396,19 @@ static int connection_handle_read(server *srv, connection *con) {
return -2;
} else if ((size_t)len < b->size - 1) {
/* we got less then expected, wait for the next fd-event */
-
+
con->is_readable = 0;
}
-
- b->used = len;
+
+ if (b->used > 0) b->used--;
+ b->used += len;
b->ptr[b->used++] = '\0';
-
+
con->bytes_read += len;
#if 0
dump_packet(b->ptr, len);
#endif
-
+
return 0;
}
@@ -344,23 +420,29 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
case HTTP_METHOD_POST:
case HTTP_METHOD_HEAD:
case HTTP_METHOD_PUT:
+ case HTTP_METHOD_PATCH:
case HTTP_METHOD_MKCOL:
case HTTP_METHOD_DELETE:
case HTTP_METHOD_COPY:
case HTTP_METHOD_MOVE:
case HTTP_METHOD_PROPFIND:
case HTTP_METHOD_PROPPATCH:
+ case HTTP_METHOD_LOCK:
+ case HTTP_METHOD_UNLOCK:
break;
case HTTP_METHOD_OPTIONS:
/*
* 400 is coming from the request-parser BEFORE uri.path is set
- * 403 is from the response handler when noone else catched it
- *
+ * 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;
@@ -370,6 +452,7 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
default:
switch(con->http_status) {
case 400: /* bad request */
+ case 401: /* authorization required */
case 414: /* overload request header */
case 505: /* unknown protocol */
case 207: /* this was webdav */
@@ -381,152 +464,170 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
break;
}
}
-
+
if (con->http_status == 0) {
con->http_status = 403;
}
-
+
switch(con->http_status) {
- case 400: /* class: header + custom body */
- case 401:
- case 403:
- case 404:
- case 408:
- case 411:
- case 416:
- case 500:
- case 501:
- case 503:
- case 505:
+ case 204: /* class: header only */
+ case 205:
+ case 304:
+ /* 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;
+ default: /* class: header + body */
if (con->mode != DIRECT) break;
-
+
+ /* only custom body for 4xx and 5xx */
+ if (con->http_status < 400 || con->http_status >= 600) break;
+
con->file_finished = 0;
-
+
buffer_reset(con->physical.path);
-
+
/* try to send static errorfile */
if (!buffer_is_empty(con->conf.errorfile_prefix)) {
stat_cache_entry *sce = NULL;
-
+
buffer_copy_string_buffer(con->physical.path, con->conf.errorfile_prefix);
- buffer_append_string(con->physical.path, get_http_status_body_name(con->http_status));
-
+ buffer_append_long(con->physical.path, con->http_status);
+ buffer_append_string_len(con->physical.path, CONST_STR_LEN(".html"));
+
if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
con->file_finished = 1;
-
+
http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
}
}
-
- if (!con->file_finished) {
+
+ if (!con->file_finished) {
buffer *b;
-
+
buffer_reset(con->physical.path);
-
+
con->file_finished = 1;
b = chunkqueue_get_append_buffer(con->write_queue);
-
+
/* build default error-page */
- buffer_copy_string(b,
+ buffer_copy_string_len(b, CONST_STR_LEN(
"<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
"<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
" <head>\n"
- " <title>");
+ " <title>"));
buffer_append_long(b, con->http_status);
- buffer_append_string(b, " - ");
+ buffer_append_string_len(b, CONST_STR_LEN(" - "));
buffer_append_string(b, get_http_status_name(con->http_status));
-
- buffer_append_string(b,
+
+ buffer_append_string_len(b, CONST_STR_LEN(
"</title>\n"
" </head>\n"
" <body>\n"
- " <h1>");
+ " <h1>"));
buffer_append_long(b, con->http_status);
- buffer_append_string(b, " - ");
+ buffer_append_string_len(b, CONST_STR_LEN(" - "));
buffer_append_string(b, get_http_status_name(con->http_status));
-
- buffer_append_string(b,"</h1>\n"
+
+ buffer_append_string_len(b, CONST_STR_LEN("</h1>\n"
" </body>\n"
"</html>\n"
- );
-
+ ));
+
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
}
- /* fall through */
- case 207:
- case 200: /* class: header + body */
- case 302:
- break;
-
- case 206: /* write_queue is already prepared */
- con->file_finished = 1;
-
- break;
- case 205: /* class: header only */
- case 301:
- case 304:
- default:
- /* disable chunked encoding again as we have no body */
- con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
- 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 */
-
- if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) &&
+ /* we have all the content and chunked encoding is not used, set a content-length */
+
+ if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) &&
(con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) {
- buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->write_queue));
-
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf));
+ off_t qlen = chunkqueue_length(con->write_queue);
+
+ /**
+ * The Content-Length header only can be sent if we have content:
+ * - HEAD doesn't have a content-body (but have a content-length)
+ * - 1xx, 204 and 304 don't have a content-body (RFC 2616 Section 4.3)
+ *
+ * Otherwise generate a Content-Length header as chunked encoding is not
+ * available
+ */
+ 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 */
+ 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, qlen);
+
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf));
+ }
}
} else {
- /* disable keep-alive if size-info for the body is missing */
- if ((con->parsed_response & HTTP_CONTENT_LENGTH) &&
+ /**
+ * the file isn't finished yet, but we have all headers
+ *
+ * to get keep-alive we either need:
+ * - Content-Length: ... (HTTP/1.0 and HTTP/1.0) or
+ * - Transfer-Encoding: chunked (HTTP/1.1)
+ */
+
+ if (((con->parsed_response & HTTP_CONTENT_LENGTH) == 0) &&
((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0)) {
con->keep_alive = 0;
}
-
- if (0 == (con->parsed_response & HTTP_CONNECTION)) {
- /* (f)cgi did'nt send Connection: header
- *
- * shall we ?
- */
- if (((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) &&
- (con->parsed_response & HTTP_CONTENT_LENGTH) == 0) {
- /* without content_length, no keep-alive */
-
- con->keep_alive = 0;
- }
- } else {
+
+ /**
+ * if the backend sent a Connection: close, follow the wish
+ *
+ * NOTE: if the backend sent Connection: Keep-Alive, but no Content-Length, we
+ * will close the connection. That's fine. We can always decide the close
+ * the connection
+ *
+ * FIXME: to be nice we should remove the Connection: ...
+ */
+ if (con->parsed_response & HTTP_CONNECTION) {
/* a subrequest disable keep-alive although the client wanted it */
if (con->keep_alive && !con->response.keep_alive) {
con->keep_alive = 0;
-
- /* FIXME: we have to drop the Connection: Header from the subrequest */
}
}
}
-
+
if (con->request.http_method == HTTP_METHOD_HEAD) {
+ /**
+ * 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;
}
http_response_write_header(srv, con);
-
+
return 0;
}
static int connection_handle_write(server *srv, connection *con) {
- switch(network_write_chunkqueue(srv, con, con->write_queue)) {
+ switch(network_write_chunkqueue(srv, con, con->write_queue, MAX_WRITE_LIMIT)) {
case 0:
+ con->write_request_ts = srv->cur_ts;
if (con->file_finished) {
connection_set_state(srv, con, CON_STATE_RESPONSE_END);
joblist_append(srv, con);
@@ -543,12 +644,13 @@ static int connection_handle_write(server *srv, connection *con) {
joblist_append(srv, con);
break;
case 1:
+ con->write_request_ts = srv->cur_ts;
con->is_writable = 0;
-
+
/* not finished yet -> WRITE */
break;
}
-
+
return 0;
}
@@ -556,11 +658,11 @@ static int connection_handle_write(server *srv, connection *con) {
connection *connection_init(server *srv) {
connection *con;
-
+
UNUSED(srv);
con = calloc(1, sizeof(*con));
-
+
con->fd = 0;
con->ndx = -1;
con->fde_ndx = -1;
@@ -571,32 +673,35 @@ connection *connection_init(server *srv) {
#define CLEAN(x) \
con->x = buffer_init();
-
+
CLEAN(request.uri);
CLEAN(request.request_line);
CLEAN(request.request);
CLEAN(request.pathinfo);
-
+
CLEAN(request.orig_uri);
-
+
CLEAN(uri.scheme);
CLEAN(uri.authority);
CLEAN(uri.path);
CLEAN(uri.path_raw);
CLEAN(uri.query);
-
+
CLEAN(physical.doc_root);
CLEAN(physical.path);
CLEAN(physical.basedir);
CLEAN(physical.rel_path);
CLEAN(physical.etag);
CLEAN(parse_request);
-
+
CLEAN(authed_user);
CLEAN(server_name);
CLEAN(error_handler);
CLEAN(dst_addr_buf);
-
+#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
+ CLEAN(tlsext_server_name);
+#endif
+
#undef CLEAN
con->write_queue = chunkqueue_init();
con->read_queue = chunkqueue_init();
@@ -606,26 +711,26 @@ connection *connection_init(server *srv) {
con->request.headers = array_init();
con->response.headers = array_init();
con->environment = array_init();
-
+
/* init plugin specific connection structures */
-
+
con->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *));
-
+
con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t));
config_setup_connection(srv, con);
-
+
return con;
}
void connections_free(server *srv) {
connections *conns = srv->conns;
- size_t i;
-
+ size_t i;
+
for (i = 0; i < conns->size; i++) {
connection *con = conns->ptr[i];
-
+
connection_reset(srv, con);
-
+
chunkqueue_free(con->write_queue);
chunkqueue_free(con->read_queue);
chunkqueue_free(con->request_content_queue);
@@ -635,125 +740,131 @@ void connections_free(server *srv) {
#define CLEAN(x) \
buffer_free(con->x);
-
+
CLEAN(request.uri);
CLEAN(request.request_line);
CLEAN(request.request);
CLEAN(request.pathinfo);
-
+
CLEAN(request.orig_uri);
-
+
CLEAN(uri.scheme);
CLEAN(uri.authority);
CLEAN(uri.path);
CLEAN(uri.path_raw);
CLEAN(uri.query);
-
+
CLEAN(physical.doc_root);
CLEAN(physical.path);
CLEAN(physical.basedir);
CLEAN(physical.etag);
CLEAN(physical.rel_path);
CLEAN(parse_request);
-
+
CLEAN(authed_user);
CLEAN(server_name);
CLEAN(error_handler);
CLEAN(dst_addr_buf);
+#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
+ CLEAN(tlsext_server_name);
+#endif
#undef CLEAN
free(con->plugin_ctx);
free(con->cond_cache);
-
+
free(con);
}
-
+
free(conns->ptr);
}
int connection_reset(server *srv, connection *con) {
size_t i;
-
+
plugins_call_connection_reset(srv, con);
-
+
con->is_readable = 1;
con->is_writable = 1;
con->http_status = 0;
con->file_finished = 0;
con->file_started = 0;
con->got_response = 0;
-
+
con->parsed_response = 0;
-
+
con->bytes_written = 0;
con->bytes_written_cur_second = 0;
con->bytes_read = 0;
con->bytes_header = 0;
con->loops_per_request = 0;
-
+
con->request.http_method = HTTP_METHOD_UNSET;
con->request.http_version = HTTP_VERSION_UNSET;
-
+
con->request.http_if_modified_since = NULL;
con->request.http_if_none_match = NULL;
-
+
con->response.keep_alive = 0;
con->response.content_length = -1;
con->response.transfer_encoding = 0;
-
+
con->mode = DIRECT;
-
+
#define CLEAN(x) \
if (con->x) buffer_reset(con->x);
-
+
CLEAN(request.uri);
CLEAN(request.request_line);
CLEAN(request.pathinfo);
CLEAN(request.request);
-
- CLEAN(request.orig_uri);
-
+
+ /* CLEAN(request.orig_uri); */
+
CLEAN(uri.scheme);
- CLEAN(uri.authority);
- CLEAN(uri.path);
+ /* CLEAN(uri.authority); */
+ /* CLEAN(uri.path); */
CLEAN(uri.path_raw);
- CLEAN(uri.query);
-
+ /* CLEAN(uri.query); */
+
CLEAN(physical.doc_root);
CLEAN(physical.path);
CLEAN(physical.basedir);
CLEAN(physical.rel_path);
CLEAN(physical.etag);
-
+
CLEAN(parse_request);
-
+
CLEAN(authed_user);
CLEAN(server_name);
CLEAN(error_handler);
-#undef CLEAN
-
+#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
+ CLEAN(tlsext_server_name);
+#endif
+#undef CLEAN
+
#define CLEAN(x) \
- if (con->x) con->x->used = 0;
-
+ if (con->x) con->x->used = 0;
+
#undef CLEAN
-
+
#define CLEAN(x) \
con->request.x = NULL;
-
+
CLEAN(http_host);
CLEAN(http_range);
CLEAN(http_content_type);
#undef CLEAN
con->request.content_length = 0;
-
+
array_reset(con->request.headers);
array_reset(con->response.headers);
array_reset(con->environment);
-
+
chunkqueue_reset(con->write_queue);
chunkqueue_reset(con->request_content_queue);
- /* the plugins should cleanup themself */
+ /* the plugins should cleanup themself */
for (i = 0; i < srv->plugins.used; i++) {
plugin *p = ((plugin **)(srv->plugins.ptr))[i];
plugin_data *pd = p->data;
@@ -766,95 +877,40 @@ 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); */
+
con->header_len = 0;
con->in_error_handler = 0;
-
+
config_setup_connection(srv, con);
-
+
return 0;
}
/**
- *
- * search for \r\n\r\n
- *
- * this is a special 32bit version which is using a sliding window for
- * the comparisions
- *
- * how it works:
- *
- * b: 'abcdefg'
- * rnrn: 'cdef'
- *
- * cmpbuf: abcd != cdef
- * cmpbuf: bcde != cdef
- * cmpbuf: cdef == cdef -> return &c
- *
- * cmpbuf and rnrn are treated as 32bit uint and bit-ops are used to
- * maintain cmpbuf and rnrn
- *
- */
-
-char *buffer_search_rnrn(buffer *b) {
- uint32_t cmpbuf, rnrn;
- char *cp;
- size_t i;
-
- if (b->used < 4) return NULL;
-
- rnrn = ('\r' << 24) | ('\n' << 16) |
- ('\r' << 8) | ('\n' << 0);
-
- cmpbuf = (b->ptr[0] << 24) | (b->ptr[1] << 16) |
- (b->ptr[2] << 8) | (b->ptr[3] << 0);
-
- cp = b->ptr + 4;
- for (i = 0; i < b->used - 4; i++) {
- if (cmpbuf == rnrn) return cp - 4;
-
- cmpbuf = (cmpbuf << 8 | *(cp++)) & 0xffffffff;
- }
-
- return NULL;
-}
-/**
* handle all header and content read
*
* we get called by the state-engine and by the fdevent-handler
*/
-int connection_handle_read_state(server *srv, connection *con) {
- int ostate = con->state;
- char *h_term = NULL;
- chunk *c;
+static int connection_handle_read_state(server *srv, connection *con) {
+ connection_state_t ostate = con->state;
+ chunk *c, *last_chunk;
+ off_t last_offset;
chunkqueue *cq = con->read_queue;
chunkqueue *dst_cq = con->request_content_queue;
-
+ int is_closed = 0; /* the connection got closed, if we don't have a complete header, -> error */
+
if (con->is_readable) {
con->read_idle_ts = srv->cur_ts;
-
+
switch(connection_handle_read(srv, con)) {
case -1:
return -1;
case -2:
- /* remote side closed the connection
- * if we still have content, handle it, if not leave here */
-
- if (cq->first == cq->last &&
- cq->first->mem->used == 0) {
-
- /* conn-closed, leave here */
- connection_set_state(srv, con, CON_STATE_ERROR);
- }
+ is_closed = 1;
+ break;
default:
break;
}
@@ -889,107 +945,103 @@ int connection_handle_read_state(server *srv, connection *con) {
/* the last node was empty */
if (c->next == NULL) {
cq->last = c;
- }
+ }
c = c->next;
} else {
c = c->next;
}
}
-
- /* nothing to handle */
- if (cq->first == NULL) return 0;
+
+ /* we might have got several packets at once
+ */
switch(ostate) {
case CON_STATE_READ:
- /* prepare con->request.request */
- c = cq->first;
-
- /* check if we need the full package */
- if (con->request.request->used == 0) {
- buffer b;
-
- b.ptr = c->mem->ptr + c->offset;
- b.used = c->mem->used - c->offset;
-
- if (NULL != (h_term = buffer_search_rnrn(&b))) {
- /* \r\n\r\n found
- * - copy everything incl. the terminator to request.request
- */
-
- buffer_copy_string_len(con->request.request,
- b.ptr,
- h_term - b.ptr + 4);
-
- /* the buffer has been read up to the terminator */
- c->offset += h_term - b.ptr + 4;
- } else {
- /* not found, copy everything */
- buffer_copy_string_len(con->request.request, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
- c->offset = c->mem->used - 1;
- }
- } else {
- /* have to take care of overlapping header terminators */
-
- size_t l = con->request.request->used - 2;
- char *s = con->request.request->ptr;
+ /* if there is a \r\n\r\n in the chunkqueue
+ *
+ * scan the chunk-queue twice
+ * 1. to find the \r\n\r\n
+ * 2. to copy the header-packet
+ *
+ */
+
+ last_chunk = NULL;
+ last_offset = 0;
+
+ for (c = cq->first; c; c = c->next) {
buffer b;
-
+ size_t i;
+
b.ptr = c->mem->ptr + c->offset;
b.used = c->mem->used - c->offset;
-
- if (con->request.request->used - 1 > 3 &&
- c->mem->used > 1 &&
- s[l-2] == '\r' &&
- s[l-1] == '\n' &&
- s[l-0] == '\r' &&
- c->mem->ptr[0] == '\n') {
- buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 1);
- c->offset += 1;
-
- h_term = con->request.request->ptr;
- } else if (con->request.request->used - 1 > 2 &&
- c->mem->used > 2 &&
- s[l-1] == '\r' &&
- s[l-0] == '\n' &&
- c->mem->ptr[0] == '\r' &&
- c->mem->ptr[1] == '\n') {
- buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 2);
- c->offset += 2;
-
- h_term = con->request.request->ptr;
- } else if (con->request.request->used - 1 > 1 &&
- c->mem->used > 3 &&
- s[l-0] == '\r' &&
- c->mem->ptr[0] == '\n' &&
- c->mem->ptr[1] == '\r' &&
- c->mem->ptr[2] == '\n') {
- buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 3);
- c->offset += 3;
-
- h_term = con->request.request->ptr;
- } else if (NULL != (h_term = buffer_search_string_len(&b, "\r\n\r\n", 4))) {
- /* \r\n\r\n found
- * - copy everything incl. the terminator to request.request
- */
-
- buffer_append_string_len(con->request.request,
- c->mem->ptr + c->offset,
- c->offset + h_term - b.ptr + 4);
-
- /* the buffer has been read up to the terminator */
- c->offset += h_term - b.ptr + 4;
- } else {
- /* not found, copy everything */
- buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
- c->offset = c->mem->used - 1;
+ if (b.used > 0) b.used--; /* buffer "used" includes terminating zero */
+
+ for (i = 0; i < b.used; i++) {
+ char ch = b.ptr[i];
+
+ if ('\r' == ch) {
+ /* chec if \n\r\n follows */
+ size_t j = i+1;
+ chunk *cc = c;
+ const char header_end[] = "\r\n\r\n";
+ int header_end_match_pos = 1;
+
+ for ( ; cc; cc = cc->next, j = 0 ) {
+ buffer bb;
+ bb.ptr = cc->mem->ptr + cc->offset;
+ bb.used = cc->mem->used - cc->offset;
+ if (bb.used > 0) bb.used--; /* buffer "used" includes terminating zero */
+
+ for ( ; j < bb.used; j++) {
+ ch = bb.ptr[j];
+
+ if (ch == header_end[header_end_match_pos]) {
+ header_end_match_pos++;
+ if (4 == header_end_match_pos) {
+ last_chunk = cc;
+ last_offset = j+1;
+ goto found_header_end;
+ }
+ } else {
+ goto reset_search;
+ }
+ }
+ }
+ }
+reset_search: ;
}
}
+found_header_end:
+
+ /* found */
+ if (last_chunk) {
+ buffer_reset(con->request.request);
+
+ for (c = cq->first; c; c = c->next) {
+ buffer b;
+
+ b.ptr = c->mem->ptr + c->offset;
+ b.used = c->mem->used - c->offset;
+
+ if (c == last_chunk) {
+ b.used = last_offset + 1;
+ }
+
+ buffer_append_string_buffer(con->request.request, &b);
+
+ if (c == last_chunk) {
+ c->offset += last_offset;
+
+ break;
+ } else {
+ /* the whole packet was copied */
+ c->offset = c->mem->used - 1;
+ }
+ }
- /* con->request.request is setup up */
- if (h_term) {
connection_set_state(srv, con, CON_STATE_REQUEST_END);
- } else if (con->request.request->used > 64 * 1024) {
+ } else if (chunkqueue_length(cq) > 64 * 1024) {
log_error_write(srv, __FILE__, __LINE__, "s", "oversized request-header -> sending Status 414");
con->http_status = 414; /* Request-URI too large */
@@ -997,16 +1049,16 @@ int connection_handle_read_state(server *srv, connection *con) {
connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
}
break;
- case CON_STATE_READ_POST:
+ case CON_STATE_READ_POST:
for (c = cq->first; c && (dst_cq->bytes_in != (off_t)con->request.content_length); c = c->next) {
off_t weWant, weHave, toRead;
-
+
weWant = con->request.content_length - dst_cq->bytes_in;
-
+
assert(c->mem->used);
-
+
weHave = c->mem->used - c->offset - 1;
-
+
toRead = weHave > weWant ? weWant : weHave;
/* the new way, copy everything into a chunkqueue whcih might use tempfiles */
@@ -1015,13 +1067,13 @@ int connection_handle_read_state(server *srv, connection *con) {
/* copy everything to max 1Mb sized tempfiles */
/*
- * if the last chunk is
+ * if the last chunk is
* - smaller than 1Mb (size < 1Mb)
* - not read yet (offset == 0)
* -> append to it
* otherwise
- * -> create a new chunk
- *
+ * -> create a new chunk
+ *
* */
if (dst_cq->last &&
@@ -1036,6 +1088,9 @@ int connection_handle_read_state(server *srv, connection *con) {
if (dst_c->file.fd == -1) {
/* this should not happen as we cache the fd, but you never know */
dst_c->file.fd = open(dst_c->file.name->ptr, O_WRONLY | O_APPEND);
+#ifdef FD_CLOEXEC
+ fcntl(dst_c->file.fd, F_SETFD, FD_CLOEXEC);
+#endif
}
} else {
/* the chunk is too large now, close it */
@@ -1054,14 +1109,14 @@ int connection_handle_read_state(server *srv, connection *con) {
/* we have a chunk, let's write to it */
if (dst_c->file.fd == -1) {
- /* we don't have file to write to,
+ /* we don't have file to write to,
* EACCES might be one reason.
*
* Instead of sending 500 we send 413 and say the request is too large
* */
log_error_write(srv, __FILE__, __LINE__, "sbs",
- "denying upload as opening to temp-file for upload failed:",
+ "denying upload as opening to temp-file for upload failed:",
dst_c->file.name, strerror(errno));
con->http_status = 413; /* Request-Entity too large */
@@ -1072,15 +1127,15 @@ int connection_handle_read_state(server *srv, connection *con) {
}
if (toRead != write(dst_c->file.fd, c->mem->ptr + c->offset, toRead)) {
- /* write failed for some reason ... disk full ? */
+ /* write failed for some reason ... disk full ? */
log_error_write(srv, __FILE__, __LINE__, "sbs",
- "denying upload as writing to file failed:",
+ "denying upload as writing to file failed:",
dst_c->file.name, strerror(errno));
-
+
con->http_status = 413; /* Request-Entity too large */
con->keep_alive = 0;
connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
-
+
close(dst_c->file.fd);
dst_c->file.fd = -1;
@@ -1088,7 +1143,7 @@ int connection_handle_read_state(server *srv, connection *con) {
}
dst_c->file.length += toRead;
-
+
if (dst_cq->bytes_in + toRead == (off_t)con->request.content_length) {
/* we read everything, close the chunk */
close(dst_c->file.fd);
@@ -1097,10 +1152,17 @@ int connection_handle_read_state(server *srv, connection *con) {
} else {
buffer *b;
- b = chunkqueue_get_append_buffer(dst_cq);
- buffer_copy_string_len(b, c->mem->ptr + c->offset, toRead);
+ if (dst_cq->last &&
+ dst_cq->last->type == MEM_CHUNK) {
+ b = dst_cq->last->mem;
+ } else {
+ b = chunkqueue_get_append_buffer(dst_cq);
+ /* prepare buffer size for remaining POST data; is < 64kb */
+ buffer_prepare_copy(b, con->request.content_length - dst_cq->bytes_in + 1);
+ }
+ buffer_append_string_len(b, c->mem->ptr + c->offset, toRead);
}
-
+
c->offset += toRead;
dst_cq->bytes_in += toRead;
}
@@ -1109,8 +1171,15 @@ int connection_handle_read_state(server *srv, connection *con) {
if (dst_cq->bytes_in == (off_t)con->request.content_length) {
connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
}
-
+
break;
+ default: break;
+ }
+
+ /* the connection got closed and we didn't got enough data to leave one of the READ states
+ * the only way is to leave here */
+ if (is_closed && ostate == con->state) {
+ connection_set_state(srv, con, CON_STATE_ERROR);
}
chunkqueue_remove_finished_chunks(cq);
@@ -1118,35 +1187,39 @@ int connection_handle_read_state(server *srv, connection *con) {
return 0;
}
-handler_t connection_handle_fdevent(void *s, void *context, int revents) {
- server *srv = (server *)s;
+static handler_t connection_handle_fdevent(server *srv, void *context, int revents) {
connection *con = context;
-
+
joblist_append(srv, con);
-
- if (revents & FDEVENT_IN) {
- con->is_readable = 1;
-#if 0
- log_error_write(srv, __FILE__, __LINE__, "sd", "read-wait - done", con->fd);
-#endif
- }
- if (revents & FDEVENT_OUT) {
- con->is_writable = 1;
- /* we don't need the event twice */
+
+ if (con->conf.is_ssl) {
+ /* ssl may read and write for both reads and writes */
+ if (revents & (FDEVENT_IN | FDEVENT_OUT)) {
+ con->is_readable = 1;
+ con->is_writable = 1;
+ }
+ } else {
+ if (revents & FDEVENT_IN) {
+ con->is_readable = 1;
+ }
+ if (revents & FDEVENT_OUT) {
+ con->is_writable = 1;
+ /* we don't need the event twice */
+ }
}
-
-
+
+
if (revents & ~(FDEVENT_IN | FDEVENT_OUT)) {
/* looks like an error */
-
+
/* FIXME: revents = 0x19 still means that we should read from the queue */
if (revents & FDEVENT_HUP) {
if (con->state == CON_STATE_CLOSE) {
- con->close_timeout_ts = 0;
+ con->close_timeout_ts = srv->cur_ts - (HTTP_LINGER_TIMEOUT+1);
} else {
/* sigio reports the wrong event here
- *
- * there was no HUP at all
+ *
+ * there was no HUP at all
*/
#ifdef USE_LINUX_SIGIO
if (srv->ev->in_sigio == 1) {
@@ -1158,63 +1231,50 @@ handler_t connection_handle_fdevent(void *s, void *context, int revents) {
#else
connection_set_state(srv, con, CON_STATE_ERROR);
#endif
-
+
}
} else if (revents & FDEVENT_ERR) {
-#ifndef USE_LINUX_SIGIO
+ /* error, connection reset, whatever... we don't want to spam the logfile */
+#if 0
log_error_write(srv, __FILE__, __LINE__, "sd",
"connection closed: poll() -> ERR", con->fd);
-#endif
+#endif
connection_set_state(srv, con, CON_STATE_ERROR);
} else {
log_error_write(srv, __FILE__, __LINE__, "sd",
"connection closed: poll() -> ???", revents);
- }
+ }
}
-
+
if (con->state == CON_STATE_READ ||
con->state == CON_STATE_READ_POST) {
connection_handle_read_state(srv, con);
}
-
+
if (con->state == CON_STATE_WRITE &&
!chunkqueue_is_empty(con->write_queue) &&
con->is_writable) {
-
+
if (-1 == connection_handle_write(srv, con)) {
connection_set_state(srv, con, CON_STATE_ERROR);
-
+
log_error_write(srv, __FILE__, __LINE__, "ds",
con->fd,
"handle write failed.");
- } else if (con->state == CON_STATE_WRITE) {
- con->write_request_ts = srv->cur_ts;
}
}
-
+
if (con->state == CON_STATE_CLOSE) {
/* flush the read buffers */
- int b;
-
- if (ioctl(con->fd, FIONREAD, &b)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "ioctl() failed", strerror(errno));
- }
-
- if (b > 0) {
- char buf[1024];
- log_error_write(srv, __FILE__, __LINE__, "sdd",
- "CLOSE-read()", con->fd, b);
-
- /* */
- read(con->fd, buf, sizeof(buf));
- } else {
- /* nothing to read */
-
- con->close_timeout_ts = 0;
+ int len;
+ char buf[1024];
+
+ len = read(con->fd, buf, sizeof(buf));
+ if (len == 0 || (len < 0 && errno != EAGAIN && errno != EINTR) ) {
+ con->close_timeout_ts = srv->cur_ts - (HTTP_LINGER_TIMEOUT+1);
}
}
-
+
return HANDLER_FINISHED;
}
@@ -1227,43 +1287,65 @@ connection *connection_accept(server *srv, server_socket *srv_socket) {
sock_addr cnt_addr;
socklen_t cnt_len;
/* accept it and register the fd */
-
+
+ /**
+ * check if we can still open a new connections
+ *
+ * see #1216
+ */
+
+ if (srv->conns->used >= srv->max_conns) {
+ return NULL;
+ }
+
cnt_len = sizeof(cnt_addr);
if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
- if ((errno != EAGAIN) &&
- (errno != EINTR)) {
+ switch (errno) {
+ case EAGAIN:
+#if EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK:
+#endif
+ case EINTR:
+ /* we were stopped _before_ we had a connection */
+ case ECONNABORTED: /* this is a FreeBSD thingy */
+ /* we were stopped _after_ we had a connection */
+ break;
+ case EMFILE:
+ /* out of fds */
+ break;
+ default:
log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), errno);
}
return NULL;
} else {
connection *con;
-
+
srv->cur_fds++;
-
+
/* ok, we have the connection, register it */
#if 0
log_error_write(srv, __FILE__, __LINE__, "sd",
"appected()", cnt);
#endif
srv->con_opened++;
-
+
con = connections_get_new_connection(srv);
-
+
con->fd = cnt;
con->fde_ndx = -1;
-#if 0
+#if 0
gettimeofday(&(con->start_tv), NULL);
-#endif
+#endif
fdevent_register(srv->ev, con->fd, connection_handle_fdevent, con);
-
+
connection_set_state(srv, con, CON_STATE_REQUEST_START);
-
+
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))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
return NULL;
@@ -1272,17 +1354,19 @@ connection *connection_accept(server *srv, server_socket *srv_socket) {
/* connect FD to SSL */
if (srv_socket->is_ssl) {
if (NULL == (con->ssl = SSL_new(srv_socket->ssl_ctx))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
ERR_error_string(ERR_get_error(), NULL));
-
+
return NULL;
}
-
+
+ con->renegotiations = 0;
+ SSL_set_app_data(con->ssl, con);
SSL_set_accept_state(con->ssl);
con->conf.is_ssl=1;
-
+
if (1 != (SSL_set_fd(con->ssl, cnt))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
ERR_error_string(ERR_get_error(), NULL));
return NULL;
}
@@ -1298,129 +1382,133 @@ int connection_state_machine(server *srv, connection *con) {
#ifdef USE_OPENSSL
server_socket *srv_sock = con->srv_socket;
#endif
-
+
if (srv->srvconf.log_state_handling) {
- log_error_write(srv, __FILE__, __LINE__, "sds",
- "state at start",
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "state at start",
con->fd,
connection_get_state(con->state));
}
while (done == 0) {
size_t ostate = con->state;
- int b;
-
+
switch (con->state) {
case CON_STATE_REQUEST_START: /* transient */
if (srv->srvconf.log_state_handling) {
- log_error_write(srv, __FILE__, __LINE__, "sds",
+ log_error_write(srv, __FILE__, __LINE__, "sds",
"state for fd", con->fd, connection_get_state(con->state));
}
-
+
con->request_start = srv->cur_ts;
con->read_idle_ts = srv->cur_ts;
-
+
con->request_count++;
con->loops_per_request = 0;
-
+
connection_set_state(srv, con, CON_STATE_READ);
-
+
+ /* patch con->conf.is_ssl if the connection is a ssl-socket already */
+
+#ifdef USE_OPENSSL
+ con->conf.is_ssl = srv_sock->is_ssl;
+#endif
+
break;
case CON_STATE_REQUEST_END: /* transient */
if (srv->srvconf.log_state_handling) {
- log_error_write(srv, __FILE__, __LINE__, "sds",
+ log_error_write(srv, __FILE__, __LINE__, "sds",
"state for fd", con->fd, connection_get_state(con->state));
}
-
+
+ buffer_reset(con->uri.authority);
+ buffer_reset(con->uri.path);
+ buffer_reset(con->uri.query);
+ buffer_reset(con->request.orig_uri);
+
if (http_request_parse(srv, con)) {
/* we have to read some data from the POST request */
-
+
connection_set_state(srv, con, CON_STATE_READ_POST);
break;
}
-
+
connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
-
+
break;
case CON_STATE_HANDLE_REQUEST:
- /*
+ /*
* the request is parsed
- *
+ *
* decided what to do with the request
- * -
- *
- *
+ * -
+ *
+ *
*/
-
+
if (srv->srvconf.log_state_handling) {
- log_error_write(srv, __FILE__, __LINE__, "sds",
+ log_error_write(srv, __FILE__, __LINE__, "sds",
"state for fd", con->fd, connection_get_state(con->state));
}
-
+
switch (r = http_response_prepare(srv, con)) {
case HANDLER_FINISHED:
- if (con->http_status == 404 ||
- con->http_status == 403) {
- /* 404 error-handler */
-
- if (con->in_error_handler == 0 &&
- (!buffer_is_empty(con->conf.error_handler) ||
- !buffer_is_empty(con->error_handler))) {
- /* call error-handler */
-
- con->error_handler_saved_status = con->http_status;
- con->http_status = 0;
-
- if (buffer_is_empty(con->error_handler)) {
- buffer_copy_string_buffer(con->request.uri, con->conf.error_handler);
- } else {
- buffer_copy_string_buffer(con->request.uri, con->error_handler);
+ if (con->mode == DIRECT) {
+ if (con->http_status == 404 ||
+ con->http_status == 403) {
+ /* 404 error-handler */
+
+ if (con->in_error_handler == 0 &&
+ (!buffer_is_empty(con->conf.error_handler) ||
+ !buffer_is_empty(con->error_handler))) {
+ /* call error-handler */
+
+ con->error_handler_saved_status = con->http_status;
+ con->http_status = 0;
+
+ if (buffer_is_empty(con->error_handler)) {
+ buffer_copy_string_buffer(con->request.uri, con->conf.error_handler);
+ } else {
+ buffer_copy_string_buffer(con->request.uri, con->error_handler);
+ }
+ buffer_reset(con->physical.path);
+
+ con->in_error_handler = 1;
+
+ connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
+
+ done = -1;
+ break;
+ } else if (con->in_error_handler) {
+ /* error-handler is a 404 */
+
+ con->http_status = con->error_handler_saved_status;
}
- buffer_reset(con->physical.path);
-
- con->in_error_handler = 1;
-
- connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
-
- done = -1;
- break;
} else if (con->in_error_handler) {
- /* error-handler is a 404 */
-
- /* continue as normal, status is the same */
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "Warning: Either the error-handler returned status 404 or the error-handler itself was not found:", con->request.uri);
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "returning the original status", con->error_handler_saved_status);
- log_error_write(srv, __FILE__, __LINE__, "s",
- "If this is a rails app: check your production.log");
- con->http_status = con->error_handler_saved_status;
+ /* error-handler is back and has generated content */
+ /* if Status: was set, take it otherwise use 200 */
}
- } else if (con->in_error_handler) {
- /* error-handler is back and has generated content */
- /* if Status: was set, take it otherwise use 200 */
}
-
if (con->http_status == 0) con->http_status = 200;
-
+
/* we have something to send, go on */
connection_set_state(srv, con, CON_STATE_RESPONSE_START);
break;
case HANDLER_WAIT_FOR_FD:
srv->want_fds++;
-
+
fdwaitqueue_append(srv, con);
-
+
connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
-
+
break;
case HANDLER_COMEBACK:
done = -1;
case HANDLER_WAIT_FOR_EVENT:
/* come back here */
connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
-
+
break;
case HANDLER_ERROR:
/* something went wrong */
@@ -1430,44 +1518,44 @@ int connection_state_machine(server *srv, connection *con) {
log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->fd, r);
break;
}
-
+
break;
case CON_STATE_RESPONSE_START:
- /*
+ /*
* the decision is done
* - create the HTTP-Response-Header
- *
+ *
*/
-
+
if (srv->srvconf.log_state_handling) {
- log_error_write(srv, __FILE__, __LINE__, "sds",
+ log_error_write(srv, __FILE__, __LINE__, "sds",
"state for fd", con->fd, connection_get_state(con->state));
}
-
+
if (-1 == connection_handle_write_prepare(srv, con)) {
connection_set_state(srv, con, CON_STATE_ERROR);
-
+
break;
}
-
+
connection_set_state(srv, con, CON_STATE_WRITE);
break;
case CON_STATE_RESPONSE_END: /* transient */
/* log the request */
-
+
if (srv->srvconf.log_state_handling) {
- log_error_write(srv, __FILE__, __LINE__, "sds",
+ log_error_write(srv, __FILE__, __LINE__, "sds",
"state for fd", con->fd, connection_get_state(con->state));
}
-
+
plugins_call_handle_request_done(srv, con);
-
+
srv->con_written++;
-
+
if (con->keep_alive) {
connection_set_state(srv, con, CON_STATE_REQUEST_START);
-
-#if 0
+
+#if 0
con->request_start = srv->cur_ts;
con->read_idle_ts = srv->cur_ts;
#endif
@@ -1480,7 +1568,7 @@ int connection_state_machine(server *srv, connection *con) {
log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r);
break;
}
-
+
#ifdef USE_OPENSSL
if (srv_sock->is_ssl) {
switch (SSL_shutdown(con->ssl)) {
@@ -1488,90 +1576,89 @@ int connection_state_machine(server *srv, connection *con) {
/* done */
break;
case 0:
- /* wait for fd-event
- *
+ /* wait for fd-event
+ *
* FIXME: wait for fdevent and call SSL_shutdown again
- *
+ *
*/
-
+
break;
default:
- log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
ERR_error_string(ERR_get_error(), NULL));
}
}
#endif
- connection_close(srv, con);
-
+ if ((0 == shutdown(con->fd, SHUT_WR))) {
+ con->close_timeout_ts = srv->cur_ts;
+ connection_set_state(srv, con, CON_STATE_CLOSE);
+ } else {
+ connection_close(srv, con);
+ }
+
srv->con_closed++;
}
-
+
connection_reset(srv, con);
-
+
break;
case CON_STATE_CONNECT:
if (srv->srvconf.log_state_handling) {
- log_error_write(srv, __FILE__, __LINE__, "sds",
+ log_error_write(srv, __FILE__, __LINE__, "sds",
"state for fd", con->fd, connection_get_state(con->state));
}
-
+
chunkqueue_reset(con->read_queue);
-
+
con->request_count = 0;
-
+
break;
case CON_STATE_CLOSE:
if (srv->srvconf.log_state_handling) {
- log_error_write(srv, __FILE__, __LINE__, "sds",
+ log_error_write(srv, __FILE__, __LINE__, "sds",
"state for fd", con->fd, connection_get_state(con->state));
}
-
- if (con->keep_alive) {
- if (ioctl(con->fd, FIONREAD, &b)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "ioctl() failed", strerror(errno));
- }
- if (b > 0) {
- char buf[1024];
- log_error_write(srv, __FILE__, __LINE__, "sdd",
- "CLOSE-read()", con->fd, b);
-
- /* */
- read(con->fd, buf, sizeof(buf));
- } else {
- /* nothing to read */
-
- con->close_timeout_ts = 0;
+
+ /* we have to do the linger_on_close stuff regardless
+ * of con->keep_alive; even non-keepalive sockets may
+ * still have unread data, and closing before reading
+ * it will make the client not see all our output.
+ */
+ {
+ int len;
+ char buf[1024];
+
+ len = read(con->fd, buf, sizeof(buf));
+ if (len == 0 || (len < 0 && errno != EAGAIN && errno != EINTR) ) {
+ con->close_timeout_ts = srv->cur_ts - (HTTP_LINGER_TIMEOUT+1);
}
- } else {
- con->close_timeout_ts = 0;
}
-
- if (srv->cur_ts - con->close_timeout_ts > 1) {
+
+ if (srv->cur_ts - con->close_timeout_ts > HTTP_LINGER_TIMEOUT) {
connection_close(srv, con);
-
+
if (srv->srvconf.log_state_handling) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"connection closed for fd", con->fd);
}
}
-
+
break;
case CON_STATE_READ_POST:
case CON_STATE_READ:
if (srv->srvconf.log_state_handling) {
- log_error_write(srv, __FILE__, __LINE__, "sds",
+ log_error_write(srv, __FILE__, __LINE__, "sds",
"state for fd", con->fd, connection_get_state(con->state));
}
-
+
connection_handle_read_state(srv, con);
break;
case CON_STATE_WRITE:
if (srv->srvconf.log_state_handling) {
- log_error_write(srv, __FILE__, __LINE__, "sds",
+ log_error_write(srv, __FILE__, __LINE__, "sds",
"state for fd", con->fd, connection_get_state(con->state));
}
-
+
/* only try to write if we have something in the queue */
if (!chunkqueue_is_empty(con->write_queue)) {
#if 0
@@ -1587,42 +1674,77 @@ int connection_state_machine(server *srv, connection *con) {
con->fd,
"handle write failed.");
connection_set_state(srv, con, CON_STATE_ERROR);
- } else if (con->state == CON_STATE_WRITE) {
- con->write_request_ts = srv->cur_ts;
}
}
-
+
break;
case CON_STATE_ERROR: /* transient */
-
+
/* even if the connection was drop we still have to write it to the access log */
if (con->http_status) {
plugins_call_handle_request_done(srv, con);
}
#ifdef USE_OPENSSL
if (srv_sock->is_ssl) {
- int ret;
+ int ret, ssl_r;
+ unsigned long err;
+ ERR_clear_error();
switch ((ret = SSL_shutdown(con->ssl))) {
case 1:
/* ok */
break;
case 0:
- SSL_shutdown(con->ssl);
- break;
+ ERR_clear_error();
+ if (-1 != (ret = SSL_shutdown(con->ssl))) break;
+
+ /* fall through */
default:
- log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
- SSL_get_error(con->ssl, ret),
- ERR_error_string(ERR_get_error(), NULL));
- return -1;
+
+ switch ((ssl_r = SSL_get_error(con->ssl, ret))) {
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ break;
+ case SSL_ERROR_SYSCALL:
+ /* perhaps we have error waiting in our error-queue */
+ if (0 != (err = ERR_get_error())) {
+ do {
+ log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
+ ssl_r, ret,
+ ERR_error_string(err, NULL));
+ } while((err = ERR_get_error()));
+ } else if (errno != 0) { /* ssl bug (see lighttpd ticket #2213): sometimes errno == 0 */
+ switch(errno) {
+ case EPIPE:
+ case ECONNRESET:
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
+ ssl_r, ret, errno,
+ strerror(errno));
+ break;
+ }
+ }
+
+ break;
+ default:
+ while((err = ERR_get_error())) {
+ log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
+ ssl_r, ret,
+ ERR_error_string(err, NULL));
+ }
+
+ break;
+ }
}
}
+ ERR_clear_error();
#endif
-
+
switch(con->mode) {
case DIRECT:
#if 0
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "emergency exit: direct",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "emergency exit: direct",
con->fd);
#endif
break;
@@ -1632,40 +1754,39 @@ int connection_state_machine(server *srv, connection *con) {
case HANDLER_FINISHED:
break;
default:
- log_error_write(srv, __FILE__, __LINE__, "");
+ log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r);
break;
}
break;
}
-
+
connection_reset(srv, con);
-
+
/* close the connection */
- if ((con->keep_alive == 1) &&
- (0 == shutdown(con->fd, SHUT_WR))) {
+ if ((0 == shutdown(con->fd, SHUT_WR))) {
con->close_timeout_ts = srv->cur_ts;
connection_set_state(srv, con, CON_STATE_CLOSE);
-
+
if (srv->srvconf.log_state_handling) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"shutdown for fd", con->fd);
}
} else {
connection_close(srv, con);
}
-
+
con->keep_alive = 0;
-
+
srv->con_closed++;
-
+
break;
default:
- log_error_write(srv, __FILE__, __LINE__, "sdd",
+ log_error_write(srv, __FILE__, __LINE__, "sdd",
"unknown state:", con->fd, con->state);
-
+
break;
}
-
+
if (done == -1) {
done = 0;
} else if (ostate == con->state) {
@@ -1674,27 +1795,27 @@ int connection_state_machine(server *srv, connection *con) {
}
if (srv->srvconf.log_state_handling) {
- log_error_write(srv, __FILE__, __LINE__, "sds",
- "state at exit:",
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "state at exit:",
con->fd,
connection_get_state(con->state));
}
-
+
switch(con->state) {
case CON_STATE_READ_POST:
case CON_STATE_READ:
case CON_STATE_CLOSE:
- fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_IN);
+ fdevent_event_set(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_IN);
break;
case CON_STATE_WRITE:
- /* request write-fdevent only if we really need it
+ /* request write-fdevent only if we really need it
* - if we have data to write
- * - if the socket is not writable yet
+ * - if the socket is not writable yet
*/
- if (!chunkqueue_is_empty(con->write_queue) &&
+ if (!chunkqueue_is_empty(con->write_queue) &&
(con->is_writable == 0) &&
(con->traffic_limit_reached == 0)) {
- fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT);
+ fdevent_event_set(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT);
} else {
fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
}
diff --git a/src/crc32.h b/src/crc32.h
index d671c53..c5b4245 100644
--- a/src/crc32.h
+++ b/src/crc32.h
@@ -2,15 +2,15 @@
#define __crc32cr_table_h__
#ifdef HAVE_CONFIG_H
-#include "config.h"
+# include "config.h"
#endif
#include <sys/types.h>
#if defined HAVE_STDINT_H
-#include <stdint.h>
+# include <stdint.h>
#elif defined HAVE_INTTYPES_H
-#include <inttypes.h>
+# include <inttypes.h>
#endif
uint32_t generate_crc32c(char *string, size_t length);
diff --git a/src/data_array.c b/src/data_array.c
index 9dfa6fd..094d8c0 100644
--- a/src/data_array.c
+++ b/src/data_array.c
@@ -1,9 +1,9 @@
+#include "array.h"
+
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
-#include "array.h"
-
static data_unset *data_array_copy(const data_unset *s) {
data_array *src = (data_array *)s;
data_array *ds = data_array_init();
@@ -17,16 +17,16 @@ static data_unset *data_array_copy(const data_unset *s) {
static void data_array_free(data_unset *d) {
data_array *ds = (data_array *)d;
-
+
buffer_free(ds->key);
array_free(ds->value);
-
+
free(d);
}
static void data_array_reset(data_unset *d) {
data_array *ds = (data_array *)d;
-
+
/* reused array elements */
buffer_reset(ds->key);
array_reset(ds->value);
@@ -36,7 +36,7 @@ static int data_array_insert_dup(data_unset *dst, data_unset *src) {
UNUSED(dst);
src->free(src);
-
+
return 0;
}
@@ -48,18 +48,18 @@ static void data_array_print(const data_unset *d, int depth) {
data_array *data_array_init(void) {
data_array *ds;
-
+
ds = calloc(1, sizeof(*ds));
-
+
ds->key = buffer_init();
ds->value = array_init();
-
+
ds->copy = data_array_copy;
ds->free = data_array_free;
ds->reset = data_array_reset;
ds->insert_dup = data_array_insert_dup;
ds->print = data_array_print;
ds->type = TYPE_ARRAY;
-
+
return ds;
}
diff --git a/src/data_config.c b/src/data_config.c
index 8b3735e..80e38de 100644
--- a/src/data_config.c
+++ b/src/data_config.c
@@ -1,9 +1,9 @@
+#include "array.h"
+
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
-#include "array.h"
-
static data_unset *data_config_copy(const data_unset *s) {
data_config *src = (data_config *)s;
data_config *ds = data_config_init();
@@ -17,26 +17,26 @@ static data_unset *data_config_copy(const data_unset *s) {
static void data_config_free(data_unset *d) {
data_config *ds = (data_config *)d;
-
+
buffer_free(ds->key);
buffer_free(ds->op);
buffer_free(ds->comp_key);
-
+
array_free(ds->value);
array_free(ds->childs);
-
+
if (ds->string) buffer_free(ds->string);
#ifdef HAVE_PCRE_H
if (ds->regex) pcre_free(ds->regex);
if (ds->regex_study) pcre_free(ds->regex_study);
#endif
-
+
free(d);
}
static void data_config_reset(data_unset *d) {
data_config *ds = (data_config *)d;
-
+
/* reused array elements */
buffer_reset(ds->key);
buffer_reset(ds->comp_key);
@@ -45,9 +45,9 @@ static void data_config_reset(data_unset *d) {
static int data_config_insert_dup(data_unset *dst, data_unset *src) {
UNUSED(dst);
-
+
src->free(src);
-
+
return 0;
}
@@ -56,15 +56,15 @@ static void data_config_print(const data_unset *d, int depth) {
array *a = (array *)ds->value;
size_t i;
size_t maxlen;
-
+
if (0 == ds->context_ndx) {
- fprintf(stderr, "config {\n");
+ fprintf(stdout, "config {\n");
}
else {
- fprintf(stderr, "$%s %s \"%s\" {\n",
+ fprintf(stdout, "$%s %s \"%s\" {\n",
ds->comp_key->ptr, ds->op->ptr, ds->string->ptr);
array_print_indent(depth + 1);
- fprintf(stderr, "# block %d\n", ds->context_ndx);
+ fprintf(stdout, "# block %d\n", ds->context_ndx);
}
depth ++;
@@ -75,64 +75,64 @@ static void data_config_print(const data_unset *d, int depth) {
size_t j;
array_print_indent(depth);
- fprintf(stderr, "%s", du->key->ptr);
+ fprintf(stdout, "%s", du->key->ptr);
for (j = maxlen - len; j > 0; j --) {
- fprintf(stderr, " ");
+ fprintf(stdout, " ");
}
- fprintf(stderr, " = ");
+ fprintf(stdout, " = ");
du->print(du, depth);
- fprintf(stderr, "\n");
+ fprintf(stdout, "\n");
}
if (ds->childs) {
- fprintf(stderr, "\n");
+ fprintf(stdout, "\n");
for (i = 0; i < ds->childs->used; i ++) {
data_unset *du = ds->childs->data[i];
/* only the 1st block of chaining */
if (NULL == ((data_config *)du)->prev) {
- fprintf(stderr, "\n");
+ fprintf(stdout, "\n");
array_print_indent(depth);
du->print(du, depth);
- fprintf(stderr, "\n");
+ fprintf(stdout, "\n");
}
}
}
depth --;
array_print_indent(depth);
- fprintf(stderr, "}");
+ fprintf(stdout, "}");
if (0 != ds->context_ndx) {
- fprintf(stderr, " # end of $%s %s \"%s\"",
+ fprintf(stdout, " # end of $%s %s \"%s\"",
ds->comp_key->ptr, ds->op->ptr, ds->string->ptr);
}
if (ds->next) {
- fprintf(stderr, "\n");
+ fprintf(stdout, "\n");
array_print_indent(depth);
- fprintf(stderr, "else ");
+ fprintf(stdout, "else ");
ds->next->print((data_unset *)ds->next, depth);
}
}
data_config *data_config_init(void) {
data_config *ds;
-
+
ds = calloc(1, sizeof(*ds));
-
+
ds->key = buffer_init();
ds->op = buffer_init();
ds->comp_key = buffer_init();
ds->value = array_init();
ds->childs = array_init();
ds->childs->is_weakref = 1;
-
+
ds->copy = data_config_copy;
ds->free = data_config_free;
ds->reset = data_config_reset;
ds->insert_dup = data_config_insert_dup;
ds->print = data_config_print;
ds->type = TYPE_CONFIG;
-
+
return ds;
}
diff --git a/src/data_count.c b/src/data_count.c
index ca51f67..8d36c8b 100644
--- a/src/data_count.c
+++ b/src/data_count.c
@@ -1,9 +1,9 @@
+#include "array.h"
+
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
-#include "array.h"
-
static data_unset *data_count_copy(const data_unset *s) {
data_count *src = (data_count *)s;
data_count *ds = data_count_init();
@@ -16,53 +16,53 @@ static data_unset *data_count_copy(const data_unset *s) {
static void data_count_free(data_unset *d) {
data_count *ds = (data_count *)d;
-
+
buffer_free(ds->key);
-
+
free(d);
}
static void data_count_reset(data_unset *d) {
data_count *ds = (data_count *)d;
-
+
buffer_reset(ds->key);
-
+
ds->count = 0;
}
static int data_count_insert_dup(data_unset *dst, data_unset *src) {
data_count *ds_dst = (data_count *)dst;
data_count *ds_src = (data_count *)src;
-
+
ds_dst->count += ds_src->count;
-
+
src->free(src);
-
+
return 0;
}
static void data_count_print(const data_unset *d, int depth) {
data_count *ds = (data_count *)d;
UNUSED(depth);
-
- fprintf(stderr, "count(%d)", ds->count);
+
+ fprintf(stdout, "count(%d)", ds->count);
}
data_count *data_count_init(void) {
data_count *ds;
-
+
ds = calloc(1, sizeof(*ds));
-
+
ds->key = buffer_init();
ds->count = 1;
-
+
ds->copy = data_count_copy;
ds->free = data_count_free;
ds->reset = data_count_reset;
ds->insert_dup = data_count_insert_dup;
ds->print = data_count_print;
ds->type = TYPE_COUNT;
-
+
return ds;
}
diff --git a/src/data_fastcgi.c b/src/data_fastcgi.c
index 714b290..e13a470 100644
--- a/src/data_fastcgi.c
+++ b/src/data_fastcgi.c
@@ -1,10 +1,10 @@
+#include "array.h"
+#include "fastcgi.h"
+
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
-#include "array.h"
-#include "fastcgi.h"
-
static data_unset *data_fastcgi_copy(const data_unset *s) {
data_fastcgi *src = (data_fastcgi *)s;
data_fastcgi *ds = data_fastcgi_init();
@@ -17,53 +17,53 @@ static data_unset *data_fastcgi_copy(const data_unset *s) {
static void data_fastcgi_free(data_unset *d) {
data_fastcgi *ds = (data_fastcgi *)d;
-
+
buffer_free(ds->key);
buffer_free(ds->host);
-
+
free(d);
}
static void data_fastcgi_reset(data_unset *d) {
data_fastcgi *ds = (data_fastcgi *)d;
-
+
buffer_reset(ds->key);
buffer_reset(ds->host);
-
+
}
static int data_fastcgi_insert_dup(data_unset *dst, data_unset *src) {
UNUSED(dst);
src->free(src);
-
+
return 0;
}
static void data_fastcgi_print(const data_unset *d, int depth) {
data_fastcgi *ds = (data_fastcgi *)d;
UNUSED(depth);
-
- fprintf(stderr, "fastcgi(%s)", ds->host->ptr);
+
+ fprintf(stdout, "fastcgi(%s)", ds->host->ptr);
}
data_fastcgi *data_fastcgi_init(void) {
data_fastcgi *ds;
-
+
ds = calloc(1, sizeof(*ds));
-
+
ds->key = buffer_init();
ds->host = buffer_init();
ds->port = 0;
ds->is_disabled = 0;
-
+
ds->copy = data_fastcgi_copy;
ds->free = data_fastcgi_free;
ds->reset = data_fastcgi_reset;
ds->insert_dup = data_fastcgi_insert_dup;
ds->print = data_fastcgi_print;
ds->type = TYPE_FASTCGI;
-
+
return ds;
}
diff --git a/src/data_integer.c b/src/data_integer.c
index 96d1d0a..63cbb10 100644
--- a/src/data_integer.c
+++ b/src/data_integer.c
@@ -1,9 +1,9 @@
+#include "array.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "array.h"
-
static data_unset *data_integer_copy(const data_unset *s) {
data_integer *src = (data_integer *)s;
data_integer *ds = data_integer_init();
@@ -16,15 +16,15 @@ static data_unset *data_integer_copy(const data_unset *s) {
static void data_integer_free(data_unset *d) {
data_integer *ds = (data_integer *)d;
-
+
buffer_free(ds->key);
-
+
free(d);
}
static void data_integer_reset(data_unset *d) {
data_integer *ds = (data_integer *)d;
-
+
/* reused integer elements */
buffer_reset(ds->key);
ds->value = 0;
@@ -32,9 +32,9 @@ static void data_integer_reset(data_unset *d) {
static int data_integer_insert_dup(data_unset *dst, data_unset *src) {
UNUSED(dst);
-
+
src->free(src);
-
+
return 0;
}
@@ -42,24 +42,24 @@ static void data_integer_print(const data_unset *d, int depth) {
data_integer *ds = (data_integer *)d;
UNUSED(depth);
- fprintf(stderr, "%d", ds->value);
+ fprintf(stdout, "%d", ds->value);
}
data_integer *data_integer_init(void) {
data_integer *ds;
-
+
ds = calloc(1, sizeof(*ds));
-
+
ds->key = buffer_init();
ds->value = 0;
-
+
ds->copy = data_integer_copy;
ds->free = data_integer_free;
ds->reset = data_integer_reset;
ds->insert_dup = data_integer_insert_dup;
ds->print = data_integer_print;
ds->type = TYPE_INTEGER;
-
+
return ds;
}
diff --git a/src/data_string.c b/src/data_string.c
index d9325da..7648946 100644
--- a/src/data_string.c
+++ b/src/data_string.c
@@ -1,10 +1,10 @@
+#include "array.h"
+
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
-#include "array.h"
-
static data_unset *data_string_copy(const data_unset *s) {
data_string *src = (data_string *)s;
data_string *ds = data_string_init();
@@ -17,16 +17,16 @@ static data_unset *data_string_copy(const data_unset *s) {
static void data_string_free(data_unset *d) {
data_string *ds = (data_string *)d;
-
+
buffer_free(ds->key);
buffer_free(ds->value);
-
+
free(d);
}
static void data_string_reset(data_unset *d) {
data_string *ds = (data_string *)d;
-
+
/* reused array elements */
buffer_reset(ds->key);
buffer_reset(ds->value);
@@ -35,70 +35,87 @@ static void data_string_reset(data_unset *d) {
static int data_string_insert_dup(data_unset *dst, data_unset *src) {
data_string *ds_dst = (data_string *)dst;
data_string *ds_src = (data_string *)src;
-
+
if (ds_dst->value->used) {
- buffer_append_string(ds_dst->value, ", ");
+ buffer_append_string_len(ds_dst->value, CONST_STR_LEN(", "));
buffer_append_string_buffer(ds_dst->value, ds_src->value);
} else {
buffer_copy_string_buffer(ds_dst->value, ds_src->value);
}
-
+
src->free(src);
-
+
return 0;
}
static int data_response_insert_dup(data_unset *dst, data_unset *src) {
data_string *ds_dst = (data_string *)dst;
data_string *ds_src = (data_string *)src;
-
+
if (ds_dst->value->used) {
- buffer_append_string(ds_dst->value, "\r\n");
+ buffer_append_string_len(ds_dst->value, CONST_STR_LEN("\r\n"));
buffer_append_string_buffer(ds_dst->value, ds_dst->key);
- buffer_append_string(ds_dst->value, ": ");
+ buffer_append_string_len(ds_dst->value, CONST_STR_LEN(": "));
buffer_append_string_buffer(ds_dst->value, ds_src->value);
} else {
buffer_copy_string_buffer(ds_dst->value, ds_src->value);
}
-
+
src->free(src);
-
+
return 0;
}
static void data_string_print(const data_unset *d, int depth) {
data_string *ds = (data_string *)d;
+ unsigned int i;
UNUSED(depth);
- fprintf(stderr, "\"%s\"", ds->value->used ? ds->value->ptr : "");
+ /* empty and uninitialized strings */
+ if (ds->value->used < 1) {
+ fputs("\"\"", stdout);
+ return;
+ }
+
+ /* print out the string as is, except prepend " with backslash */
+ putc('"', stdout);
+ for (i = 0; i < ds->value->used - 1; i++) {
+ unsigned char c = ds->value->ptr[i];
+ if (c == '"') {
+ fputs("\\\"", stdout);
+ } else {
+ putc(c, stdout);
+ }
+ }
+ putc('"', stdout);
}
data_string *data_string_init(void) {
data_string *ds;
-
+
ds = calloc(1, sizeof(*ds));
assert(ds);
-
+
ds->key = buffer_init();
ds->value = buffer_init();
-
+
ds->copy = data_string_copy;
ds->free = data_string_free;
ds->reset = data_string_reset;
ds->insert_dup = data_string_insert_dup;
ds->print = data_string_print;
ds->type = TYPE_STRING;
-
+
return ds;
}
data_string *data_response_init(void) {
data_string *ds;
-
+
ds = data_string_init();
ds->insert_dup = data_response_insert_dup;
-
+
return ds;
}
diff --git a/src/etag.c b/src/etag.c
index 89dfb9c..e7e9e3f 100644
--- a/src/etag.c
+++ b/src/etag.c
@@ -1,32 +1,51 @@
-#include <string.h>
-
#include "buffer.h"
#include "etag.h"
+#if defined HAVE_STDINT_H
+# include <stdint.h>
+#elif defined HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+#include <string.h>
+
int etag_is_equal(buffer *etag, const char *matches) {
- if (0 == strcmp(etag->ptr, matches)) return 1;
+ if (etag && !buffer_is_empty(etag) && 0 == strcmp(etag->ptr, matches)) return 1;
return 0;
}
-int etag_create(buffer *etag, struct stat *st) {
- buffer_copy_off_t(etag, st->st_ino);
- buffer_append_string_len(etag, CONST_STR_LEN("-"));
- buffer_append_off_t(etag, st->st_size);
- buffer_append_string_len(etag, CONST_STR_LEN("-"));
- buffer_append_long(etag, st->st_mtime);
+int etag_create(buffer *etag, struct stat *st,etag_flags_t flags) {
+ if (0 == flags) return 0;
+
+ buffer_reset(etag);
+
+ if (flags & ETAG_USE_INODE) {
+ buffer_append_off_t(etag, st->st_ino);
+ buffer_append_string_len(etag, CONST_STR_LEN("-"));
+ }
+
+ if (flags & ETAG_USE_SIZE) {
+ buffer_append_off_t(etag, st->st_size);
+ buffer_append_string_len(etag, CONST_STR_LEN("-"));
+ }
+ if (flags & ETAG_USE_MTIME) {
+ buffer_append_long(etag, st->st_mtime);
+ }
+
return 0;
}
int etag_mutate(buffer *mut, buffer *etag) {
- size_t h, i;
-
- for (h=0, i=0; i < etag->used; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]);
-
+ size_t i;
+ uint32_t h;
+
+ for (h=0, i=0; i < etag->used-1; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]);
+
buffer_reset(mut);
buffer_copy_string_len(mut, CONST_STR_LEN("\""));
- buffer_append_long(mut, h);
+ buffer_append_off_t(mut, h);
buffer_append_string_len(mut, CONST_STR_LEN("\""));
-
+
return 0;
}
diff --git a/src/etag.h b/src/etag.h
index 53fae00..97cb063 100644
--- a/src/etag.h
+++ b/src/etag.h
@@ -1,15 +1,17 @@
#ifndef ETAG_H
#define ETAG_H
+#include "buffer.h"
+
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
-#include "buffer.h"
+typedef enum { ETAG_USE_INODE = 1, ETAG_USE_MTIME = 2, ETAG_USE_SIZE = 4 } etag_flags_t;
int etag_is_equal(buffer *etag, const char *matches);
-int etag_create(buffer *etag, struct stat *st);
+int etag_create(buffer *etag, struct stat *st, etag_flags_t flags);
int etag_mutate(buffer *mut, buffer *etag);
-
+
#endif
diff --git a/src/fastcgi.h b/src/fastcgi.h
index 15f1dea..31c00ad 100644
--- a/src/fastcgi.h
+++ b/src/fastcgi.h
@@ -1,4 +1,4 @@
-/*
+/*
* fastcgi.h --
*
* Defines for the FastCGI protocol.
@@ -123,7 +123,7 @@ typedef struct {
typedef struct {
- unsigned char type;
+ unsigned char type;
unsigned char reserved[7];
} FCGI_UnknownTypeBody;
diff --git a/src/fdevent.c b/src/fdevent.c
index fdf834f..fdd178d 100644
--- a/src/fdevent.c
+++ b/src/fdevent.c
@@ -1,6 +1,7 @@
-#include <sys/types.h>
+#include "base.h"
+#include "log.h"
-#include "settings.h"
+#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
@@ -8,110 +9,119 @@
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
+#include <assert.h>
-#include "fdevent.h"
-#include "buffer.h"
-fdevents *fdevent_init(size_t maxfds, fdevent_handler_t type) {
+fdevents *fdevent_init(server *srv, size_t maxfds, fdevent_handler_t type) {
fdevents *ev;
-
+
ev = calloc(1, sizeof(*ev));
+ ev->srv = srv;
ev->fdarray = calloc(maxfds, sizeof(*ev->fdarray));
ev->maxfds = maxfds;
-
+
switch(type) {
case FDEVENT_HANDLER_POLL:
if (0 != fdevent_poll_init(ev)) {
- fprintf(stderr, "%s.%d: event-handler poll failed\n",
- __FILE__, __LINE__);
-
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "event-handler poll failed");
+
return NULL;
}
- break;
+ return ev;
case FDEVENT_HANDLER_SELECT:
if (0 != fdevent_select_init(ev)) {
- fprintf(stderr, "%s.%d: event-handler select failed\n",
- __FILE__, __LINE__);
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "event-handler select failed");
return NULL;
}
- break;
- case FDEVENT_HANDLER_LINUX_RTSIG:
- if (0 != fdevent_linux_rtsig_init(ev)) {
- fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__);
- return NULL;
- }
- break;
+ return ev;
case FDEVENT_HANDLER_LINUX_SYSEPOLL:
if (0 != fdevent_linux_sysepoll_init(ev)) {
- fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__);
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"");
return NULL;
}
- break;
+ return ev;
case FDEVENT_HANDLER_SOLARIS_DEVPOLL:
if (0 != fdevent_solaris_devpoll_init(ev)) {
- fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__);
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"");
return NULL;
}
- break;
+ return ev;
+ case FDEVENT_HANDLER_SOLARIS_PORT:
+ if (0 != fdevent_solaris_port_init(ev)) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "event-handler solaris-eventports failed, try to set server.event-handler = \"poll\" or \"select\"");
+ return NULL;
+ }
+ return ev;
case FDEVENT_HANDLER_FREEBSD_KQUEUE:
if (0 != fdevent_freebsd_kqueue_init(ev)) {
- fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__);
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"");
+ return NULL;
+ }
+ return ev;
+ case FDEVENT_HANDLER_LIBEV:
+ if (0 != fdevent_libev_init(ev)) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "event-handler libev failed, try to set server.event-handler = \"poll\" or \"select\"");
return NULL;
}
+ return ev;
+ case FDEVENT_HANDLER_UNSET:
break;
- default:
- fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__);
- return NULL;
}
- return ev;
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"");
+ return NULL;
}
void fdevent_free(fdevents *ev) {
size_t i;
if (!ev) return;
-
+
if (ev->free) ev->free(ev);
-
+
for (i = 0; i < ev->maxfds; i++) {
if (ev->fdarray[i]) free(ev->fdarray[i]);
}
-
+
free(ev->fdarray);
free(ev);
}
int fdevent_reset(fdevents *ev) {
if (ev->reset) return ev->reset(ev);
-
+
return 0;
}
-fdnode *fdnode_init() {
+static fdnode *fdnode_init(void) {
fdnode *fdn;
-
+
fdn = calloc(1, sizeof(*fdn));
fdn->fd = -1;
return fdn;
}
-void fdnode_free(fdnode *fdn) {
+static void fdnode_free(fdnode *fdn) {
free(fdn);
}
int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) {
fdnode *fdn;
-
+
fdn = fdnode_init();
fdn->handler = handler;
fdn->fd = fd;
fdn->ctx = ctx;
-
+ fdn->handler_ctx = NULL;
+ fdn->events = 0;
+
ev->fdarray[fd] = fdn;
return 0;
@@ -119,33 +129,40 @@ int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) {
int fdevent_unregister(fdevents *ev, int fd) {
fdnode *fdn;
- if (!ev) return 0;
+
+ if (!ev) return 0;
fdn = ev->fdarray[fd];
-
+
+ assert(fdn->events == 0);
+
fdnode_free(fdn);
-
+
ev->fdarray[fd] = NULL;
-
+
return 0;
}
int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd) {
int fde = fde_ndx ? *fde_ndx : -1;
-
+
+ if (NULL == ev->fdarray[fd]) return 0;
+
if (ev->event_del) fde = ev->event_del(ev, fde, fd);
-
+ ev->fdarray[fd]->events = 0;
+
if (fde_ndx) *fde_ndx = fde;
-
+
return 0;
}
-int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events) {
+int fdevent_event_set(fdevents *ev, int *fde_ndx, int fd, int events) {
int fde = fde_ndx ? *fde_ndx : -1;
-
- if (ev->event_add) fde = ev->event_add(ev, fde, fd, events);
-
+
+ if (ev->event_set) fde = ev->event_set(ev, fde, fd, events);
+ ev->fdarray[fd]->events = events;
+
if (fde_ndx) *fde_ndx = fde;
-
+
return 0;
}
@@ -156,27 +173,27 @@ int fdevent_poll(fdevents *ev, int timeout_ms) {
int fdevent_event_get_revent(fdevents *ev, size_t ndx) {
if (ev->event_get_revent == NULL) SEGFAULT();
-
+
return ev->event_get_revent(ev, ndx);
}
int fdevent_event_get_fd(fdevents *ev, size_t ndx) {
if (ev->event_get_fd == NULL) SEGFAULT();
-
+
return ev->event_get_fd(ev, ndx);
}
fdevent_handler fdevent_get_handler(fdevents *ev, int fd) {
if (ev->fdarray[fd] == NULL) SEGFAULT();
if (ev->fdarray[fd]->fd != fd) SEGFAULT();
-
+
return ev->fdarray[fd]->handler;
}
void * fdevent_get_context(fdevents *ev, int fd) {
if (ev->fdarray[fd] == NULL) SEGFAULT();
if (ev->fdarray[fd]->fd != fd) SEGFAULT();
-
+
return ev->fdarray[fd]->ctx;
}
@@ -186,7 +203,7 @@ int fdevent_fcntl_set(fdevents *ev, int fd) {
fcntl(fd, F_SETFD, FD_CLOEXEC);
#endif
if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, fd);
-#ifdef O_NONBLOCK
+#ifdef O_NONBLOCK
return fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
#else
return 0;
@@ -196,7 +213,7 @@ int fdevent_fcntl_set(fdevents *ev, int fd) {
int fdevent_event_next_fdndx(fdevents *ev, int ndx) {
if (ev->event_next_fdndx) return ev->event_next_fdndx(ev, ndx);
-
+
return -1;
}
diff --git a/src/fdevent.h b/src/fdevent.h
index 0bc05ca..9dd9a6c 100644
--- a/src/fdevent.h
+++ b/src/fdevent.h
@@ -2,34 +2,30 @@
#define _FDEVENT_H_
#ifdef HAVE_CONFIG_H
-#include "config.h"
+# include "config.h"
#endif
+
#include "settings.h"
#include "bitset.h"
+#if defined HAVE_STDINT_H
+# include <stdint.h>
+#elif defined HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+#include <sys/types.h>
+
/* select event-system */
#if defined(HAVE_EPOLL_CTL) && defined(HAVE_SYS_EPOLL_H)
-# if defined HAVE_STDINT_H
-# include <stdint.h>
-# endif
# define USE_LINUX_EPOLL
-# include <sys/epoll.h>
#endif
-/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes
+/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes
* under /usr/include/sys/ */
#if defined HAVE_POLL && (defined(HAVE_SYS_POLL_H) || defined(HAVE_POLL_H))
# define USE_POLL
-# ifdef HAVE_POLL_H
-# include <poll.h>
-# else
-# include <sys/poll.h>
-# endif
-# if defined HAVE_SIGTIMEDWAIT && defined(__linux__)
-# define USE_LINUX_SIGIO
-# include <signal.h>
-# endif
#endif
#if defined HAVE_SELECT
@@ -44,21 +40,27 @@
#if defined HAVE_SYS_DEVPOLL_H && defined(__sun)
# define USE_SOLARIS_DEVPOLL
-# include <sys/devpoll.h>
+#endif
+
+#if defined HAVE_PORT_H && defined HAVE_PORT_CREATE && defined(__sun)
+# define USE_SOLARIS_PORT
+# include <port.h>
#endif
#if defined HAVE_SYS_EVENT_H && defined HAVE_KQUEUE
# define USE_FREEBSD_KQUEUE
-# include <sys/event.h>
#endif
-#if defined HAVE_SYS_PORT_H && defined HAVE_PORT_CREATE
-# define USE_SOLARIS_PORT
-# include <sys/port.h>
+#if defined HAVE_LIBEV
+# define USE_LIBEV
#endif
+struct server;
-typedef handler_t (*fdevent_handler)(void *srv, void *ctx, int revents);
+typedef handler_t (*fdevent_handler)(struct server *srv, void *ctx, int revents);
+
+/* these are the POLL* values from <bits/poll.h> (linux poll)
+ */
#define FDEVENT_IN BV(0)
#define FDEVENT_PRI BV(1)
@@ -67,134 +69,115 @@ typedef handler_t (*fdevent_handler)(void *srv, void *ctx, int revents);
#define FDEVENT_HUP BV(4)
#define FDEVENT_NVAL BV(5)
-typedef enum { FD_EVENT_TYPE_UNSET = -1,
- FD_EVENT_TYPE_CONNECTION,
- FD_EVENT_TYPE_FCGI_CONNECTION,
- FD_EVENT_TYPE_DIRWATCH,
- FD_EVENT_TYPE_CGI_CONNECTION
+typedef enum { FD_EVENT_TYPE_UNSET = -1,
+ FD_EVENT_TYPE_CONNECTION,
+ FD_EVENT_TYPE_FCGI_CONNECTION,
+ FD_EVENT_TYPE_DIRWATCH,
+ FD_EVENT_TYPE_CGI_CONNECTION
} fd_event_t;
-typedef enum { FDEVENT_HANDLER_UNSET,
+typedef enum { FDEVENT_HANDLER_UNSET,
FDEVENT_HANDLER_SELECT,
FDEVENT_HANDLER_POLL,
- FDEVENT_HANDLER_LINUX_RTSIG,
FDEVENT_HANDLER_LINUX_SYSEPOLL,
FDEVENT_HANDLER_SOLARIS_DEVPOLL,
+ FDEVENT_HANDLER_SOLARIS_PORT,
FDEVENT_HANDLER_FREEBSD_KQUEUE,
- FDEVENT_HANDLER_SOLARIS_PORT
+ FDEVENT_HANDLER_LIBEV
} fdevent_handler_t;
-/**
- * a mapping from fd to connection structure
- *
- */
-typedef struct {
- int fd; /**< the fd */
- void *conn; /**< a reference the corresponding data-structure */
- fd_event_t fd_type; /**< type of the fd */
- int events; /**< registered events */
- int revents;
-} fd_conn;
-
-typedef struct {
- fd_conn *ptr;
-
- size_t size;
- size_t used;
-} fd_conn_buffer;
-
-/**
- * array of unused fd's
- *
- */
typedef struct _fdnode {
fdevent_handler handler;
void *ctx;
+ void *handler_ctx;
int fd;
-
- struct _fdnode *prev, *next;
+ int events;
} fdnode;
+/**
+ * array of unused fd's
+ *
+ */
+
typedef struct {
int *ptr;
-
+
size_t used;
size_t size;
} buffer_int;
/**
* fd-event handler for select(), poll() and rt-signals on Linux 2.4
- *
+ *
*/
typedef struct fdevents {
+ struct server *srv;
fdevent_handler_t type;
-
+
fdnode **fdarray;
size_t maxfds;
-
-#ifdef USE_LINUX_SIGIO
- int in_sigio;
- int signum;
- sigset_t sigset;
- siginfo_t siginfo;
- bitset *sigbset;
-#endif
+
#ifdef USE_LINUX_EPOLL
int epoll_fd;
struct epoll_event *epoll_events;
#endif
#ifdef USE_POLL
struct pollfd *pollfds;
-
+
size_t size;
size_t used;
-
+
buffer_int unused;
#endif
#ifdef USE_SELECT
fd_set select_read;
fd_set select_write;
fd_set select_error;
-
+
fd_set select_set_read;
fd_set select_set_write;
fd_set select_set_error;
-
+
int select_max_fd;
#endif
#ifdef USE_SOLARIS_DEVPOLL
int devpoll_fd;
struct pollfd *devpollfds;
#endif
+#ifdef USE_SOLARIS_PORT
+ port_event_t *port_events;
+#endif
#ifdef USE_FREEBSD_KQUEUE
int kq_fd;
struct kevent *kq_results;
- bitset *kq_bevents;
#endif
#ifdef USE_SOLARIS_PORT
int port_fd;
#endif
+#ifdef USE_LIBEV
+ struct ev_loop *libev_loop;
+#endif
int (*reset)(struct fdevents *ev);
void (*free)(struct fdevents *ev);
-
- int (*event_add)(struct fdevents *ev, int fde_ndx, int fd, int events);
+
+ int (*event_set)(struct fdevents *ev, int fde_ndx, int fd, int events);
int (*event_del)(struct fdevents *ev, int fde_ndx, int fd);
int (*event_get_revent)(struct fdevents *ev, size_t ndx);
int (*event_get_fd)(struct fdevents *ev, size_t ndx);
-
+
int (*event_next_fdndx)(struct fdevents *ev, int ndx);
-
+
int (*poll)(struct fdevents *ev, int timeout_ms);
-
+
int (*fcntl_set)(struct fdevents *ev, int fd);
} fdevents;
-fdevents *fdevent_init(size_t maxfds, fdevent_handler_t type);
-int fdevent_reset(fdevents *ev);
+fdevents *fdevent_init(struct server *srv, size_t maxfds, fdevent_handler_t type);
+int fdevent_reset(fdevents *ev); /* "init" after fork() */
void fdevent_free(fdevents *ev);
-int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events);
+int fdevent_event_set(fdevents *ev, int *fde_ndx, int fd, int events); /* events can be FDEVENT_IN, FDEVENT_OUT or FDEVENT_IN | FDEVENT_OUT */
int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd);
int fdevent_event_get_revent(fdevents *ev, size_t ndx);
int fdevent_event_get_fd(fdevents *ev, size_t ndx);
@@ -212,11 +195,10 @@ int fdevent_fcntl_set(fdevents *ev, int fd);
int fdevent_select_init(fdevents *ev);
int fdevent_poll_init(fdevents *ev);
-int fdevent_linux_rtsig_init(fdevents *ev);
int fdevent_linux_sysepoll_init(fdevents *ev);
int fdevent_solaris_devpoll_init(fdevents *ev);
+int fdevent_solaris_port_init(fdevents *ev);
int fdevent_freebsd_kqueue_init(fdevents *ev);
+int fdevent_libev_init(fdevents *ev);
#endif
-
-
diff --git a/src/fdevent_freebsd_kqueue.c b/src/fdevent_freebsd_kqueue.c
index b955726..220e265 100644
--- a/src/fdevent_freebsd_kqueue.c
+++ b/src/fdevent_freebsd_kqueue.c
@@ -1,3 +1,7 @@
+#include "fdevent.h"
+#include "buffer.h"
+#include "log.h"
+
#include <sys/types.h>
#include <unistd.h>
@@ -8,81 +12,97 @@
#include <signal.h>
#include <fcntl.h>
-#include "fdevent.h"
-#include "settings.h"
-#include "buffer.h"
-#include "server.h"
-
#ifdef USE_FREEBSD_KQUEUE
-#include <sys/event.h>
-#include <sys/time.h>
+# include <sys/event.h>
+# include <sys/time.h>
static void fdevent_freebsd_kqueue_free(fdevents *ev) {
close(ev->kq_fd);
free(ev->kq_results);
- bitset_free(ev->kq_bevents);
}
static int fdevent_freebsd_kqueue_event_del(fdevents *ev, int fde_ndx, int fd) {
- int filter, ret;
- struct kevent kev;
+ int ret, n = 0;
+ struct kevent kev[2];
struct timespec ts;
+ int oevents;
if (fde_ndx < 0) return -1;
- filter = bitset_test_bit(ev->kq_bevents, fd) ? EVFILT_READ : EVFILT_WRITE;
+ oevents = ev->fdarray[fd]->events;
- EV_SET(&kev, fd, filter, EV_DELETE, 0, 0, NULL);
+ if (oevents & FDEVENT_IN) {
+ EV_SET(&kev[n], fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
+ n++;
+ }
+ if (oevents & FDEVENT_OUT) {
+ EV_SET(&kev[n], fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
+ n++;
+ }
+
+ if (0 == n) return -1;
ts.tv_sec = 0;
ts.tv_nsec = 0;
ret = kevent(ev->kq_fd,
- &kev, 1,
- NULL, 0,
- &ts);
+ &kev, n,
+ NULL, 0,
+ &ts);
if (ret == -1) {
- fprintf(stderr, "%s.%d: kqueue failed polling: %s\n",
- __FILE__, __LINE__, strerror(errno));
+ log_error_write(ev->srv, __FILE__, __LINE__, "SS",
+ "kqueue event delete failed: ", strerror(errno));
return -1;
}
-
+
return -1;
}
-static int fdevent_freebsd_kqueue_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
- int filter, ret;
- struct kevent kev;
+static int fdevent_freebsd_kqueue_event_set(fdevents *ev, int fde_ndx, int fd, int events) {
+ int ret, n = 0;
+ struct kevent kev[2];
struct timespec ts;
+ int oevents = ev->fdarray[fd]->events;
+ int addevents = events & ~oevents;
+ int delevents = ~events & oevents;
UNUSED(fde_ndx);
- filter = (events & FDEVENT_IN) ? EVFILT_READ : EVFILT_WRITE;
+ if (events == oevents) return fd;
- EV_SET(&kev, fd, filter, EV_ADD|EV_CLEAR, 0, 0, NULL);
+ if (addevents & FDEVENT_IN) {
+ EV_SET(&kev[n], fd, EVFILT_READ, EV_ADD|EV_CLEAR, 0, 0, NULL);
+ n++;
+ } else if (delevents & FDEVENT_IN) {
+ EV_SET(&kev[n], fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
+ n++;
+ }
+ if (addevents & FDEVENT_OUT) {
+ EV_SET(&kev[n], fd, EVFILT_WRITE, EV_ADD|EV_CLEAR, 0, 0, NULL);
+ n++;
+ } else if (delevents & FDEVENT_OUT) {
+ EV_SET(&kev[n], fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
+ n++;
+ }
+
+ if (0 == n) return fd;
ts.tv_sec = 0;
ts.tv_nsec = 0;
-
+
ret = kevent(ev->kq_fd,
- &kev, 1,
- NULL, 0,
- &ts);
+ kev, n,
+ NULL, 0,
+ &ts);
if (ret == -1) {
- fprintf(stderr, "%s.%d: kqueue failed polling: %s\n",
- __FILE__, __LINE__, strerror(errno));
+ log_error_write(ev->srv, __FILE__, __LINE__, "SS",
+ "kqueue event set failed: ", strerror(errno));
return -1;
}
-
- if (filter == EVFILT_READ) {
- bitset_set_bit(ev->kq_bevents, fd);
- } else {
- bitset_clear_bit(ev->kq_bevents, fd);
- }
return fd;
}
@@ -95,9 +115,9 @@ static int fdevent_freebsd_kqueue_poll(fdevents *ev, int timeout_ms) {
ts.tv_nsec = (timeout_ms % 1000) * 1000000;
ret = kevent(ev->kq_fd,
- NULL, 0,
- ev->kq_results, ev->maxfds,
- &ts);
+ NULL, 0,
+ ev->kq_results, ev->maxfds,
+ &ts);
if (ret == -1) {
switch(errno) {
@@ -105,8 +125,8 @@ static int fdevent_freebsd_kqueue_poll(fdevents *ev, int timeout_ms) {
/* we got interrupted, perhaps just a SIGCHLD of a CGI script */
return 0;
default:
- fprintf(stderr, "%s.%d: kqueue failed polling: %s\n",
- __FILE__, __LINE__, strerror(errno));
+ log_error_write(ev->srv, __FILE__, __LINE__, "SS",
+ "kqueue failed polling: ", strerror(errno));
break;
}
}
@@ -124,7 +144,7 @@ static int fdevent_freebsd_kqueue_event_get_revent(fdevents *ev, size_t ndx) {
} else if (e == EVFILT_WRITE) {
events |= FDEVENT_OUT;
}
-
+
e = ev->kq_results[ndx].flags;
if (e & EV_EOF) {
@@ -150,12 +170,12 @@ static int fdevent_freebsd_kqueue_event_next_fdndx(fdevents *ev, int ndx) {
static int fdevent_freebsd_kqueue_reset(fdevents *ev) {
if (-1 == (ev->kq_fd = kqueue())) {
- fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__, strerror(errno));
-
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "kqueue failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\"");
+
return -1;
}
-
+
return 0;
}
@@ -170,7 +190,7 @@ int fdevent_freebsd_kqueue_init(fdevents *ev) {
SET(reset);
SET(event_del);
- SET(event_add);
+ SET(event_set);
SET(event_next_fdndx);
SET(event_get_fd);
@@ -179,14 +199,13 @@ int fdevent_freebsd_kqueue_init(fdevents *ev) {
ev->kq_fd = -1;
ev->kq_results = calloc(ev->maxfds, sizeof(*ev->kq_results));
- ev->kq_bevents = bitset_init(ev->maxfds);
/* check that kqueue works */
if (-1 == (ev->kq_fd = kqueue())) {
- fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__, strerror(errno));
-
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "kqueue failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\"");
+
return -1;
}
@@ -199,8 +218,8 @@ int fdevent_freebsd_kqueue_init(fdevents *ev) {
int fdevent_freebsd_kqueue_init(fdevents *ev) {
UNUSED(ev);
- fprintf(stderr, "%s.%d: kqueue not available, try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__);
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "kqueue not available, try to set server.event-handler = \"poll\" or \"select\"");
return -1;
}
diff --git a/src/fdevent_libev.c b/src/fdevent_libev.c
new file mode 100644
index 0000000..de62676
--- /dev/null
+++ b/src/fdevent_libev.c
@@ -0,0 +1,171 @@
+#include "fdevent.h"
+#include "buffer.h"
+#include "log.h"
+
+#include <assert.h>
+
+#ifdef USE_LIBEV
+
+# include <ev.h>
+
+static void io_watcher_cb(struct ev_loop *loop, ev_io *w, int revents) {
+ fdevents *ev = w->data;
+ fdnode *fdn = ev->fdarray[w->fd];
+ int r = 0;
+ UNUSED(loop);
+
+ if (revents & EV_READ) r |= FDEVENT_IN;
+ if (revents & EV_WRITE) r |= FDEVENT_OUT;
+ if (revents & EV_ERROR) r |= FDEVENT_ERR;
+
+ switch (r = (*fdn->handler)(ev->srv, fdn->ctx, r)) {
+ case HANDLER_FINISHED:
+ case HANDLER_GO_ON:
+ case HANDLER_WAIT_FOR_EVENT:
+ case HANDLER_WAIT_FOR_FD:
+ break;
+ case HANDLER_ERROR:
+ /* should never happen */
+ SEGFAULT();
+ break;
+ default:
+ log_error_write(ev->srv, __FILE__, __LINE__, "d", r);
+ break;
+ }
+}
+
+static void fdevent_libev_free(fdevents *ev) {
+ UNUSED(ev);
+}
+
+static int fdevent_libev_event_del(fdevents *ev, int fde_ndx, int fd) {
+ fdnode *fdn;
+ ev_io *watcher;
+
+ if (-1 == fde_ndx) return -1;
+
+ fdn = ev->fdarray[fd];
+ watcher = fdn->handler_ctx;
+
+ if (!watcher) return -1;
+
+ ev_io_stop(ev->libev_loop, watcher);
+ free(watcher);
+ fdn->handler_ctx = NULL;
+
+ return -1;
+}
+
+static int fdevent_libev_event_set(fdevents *ev, int fde_ndx, int fd, int events) {
+ fdnode *fdn = ev->fdarray[fd];
+ ev_io *watcher = fdn->handler_ctx;
+ int ev_events = 0;
+ UNUSED(fde_ndx);
+
+ if (events & FDEVENT_IN) ev_events |= EV_READ;
+ if (events & FDEVENT_OUT) ev_events |= EV_WRITE;
+
+ if (!watcher) {
+ fdn->handler_ctx = watcher = calloc(1, sizeof(ev_io));
+ assert(watcher);
+
+ ev_io_init(watcher, io_watcher_cb, fd, ev_events);
+ watcher->data = ev;
+ ev_io_start(ev->libev_loop, watcher);
+ } else {
+ if ((watcher->events & (EV_READ | EV_WRITE)) != ev_events) {
+ ev_io_stop(ev->libev_loop, watcher);
+ ev_io_set(watcher, watcher->fd, ev_events);
+ ev_io_start(ev->libev_loop, watcher);
+ }
+ }
+
+ return fd;
+}
+
+static void timeout_watcher_cb(struct ev_loop *loop, ev_timer *w, int revents) {
+ UNUSED(loop);
+ UNUSED(w);
+ UNUSED(revents);
+}
+
+
+static int fdevent_libev_poll(fdevents *ev, int timeout_ms) {
+ ev_timer timeout_watcher;
+
+ ev_init(&timeout_watcher, timeout_watcher_cb);
+ ev_timer_set(&timeout_watcher, ((ev_tstamp) timeout_ms)/1000.0, 0.0);
+ ev_timer_start(ev->libev_loop, &timeout_watcher);
+
+ ev_loop(ev->libev_loop, EVLOOP_ONESHOT);
+
+ ev_timer_stop(ev->libev_loop, &timeout_watcher);
+
+ return 0;
+}
+
+static int fdevent_libev_event_get_revent(fdevents *ev, size_t ndx) {
+ UNUSED(ev);
+ UNUSED(ndx);
+
+ return 0;
+}
+
+static int fdevent_libev_event_get_fd(fdevents *ev, size_t ndx) {
+ UNUSED(ev);
+ UNUSED(ndx);
+
+ return -1;
+}
+
+static int fdevent_libev_event_next_fdndx(fdevents *ev, int ndx) {
+ UNUSED(ev);
+ UNUSED(ndx);
+
+ return -1;
+}
+
+static int fdevent_libev_reset(fdevents *ev) {
+ UNUSED(ev);
+
+ ev_default_fork();
+
+ return 0;
+}
+
+int fdevent_libev_init(fdevents *ev) {
+ ev->type = FDEVENT_HANDLER_LIBEV;
+#define SET(x) \
+ ev->x = fdevent_libev_##x;
+
+ SET(free);
+ SET(poll);
+ SET(reset);
+
+ SET(event_del);
+ SET(event_set);
+
+ SET(event_next_fdndx);
+ SET(event_get_fd);
+ SET(event_get_revent);
+
+ if (NULL == (ev->libev_loop = ev_default_loop(0))) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "ev_default_loop failed , try to set server.event-handler = \"poll\" or \"select\"");
+
+ return -1;
+ }
+
+ return 0;
+}
+
+#else
+int fdevent_libev_init(fdevents *ev) {
+ UNUSED(ev);
+
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "libev not supported, try to set server.event-handler = \"poll\" or \"select\"");
+
+ return -1;
+}
+#endif
diff --git a/src/fdevent_linux_rtsig.c b/src/fdevent_linux_rtsig.c
deleted file mode 100644
index dcefff8..0000000
--- a/src/fdevent_linux_rtsig.c
+++ /dev/null
@@ -1,260 +0,0 @@
-#include <sys/types.h>
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <signal.h>
-#include <limits.h>
-
-#define __USE_GNU
-#include <fcntl.h>
-
-#include "fdevent.h"
-#include "settings.h"
-#include "buffer.h"
-
-#ifdef USE_LINUX_SIGIO
-static void fdevent_linux_rtsig_free(fdevents *ev) {
- free(ev->pollfds);
- if (ev->unused.ptr) free(ev->unused.ptr);
-
- bitset_free(ev->sigbset);
-}
-
-
-static int fdevent_linux_rtsig_event_del(fdevents *ev, int fde_ndx, int fd) {
- if (fde_ndx < 0) return -1;
-
- if ((size_t)fde_ndx >= ev->used) {
- fprintf(stderr, "%s.%d: del! out of range %d %zu\n", __FILE__, __LINE__, fde_ndx, ev->used);
- SEGFAULT();
- }
-
- if (ev->pollfds[fde_ndx].fd == fd) {
- size_t k = fde_ndx;
-
- ev->pollfds[k].fd = -1;
-
- bitset_clear_bit(ev->sigbset, fd);
-
- if (ev->unused.size == 0) {
- ev->unused.size = 16;
- ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
- } else if (ev->unused.size == ev->unused.used) {
- ev->unused.size += 16;
- ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
- }
-
- ev->unused.ptr[ev->unused.used++] = k;
- } else {
- fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[fde_ndx].fd, fd);
-
- SEGFAULT();
- }
-
- return -1;
-}
-
-#if 0
-static int fdevent_linux_rtsig_event_compress(fdevents *ev) {
- size_t j;
-
- if (ev->used == 0) return 0;
- if (ev->unused.used != 0) return 0;
-
- for (j = ev->used - 1; j + 1 > 0; j--) {
- if (ev->pollfds[j].fd == -1) ev->used--;
- }
-
-
- return 0;
-}
-#endif
-
-static int fdevent_linux_rtsig_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
- /* known index */
- if (fde_ndx != -1) {
- if (ev->pollfds[fde_ndx].fd == fd) {
- ev->pollfds[fde_ndx].events = events;
-
- return fde_ndx;
- }
- fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
- SEGFAULT();
- }
-
- if (ev->unused.used > 0) {
- int k = ev->unused.ptr[--ev->unused.used];
-
- ev->pollfds[k].fd = fd;
- ev->pollfds[k].events = events;
-
- bitset_set_bit(ev->sigbset, fd);
-
- return k;
- } else {
- if (ev->size == 0) {
- ev->size = 16;
- ev->pollfds = malloc(sizeof(*ev->pollfds) * ev->size);
- } else if (ev->size == ev->used) {
- ev->size += 16;
- ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
- }
-
- ev->pollfds[ev->used].fd = fd;
- ev->pollfds[ev->used].events = events;
-
- bitset_set_bit(ev->sigbset, fd);
-
- return ev->used++;
- }
-}
-
-static int fdevent_linux_rtsig_poll(fdevents *ev, int timeout_ms) {
- struct timespec ts;
- int r;
-
-#if 0
- fdevent_linux_rtsig_event_compress(ev);
-#endif
-
- ev->in_sigio = 1;
-
- ts.tv_sec = timeout_ms / 1000;
- ts.tv_nsec = (timeout_ms % 1000) * 1000000;
- r = sigtimedwait(&(ev->sigset), &(ev->siginfo), &(ts));
-
- if (r == -1) {
- if (errno == EAGAIN) return 0;
- return r;
- } else if (r == SIGIO) {
- struct sigaction act;
-
- /* flush the signal queue */
- memset(&act, 0, sizeof(act));
- act.sa_handler = SIG_IGN;
- sigaction(ev->signum, &act, NULL);
-
- /* re-enable the signal queue */
- act.sa_handler = SIG_DFL;
- sigaction(ev->signum, &act, NULL);
-
- ev->in_sigio = 0;
- r = poll(ev->pollfds, ev->used, timeout_ms);
-
- return r;
- } else if (r == ev->signum) {
-# if 0
- fprintf(stderr, "event: %d %02lx\n", ev->siginfo.si_fd, ev->siginfo.si_band);
-# endif
- return bitset_test_bit(ev->sigbset, ev->siginfo.si_fd);
- } else {
- /* ? */
- return -1;
- }
-}
-
-static int fdevent_linux_rtsig_event_get_revent(fdevents *ev, size_t ndx) {
- if (ev->in_sigio == 1) {
-# if 0
- if (ev->siginfo.si_band == POLLERR) {
- fprintf(stderr, "event: %d %02lx %02x %s\n", ev->siginfo.si_fd, ev->siginfo.si_band, errno, strerror(errno));
- }
-# endif
- if (ndx != 0) {
- fprintf(stderr, "+\n");
- return 0;
- }
-
- return ev->siginfo.si_band & 0x3f;
- } else {
- if (ndx >= ev->used) {
- fprintf(stderr, "%s.%d: event: %zu %zu\n", __FILE__, __LINE__, ndx, ev->used);
- return 0;
- }
- return ev->pollfds[ndx].revents;
- }
-}
-
-static int fdevent_linux_rtsig_event_get_fd(fdevents *ev, size_t ndx) {
- if (ev->in_sigio == 1) {
- return ev->siginfo.si_fd;
- } else {
- return ev->pollfds[ndx].fd;
- }
-}
-
-static int fdevent_linux_rtsig_fcntl_set(fdevents *ev, int fd) {
- static pid_t pid = 0;
-
- if (pid == 0) pid = getpid();
-
- if (-1 == fcntl(fd, F_SETSIG, ev->signum)) return -1;
-
- if (-1 == fcntl(fd, F_SETOWN, (int) pid)) return -1;
-
- return fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK | O_RDWR);
-}
-
-
-static int fdevent_linux_rtsig_event_next_fdndx(fdevents *ev, int ndx) {
- if (ev->in_sigio == 1) {
- if (ndx < 0) return 0;
- return -1;
- } else {
- size_t i;
-
- i = (ndx < 0) ? 0 : ndx + 1;
- for (; i < ev->used; i++) {
- if (ev->pollfds[i].revents) break;
- }
-
- return i;
- }
-}
-
-int fdevent_linux_rtsig_init(fdevents *ev) {
- ev->type = FDEVENT_HANDLER_LINUX_RTSIG;
-#define SET(x) \
- ev->x = fdevent_linux_rtsig_##x;
-
- SET(free);
- SET(poll);
-
- SET(event_del);
- SET(event_add);
-
- SET(event_next_fdndx);
- SET(fcntl_set);
- SET(event_get_fd);
- SET(event_get_revent);
-
- ev->signum = SIGRTMIN + 1;
-
- sigemptyset(&(ev->sigset));
- sigaddset(&(ev->sigset), ev->signum);
- sigaddset(&(ev->sigset), SIGIO);
- if (-1 == sigprocmask(SIG_BLOCK, &(ev->sigset), NULL)) {
- fprintf(stderr, "%s.%d: sigprocmask failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__, strerror(errno));
-
- return -1;
- }
-
- ev->in_sigio = 1;
-
- ev->sigbset = bitset_init(ev->maxfds);
-
- return 0;
-}
-#else
-int fdevent_linux_rtsig_init(fdevents *ev) {
- UNUSED(ev);
-
- fprintf(stderr, "%s.%d: linux-rtsig not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__);
- return -1;
-}
-#endif
diff --git a/src/fdevent_linux_sysepoll.c b/src/fdevent_linux_sysepoll.c
index 31caabd..f761ed6 100644
--- a/src/fdevent_linux_sysepoll.c
+++ b/src/fdevent_linux_sysepoll.c
@@ -1,3 +1,7 @@
+#include "fdevent.h"
+#include "buffer.h"
+#include "log.h"
+
#include <sys/types.h>
#include <unistd.h>
@@ -8,11 +12,10 @@
#include <signal.h>
#include <fcntl.h>
-#include "fdevent.h"
-#include "settings.h"
-#include "buffer.h"
-
#ifdef USE_LINUX_EPOLL
+
+# include <sys/epoll.h>
+
static void fdevent_linux_sysepoll_free(fdevents *ev) {
close(ev->epoll_fd);
free(ev->epoll_events);
@@ -20,36 +23,37 @@ static void fdevent_linux_sysepoll_free(fdevents *ev) {
static int fdevent_linux_sysepoll_event_del(fdevents *ev, int fde_ndx, int fd) {
struct epoll_event ep;
-
+
if (fde_ndx < 0) return -1;
-
+
memset(&ep, 0, sizeof(ep));
-
+
ep.data.fd = fd;
ep.data.ptr = NULL;
-
+
if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fd, &ep)) {
- fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
-
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "epoll_ctl failed: ", strerror(errno), ", dying");
+
SEGFAULT();
-
+
return 0;
}
-
-
+
+
return -1;
}
-static int fdevent_linux_sysepoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
+static int fdevent_linux_sysepoll_event_set(fdevents *ev, int fde_ndx, int fd, int events) {
struct epoll_event ep;
int add = 0;
-
+
if (fde_ndx == -1) add = 1;
-
+
memset(&ep, 0, sizeof(ep));
-
+
ep.events = 0;
-
+
if (events & FDEVENT_IN) ep.events |= EPOLLIN;
if (events & FDEVENT_OUT) ep.events |= EPOLLOUT;
@@ -60,20 +64,21 @@ static int fdevent_linux_sysepoll_event_add(fdevents *ev, int fde_ndx, int fd, i
* sent.
*
*/
-
+
ep.events |= EPOLLERR | EPOLLHUP /* | EPOLLET */;
-
+
ep.data.ptr = NULL;
ep.data.fd = fd;
-
+
if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, &ep)) {
- fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
-
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "epoll_ctl failed: ", strerror(errno), ", dying");
+
SEGFAULT();
-
+
return 0;
}
-
+
return fd;
}
@@ -83,32 +88,33 @@ static int fdevent_linux_sysepoll_poll(fdevents *ev, int timeout_ms) {
static int fdevent_linux_sysepoll_event_get_revent(fdevents *ev, size_t ndx) {
int events = 0, e;
-
+
e = ev->epoll_events[ndx].events;
if (e & EPOLLIN) events |= FDEVENT_IN;
if (e & EPOLLOUT) events |= FDEVENT_OUT;
if (e & EPOLLERR) events |= FDEVENT_ERR;
if (e & EPOLLHUP) events |= FDEVENT_HUP;
if (e & EPOLLPRI) events |= FDEVENT_PRI;
-
- return e;
+
+ return events;
}
static int fdevent_linux_sysepoll_event_get_fd(fdevents *ev, size_t ndx) {
# if 0
- fprintf(stderr, "%s.%d: %d, %d\n", __FILE__, __LINE__, ndx, ev->epoll_events[ndx].data.fd);
+ log_error_write(ev->srv, __FILE__, __LINE__, "SD, D",
+ "fdevent_linux_sysepoll_event_get_fd: ", (int) ndx, ev->epoll_events[ndx].data.fd);
# endif
-
+
return ev->epoll_events[ndx].data.fd;
}
static int fdevent_linux_sysepoll_event_next_fdndx(fdevents *ev, int ndx) {
size_t i;
-
+
UNUSED(ev);
i = (ndx < 0) ? 0 : ndx + 1;
-
+
return i;
}
@@ -116,27 +122,27 @@ int fdevent_linux_sysepoll_init(fdevents *ev) {
ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL;
#define SET(x) \
ev->x = fdevent_linux_sysepoll_##x;
-
+
SET(free);
SET(poll);
-
+
SET(event_del);
- SET(event_add);
-
+ SET(event_set);
+
SET(event_next_fdndx);
SET(event_get_fd);
SET(event_get_revent);
-
+
if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) {
- fprintf(stderr, "%s.%d: epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__, strerror(errno));
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "epoll_create failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\"");
return -1;
}
if (-1 == fcntl(ev->epoll_fd, F_SETFD, FD_CLOEXEC)) {
- fprintf(stderr, "%s.%d: epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__, strerror(errno));
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "fcntl on epoll-fd failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\"");
close(ev->epoll_fd);
@@ -152,9 +158,9 @@ int fdevent_linux_sysepoll_init(fdevents *ev) {
int fdevent_linux_sysepoll_init(fdevents *ev) {
UNUSED(ev);
- fprintf(stderr, "%s.%d: linux-sysepoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__);
-
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "linux-sysepoll not supported, try to set server.event-handler = \"poll\" or \"select\"");
+
return -1;
}
#endif
diff --git a/src/fdevent_poll.c b/src/fdevent_poll.c
index 7d8017a..e8dc385 100644
--- a/src/fdevent_poll.c
+++ b/src/fdevent_poll.c
@@ -1,3 +1,7 @@
+#include "fdevent.h"
+#include "buffer.h"
+#include "log.h"
+
#include <sys/types.h>
#include <unistd.h>
@@ -8,11 +12,14 @@
#include <signal.h>
#include <fcntl.h>
-#include "fdevent.h"
-#include "settings.h"
-#include "buffer.h"
-
#ifdef USE_POLL
+
+# ifdef HAVE_POLL_H
+# include <poll.h>
+# else
+# include <sys/poll.h>
+# endif
+
static void fdevent_poll_free(fdevents *ev) {
free(ev->pollfds);
if (ev->unused.ptr) free(ev->unused.ptr);
@@ -20,19 +27,20 @@ static void fdevent_poll_free(fdevents *ev) {
static int fdevent_poll_event_del(fdevents *ev, int fde_ndx, int fd) {
if (fde_ndx < 0) return -1;
-
+
if ((size_t)fde_ndx >= ev->used) {
- fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, fde_ndx, ev->used);
+ log_error_write(ev->srv, __FILE__, __LINE__, "SdD",
+ "del! out of range ", fde_ndx, (int) ev->used);
SEGFAULT();
}
-
+
if (ev->pollfds[fde_ndx].fd == fd) {
size_t k = fde_ndx;
-
+
ev->pollfds[k].fd = -1;
/* ev->pollfds[k].events = 0; */
/* ev->pollfds[k].revents = 0; */
-
+
if (ev->unused.size == 0) {
ev->unused.size = 16;
ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
@@ -40,47 +48,55 @@ static int fdevent_poll_event_del(fdevents *ev, int fde_ndx, int fd) {
ev->unused.size += 16;
ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
}
-
+
ev->unused.ptr[ev->unused.used++] = k;
} else {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SdD",
+ "del! ", ev->pollfds[fde_ndx].fd, fd);
+
SEGFAULT();
}
-
+
return -1;
}
#if 0
static int fdevent_poll_event_compress(fdevents *ev) {
size_t j;
-
+
if (ev->used == 0) return 0;
if (ev->unused.used != 0) return 0;
-
+
for (j = ev->used - 1; j + 1 > 0 && ev->pollfds[j].fd == -1; j--) ev->used--;
-
+
return 0;
}
#endif
-static int fdevent_poll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
+static int fdevent_poll_event_set(fdevents *ev, int fde_ndx, int fd, int events) {
+ int pevents = 0;
+ if (events & FDEVENT_IN) pevents |= POLLIN;
+ if (events & FDEVENT_OUT) pevents |= POLLOUT;
+
/* known index */
-
+
if (fde_ndx != -1) {
if (ev->pollfds[fde_ndx].fd == fd) {
- ev->pollfds[fde_ndx].events = events;
-
+ ev->pollfds[fde_ndx].events = pevents;
+
return fde_ndx;
}
- fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
+ log_error_write(ev->srv, __FILE__, __LINE__, "SdD",
+ "set: ", fde_ndx, ev->pollfds[fde_ndx].fd);
SEGFAULT();
}
-
+
if (ev->unused.used > 0) {
int k = ev->unused.ptr[--ev->unused.used];
-
+
ev->pollfds[k].fd = fd;
- ev->pollfds[k].events = events;
-
+ ev->pollfds[k].events = pevents;
+
return k;
} else {
if (ev->size == 0) {
@@ -90,10 +106,10 @@ static int fdevent_poll_event_add(fdevents *ev, int fde_ndx, int fd, int events)
ev->size += 16;
ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
}
-
+
ev->pollfds[ev->used].fd = fd;
- ev->pollfds[ev->used].events = events;
-
+ ev->pollfds[ev->used].events = pevents;
+
return ev->used++;
}
}
@@ -107,14 +123,16 @@ static int fdevent_poll_poll(fdevents *ev, int timeout_ms) {
static int fdevent_poll_event_get_revent(fdevents *ev, size_t ndx) {
int r, poll_r;
+
if (ndx >= ev->used) {
- fprintf(stderr, "%s.%d: dying because: event: %zd >= %zd\n", __FILE__, __LINE__, ndx, ev->used);
-
+ log_error_write(ev->srv, __FILE__, __LINE__, "sii",
+ "dying because: event: ", (int) ndx, (int) ev->used);
+
SEGFAULT();
-
+
return 0;
}
-
+
if (ev->pollfds[ndx].revents & POLLNVAL) {
/* should never happen */
SEGFAULT();
@@ -123,7 +141,7 @@ static int fdevent_poll_event_get_revent(fdevents *ev, size_t ndx) {
r = 0;
poll_r = ev->pollfds[ndx].revents;
- /* map POLL* to FDEVEN_* */
+ /* map POLL* to FDEVEN_*; they are probably the same, but still. */
if (poll_r & POLLIN) r |= FDEVENT_IN;
if (poll_r & POLLOUT) r |= FDEVENT_OUT;
@@ -131,8 +149,8 @@ static int fdevent_poll_event_get_revent(fdevents *ev, size_t ndx) {
if (poll_r & POLLHUP) r |= FDEVENT_HUP;
if (poll_r & POLLNVAL) r |= FDEVENT_NVAL;
if (poll_r & POLLPRI) r |= FDEVENT_PRI;
-
- return ev->pollfds[ndx].revents;
+
+ return r;
}
static int fdevent_poll_event_get_fd(fdevents *ev, size_t ndx) {
@@ -141,30 +159,30 @@ static int fdevent_poll_event_get_fd(fdevents *ev, size_t ndx) {
static int fdevent_poll_event_next_fdndx(fdevents *ev, int ndx) {
size_t i;
-
+
i = (ndx < 0) ? 0 : ndx + 1;
for (; i < ev->used; i++) {
- if (ev->pollfds[i].revents) break;
+ if (ev->pollfds[i].revents) return i;
}
-
- return i;
+
+ return -1;
}
int fdevent_poll_init(fdevents *ev) {
ev->type = FDEVENT_HANDLER_POLL;
#define SET(x) \
ev->x = fdevent_poll_##x;
-
+
SET(free);
SET(poll);
-
+
SET(event_del);
- SET(event_add);
-
+ SET(event_set);
+
SET(event_next_fdndx);
SET(event_get_fd);
SET(event_get_revent);
-
+
return 0;
}
@@ -175,8 +193,9 @@ int fdevent_poll_init(fdevents *ev) {
int fdevent_poll_init(fdevents *ev) {
UNUSED(ev);
- fprintf(stderr, "%s.%d: poll is not supported, try to set server.event-handler = \"select\"\n",
- __FILE__, __LINE__);
+ log_error_write(srv, __FILE__, __LINE__,
+ "s", "poll is not supported, try to set server.event-handler = \"select\"");
+
return -1;
}
#endif
diff --git a/src/fdevent_select.c b/src/fdevent_select.c
index 3eb10f3..2e23dce 100644
--- a/src/fdevent_select.c
+++ b/src/fdevent_select.c
@@ -1,3 +1,7 @@
+#include "fdevent.h"
+#include "buffer.h"
+#include "log.h"
+
#include <sys/time.h>
#include <sys/types.h>
@@ -9,10 +13,6 @@
#include <fcntl.h>
#include <assert.h>
-#include "fdevent.h"
-#include "settings.h"
-#include "buffer.h"
-
#ifdef USE_SELECT
static int fdevent_select_reset(fdevents *ev) {
@@ -34,43 +34,45 @@ static int fdevent_select_event_del(fdevents *ev, int fde_ndx, int fd) {
return -1;
}
-static int fdevent_select_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
+static int fdevent_select_event_set(fdevents *ev, int fde_ndx, int fd, int events) {
UNUSED(fde_ndx);
/* we should be protected by max-fds, but you never know */
- assert(fd < FD_SETSIZE);
+ assert(fd < ((int)FD_SETSIZE));
if (events & FDEVENT_IN) {
FD_SET(fd, &(ev->select_set_read));
- FD_CLR(fd, &(ev->select_set_write));
+ } else {
+ FD_CLR(fd, &(ev->select_set_read));
}
if (events & FDEVENT_OUT) {
- FD_CLR(fd, &(ev->select_set_read));
FD_SET(fd, &(ev->select_set_write));
+ } else {
+ FD_CLR(fd, &(ev->select_set_write));
}
FD_SET(fd, &(ev->select_set_error));
-
+
if (fd > ev->select_max_fd) ev->select_max_fd = fd;
-
+
return fd;
}
static int fdevent_select_poll(fdevents *ev, int timeout_ms) {
struct timeval tv;
-
+
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
-
+
ev->select_read = ev->select_set_read;
ev->select_write = ev->select_set_write;
ev->select_error = ev->select_set_error;
-
+
return select(ev->select_max_fd + 1, &(ev->select_read), &(ev->select_write), &(ev->select_error), &tv);
}
static int fdevent_select_event_get_revent(fdevents *ev, size_t ndx) {
int revents = 0;
-
+
if (FD_ISSET(ndx, &(ev->select_read))) {
revents |= FDEVENT_IN;
}
@@ -80,7 +82,7 @@ static int fdevent_select_event_get_revent(fdevents *ev, size_t ndx) {
if (FD_ISSET(ndx, &(ev->select_error))) {
revents |= FDEVENT_ERR;
}
-
+
return revents;
}
@@ -92,33 +94,33 @@ static int fdevent_select_event_get_fd(fdevents *ev, size_t ndx) {
static int fdevent_select_event_next_fdndx(fdevents *ev, int ndx) {
int i;
-
+
i = (ndx < 0) ? 0 : ndx + 1;
-
+
for (; i < ev->select_max_fd + 1; i++) {
- if (FD_ISSET(i, &(ev->select_read))) break;
- if (FD_ISSET(i, &(ev->select_write))) break;
- if (FD_ISSET(i, &(ev->select_error))) break;
+ if (FD_ISSET(i, &(ev->select_read))) return i;
+ if (FD_ISSET(i, &(ev->select_write))) return i;
+ if (FD_ISSET(i, &(ev->select_error))) return i;
}
-
- return i;
+
+ return -1;
}
int fdevent_select_init(fdevents *ev) {
ev->type = FDEVENT_HANDLER_SELECT;
#define SET(x) \
ev->x = fdevent_select_##x;
-
+
SET(reset);
SET(poll);
-
+
SET(event_del);
- SET(event_add);
-
+ SET(event_set);
+
SET(event_next_fdndx);
SET(event_get_fd);
SET(event_get_revent);
-
+
return 0;
}
diff --git a/src/fdevent_solaris_devpoll.c b/src/fdevent_solaris_devpoll.c
index 91238b0..dd273e6 100644
--- a/src/fdevent_solaris_devpoll.c
+++ b/src/fdevent_solaris_devpoll.c
@@ -1,3 +1,7 @@
+#include "fdevent.h"
+#include "buffer.h"
+#include "log.h"
+
#include <sys/types.h>
#include <unistd.h>
@@ -8,12 +12,10 @@
#include <signal.h>
#include <fcntl.h>
-#include "fdevent.h"
-#include "settings.h"
-#include "buffer.h"
-
#ifdef USE_SOLARIS_DEVPOLL
+# include <sys/devpoll.h>
+
static void fdevent_solaris_devpoll_free(fdevents *ev) {
free(ev->devpollfds);
close(ev->devpoll_fd);
@@ -23,60 +25,76 @@ static void fdevent_solaris_devpoll_free(fdevents *ev) {
static int fdevent_solaris_devpoll_event_del(fdevents *ev, int fde_ndx, int fd) {
struct pollfd pfd;
-
+
if (fde_ndx < 0) return -1;
-
+
pfd.fd = fd;
pfd.events = POLLREMOVE;
pfd.revents = 0;
-
+
if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
- fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
- __FILE__, __LINE__,
- fd, strerror(errno));
-
+ log_error_write(ev->srv, __FILE__, __LINE__, "S(D, S)",
+ "(del) write failed: ", fd, strerror(errno));
+
return -1;
}
-
+
return -1;
}
-static int fdevent_solaris_devpoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
+static int fdevent_solaris_devpoll_event_set(fdevents *ev, int fde_ndx, int fd, int events) {
struct pollfd pfd;
int add = 0;
-
+
+ int pevents = 0;
+ if (events & FDEVENT_IN) pevents |= POLLIN;
+ if (events & FDEVENT_OUT) pevents |= POLLOUT;
+
if (fde_ndx == -1) add = 1;
-
+
pfd.fd = fd;
- pfd.events = events;
+ pfd.events = pevents;
pfd.revents = 0;
-
+
if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
- fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
- __FILE__, __LINE__,
- fd, strerror(errno));
-
+ log_error_write(ev->srv, __FILE__, __LINE__, "S(D, S)",
+ "(set) write failed: ", fd, strerror(errno));
+
return -1;
}
-
+
return fd;
}
static int fdevent_solaris_devpoll_poll(fdevents *ev, int timeout_ms) {
struct dvpoll dopoll;
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);
-
+
return ret;
}
static int fdevent_solaris_devpoll_event_get_revent(fdevents *ev, size_t ndx) {
- return ev->devpollfds[ndx].revents;
+ int r, poll_r;
+
+ r = 0;
+ poll_r = ev->devpollfds[ndx].revents;
+
+ /* map POLL* to FDEVEN_*; they are probably the same, but still. */
+
+ if (poll_r & POLLIN) r |= FDEVENT_IN;
+ if (poll_r & POLLOUT) r |= FDEVENT_OUT;
+ if (poll_r & POLLERR) r |= FDEVENT_ERR;
+ if (poll_r & POLLHUP) r |= FDEVENT_HUP;
+ if (poll_r & POLLNVAL) r |= FDEVENT_NVAL;
+ if (poll_r & POLLPRI) r |= FDEVENT_PRI;
+
+ return r;
}
static int fdevent_solaris_devpoll_event_get_fd(fdevents *ev, size_t ndx) {
@@ -85,11 +103,11 @@ static int fdevent_solaris_devpoll_event_get_fd(fdevents *ev, size_t ndx) {
static int fdevent_solaris_devpoll_event_next_fdndx(fdevents *ev, int last_ndx) {
size_t i;
-
+
UNUSED(ev);
i = (last_ndx < 0) ? 0 : last_ndx + 1;
-
+
return i;
}
@@ -97,15 +115,15 @@ int fdevent_solaris_devpoll_reset(fdevents *ev) {
/* a forked process does only inherit the filedescriptor,
* but every operation on the device will lead to a EACCES */
if ((ev->devpoll_fd = open("/dev/poll", O_RDWR)) < 0) {
- fprintf(stderr, "%s.%d: opening /dev/poll failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__, strerror(errno));
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "opening /dev/poll failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\"");
return -1;
}
if (fcntl(ev->devpoll_fd, F_SETFD, FD_CLOEXEC) < 0) {
- fprintf(stderr, "%s.%d: opening /dev/poll failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__, strerror(errno));
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "fcntl /dev/poll fd failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\"");
close(ev->devpoll_fd);
@@ -117,23 +135,23 @@ int fdevent_solaris_devpoll_init(fdevents *ev) {
ev->type = FDEVENT_HANDLER_SOLARIS_DEVPOLL;
#define SET(x) \
ev->x = fdevent_solaris_devpoll_##x;
-
+
SET(free);
SET(poll);
SET(reset);
-
+
SET(event_del);
- SET(event_add);
-
+ SET(event_set);
+
SET(event_next_fdndx);
SET(event_get_fd);
SET(event_get_revent);
-
+
ev->devpollfds = malloc(sizeof(*ev->devpollfds) * ev->maxfds);
-
+
if ((ev->devpoll_fd = open("/dev/poll", O_RDWR)) < 0) {
- fprintf(stderr, "%s.%d: opening /dev/poll failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__, strerror(errno));
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "opening /dev/poll failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\"");
return -1;
}
@@ -150,9 +168,9 @@ int fdevent_solaris_devpoll_init(fdevents *ev) {
int fdevent_solaris_devpoll_init(fdevents *ev) {
UNUSED(ev);
- fprintf(stderr, "%s.%d: solaris-devpoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
- __FILE__, __LINE__);
-
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "solaris-devpoll not supported, try to set server.event-handler = \"poll\" or \"select\"");
+
return -1;
}
#endif
diff --git a/src/fdevent_solaris_port.c b/src/fdevent_solaris_port.c
new file mode 100644
index 0000000..8dea4d2
--- /dev/null
+++ b/src/fdevent_solaris_port.c
@@ -0,0 +1,172 @@
+#include "fdevent.h"
+#include "buffer.h"
+#include "log.h"
+
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+
+#ifdef USE_SOLARIS_PORT
+
+static const int SOLARIS_PORT_POLL_READ = POLLIN;
+static const int SOLARIS_PORT_POLL_WRITE = POLLOUT;
+static const int SOLARIS_PORT_POLL_READ_WRITE = POLLIN & POLLOUT;
+
+static int fdevent_solaris_port_event_del(fdevents *ev, int fde_ndx, int fd) {
+ if (fde_ndx < 0) return -1;
+
+ if (0 != port_dissociate(ev->port_fd, PORT_SOURCE_FD, fd)) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "port_dissociate failed: ", strerror(errno), ", dying");
+
+ SEGFAULT();
+
+ return 0;
+ }
+
+ return -1;
+}
+
+static int fdevent_solaris_port_event_set(fdevents *ev, int fde_ndx, int fd, int events) {
+ const int* user_data = NULL;
+
+ if ((events & FDEVENT_IN) && (events & FDEVENT_OUT)) {
+ user_data = &SOLARIS_PORT_POLL_READ_WRITE;
+ } else if (events & FDEVENT_IN) {
+ user_data = &SOLARIS_PORT_POLL_READ;
+ } else if (events & FDEVENT_OUT) {
+ user_data = &SOLARIS_PORT_POLL_WRITE;
+ }
+
+ if (0 != port_associate(ev->port_fd, PORT_SOURCE_FD, fd, *user_data, (void*) user_data)) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "port_associate failed: ", strerror(errno), ", dying");
+
+ SEGFAULT();
+
+ return 0;
+ }
+
+ return fd;
+}
+
+static int fdevent_solaris_port_event_get_revent(fdevents *ev, size_t ndx) {
+ int events = 0, e;
+
+ e = ev->port_events[ndx].portev_events;
+ if (e & POLLIN) events |= FDEVENT_IN;
+ if (e & POLLOUT) events |= FDEVENT_OUT;
+ if (e & POLLERR) events |= FDEVENT_ERR;
+ if (e & POLLHUP) events |= FDEVENT_HUP;
+ if (e & POLLPRI) events |= FDEVENT_PRI;
+ if (e & POLLNVAL) events |= FDEVENT_NVAL;
+
+ return e;
+}
+
+static int fdevent_solaris_port_event_get_fd(fdevents *ev, size_t ndx) {
+ return ev->port_events[ndx].portev_object;
+}
+
+static int fdevent_solaris_port_event_next_fdndx(fdevents *ev, int ndx) {
+ size_t i;
+
+ UNUSED(ev);
+
+ i = (ndx < 0) ? 0 : ndx + 1;
+
+ return i;
+}
+
+static void fdevent_solaris_port_free(fdevents *ev) {
+ close(ev->port_fd);
+ free(ev->port_events);
+}
+
+/* if there is any error it will return the return values of port_getn, otherwise it will return number of events **/
+static int fdevent_solaris_port_poll(fdevents *ev, int timeout_ms) {
+ int i = 0;
+ int ret;
+ unsigned int available_events, wait_for_events = 0;
+ const int *user_data;
+
+ struct timespec timeout;
+
+ timeout.tv_sec = timeout_ms/1000L;
+ timeout.tv_nsec = (timeout_ms % 1000L) * 1000000L;
+
+ /* get the number of file descriptors with events */
+ if ((ret = port_getn(ev->port_fd, ev->port_events, 0, &wait_for_events, &timeout)) < 0) return ret;
+
+ /* wait for at least one event */
+ if (0 == wait_for_events) wait_for_events = 1;
+
+ available_events = wait_for_events;
+
+ /* get the events of the file descriptors */
+ if ((ret = port_getn(ev->port_fd, ev->port_events, ev->maxfds, &available_events, &timeout)) < 0) {
+ /* if errno == ETIME and available_event == wait_for_events we didn't get any events */
+ /* for other errors we didn't get any events either */
+ if (!(errno == ETIME && wait_for_events != available_events)) return ret;
+ }
+
+ for (i = 0; i < available_events; ++i) {
+ user_data = (const int *) ev->port_events[i].portev_user;
+
+ if ((ret = port_associate(ev->port_fd, PORT_SOURCE_FD, ev->port_events[i].portev_object,
+ *user_data, (void*) user_data)) < 0) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "port_associate failed: ", strerror(errno), ", dying");
+
+ SEGFAULT();
+
+ return 0;
+ }
+ }
+
+ return available_events;
+}
+
+int fdevent_solaris_port_init(fdevents *ev) {
+ ev->type = FDEVENT_HANDLER_SOLARIS_PORT;
+#define SET(x) \
+ ev->x = fdevent_solaris_port_##x;
+
+ SET(free);
+ SET(poll);
+
+ SET(event_del);
+ SET(event_set);
+
+ SET(event_next_fdndx);
+ SET(event_get_fd);
+ SET(event_get_revent);
+
+ if ((ev->port_fd = port_create()) < 0) {
+ log_error_write(ev->srv, __FILE__, __LINE__, "SSS",
+ "port_create() failed (", strerror(errno), "), try to set server.event-handler = \"poll\" or \"select\"");
+
+ return -1;
+ }
+
+ ev->port_events = malloc(ev->maxfds * sizeof(*ev->port_events));
+
+ return 0;
+}
+
+#else
+int fdevent_solaris_port_init(fdevents *ev) {
+ UNUSED(ev);
+
+ log_error_write(ev->srv, __FILE__, __LINE__, "S",
+ "solaris-eventports not supported, try to set server.event-handler = \"poll\" or \"select\"");
+
+ return -1;
+}
+#endif
diff --git a/src/http-header-glue.c b/src/http-header-glue.c
index 1e74098..a33ed3b 100644
--- a/src/http-header-glue.c
+++ b/src/http-header-glue.c
@@ -1,14 +1,14 @@
-#define _GNU_SOURCE
-
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-
#include "base.h"
#include "array.h"
#include "buffer.h"
#include "log.h"
#include "etag.h"
+#include "response.h"
+
+#include <string.h>
+#include <errno.h>
+
+#include <time.h>
/*
* This was 'borrowed' from tcpdump.
@@ -45,20 +45,20 @@
# ifdef HAVE_STRUCT_SOCKADDR_STORAGE
static size_t get_sa_len(const struct sockaddr *addr) {
switch (addr->sa_family) {
-
+
# ifdef AF_INET
case AF_INET:
return (sizeof (struct sockaddr_in));
# endif
-
+
# ifdef AF_INET6
case AF_INET6:
return (sizeof (struct sockaddr_in6));
# endif
-
+
default:
return (sizeof (struct sockaddr));
-
+
}
}
# define SA_LEN(addr) (get_sa_len(addr))
@@ -74,7 +74,7 @@ static size_t get_sa_len(const struct sockaddr *addr) {
int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
data_string *ds;
-
+
UNUSED(srv);
if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
@@ -82,36 +82,51 @@ int response_header_insert(server *srv, connection *con, const char *key, size_t
}
buffer_copy_string_len(ds->key, key, keylen);
buffer_copy_string_len(ds->value, value, vallen);
-
+
array_insert_unique(con->response.headers, (data_unset *)ds);
-
+
return 0;
}
int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
data_string *ds;
-
+
UNUSED(srv);
/* if there already is a key by this name overwrite the value */
if (NULL != (ds = (data_string *)array_get_element(con->response.headers, key))) {
buffer_copy_string(ds->value, value);
-
+
return 0;
}
-
+
+ return response_header_insert(srv, con, key, keylen, value, vallen);
+}
+
+int response_header_append(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
+ data_string *ds;
+
+ UNUSED(srv);
+
+ /* if there already is a key by this name append the value */
+ if (NULL != (ds = (data_string *)array_get_element(con->response.headers, key))) {
+ buffer_append_string_len(ds->value, CONST_STR_LEN(", "));
+ buffer_append_string_len(ds->value, value, vallen);
+ return 0;
+ }
+
return response_header_insert(srv, con, key, keylen, value, vallen);
}
int http_response_redirect_to_directory(server *srv, connection *con) {
buffer *o;
-
+
o = buffer_init();
-
+
if (con->conf.is_ssl) {
- buffer_copy_string(o, "https://");
+ buffer_copy_string_len(o, CONST_STR_LEN("https://"));
} else {
- buffer_copy_string(o, "http://");
+ buffer_copy_string_len(o, CONST_STR_LEN("http://"));
}
if (con->uri.authority->used) {
buffer_append_string_buffer(o, con->uri.authority);
@@ -123,36 +138,36 @@ int http_response_redirect_to_directory(server *srv, connection *con) {
#endif
sock_addr our_addr;
socklen_t our_addr_len;
-
+
our_addr_len = sizeof(our_addr);
-
+
if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
con->http_status = 500;
-
+
log_error_write(srv, __FILE__, __LINE__, "ss",
"can't get sockname", strerror(errno));
-
+
buffer_free(o);
return 0;
}
-
-
+
+
/* Lookup name: secondly try to get hostname for bind address */
switch(our_addr.plain.sa_family) {
#ifdef HAVE_IPV6
case AF_INET6:
- if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6),
- SA_LEN((const struct sockaddr *)&our_addr.ipv6),
+ if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6),
+ SA_LEN((const struct sockaddr *)&our_addr.ipv6),
hbuf, sizeof(hbuf), NULL, 0, 0)) {
-
+
char dst[INET6_ADDRSTRLEN];
-
+
log_error_write(srv, __FILE__, __LINE__,
- "SSSS", "NOTICE: getnameinfo failed: ",
+ "SSS", "NOTICE: getnameinfo failed: ",
strerror(errno), ", using ip-address instead");
-
- buffer_append_string(o,
- inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr,
+
+ buffer_append_string(o,
+ inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr,
dst, sizeof(dst)));
} else {
buffer_append_string(o, hbuf);
@@ -162,9 +177,9 @@ int http_response_redirect_to_directory(server *srv, connection *con) {
case AF_INET:
if (NULL == (he = gethostbyaddr((char *)&our_addr.ipv4.sin_addr, sizeof(struct in_addr), AF_INET))) {
log_error_write(srv, __FILE__, __LINE__,
- "SdSS", "NOTICE: gethostbyaddr failed: ",
+ "SdS", "NOTICE: gethostbyaddr failed: ",
h_errno, ", using ip-address instead");
-
+
buffer_append_string(o, inet_ntoa(our_addr.ipv4.sin_addr));
} else {
buffer_append_string(o, he->h_name);
@@ -173,57 +188,58 @@ int http_response_redirect_to_directory(server *srv, connection *con) {
default:
log_error_write(srv, __FILE__, __LINE__,
"S", "ERROR: unsupported address-type");
-
+
buffer_free(o);
return -1;
}
-
- if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) ||
+
+ if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) ||
(con->conf.is_ssl == 1 && srv->srvconf.port == 443))) {
- buffer_append_string(o, ":");
+ buffer_append_string_len(o, CONST_STR_LEN(":"));
buffer_append_long(o, srv->srvconf.port);
}
}
buffer_append_string_buffer(o, con->uri.path);
- buffer_append_string(o, "/");
+ buffer_append_string_len(o, CONST_STR_LEN("/"));
if (!buffer_is_empty(con->uri.query)) {
- buffer_append_string(o, "?");
+ buffer_append_string_len(o, CONST_STR_LEN("?"));
buffer_append_string_buffer(o, con->uri.query);
}
-
+
response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(o));
-
+
con->http_status = 301;
-
+ con->file_finished = 1;
+
buffer_free(o);
-
+
return 0;
}
buffer * strftime_cache_get(server *srv, time_t last_mod) {
struct tm *tm;
size_t i;
-
+
for (i = 0; i < FILE_CACHE_MAX; i++) {
/* found cache-entry */
if (srv->mtime_cache[i].mtime == last_mod) return srv->mtime_cache[i].str;
-
+
/* found empty slot */
if (srv->mtime_cache[i].mtime == 0) break;
}
-
+
if (i == FILE_CACHE_MAX) {
i = 0;
}
-
+
srv->mtime_cache[i].mtime = last_mod;
buffer_prepare_copy(srv->mtime_cache[i].str, 1024);
tm = gmtime(&(srv->mtime_cache[i].mtime));
- srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
+ srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
srv->mtime_cache[i].str->size - 1,
"%a, %d %b %Y %H:%M:%S GMT", tm);
srv->mtime_cache[i].str->used++;
-
+
return srv->mtime_cache[i].str;
}
@@ -238,56 +254,63 @@ int http_response_handle_cachable(server *srv, connection *con, buffer *mtime) {
* request. That is, if no entity tags match, then the server MUST NOT
* return a 304 (Not Modified) response.
*/
-
+
/* last-modified handling */
if (con->request.http_if_none_match) {
if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) {
- if (con->request.http_method == HTTP_METHOD_GET ||
+ if (con->request.http_method == HTTP_METHOD_GET ||
con->request.http_method == HTTP_METHOD_HEAD) {
-
+
/* check if etag + last-modified */
if (con->request.http_if_modified_since) {
size_t used_len;
char *semicolon;
-
+
if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
used_len = strlen(con->request.http_if_modified_since);
} else {
used_len = semicolon - con->request.http_if_modified_since;
}
-
+
if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
- con->http_status = 304;
+ if ('\0' == mtime->ptr[used_len]) con->http_status = 304;
return HANDLER_FINISHED;
} else {
char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
+ time_t t_header, t_file;
+ struct tm tm;
- /* convert to timestamp */
- if (used_len < sizeof(buf)) {
- time_t t_header, t_file;
- struct tm tm;
-
- strncpy(buf, con->request.http_if_modified_since, used_len);
- buf[used_len] = '\0';
-
- strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
- t_header = mktime(&tm);
-
- strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
- t_file = mktime(&tm);
-
- if (t_file > t_header) {
- con->http_status = 304;
- return HANDLER_FINISHED;
- }
- } else {
- log_error_write(srv, __FILE__, __LINE__, "ssdd",
- "DEBUG: Last-Modified check failed as the received timestamp was too long:",
+ /* check if we can safely copy the string */
+ if (used_len >= sizeof(buf)) {
+ log_error_write(srv, __FILE__, __LINE__, "ssdd",
+ "DEBUG: Last-Modified check failed as the received timestamp was too long:",
con->request.http_if_modified_since, used_len, sizeof(buf) - 1);
-
+
con->http_status = 412;
+ con->mode = DIRECT;
return HANDLER_FINISHED;
}
+
+
+ strncpy(buf, con->request.http_if_modified_since, used_len);
+ buf[used_len] = '\0';
+
+ if (NULL == strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm)) {
+ con->http_status = 412;
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
+ }
+ tm.tm_isdst = 0;
+ t_header = mktime(&tm);
+
+ strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
+ tm.tm_isdst = 0;
+ t_file = mktime(&tm);
+
+ if (t_file > t_header) return HANDLER_GO_ON;
+
+ con->http_status = 304;
+ return HANDLER_FINISHED;
}
} else {
con->http_status = 304;
@@ -295,20 +318,49 @@ int http_response_handle_cachable(server *srv, connection *con, buffer *mtime) {
}
} else {
con->http_status = 412;
+ con->mode = DIRECT;
return HANDLER_FINISHED;
}
}
} else if (con->request.http_if_modified_since) {
size_t used_len;
char *semicolon;
-
+
if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
used_len = strlen(con->request.http_if_modified_since);
} else {
used_len = semicolon - con->request.http_if_modified_since;
}
-
+
if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
+ if ('\0' == mtime->ptr[used_len]) con->http_status = 304;
+ return HANDLER_FINISHED;
+ } else {
+ char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
+ time_t t_header, t_file;
+ struct tm tm;
+
+ /* convert to timestamp */
+ if (used_len >= sizeof(buf)) return HANDLER_GO_ON;
+
+ strncpy(buf, con->request.http_if_modified_since, used_len);
+ buf[used_len] = '\0';
+
+ if (NULL == strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm)) {
+ /**
+ * parsing failed, let's get out of here
+ */
+ return HANDLER_GO_ON;
+ }
+ tm.tm_isdst = 0;
+ t_header = mktime(&tm);
+
+ strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
+ tm.tm_isdst = 0;
+ t_file = mktime(&tm);
+
+ if (t_file > t_header) return HANDLER_GO_ON;
+
con->http_status = 304;
return HANDLER_FINISHED;
}
diff --git a/src/http_auth.c b/src/http_auth.c
index 9976c15..d7d246b 100644
--- a/src/http_auth.c
+++ b/src/http_auth.c
@@ -1,6 +1,8 @@
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include "server.h"
+#include "log.h"
+#include "http_auth.h"
+#include "inet_ntop_cache.h"
+#include "stream.h"
#ifdef HAVE_CRYPT_H
# include <crypt.h>
@@ -25,49 +27,61 @@
#include <unistd.h>
#include <ctype.h>
-#include "server.h"
-#include "log.h"
-#include "http_auth.h"
-#include "http_auth_digest.h"
-#include "stream.h"
+#include "md5.h"
-#ifdef USE_OPENSSL
-# include <openssl/md5.h>
-#else
-# include "md5.h"
-#endif
+#define HASHLEN 16
+#define HASHHEXLEN 32
+typedef unsigned char HASH[HASHLEN];
+typedef char HASHHEX[HASHHEXLEN+1];
+static void CvtHex(const HASH Bin, char Hex[33]) {
+ unsigned short i;
-#ifdef USE_PAM
-#include <security/pam_appl.h>
-#include <security/pam_misc.h>
+ for (i = 0; i < 16; i++) {
+ Hex[i*2] = int2hex((Bin[i] >> 4) & 0xf);
+ Hex[i*2+1] = int2hex(Bin[i] & 0xf);
+ }
+ Hex[32] = '\0';
+}
-static struct pam_conv conv = {
- misc_conv,
- NULL
-};
-#endif
+/**
+ * the $apr1$ handling is taken from apache 1.3.x
+ */
+
+/*
+ * The apr_md5_encode() routine uses much code obtained from the FreeBSD 3.0
+ * MD5 crypt() function, which is licenced as follows:
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
static const char base64_pad = '=';
+/* "A-Z a-z 0-9 + /" maps to 0-63 */
static const short base64_reverse_table[256] = {
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
- -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 - 0x0F */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 - 0x1F */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 - 0x2F */
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 - 0x3F */
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 - 0x4F */
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 - 0x5F */
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 - 0x6F */
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70 - 0x7F */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80 - 0x8F */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90 - 0x9F */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xA0 - 0xAF */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xB0 - 0xBF */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xC0 - 0xCF */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xD0 - 0xDF */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xE0 - 0xEF */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xF0 - 0xFF */
};
@@ -75,25 +89,25 @@ static unsigned char * base64_decode(buffer *out, const char *in) {
unsigned char *result;
int ch, j = 0, k;
size_t i;
-
+
size_t in_len = strlen(in);
-
+
buffer_prepare_copy(out, in_len);
-
+
result = (unsigned char *)out->ptr;
-
+
ch = in[0];
/* run through the whole string, converting as we go */
for (i = 0; i < in_len; i++) {
- ch = in[i];
-
+ ch = (unsigned char) in[i];
+
if (ch == '\0') break;
-
+
if (ch == base64_pad) break;
-
+
ch = base64_reverse_table[ch];
if (ch < 0) continue;
-
+
switch(i % 4) {
case 0:
result[j] = ch << 2;
@@ -125,168 +139,168 @@ static unsigned char * base64_decode(buffer *out, const char *in) {
}
}
result[k] = '\0';
-
+
out->used = k;
-
+
return result;
}
static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *username, buffer *realm, buffer *password) {
int ret = -1;
-
+
if (!username->used|| !realm->used) return -1;
-
+
if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
stream f;
char * f_line;
-
+
if (buffer_is_empty(p->conf.auth_htdigest_userfile)) return -1;
-
+
if (0 != stream_open(&f, p->conf.auth_htdigest_userfile)) {
log_error_write(srv, __FILE__, __LINE__, "sbss", "opening digest-userfile", p->conf.auth_htdigest_userfile, "failed:", strerror(errno));
-
+
return -1;
}
-
+
f_line = f.start;
-
+
while (f_line - f.start != f.size) {
char *f_user, *f_pwd, *e, *f_realm;
size_t u_len, pwd_len, r_len;
-
+
f_user = f_line;
-
- /*
+
+ /*
* htdigest format
- *
- * user:realm:md5(user:realm:password)
+ *
+ * user:realm:md5(user:realm:password)
*/
-
+
if (NULL == (f_realm = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
- "parsed error in", p->conf.auth_htdigest_userfile,
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "parsed error in", p->conf.auth_htdigest_userfile,
"expected 'username:realm:hashed password'");
-
+
stream_close(&f);
-
+
return -1;
}
-
+
if (NULL == (f_pwd = memchr(f_realm + 1, ':', f.size - (f_realm + 1 - f.start)))) {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
- "parsed error in", p->conf.auth_plain_userfile,
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "parsed error in", p->conf.auth_plain_userfile,
"expected 'username:realm:hashed password'");
-
+
stream_close(&f);
-
+
return -1;
}
-
+
/* get pointers to the fields */
- u_len = f_realm - f_user;
+ u_len = f_realm - f_user;
f_realm++;
r_len = f_pwd - f_realm;
f_pwd++;
-
+
if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
pwd_len = e - f_pwd;
} else {
pwd_len = f.size - (f_pwd - f.start);
}
-
+
if (username->used - 1 == u_len &&
(realm->used - 1 == r_len) &&
(0 == strncmp(username->ptr, f_user, u_len)) &&
(0 == strncmp(realm->ptr, f_realm, r_len))) {
/* found */
-
+
buffer_copy_string_len(password, f_pwd, pwd_len);
-
+
ret = 0;
break;
}
-
+
/* EOL */
if (!e) break;
-
+
f_line = e + 1;
}
-
+
stream_close(&f);
} else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD ||
p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
stream f;
char * f_line;
buffer *auth_fn;
-
+
auth_fn = (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) ? p->conf.auth_htpasswd_userfile : p->conf.auth_plain_userfile;
-
+
if (buffer_is_empty(auth_fn)) return -1;
-
+
if (0 != stream_open(&f, auth_fn)) {
- log_error_write(srv, __FILE__, __LINE__, "sbss",
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
"opening plain-userfile", auth_fn, "failed:", strerror(errno));
-
+
return -1;
}
-
+
f_line = f.start;
-
+
while (f_line - f.start != f.size) {
char *f_user, *f_pwd, *e;
size_t u_len, pwd_len;
-
+
f_user = f_line;
-
- /*
+
+ /*
* htpasswd format
- *
+ *
* user:crypted passwd
*/
-
+
if (NULL == (f_pwd = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
- "parsed error in", auth_fn,
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "parsed error in", auth_fn,
"expected 'username:hashed password'");
-
+
stream_close(&f);
-
+
return -1;
}
-
+
/* get pointers to the fields */
- u_len = f_pwd - f_user;
+ u_len = f_pwd - f_user;
f_pwd++;
-
+
if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
pwd_len = e - f_pwd;
} else {
pwd_len = f.size - (f_pwd - f.start);
}
-
+
if (username->used - 1 == u_len &&
(0 == strncmp(username->ptr, f_user, u_len))) {
/* found */
-
+
buffer_copy_string_len(password, f_pwd, pwd_len);
-
+
ret = 0;
break;
}
-
+
/* EOL */
if (!e) break;
-
+
f_line = e + 1;
}
-
+
stream_close(&f);
} else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
ret = 0;
} else {
return -1;
}
-
+
return ret;
}
@@ -296,7 +310,7 @@ static int http_auth_match_rules(server *srv, mod_auth_plugin_data *p, const cha
int username_len;
data_string *require;
array *req;
-
+
UNUSED(group);
UNUSED(host);
@@ -304,12 +318,12 @@ static int http_auth_match_rules(server *srv, mod_auth_plugin_data *p, const cha
/* search auth-directives for path */
for (i = 0; i < p->conf.auth_require->used; i++) {
if (p->conf.auth_require->data[i]->key->used == 0) continue;
-
+
if (0 == strncmp(url, p->conf.auth_require->data[i]->key->ptr, p->conf.auth_require->data[i]->key->used - 1)) {
break;
}
}
-
+
if (i == p->conf.auth_require->used) {
return -1;
}
@@ -317,72 +331,72 @@ static int http_auth_match_rules(server *srv, mod_auth_plugin_data *p, const cha
req = ((data_array *)(p->conf.auth_require->data[i]))->value;
require = (data_string *)array_get_element(req, "require");
-
+
/* if we get here, the user we got a authed user */
if (0 == strcmp(require->value->ptr, "valid-user")) {
return 0;
}
-
+
/* user=name1|group=name3|host=name4 */
-
+
/* seperate the string by | */
#if 0
log_error_write(srv, __FILE__, __LINE__, "sb", "rules", require->value);
-#endif
-
+#endif
+
username_len = username ? strlen(username) : 0;
-
+
r = rules = require->value->ptr;
-
+
while (1) {
const char *eq;
const char *k, *v, *e;
int k_len, v_len, r_len;
-
+
e = strchr(r, '|');
-
+
if (e) {
r_len = e - r;
} else {
r_len = strlen(rules) - (r - rules);
}
-
+
/* from r to r + r_len is a rule */
-
+
if (0 == strncmp(r, "valid-user", r_len)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
"parsing the 'require' section in 'auth.require' failed: valid-user cannot be combined with other require rules",
require->value);
return -1;
}
-
+
/* search for = in the rules */
if (NULL == (eq = strchr(r, '='))) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "parsing the 'require' section in 'auth.require' failed: a = is missing",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "parsing the 'require' section in 'auth.require' failed: a = is missing",
require->value);
return -1;
}
-
+
/* = out of range */
if (eq > r + r_len) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
"parsing the 'require' section in 'auth.require' failed: = out of range",
require->value);
-
+
return -1;
}
-
+
/* the part before the = is user|group|host */
-
+
k = r;
k_len = eq - r;
v = eq + 1;
v_len = r_len - k_len - 1;
-
+
if (k_len == 4) {
if (0 == strncmp(k, "user", k_len)) {
- if (username &&
+ if (username &&
username_len == v_len &&
0 == strncmp(username, v, v_len)) {
return 0;
@@ -404,19 +418,191 @@ static int http_auth_match_rules(server *srv, mod_auth_plugin_data *p, const cha
log_error_write(srv, __FILE__, __LINE__, "s", "unknown key");
return -1;
}
-
+
if (!e) break;
r = e + 1;
}
-
+
log_error_write(srv, __FILE__, __LINE__, "s", "nothing matched");
-
+
return -1;
}
+#define APR_MD5_DIGESTSIZE 16
+#define APR1_ID "$apr1$"
+
+/*
+ * The following MD5 password encryption code was largely borrowed from
+ * the FreeBSD 3.0 /usr/src/lib/libcrypt/crypt.c file, which is
+ * licenced as stated at the top of this file.
+ */
+
+static void to64(char *s, unsigned long v, int n)
+{
+ static const unsigned char itoa64[] = /* 0 ... 63 => ASCII - 64 */
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+ while (--n >= 0) {
+ *s++ = itoa64[v&0x3f];
+ v >>= 6;
+ }
+}
+
+static void apr_md5_encode(const char *pw, const char *salt, char *result, size_t nbytes) {
+ /*
+ * Minimum size is 8 bytes for salt, plus 1 for the trailing NUL,
+ * plus 4 for the '$' separators, plus the password hash itself.
+ * Let's leave a goodly amount of leeway.
+ */
+
+ char passwd[120], *p;
+ const char *sp, *ep;
+ unsigned char final[APR_MD5_DIGESTSIZE];
+ ssize_t sl, pl, i;
+ li_MD5_CTX ctx, ctx1;
+ unsigned long l;
+
+ /*
+ * Refine the salt first. It's possible we were given an already-hashed
+ * string as the salt argument, so extract the actual salt value from it
+ * if so. Otherwise just use the string up to the first '$' as the salt.
+ */
+ sp = salt;
+
+ /*
+ * If it starts with the magic string, then skip that.
+ */
+ if (!strncmp(sp, APR1_ID, strlen(APR1_ID))) {
+ sp += strlen(APR1_ID);
+ }
+
+ /*
+ * It stops at the first '$' or 8 chars, whichever comes first
+ */
+ for (ep = sp; (*ep != '\0') && (*ep != '$') && (ep < (sp + 8)); ep++) {
+ continue;
+ }
+
+ /*
+ * Get the length of the true salt
+ */
+ sl = ep - sp;
+
+ /*
+ * 'Time to make the doughnuts..'
+ */
+ li_MD5_Init(&ctx);
+
+ /*
+ * The password first, since that is what is most unknown
+ */
+ li_MD5_Update(&ctx, pw, strlen(pw));
+
+ /*
+ * Then our magic string
+ */
+ li_MD5_Update(&ctx, APR1_ID, strlen(APR1_ID));
+
+ /*
+ * Then the raw salt
+ */
+ li_MD5_Update(&ctx, sp, sl);
+
+ /*
+ * Then just as many characters of the MD5(pw, salt, pw)
+ */
+ li_MD5_Init(&ctx1);
+ li_MD5_Update(&ctx1, pw, strlen(pw));
+ li_MD5_Update(&ctx1, sp, sl);
+ li_MD5_Update(&ctx1, pw, strlen(pw));
+ li_MD5_Final(final, &ctx1);
+ for (pl = strlen(pw); pl > 0; pl -= APR_MD5_DIGESTSIZE) {
+ li_MD5_Update(&ctx, final,
+ (pl > APR_MD5_DIGESTSIZE) ? APR_MD5_DIGESTSIZE : pl);
+ }
+
+ /*
+ * Don't leave anything around in vm they could use.
+ */
+ memset(final, 0, sizeof(final));
+
+ /*
+ * Then something really weird...
+ */
+ for (i = strlen(pw); i != 0; i >>= 1) {
+ if (i & 1) {
+ li_MD5_Update(&ctx, final, 1);
+ }
+ else {
+ li_MD5_Update(&ctx, pw, 1);
+ }
+ }
+
+ /*
+ * Now make the output string. We know our limitations, so we
+ * can use the string routines without bounds checking.
+ */
+ strcpy(passwd, APR1_ID);
+ strncat(passwd, sp, sl);
+ strcat(passwd, "$");
+
+ li_MD5_Final(final, &ctx);
+
+ /*
+ * And now, just to make sure things don't run too fast..
+ * On a 60 Mhz Pentium this takes 34 msec, so you would
+ * need 30 seconds to build a 1000 entry dictionary...
+ */
+ for (i = 0; i < 1000; i++) {
+ li_MD5_Init(&ctx1);
+ if (i & 1) {
+ li_MD5_Update(&ctx1, pw, strlen(pw));
+ }
+ else {
+ li_MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE);
+ }
+ if (i % 3) {
+ li_MD5_Update(&ctx1, sp, sl);
+ }
+
+ if (i % 7) {
+ li_MD5_Update(&ctx1, pw, strlen(pw));
+ }
+
+ if (i & 1) {
+ li_MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE);
+ }
+ else {
+ li_MD5_Update(&ctx1, pw, strlen(pw));
+ }
+ li_MD5_Final(final,&ctx1);
+ }
+
+ p = passwd + strlen(passwd);
+
+ l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p, l, 4); p += 4;
+ l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p, l, 4); p += 4;
+ l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p, l, 4); p += 4;
+ l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p, l, 4); p += 4;
+ l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p, l, 4); p += 4;
+ l = final[11] ; to64(p, l, 2); p += 2;
+ *p = '\0';
+
+ /*
+ * Don't leave anything around in vm they could use.
+ */
+ memset(final, 0, sizeof(final));
+
+ /* FIXME
+ */
+#define apr_cpystrn strncpy
+ apr_cpystrn(result, passwd, nbytes - 1);
+}
+
+
/**
- *
- *
+ *
+ *
* @param password password-string from the auth-backend
* @param pw password-string from the client
*/
@@ -426,41 +612,49 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p
UNUSED(req);
if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
- /*
+ /*
* htdigest format
- *
- * user:realm:md5(user:realm:password)
+ *
+ * user:realm:md5(user:realm:password)
*/
-
- MD5_CTX Md5Ctx;
+
+ li_MD5_CTX Md5Ctx;
HASH HA1;
char a1[256];
-
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)username->ptr, username->used - 1);
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)realm->ptr, realm->used - 1);
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw));
- MD5_Final(HA1, &Md5Ctx);
-
+
+ li_MD5_Init(&Md5Ctx);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)username->ptr, username->used - 1);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)realm->ptr, realm->used - 1);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw));
+ li_MD5_Final(HA1, &Md5Ctx);
+
CvtHex(HA1, a1);
-
+
if (0 == strcmp(password->ptr, a1)) {
return 0;
}
- } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) {
-#ifdef HAVE_CRYPT
+ } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) {
+ char sample[120];
+ if (!strncmp(password->ptr, APR1_ID, strlen(APR1_ID))) {
+ /*
+ * The hash was created using $apr1$ custom algorithm.
+ */
+ apr_md5_encode(pw, password->ptr, sample, sizeof(sample));
+ return (strcmp(sample, password->ptr) == 0) ? 0 : 1;
+ } else {
+#ifdef HAVE_CRYPT
char salt[32];
char *crypted;
size_t salt_len = 0;
- /*
+ /*
* htpasswd format
- *
+ *
* user:crypted password
*/
- /*
+ /*
* Algorithm Salt
* CRYPT_STD_DES 2-character (Default)
* CRYPT_EXT_DES 9-character
@@ -469,7 +663,6 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p
*/
if (password->used < 13 + 1) {
- fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
return -1;
}
@@ -478,9 +671,8 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p
salt_len = 2;
} else if (password->ptr[0] == '$' && password->ptr[2] == '$') {
char *dollar = NULL;
-
+
if (NULL == (dollar = strchr(password->ptr + 3, '$'))) {
- fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
return -1;
}
@@ -488,55 +680,26 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p
}
if (salt_len > sizeof(salt) - 1) {
- fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
return -1;
}
strncpy(salt, password->ptr, salt_len);
salt[salt_len] = '\0';
-
+
crypted = crypt(pw, salt);
if (0 == strcmp(password->ptr, crypted)) {
return 0;
- } else {
- fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
}
-
-#endif
- } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
+
+#endif
+ }
+ } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
if (0 == strcmp(password->ptr, pw)) {
return 0;
}
- } else if (p->conf.auth_backend == AUTH_BACKEND_PAM) {
-#ifdef USE_PAM
- pam_handle_t *pamh=NULL;
- int retval;
-
- retval = pam_start("lighttpd", username->ptr, &conv, &pamh);
-
- if (retval == PAM_SUCCESS)
- retval = pam_authenticate(pamh, 0); /* is user really user? */
-
- if (retval == PAM_SUCCESS)
- retval = pam_acct_mgmt(pamh, 0); /* permitted access? */
-
- /* This is where we have been authorized or not. */
-
- if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */
- pamh = NULL;
- log_error_write(srv, __FILE__, __LINE__, "s", "failed to release authenticator");
- }
-
- if (retval == PAM_SUCCESS) {
- log_error_write(srv, __FILE__, __LINE__, "s", "Authenticated");
- return 0;
- } else {
- log_error_write(srv, __FILE__, __LINE__, "s", "Not Authenticated");
- }
-#endif
- } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
+ } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
#ifdef USE_LDAP
LDAP *ldap;
LDAPMessage *lm, *first;
@@ -544,117 +707,129 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p
int ret;
char *attrs[] = { LDAP_NO_ATTRS, NULL };
size_t i;
-
+
/* for now we stay synchronous */
-
- /*
+
+ /*
* 1. connect anonymously (done in plugin init)
* 2. get DN for uid = username
* 3. auth against ldap server
* 4. (optional) check a field
* 5. disconnect
- *
+ *
*/
-
+
/* check username
- *
+ *
* we have to protect us againt username which modifies out filter in
* a unpleasant way
*/
-
+
for (i = 0; i < username->used - 1; i++) {
char c = username->ptr[i];
-
+
if (!isalpha(c) &&
- !isdigit(c)) {
-
- log_error_write(srv, __FILE__, __LINE__, "sbd",
- "ldap: invalid character (a-zA-Z0-9 allowed) in username:", username, i);
-
+ !isdigit(c) &&
+ (c != ' ') &&
+ (c != '@') &&
+ (c != '-') &&
+ (c != '_') &&
+ (c != '.') ) {
+
+ log_error_write(srv, __FILE__, __LINE__, "sbd",
+ "ldap: invalid character (- _.@a-zA-Z0-9 allowed) in username:", username, i);
+
return -1;
}
}
-
-
-
+
+ if (p->conf.auth_ldap_allow_empty_pw != 1 && pw[0] == '\0')
+ return -1;
+
/* build filter */
buffer_copy_string_buffer(p->ldap_filter, p->conf.ldap_filter_pre);
buffer_append_string_buffer(p->ldap_filter, username);
buffer_append_string_buffer(p->ldap_filter, p->conf.ldap_filter_post);
-
-
+
+
/* 2. */
- if (p->conf.ldap == NULL ||
- LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
- if (auth_ldap_init(srv, &p->conf) != HANDLER_GO_ON)
- return -1;
- if (LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
+ if (p->anon_conf->ldap == NULL ||
+ LDAP_SUCCESS != (ret = ldap_search_s(p->anon_conf->ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
- log_error_write(srv, __FILE__, __LINE__, "sssb",
- "ldap:", ldap_err2string(ret), "filter:", p->ldap_filter);
-
- return -1;
+ /* try again; the ldap library sometimes fails for the first call but reconnects */
+ if (p->anon_conf->ldap == NULL || ret != LDAP_SERVER_DOWN ||
+ LDAP_SUCCESS != (ret = ldap_search_s(p->anon_conf->ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
+
+ if (auth_ldap_init(srv, p->anon_conf) != HANDLER_GO_ON)
+ return -1;
+
+ if (p->anon_conf->ldap == NULL ||
+ LDAP_SUCCESS != (ret = ldap_search_s(p->anon_conf->ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
+ log_error_write(srv, __FILE__, __LINE__, "sssb",
+ "ldap:", ldap_err2string(ret), "filter:", p->ldap_filter);
+ return -1;
+ }
}
}
-
- if (NULL == (first = ldap_first_entry(p->conf.ldap, lm))) {
+
+ if (NULL == (first = ldap_first_entry(p->anon_conf->ldap, lm))) {
log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
-
+
ldap_msgfree(lm);
-
+
return -1;
}
-
- if (NULL == (dn = ldap_get_dn(p->conf.ldap, first))) {
+
+ if (NULL == (dn = ldap_get_dn(p->anon_conf->ldap, first))) {
log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
-
+
ldap_msgfree(lm);
-
+
return -1;
}
-
+
ldap_msgfree(lm);
-
-
+
+
/* 3. */
if (NULL == (ldap = ldap_init(p->conf.auth_ldap_hostname->ptr, LDAP_PORT))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
return -1;
}
-
+
ret = LDAP_VERSION3;
if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
-
+
ldap_unbind_s(ldap);
-
+
return -1;
}
-
+
if (p->conf.auth_ldap_starttls == 1) {
if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(ldap, NULL, NULL))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
-
+
ldap_unbind_s(ldap);
-
+
return -1;
}
}
-
+
if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(ldap, dn, pw))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
-
+
ldap_unbind_s(ldap);
-
+
return -1;
}
-
+
/* 5. */
ldap_unbind_s(ldap);
-
+
/* everything worked, good, access granted */
-
+
return 0;
#endif
}
@@ -664,65 +839,73 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p
int http_auth_basic_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
buffer *username, *password;
char *pw;
-
+
data_string *realm;
-
+
realm = (data_string *)array_get_element(req, "realm");
-
+
username = buffer_init();
- password = buffer_init();
-
- base64_decode(username, realm_str);
-
+
+ if (!base64_decode(username, realm_str)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "decodeing base64-string failed", username);
+
+ buffer_free(username);
+ return 0;
+ }
+
/* r2 == user:password */
if (NULL == (pw = strchr(username->ptr, ':'))) {
- buffer_free(username);
-
log_error_write(srv, __FILE__, __LINE__, "sb", ": is missing in", username);
-
+
+ buffer_free(username);
return 0;
}
-
+
*pw++ = '\0';
-
+
username->used = pw - username->ptr;
-
+
+ password = buffer_init();
/* copy password to r1 */
if (http_auth_get_password(srv, p, username, realm->value, password)) {
buffer_free(username);
buffer_free(password);
-
- log_error_write(srv, __FILE__, __LINE__, "s", "get_password failed");
-
+
+ if (AUTH_BACKEND_UNSET == p->conf.auth_backend) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "auth.backend is not set");
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "get_password failed, IP:", inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
+ }
+
return 0;
}
-
+
/* 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__, "sbsBss", "password doesn't match for", con->uri.path, "username:", username, ", IP:", inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
+
buffer_free(username);
buffer_free(password);
-
+
return 0;
}
-
+
/* value is our allow-rules */
if (http_auth_match_rules(srv, p, url->ptr, username->ptr, NULL, NULL)) {
buffer_free(username);
buffer_free(password);
-
+
log_error_write(srv, __FILE__, __LINE__, "s", "rules didn't match");
-
+
return 0;
}
-
+
/* remember the username */
buffer_copy_string_buffer(p->auth_user, username);
-
+
buffer_free(username);
buffer_free(password);
-
+
return 1;
}
@@ -735,28 +918,28 @@ typedef struct {
int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
char a1[256];
char a2[256];
-
- char *username;
- char *realm;
- char *nonce;
- char *uri;
- char *algorithm;
- char *qop;
- char *cnonce;
- char *nc;
- char *respons;
-
+
+ char *username = NULL;
+ char *realm = NULL;
+ char *nonce = NULL;
+ char *uri = NULL;
+ char *algorithm = NULL;
+ char *qop = NULL;
+ char *cnonce = NULL;
+ char *nc = NULL;
+ char *respons = NULL;
+
char *e, *c;
const char *m = NULL;
int i;
buffer *password, *b, *username_buf, *realm_buf;
-
- MD5_CTX Md5Ctx;
+
+ li_MD5_CTX Md5Ctx;
HASH HA1;
HASH HA2;
HASH RespHash;
HASHHEX HA2Hex;
-
+
/* init pointers */
#define S(x) \
@@ -771,11 +954,11 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p
{ S("cnonce=") },
{ S("nc=") },
{ S("response=") },
-
+
{ NULL, 0, NULL }
};
#undef S
-
+
dkv[0].ptr = &username;
dkv[1].ptr = &realm;
dkv[2].ptr = &nonce;
@@ -785,41 +968,39 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p
dkv[6].ptr = &cnonce;
dkv[7].ptr = &nc;
dkv[8].ptr = &respons;
- dkv[9].ptr = NULL;
-
+
UNUSED(req);
-
- for (i = 0; dkv[i].key; i++) {
- *(dkv[i].ptr) = NULL;
- }
-
-
+
if (p->conf.auth_backend != AUTH_BACKEND_HTDIGEST &&
p->conf.auth_backend != AUTH_BACKEND_PLAIN) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"digest: unsupported backend (only htdigest or plain)");
-
+
return -1;
}
-
+
b = buffer_init_string(realm_str);
-
+
/* parse credentials from client */
for (c = b->ptr; *c; c++) {
+ /* skip whitespaces */
+ while (*c == ' ' || *c == '\t') c++;
+ if (!*c) break;
+
for (i = 0; dkv[i].key; i++) {
if ((0 == strncmp(c, dkv[i].key, dkv[i].key_len))) {
- if ((c[dkv[i].key_len] == '"') &&
+ if ((c[dkv[i].key_len] == '"') &&
(NULL != (e = strchr(c + dkv[i].key_len + 1, '"')))) {
/* value with "..." */
*(dkv[i].ptr) = c + dkv[i].key_len + 1;
c = e;
-
+
*e = '\0';
} else if (NULL != (e = strchr(c + dkv[i].key_len, ','))) {
/* value without "...", terminated by ',' */
*(dkv[i].ptr) = c + dkv[i].key_len;
c = e;
-
+
*e = '\0';
} else {
/* value without "...", terminated by EOL */
@@ -829,34 +1010,49 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p
}
}
}
-
+
if (p->conf.auth_debug > 1) {
log_error_write(srv, __FILE__, __LINE__, "ss", "username", username);
log_error_write(srv, __FILE__, __LINE__, "ss", "realm", realm);
log_error_write(srv, __FILE__, __LINE__, "ss", "nonce", nonce);
log_error_write(srv, __FILE__, __LINE__, "ss", "uri", uri);
- log_error_write(srv, __FILE__, __LINE__, "ss", "algorigthm", algorithm);
+ log_error_write(srv, __FILE__, __LINE__, "ss", "algorithm", algorithm);
log_error_write(srv, __FILE__, __LINE__, "ss", "qop", qop);
log_error_write(srv, __FILE__, __LINE__, "ss", "cnonce", cnonce);
log_error_write(srv, __FILE__, __LINE__, "ss", "nc", nc);
log_error_write(srv, __FILE__, __LINE__, "ss", "response", respons);
}
-
+
/* check if everything is transmitted */
- if (!username ||
+ if (!username ||
!realm ||
!nonce ||
!uri ||
- (qop && !nc && !cnonce) ||
+ (qop && (!nc || !cnonce)) ||
!respons ) {
/* missing field */
-
- log_error_write(srv, __FILE__, __LINE__, "s",
+
+ log_error_write(srv, __FILE__, __LINE__, "s",
"digest: missing field");
+
+ buffer_free(b);
+ return -1;
+ }
+
+ /**
+ * protect the md5-sess against missing cnonce and nonce
+ */
+ if (algorithm &&
+ 0 == strcasecmp(algorithm, "md5-sess") &&
+ (!nonce || !cnonce)) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "digest: (md5-sess: missing field");
+
+ buffer_free(b);
return -1;
}
- m = get_http_method_name(con->request.http_method);
+ m = get_http_method_name(con->request.http_method);
/* password-string == HA1 */
password = buffer_init();
@@ -869,108 +1065,110 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p
buffer_free(realm_buf);
return 0;
}
-
+
buffer_free(username_buf);
buffer_free(realm_buf);
-
+
if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
/* generate password from plain-text */
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)username, strlen(username));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)realm, strlen(realm));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)password->ptr, password->used - 1);
- MD5_Final(HA1, &Md5Ctx);
+ li_MD5_Init(&Md5Ctx);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)username, strlen(username));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)realm, strlen(realm));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)password->ptr, password->used - 1);
+ li_MD5_Final(HA1, &Md5Ctx);
} else if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
/* HA1 */
/* transform the 32-byte-hex-md5 to a 16-byte-md5 */
for (i = 0; i < HASHLEN; i++) {
- HA1[i] = hex2int(password->ptr[i*2]) << 4;
- HA1[i] |= hex2int(password->ptr[i*2+1]);
+ HA1[i] = hex2int(password->ptr[i*2]) << 4;
+ HA1[i] |= hex2int(password->ptr[i*2+1]);
}
} else {
/* we already check that above */
SEGFAULT();
}
-
+
buffer_free(password);
-
+
if (algorithm &&
strcasecmp(algorithm, "md5-sess") == 0) {
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)HA1, 16);
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)nonce, strlen(nonce));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
- MD5_Final(HA1, &Md5Ctx);
+ li_MD5_Init(&Md5Ctx);
+ /* Errata ID 1649: http://www.rfc-editor.org/errata_search.php?rfc=2617 */
+ CvtHex(HA1, a1);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)a1, 32);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)nonce, strlen(nonce));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
+ li_MD5_Final(HA1, &Md5Ctx);
}
-
+
CvtHex(HA1, a1);
-
+
/* calculate H(A2) */
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)uri, strlen(uri));
+ li_MD5_Init(&Md5Ctx);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)uri, strlen(uri));
if (qop && strcasecmp(qop, "auth-int") == 0) {
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)"", HASHHEXLEN);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)"", HASHHEXLEN);
}
- MD5_Final(HA2, &Md5Ctx);
+ li_MD5_Final(HA2, &Md5Ctx);
CvtHex(HA2, HA2Hex);
-
+
/* calculate response */
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN);
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)nonce, strlen(nonce));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
+ li_MD5_Init(&Md5Ctx);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)nonce, strlen(nonce));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
if (qop && *qop) {
- MD5_Update(&Md5Ctx, (unsigned char *)nc, strlen(nc));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)qop, strlen(qop));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)nc, strlen(nc));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)qop, strlen(qop));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
};
- MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
- MD5_Final(RespHash, &Md5Ctx);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
+ li_MD5_Final(RespHash, &Md5Ctx);
CvtHex(RespHash, a2);
-
+
if (0 != strcmp(a2, respons)) {
/* digest not ok */
-
+
if (p->conf.auth_debug) {
- log_error_write(srv, __FILE__, __LINE__, "sss",
+ log_error_write(srv, __FILE__, __LINE__, "sss",
"digest: digest mismatch", a2, respons);
}
-
- log_error_write(srv, __FILE__, __LINE__, "sss",
- "digest: auth failed for", username, "wrong password");
-
+
+ log_error_write(srv, __FILE__, __LINE__, "ssss",
+ "digest: auth failed for ", username, ": wrong password, IP:", inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
+
buffer_free(b);
return 0;
}
-
+
/* value is our allow-rules */
if (http_auth_match_rules(srv, p, url->ptr, username, NULL, NULL)) {
buffer_free(b);
-
- log_error_write(srv, __FILE__, __LINE__, "s",
+
+ log_error_write(srv, __FILE__, __LINE__, "s",
"digest: rules did match");
-
+
return 0;
}
-
+
/* remember the username */
buffer_copy_string(p->auth_user, username);
-
+
buffer_free(b);
-
+
if (p->conf.auth_debug) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"digest: auth ok");
}
return 1;
@@ -979,25 +1177,26 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p
int http_auth_digest_generate_nonce(server *srv, mod_auth_plugin_data *p, buffer *fn, char out[33]) {
HASH h;
- MD5_CTX Md5Ctx;
+ li_MD5_CTX Md5Ctx;
char hh[32];
-
+
UNUSED(p);
/* generate shared-secret */
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)fn->ptr, fn->used - 1);
- MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
-
+ li_MD5_Init(&Md5Ctx);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)fn->ptr, fn->used - 1);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
+
/* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
- ltostr(hh, srv->cur_ts);
- MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
- ltostr(hh, rand());
- MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
-
- MD5_Final(h, &Md5Ctx);
-
+ LI_ltostr(hh, srv->cur_ts);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)srv->entropy, sizeof(srv->entropy));
+ LI_ltostr(hh, rand());
+ li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
+
+ li_MD5_Final(h, &Md5Ctx);
+
CvtHex(h, out);
-
+
return 0;
}
diff --git a/src/http_auth.h b/src/http_auth.h
index 0b664fa..5828a7e 100644
--- a/src/http_auth.h
+++ b/src/http_auth.h
@@ -9,22 +9,26 @@
# include <ldap.h>
#endif
-typedef enum { AUTH_BACKEND_UNSET, AUTH_BACKEND_PLAIN,
- AUTH_BACKEND_LDAP, AUTH_BACKEND_HTPASSWD,
- AUTH_BACKEND_HTDIGEST, AUTH_BACKEND_PAM } auth_backend_t;
+typedef enum {
+ AUTH_BACKEND_UNSET,
+ AUTH_BACKEND_PLAIN,
+ AUTH_BACKEND_LDAP,
+ AUTH_BACKEND_HTPASSWD,
+ AUTH_BACKEND_HTDIGEST
+} auth_backend_t;
typedef struct {
/* auth */
array *auth_require;
-
+
buffer *auth_plain_groupfile;
buffer *auth_plain_userfile;
-
+
buffer *auth_htdigest_userfile;
buffer *auth_htpasswd_userfile;
-
+
buffer *auth_backend_conf;
-
+
buffer *auth_ldap_hostname;
buffer *auth_ldap_basedn;
buffer *auth_ldap_binddn;
@@ -32,15 +36,16 @@ typedef struct {
buffer *auth_ldap_filter;
buffer *auth_ldap_cafile;
unsigned short auth_ldap_starttls;
-
+ unsigned short auth_ldap_allow_empty_pw;
+
unsigned short auth_debug;
-
+
/* generated */
auth_backend_t auth_backend;
-
+
#ifdef USE_LDAP
LDAP *ldap;
-
+
buffer *ldap_filter_pre;
buffer *ldap_filter_post;
#endif
@@ -49,16 +54,16 @@ typedef struct {
typedef struct {
PLUGIN_DATA;
buffer *tmp_buf;
-
+
buffer *auth_user;
#ifdef USE_LDAP
buffer *ldap_filter;
#endif
-
+
mod_auth_plugin_config **config_storage;
-
- mod_auth_plugin_config conf; /* this is only used as long as no handler_ctx is setup */
+
+ mod_auth_plugin_config conf, *anon_conf; /* this is only used as long as no handler_ctx is setup */
} mod_auth_plugin_data;
int http_auth_basic_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str);
diff --git a/src/http_auth_digest.c b/src/http_auth_digest.c
deleted file mode 100644
index e440430..0000000
--- a/src/http_auth_digest.c
+++ /dev/null
@@ -1,19 +0,0 @@
-#include <string.h>
-#include "http_auth_digest.h"
-
-#include "buffer.h"
-
-#ifndef USE_OPENSSL
-# include "md5.h"
-#endif
-
-void CvtHex(IN HASH Bin, OUT HASHHEX Hex) {
- unsigned short i;
-
- for (i = 0; i < HASHLEN; i++) {
- Hex[i*2] = int2hex((Bin[i] >> 4) & 0xf);
- Hex[i*2+1] = int2hex(Bin[i] & 0xf);
- }
- Hex[HASHHEXLEN] = '\0';
-}
-
diff --git a/src/http_auth_digest.h b/src/http_auth_digest.h
deleted file mode 100644
index 8bffce4..0000000
--- a/src/http_auth_digest.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef _DIGCALC_H_
-#define _DIGCALC_H_
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#define HASHLEN 16
-typedef unsigned char HASH[HASHLEN];
-#define HASHHEXLEN 32
-typedef char HASHHEX[HASHHEXLEN+1];
-#ifdef USE_OPENSSL
-#define IN const
-#else
-#define IN
-#endif
-#define OUT
-
-void CvtHex(
- IN HASH Bin,
- OUT HASHHEX Hex
- );
-
-#endif
diff --git a/src/http_chunk.c b/src/http_chunk.c
index c128bf1..5557edc 100644
--- a/src/http_chunk.c
+++ b/src/http_chunk.c
@@ -1,9 +1,14 @@
/**
* the HTTP chunk-API
- *
- *
+ *
+ *
*/
+#include "server.h"
+#include "chunk.h"
+#include "http_chunk.h"
+#include "log.h"
+
#include <sys/types.h>
#include <sys/stat.h>
@@ -15,27 +20,22 @@
#include <errno.h>
#include <string.h>
-#include "server.h"
-#include "chunk.h"
-#include "http_chunk.h"
-#include "log.h"
-
static int http_chunk_append_len(server *srv, connection *con, size_t len) {
size_t i, olen = len, j;
buffer *b;
-
+
b = srv->tmp_chunk_len;
-
+
if (len == 0) {
- buffer_copy_string(b, "0");
+ buffer_copy_string_len(b, CONST_STR_LEN("0"));
} else {
for (i = 0; i < 8 && len; i++) {
len >>= 4;
}
-
+
/* i is the number of hex digits we have */
buffer_prepare_copy(b, i + 1);
-
+
for (j = i-1, len = olen; j+1 > 0; j--) {
b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
len >>= 4;
@@ -43,81 +43,80 @@ static int http_chunk_append_len(server *srv, connection *con, size_t len) {
b->used = i;
b->ptr[b->used++] = '\0';
}
-
- buffer_append_string(b, "\r\n");
+
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
chunkqueue_append_buffer(con->write_queue, b);
-
+
return 0;
}
int http_chunk_append_file(server *srv, connection *con, buffer *fn, off_t offset, off_t len) {
chunkqueue *cq;
-
+
if (!con) return -1;
-
+
cq = con->write_queue;
-
+
if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
http_chunk_append_len(srv, con, len);
}
-
+
chunkqueue_append_file(cq, fn, offset, len);
-
+
if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && len > 0) {
chunkqueue_append_mem(cq, "\r\n", 2 + 1);
}
-
+
return 0;
}
int http_chunk_append_buffer(server *srv, connection *con, buffer *mem) {
chunkqueue *cq;
-
+
if (!con) return -1;
-
+
cq = con->write_queue;
-
+
if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
http_chunk_append_len(srv, con, mem->used - 1);
}
-
+
chunkqueue_append_buffer(cq, mem);
-
+
if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && mem->used > 0) {
chunkqueue_append_mem(cq, "\r\n", 2 + 1);
}
-
+
return 0;
}
int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t len) {
chunkqueue *cq;
-
+
if (!con) return -1;
-
+
cq = con->write_queue;
-
+
if (len == 0) {
if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
- http_chunk_append_len(srv, con, 0);
- chunkqueue_append_mem(cq, "\r\n", 2 + 1);
+ chunkqueue_append_mem(cq, "0\r\n\r\n", 5 + 1);
} else {
chunkqueue_append_mem(cq, "", 1);
}
return 0;
}
-
+
if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
http_chunk_append_len(srv, con, len - 1);
}
-
+
chunkqueue_append_mem(cq, mem, len);
-
+
if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
chunkqueue_append_mem(cq, "\r\n", 2 + 1);
}
-
+
return 0;
}
@@ -125,9 +124,9 @@ int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t
off_t http_chunkqueue_length(server *srv, connection *con) {
if (!con) {
log_error_write(srv, __FILE__, __LINE__, "s", "connection is NULL!!");
-
+
return 0;
}
-
+
return chunkqueue_length(con->write_queue);
}
diff --git a/src/inet_ntop_cache.c b/src/inet_ntop_cache.c
index c0b3aa1..eac0681 100644
--- a/src/inet_ntop_cache.c
+++ b/src/inet_ntop_cache.c
@@ -1,17 +1,16 @@
-#include <sys/types.h>
-
-#include <string.h>
-
-
#include "base.h"
#include "inet_ntop_cache.h"
#include "sys-socket.h"
+#include <sys/types.h>
+
+#include <string.h>
+
const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr) {
-#ifdef HAVE_IPV6
+#ifdef HAVE_IPV6
size_t ndx = 0, i;
for (i = 0; i < INET_NTOP_CACHE_MAX; i++) {
- if (srv->inet_ntop_cache[i].ts != 0) {
+ if (srv->inet_ntop_cache[i].ts != 0 && srv->inet_ntop_cache[i].family == addr->plain.sa_family) {
if (srv->inet_ntop_cache[i].family == AF_INET6 &&
0 == memcmp(srv->inet_ntop_cache[i].addr.ipv6.s6_addr, addr->ipv6.sin6_addr.s6_addr, 16)) {
/* IPv6 found in cache */
@@ -20,31 +19,31 @@ const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr) {
srv->inet_ntop_cache[i].addr.ipv4.s_addr == addr->ipv4.sin_addr.s_addr) {
/* IPv4 found in cache */
break;
-
+
}
}
}
-
+
if (i == INET_NTOP_CACHE_MAX) {
/* not found in cache */
-
+
i = ndx;
- inet_ntop(addr->plain.sa_family,
- addr->plain.sa_family == AF_INET6 ?
+ inet_ntop(addr->plain.sa_family,
+ addr->plain.sa_family == AF_INET6 ?
(const void *) &(addr->ipv6.sin6_addr) :
(const void *) &(addr->ipv4.sin_addr),
srv->inet_ntop_cache[i].b2, INET6_ADDRSTRLEN);
-
+
srv->inet_ntop_cache[i].ts = srv->cur_ts;
srv->inet_ntop_cache[i].family = addr->plain.sa_family;
-
+
if (srv->inet_ntop_cache[i].family == AF_INET) {
srv->inet_ntop_cache[i].addr.ipv4.s_addr = addr->ipv4.sin_addr.s_addr;
} else if (srv->inet_ntop_cache[i].family == AF_INET6) {
memcpy(srv->inet_ntop_cache[i].addr.ipv6.s6_addr, addr->ipv6.sin6_addr.s6_addr, 16);
}
}
-
+
return srv->inet_ntop_cache[i].b2;
#else
UNUSED(srv);
diff --git a/src/joblist.c b/src/joblist.c
index dcab955..677a1a5 100644
--- a/src/joblist.c
+++ b/src/joblist.c
@@ -1,13 +1,13 @@
-#include <stdlib.h>
-#include <string.h>
-
#include "base.h"
#include "joblist.h"
#include "log.h"
+#include <stdlib.h>
+#include <string.h>
+
int joblist_append(server *srv, connection *con) {
if (con->in_joblist) return 0;
-
+
if (srv->joblist->size == 0) {
srv->joblist->size = 16;
srv->joblist->ptr = malloc(sizeof(*srv->joblist->ptr) * srv->joblist->size);
@@ -15,15 +15,15 @@ int joblist_append(server *srv, connection *con) {
srv->joblist->size += 16;
srv->joblist->ptr = realloc(srv->joblist->ptr, sizeof(*srv->joblist->ptr) * srv->joblist->size);
}
-
+
srv->joblist->ptr[srv->joblist->used++] = con;
-
+
return 0;
}
void joblist_free(server *srv, connections *joblist) {
UNUSED(srv);
-
+
free(joblist->ptr);
free(joblist);
}
@@ -31,14 +31,14 @@ void joblist_free(server *srv, connections *joblist) {
connection *fdwaitqueue_unshift(server *srv, connections *fdwaitqueue) {
connection *con;
UNUSED(srv);
-
-
+
+
if (fdwaitqueue->used == 0) return NULL;
-
+
con = fdwaitqueue->ptr[0];
-
+
memmove(fdwaitqueue->ptr, &(fdwaitqueue->ptr[1]), --fdwaitqueue->used * sizeof(*(fdwaitqueue->ptr)));
-
+
return con;
}
@@ -50,9 +50,9 @@ int fdwaitqueue_append(server *srv, connection *con) {
srv->fdwaitqueue->size += 16;
srv->fdwaitqueue->ptr = realloc(srv->fdwaitqueue->ptr, sizeof(*(srv->fdwaitqueue->ptr)) * srv->fdwaitqueue->size);
}
-
+
srv->fdwaitqueue->ptr[srv->fdwaitqueue->used++] = con;
-
+
return 0;
}
diff --git a/src/keyvalue.c b/src/keyvalue.c
index b26588f..ba37611 100644
--- a/src/keyvalue.c
+++ b/src/keyvalue.c
@@ -1,10 +1,11 @@
+#include "server.h"
+#include "keyvalue.h"
+#include "log.h"
+
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
-#include "server.h"
-#include "keyvalue.h"
-
static keyvalue http_versions[] = {
{ HTTP_VERSION_1_1, "HTTP/1.1" },
{ HTTP_VERSION_1_0, "HTTP/1.0" },
@@ -21,12 +22,17 @@ static keyvalue http_methods[] = {
{ HTTP_METHOD_OPTIONS, "OPTIONS" },
{ HTTP_METHOD_MKCOL, "MKCOL" },
{ HTTP_METHOD_PUT, "PUT" },
+ { HTTP_METHOD_PATCH, "PATCH" },
{ HTTP_METHOD_DELETE, "DELETE" },
{ HTTP_METHOD_COPY, "COPY" },
{ HTTP_METHOD_MOVE, "MOVE" },
{ HTTP_METHOD_LABEL, "LABEL" },
{ HTTP_METHOD_CHECKOUT, "CHECKOUT" },
{ HTTP_METHOD_CHECKIN, "CHECKIN" },
+ { HTTP_METHOD_MERGE, "MERGE" },
+ { HTTP_METHOD_LOCK, "LOCK" },
+ { HTTP_METHOD_UNLOCK, "UNLOCK" },
+ { HTTP_METHOD_MKACTIVITY, "MKACTIVITY" },
{ HTTP_METHOD_UNCHECKOUT, "UNCHECKOUT" },
{ HTTP_METHOD_VERSION_CONTROL, "VERSION-CONTROL" },
{ HTTP_METHOD_CONNECT, "CONNECT" },
@@ -83,7 +89,7 @@ static keyvalue http_status[] = {
{ 504, "Gateway Timeout" },
{ 505, "HTTP Version Not Supported" },
{ 507, "Insufficient Storage" }, /* WebDAV */
-
+
{ -1, NULL }
};
@@ -98,12 +104,12 @@ static keyvalue http_status_body[] = {
{ 501, "501.html" },
{ 503, "503.html" },
{ 505, "505.html" },
-
+
{ -1, NULL }
};
-const char *keyvalue_get_value(keyvalue *kv, int k) {
+const char *keyvalue_get_value(keyvalue *kv, int k) {
int i;
for (i = 0; kv[i].value; i++) {
if (kv[i].key == k) return kv[i].value;
@@ -111,7 +117,7 @@ const char *keyvalue_get_value(keyvalue *kv, int k) {
return NULL;
}
-int keyvalue_get_key(keyvalue *kv, const char *s) {
+int keyvalue_get_key(keyvalue *kv, const char *s) {
int i;
for (i = 0; kv[i].value; i++) {
if (0 == strcmp(kv[i].value, s)) return kv[i].key;
@@ -121,9 +127,9 @@ int keyvalue_get_key(keyvalue *kv, const char *s) {
keyvalue_buffer *keyvalue_buffer_init(void) {
keyvalue_buffer *kvb;
-
+
kvb = calloc(1, sizeof(*kvb));
-
+
return kvb;
}
@@ -131,49 +137,49 @@ int keyvalue_buffer_append(keyvalue_buffer *kvb, int key, const char *value) {
size_t i;
if (kvb->size == 0) {
kvb->size = 4;
-
+
kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
-
+
for(i = 0; i < kvb->size; i++) {
kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
}
} else if (kvb->used == kvb->size) {
kvb->size += 4;
-
+
kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
-
+
for(i = kvb->used; i < kvb->size; i++) {
kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
}
}
-
+
kvb->kv[kvb->used]->key = key;
kvb->kv[kvb->used]->value = strdup(value);
-
+
kvb->used++;
-
+
return 0;
}
void keyvalue_buffer_free(keyvalue_buffer *kvb) {
size_t i;
-
+
for (i = 0; i < kvb->size; i++) {
if (kvb->kv[i]->value) free(kvb->kv[i]->value);
free(kvb->kv[i]);
}
-
+
if (kvb->kv) free(kvb->kv);
-
+
free(kvb);
}
s_keyvalue_buffer *s_keyvalue_buffer_init(void) {
s_keyvalue_buffer *kvb;
-
+
kvb = calloc(1, sizeof(*kvb));
-
+
return kvb;
}
@@ -182,50 +188,50 @@ int s_keyvalue_buffer_append(s_keyvalue_buffer *kvb, const char *key, const char
if (kvb->size == 0) {
kvb->size = 4;
kvb->used = 0;
-
+
kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
-
+
for(i = 0; i < kvb->size; i++) {
kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
}
} else if (kvb->used == kvb->size) {
kvb->size += 4;
-
+
kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
-
+
for(i = kvb->used; i < kvb->size; i++) {
kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
}
}
-
+
kvb->kv[kvb->used]->key = key ? strdup(key) : NULL;
kvb->kv[kvb->used]->value = strdup(value);
-
+
kvb->used++;
-
+
return 0;
}
void s_keyvalue_buffer_free(s_keyvalue_buffer *kvb) {
size_t i;
-
+
for (i = 0; i < kvb->size; i++) {
if (kvb->kv[i]->key) free(kvb->kv[i]->key);
if (kvb->kv[i]->value) free(kvb->kv[i]->value);
free(kvb->kv[i]);
}
-
+
if (kvb->kv) free(kvb->kv);
-
+
free(kvb);
}
httpauth_keyvalue_buffer *httpauth_keyvalue_buffer_init(void) {
httpauth_keyvalue_buffer *kvb;
-
+
kvb = calloc(1, sizeof(*kvb));
-
+
return kvb;
}
@@ -233,42 +239,42 @@ int httpauth_keyvalue_buffer_append(httpauth_keyvalue_buffer *kvb, const char *k
size_t i;
if (kvb->size == 0) {
kvb->size = 4;
-
+
kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
-
+
for(i = 0; i < kvb->size; i++) {
kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
}
} else if (kvb->used == kvb->size) {
kvb->size += 4;
-
+
kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
-
+
for(i = kvb->used; i < kvb->size; i++) {
kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
}
}
-
+
kvb->kv[kvb->used]->key = strdup(key);
kvb->kv[kvb->used]->realm = strdup(realm);
kvb->kv[kvb->used]->type = type;
-
+
kvb->used++;
-
+
return 0;
}
void httpauth_keyvalue_buffer_free(httpauth_keyvalue_buffer *kvb) {
size_t i;
-
+
for (i = 0; i < kvb->size; i++) {
if (kvb->kv[i]->key) free(kvb->kv[i]->key);
if (kvb->kv[i]->realm) free(kvb->kv[i]->realm);
free(kvb->kv[i]);
}
-
+
if (kvb->kv) free(kvb->kv);
-
+
free(kvb);
}
@@ -302,59 +308,60 @@ http_method_t get_http_method_key(const char *s) {
pcre_keyvalue_buffer *pcre_keyvalue_buffer_init(void) {
pcre_keyvalue_buffer *kvb;
-
+
kvb = calloc(1, sizeof(*kvb));
-
+
return kvb;
}
-int pcre_keyvalue_buffer_append(pcre_keyvalue_buffer *kvb, const char *key, const char *value) {
+int pcre_keyvalue_buffer_append(server *srv, pcre_keyvalue_buffer *kvb, const char *key, const char *value) {
#ifdef HAVE_PCRE_H
size_t i;
const char *errptr;
int erroff;
pcre_keyvalue *kv;
#endif
-
+
if (!key) return -1;
#ifdef HAVE_PCRE_H
if (kvb->size == 0) {
kvb->size = 4;
kvb->used = 0;
-
+
kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
-
+
for(i = 0; i < kvb->size; i++) {
kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
}
} else if (kvb->used == kvb->size) {
kvb->size += 4;
-
+
kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
-
+
for(i = kvb->used; i < kvb->size; i++) {
kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
}
}
-
+
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);
+
+ log_error_write(srv, __FILE__, __LINE__, "SS",
+ "rexexp compilation error at ", errptr);
return -1;
}
- if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&
+ if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&
errptr != NULL) {
return -1;
}
-
+
kv->value = buffer_init_string(value);
-
+
kvb->used++;
-
+
return 0;
#else
UNUSED(kvb);
@@ -376,9 +383,9 @@ void pcre_keyvalue_buffer_free(pcre_keyvalue_buffer *kvb) {
if (kv->value) buffer_free(kv->value);
free(kv);
}
-
+
if (kvb->kv) free(kvb->kv);
#endif
-
+
free(kvb);
}
diff --git a/src/keyvalue.h b/src/keyvalue.h
index e1c940f..43ef99b 100644
--- a/src/keyvalue.h
+++ b/src/keyvalue.h
@@ -2,31 +2,38 @@
#define _KEY_VALUE_H_
#ifdef HAVE_CONFIG_H
-#include "config.h"
+# include "config.h"
#endif
#ifdef HAVE_PCRE_H
# include <pcre.h>
#endif
-typedef enum {
- HTTP_METHOD_UNSET = -1,
- HTTP_METHOD_GET,
- HTTP_METHOD_POST,
- HTTP_METHOD_HEAD,
- HTTP_METHOD_OPTIONS,
+struct server;
+
+typedef enum {
+ HTTP_METHOD_UNSET = -1,
+ HTTP_METHOD_GET,
+ HTTP_METHOD_POST,
+ HTTP_METHOD_HEAD,
+ HTTP_METHOD_OPTIONS,
HTTP_METHOD_PROPFIND, /* WebDAV */
- HTTP_METHOD_MKCOL,
- HTTP_METHOD_PUT,
- HTTP_METHOD_DELETE,
- HTTP_METHOD_COPY,
- HTTP_METHOD_MOVE,
- HTTP_METHOD_PROPPATCH,
+ HTTP_METHOD_MKCOL,
+ HTTP_METHOD_PUT,
+ HTTP_METHOD_PATCH,
+ HTTP_METHOD_DELETE,
+ HTTP_METHOD_COPY,
+ HTTP_METHOD_MOVE,
+ HTTP_METHOD_PROPPATCH,
HTTP_METHOD_REPORT, /* DeltaV */
HTTP_METHOD_CHECKOUT,
HTTP_METHOD_CHECKIN,
HTTP_METHOD_VERSION_CONTROL,
HTTP_METHOD_UNCHECKOUT,
+ HTTP_METHOD_MKACTIVITY,
+ HTTP_METHOD_MERGE,
+ HTTP_METHOD_LOCK,
+ HTTP_METHOD_UNLOCK,
HTTP_METHOD_LABEL,
HTTP_METHOD_CONNECT
} http_method_t;
@@ -35,13 +42,13 @@ typedef enum { HTTP_VERSION_UNSET = -1, HTTP_VERSION_1_0, HTTP_VERSION_1_1 } htt
typedef struct {
int key;
-
+
char *value;
} keyvalue;
typedef struct {
char *key;
-
+
char *value;
} s_keyvalue;
@@ -50,7 +57,7 @@ typedef struct {
pcre *key;
pcre_extra *key_extra;
#endif
-
+
buffer *value;
} pcre_keyvalue;
@@ -58,7 +65,7 @@ typedef enum { HTTP_AUTH_BASIC, HTTP_AUTH_DIGEST } httpauth_type;
typedef struct {
char *key;
-
+
char *realm;
httpauth_type type;
} httpauth_keyvalue;
@@ -98,7 +105,7 @@ int httpauth_keyvalue_buffer_append(httpauth_keyvalue_buffer *kvb, const char *k
void httpauth_keyvalue_buffer_free(httpauth_keyvalue_buffer *kvb);
pcre_keyvalue_buffer *pcre_keyvalue_buffer_init(void);
-int pcre_keyvalue_buffer_append(pcre_keyvalue_buffer *kvb, const char *key, const char *value);
+int pcre_keyvalue_buffer_append(struct server *srv, pcre_keyvalue_buffer *kvb, const char *key, const char *value);
void pcre_keyvalue_buffer_free(pcre_keyvalue_buffer *kvb);
#endif
diff --git a/src/lemon.c b/src/lemon.c
index dd87cdf..c3d72eb 100644
--- a/src/lemon.c
+++ b/src/lemon.c
@@ -12,12 +12,26 @@
#include <ctype.h>
#include <stdlib.h>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+#define UNUSED(x) ( (void)(x) )
+
extern void qsort();
extern double strtod();
extern long strtol();
extern void free();
extern int access();
extern int atoi();
+extern char *getenv();
#ifndef __WIN32__
# if defined(_WIN32) || defined(WIN32)
@@ -25,8 +39,14 @@ extern int atoi();
# endif
#endif
+#if __GNUC__ > 2
+#define NORETURN __attribute__ ((__noreturn__))
+#else
+#define NORETURN
+#endif
+
/* #define PRIVATE static */
-#define PRIVATE
+#define PRIVATE static
#ifdef TEST
#define MAXRHS 5 /* Set low to exercise exception code */
@@ -37,13 +57,15 @@ extern int atoi();
char *msort();
extern void *malloc();
+extern void memory_error() NORETURN;
+
/******** From the file "action.h" *************************************/
struct action *Action_new();
struct action *Action_sort();
void Action_add();
/********* From the file "assert.h" ************************************/
-void myassert();
+void myassert() NORETURN;
#ifndef NDEBUG
# define assert(X) if(!(X))myassert(__FILE__,__LINE__)
#else
@@ -278,7 +300,6 @@ struct lemon {
};
#define MemoryCheck(X) if((X)==0){ \
- extern void memory_error(); \
memory_error(); \
}
@@ -336,10 +357,10 @@ void Configtable_clear(/* int(*)(struct config *) */);
/* Allocate a new parser action */
struct action *Action_new(){
- static struct action *freelist = 0;
+ static struct action *freelist = NULL;
struct action *new;
- if( freelist==0 ){
+ if( freelist==NULL ){
int i;
int amt = 100;
freelist = (struct action *)malloc( sizeof(struct action)*amt );
@@ -383,7 +404,7 @@ void Action_add(app,type,sp,arg)
struct action **app;
enum e_action type;
struct symbol *sp;
-char *arg;
+void *arg;
{
struct action *new;
new = Action_new();
@@ -432,14 +453,16 @@ struct acttab {
#define acttab_yylookahead(X,N) ((X)->aAction[N].lookahead)
/* Free all memory associated with the given acttab */
-void acttab_free(acttab *p){
+/*
+PRIVATE void acttab_free(acttab *p){
free( p->aAction );
free( p->aLookahead );
free( p );
}
+*/
/* Allocate a new acttab structure */
-acttab *acttab_alloc(void){
+PRIVATE acttab *acttab_alloc(void){
acttab *p = malloc( sizeof(*p) );
if( p==0 ){
fprintf(stderr,"Unable to allocate memory for a new acttab.");
@@ -451,7 +474,7 @@ acttab *acttab_alloc(void){
/* Add a new action to the current transaction set
*/
-void acttab_action(acttab *p, int lookahead, int action){
+PRIVATE void acttab_action(acttab *p, int lookahead, int action){
if( p->nLookahead>=p->nLookaheadAlloc ){
p->nLookaheadAlloc += 25;
p->aLookahead = realloc( p->aLookahead,
@@ -484,7 +507,7 @@ void acttab_action(acttab *p, int lookahead, int action){
**
** Return the offset into the action table of the new transaction.
*/
-int acttab_insert(acttab *p){
+PRIVATE int acttab_insert(acttab *p){
int i, j, k, n;
assert( p->nLookahead>0 );
@@ -579,7 +602,7 @@ int line;
*/
/* Find a precedence symbol of every rule in the grammar.
-**
+**
** Those rules which have a precedence symbol coded in the input
** grammar using the "[symbol]" construct will already have the
** rp->precsym field filled. Other rules take as their precedence
@@ -869,7 +892,7 @@ struct lemon *lemp;
cfp->status = INCOMPLETE;
}
}
-
+
do{
progress = 0;
for(i=0; i<lemp->nstate; i++){
@@ -900,7 +923,7 @@ struct lemon *lemp;
struct symbol *sp;
struct rule *rp;
- /* Add all of the reduce actions
+ /* Add all of the reduce actions
** A reduce action is added for each element of the followset of
** a configuration which has its dot at the extreme right.
*/
@@ -983,6 +1006,7 @@ struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */
{
struct symbol *spx, *spy;
int errcnt = 0;
+ UNUSED(errsym);
assert( apx->sp==apy->sp ); /* Otherwise there would be no conflict */
if( apx->type==SHIFT && apy->type==REDUCE ){
spx = apx->sp;
@@ -1017,7 +1041,7 @@ struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */
apx->type = RD_RESOLVED;
}
}else{
- assert(
+ assert(
apx->type==SH_RESOLVED ||
apx->type==RD_RESOLVED ||
apx->type==CONFLICT ||
@@ -1315,7 +1339,7 @@ void ErrorMsg(const char *filename, int lineno, const char *format, ...){
/* Report an out-of-memory condition and abort. This function
** is used mostly by the "MemoryCheck" macro in struct.h
*/
-void memory_error(){
+void memory_error() {
fprintf(stderr,"Out of memory. Aborting...\n");
exit(1);
}
@@ -1347,10 +1371,11 @@ char **argv;
struct lemon lem;
char *def_tmpl_name = "lempar.c";
+ UNUSED(argc);
OptInit(argv,options,stderr);
if( version ){
printf("Lemon version 1.0\n");
- exit(0);
+ exit(0);
}
if( OptNArgs() < 1 ){
fprintf(stderr,"Exactly one filename argument is required.\n");
@@ -1589,7 +1614,6 @@ int k;
FILE *err;
{
int spcnt, i;
- spcnt = 0;
if( argv[0] ) fprintf(err,"%s",argv[0]);
spcnt = strlen(argv[0]) + 1;
for(i=1; i<n && argv[i]; i++){
@@ -1651,7 +1675,7 @@ FILE *err;
}else if( op[j].type==OPT_FLAG ){
*((int*)op[j].arg) = v;
}else if( op[j].type==OPT_FFLAG ){
- (*(void(*)())(op[j].arg))(v);
+ (*(void(*)())(intptr_t)(op[j].arg))(v);
}else{
if( err ){
fprintf(err,"%smissing argument on switch.\n",emsg);
@@ -1733,19 +1757,19 @@ FILE *err;
*(double*)(op[j].arg) = dv;
break;
case OPT_FDBL:
- (*(void(*)())(op[j].arg))(dv);
+ (*(void(*)())(intptr_t)(op[j].arg))(dv);
break;
case OPT_INT:
*(int*)(op[j].arg) = lv;
break;
case OPT_FINT:
- (*(void(*)())(op[j].arg))((int)lv);
+ (*(void(*)())(intptr_t)(op[j].arg))((int)lv);
break;
case OPT_STR:
*(char**)(op[j].arg) = sv;
break;
case OPT_FSTR:
- (*(void(*)())(op[j].arg))(sv);
+ (*(void(*)())(intptr_t)(op[j].arg))(sv);
break;
}
}
@@ -2031,7 +2055,7 @@ to follow the previous rule.");
case IN_RHS:
if( x[0]=='.' ){
struct rule *rp;
- rp = (struct rule *)malloc( sizeof(struct rule) +
+ rp = (struct rule *)malloc( sizeof(struct rule) +
sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs );
if( rp==0 ){
ErrorMsg(psp->filename,psp->tokenlineno,
@@ -2286,10 +2310,10 @@ to follow the previous rule.");
** token is passed to the function "parseonetoken" which builds all
** the appropriate data structures in the global state vector "gp".
*/
+struct pstate ps;
void Parse(gp)
struct lemon *gp;
{
- struct pstate ps;
FILE *fp;
char *filebuf;
size_t filesize;
@@ -2317,6 +2341,7 @@ struct lemon *gp;
if( filebuf==0 ){
ErrorMsg(ps.filename,0,"Can't allocate %d of memory to hold this file.",
filesize+1);
+ fclose(fp);
gp->errorcnt++;
return;
}
@@ -2324,6 +2349,7 @@ struct lemon *gp;
ErrorMsg(ps.filename,0,"Can't read in all %d bytes of this file.",
filesize);
free(filebuf);
+ fclose(fp);
gp->errorcnt++;
return;
}
@@ -2546,7 +2572,7 @@ char *mode;
return fp;
}
-/* Duplicate the input file without comments and without actions
+/* Duplicate the input file without comments and without actions
** on rules */
void Reprint(lemp)
struct lemon *lemp;
@@ -2588,7 +2614,7 @@ struct lemon *lemp;
}
}
-void ConfigPrint(fp,cfp)
+PRIVATE void ConfigPrint(fp,cfp)
FILE *fp;
struct config *cfp;
{
@@ -2625,7 +2651,7 @@ struct lemon *lemp;
}
/* Print a plink chain */
-PRIVATE void PlinkPrint(out,plp,tag)
+void PlinkPrint(out,plp,tag)
FILE *out;
struct plink *plp;
char *tag;
@@ -2642,7 +2668,7 @@ char *tag;
/* Print an action to the given file descriptor. Return FALSE if
** nothing was actually printed.
*/
-int PrintAction(struct action *ap, FILE *fp, int indent){
+PRIVATE int PrintAction(struct action *ap, FILE *fp, int indent){
int result = 1;
switch( ap->type ){
case SHIFT:
@@ -2716,6 +2742,7 @@ struct lemon *lemp;
return;
}
+ extern int access();
/* Search for the file "name" which is in the same directory as
** the exacutable */
PRIVATE char *pathsearch(argv0,name,modemask)
@@ -2726,7 +2753,6 @@ int modemask;
char *pathlist;
char *path,*cp;
char c;
- extern int access();
#ifdef __WIN32__
cp = strrchr(argv0,'\\');
@@ -2740,7 +2766,6 @@ int modemask;
if( path ) sprintf(path,"%s/%s",argv0,name);
*cp = c;
}else{
- extern char *getenv();
pathlist = getenv("PATH");
if( pathlist==0 ) pathlist = ".:/bin:/usr/bin";
path = (char *)malloc( strlen(pathlist)+strlen(name)+2 );
@@ -2822,7 +2847,7 @@ int *lineno;
PRIVATE FILE *tplt_open(lemp)
struct lemon *lemp;
{
-
+
char buf[1000];
FILE *in;
char *tpltname;
@@ -2879,7 +2904,7 @@ int *lineno;
** The following routine emits code for the destructor for the
** symbol sp
*/
-void emit_destructor_code(out,sp,lemp,lineno)
+PRIVATE void emit_destructor_code(out,sp,lemp,lineno)
FILE *out;
struct symbol *sp;
struct lemon *lemp;
@@ -2895,7 +2920,7 @@ int *lineno;
}else if( sp->destructor ){
cp = sp->destructor;
fprintf(out,"#line %d \"%s\"\n{",sp->destructorln,lemp->filename);
- }else if( lemp->vardest ){
+ }else{
cp = lemp->vardest;
if( cp==0 ) return;
fprintf(out,"#line %d \"%s\"\n{",lemp->vardestln,lemp->filename);
@@ -2917,7 +2942,7 @@ int *lineno;
/*
** Return TRUE (non-zero) if the given symbol has a destructor.
*/
-int has_destructor(sp, lemp)
+PRIVATE int has_destructor(sp, lemp)
struct symbol *sp;
struct lemon *lemp;
{
@@ -2930,7 +2955,7 @@ struct lemon *lemp;
return ret;
}
-/*
+/*
** Generate code which executes when the rule "rp" is reduced. Write
** the code to "out". Make sure lineno stays up-to-date.
*/
@@ -3018,13 +3043,13 @@ int *lineno;
** union, also set the ".dtnum" field of every terminal and nonterminal
** symbol.
*/
-void print_stack_union(out,lemp,plineno,mhflag)
+PRIVATE void print_stack_union(out,lemp,plineno,mhflag)
FILE *out; /* The output stream */
struct lemon *lemp; /* The main info structure for this parser */
int *plineno; /* Pointer to the line number */
int mhflag; /* True if generating makeheaders output */
{
- int lineno = *plineno; /* The line number of the output */
+ int lineno; /* The line number of the output */
char **types; /* A hash table of datatypes */
int arraysize; /* Size of the "types" array */
int maxdtlength; /* Maximum length of any ".datatype" field. */
@@ -3384,7 +3409,7 @@ int mhflag; /* Output in makeheaders format if true */
/* Output the yy_shift_ofst[] table */
fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++;
- fprintf(out, "static %s yy_shift_ofst[] = {\n",
+ fprintf(out, "static %s yy_shift_ofst[] = {\n",
minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++;
n = lemp->nstate;
for(i=j=0; i<n; i++){
@@ -3405,7 +3430,7 @@ int mhflag; /* Output in makeheaders format if true */
/* Output the yy_reduce_ofst[] table */
fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++;
- fprintf(out, "static %s yy_reduce_ofst[] = {\n",
+ fprintf(out, "static %s yy_reduce_ofst[] = {\n",
minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++;
n = lemp->nstate;
for(i=j=0; i<n; i++){
@@ -3480,7 +3505,7 @@ int mhflag; /* Output in makeheaders format if true */
tplt_xfer(lemp->name,in,out,&lineno);
/* Generate code which executes every time a symbol is popped from
- ** the stack while processing errors or while destroying the parser.
+ ** the stack while processing errors or while destroying the parser.
** (In other words, generate the %destructor actions)
*/
if( lemp->tokendest ){
@@ -3522,7 +3547,7 @@ int mhflag; /* Output in makeheaders format if true */
tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno);
tplt_xfer(lemp->name,in,out,&lineno);
- /* Generate the table of rule information
+ /* Generate the table of rule information
**
** Note: This code depends on the fact that rules are number
** sequentually beginning with 0.
@@ -3589,7 +3614,7 @@ struct lemon *lemp;
for(i=1; i<lemp->nterminal; i++){
fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
}
- fclose(out);
+ fclose(out);
}
return;
}
@@ -3630,7 +3655,7 @@ struct lemon *lemp;
rbest = rp;
}
}
-
+
/* Do not make a default if the number of rules to default
** is not at least 2 */
if( nbest<2 ) continue;
@@ -3669,7 +3694,6 @@ char *SetNew(){
int i;
s = (char*)malloc( global_size );
if( s==0 ){
- extern void memory_error();
memory_error();
}
for(i=0; i<global_size; i++) s[i] = 0;
@@ -3781,7 +3805,7 @@ void Strsafe_init(){
if( x1a ){
x1a->size = 1024;
x1a->count = 0;
- x1a->tbl = (x1node*)malloc(
+ x1a->tbl = (x1node*)malloc(
(sizeof(x1node) + sizeof(x1node*))*1024 );
if( x1a->tbl==0 ){
free(x1a);
@@ -3943,7 +3967,7 @@ void Symbol_init(){
if( x2a ){
x2a->size = 128;
x2a->count = 0;
- x2a->tbl = (x2node*)malloc(
+ x2a->tbl = (x2node*)malloc(
(sizeof(x2node) + sizeof(x2node*))*128 );
if( x2a->tbl==0 ){
free(x2a);
@@ -4149,7 +4173,7 @@ void State_init(){
if( x3a ){
x3a->size = 128;
x3a->count = 0;
- x3a->tbl = (x3node*)malloc(
+ x3a->tbl = (x3node*)malloc(
(sizeof(x3node) + sizeof(x3node*))*128 );
if( x3a->tbl==0 ){
free(x3a);
@@ -4295,7 +4319,7 @@ void Configtable_init(){
if( x4a ){
x4a->size = 64;
x4a->count = 0;
- x4a->tbl = (x4node*)malloc(
+ x4a->tbl = (x4node*)malloc(
(sizeof(x4node) + sizeof(x4node*))*64 );
if( x4a->tbl==0 ){
free(x4a);
diff --git a/src/lempar.c b/src/lempar.c
index ee1edbf..ef9bd94 100644
--- a/src/lempar.c
+++ b/src/lempar.c
@@ -8,10 +8,10 @@
/* 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.
*/
-/*
+/*
** These constants (all generated automatically by the parser generator)
** specify the various kinds of tokens (terminals) that the parser
-** understands.
+** understands.
**
** Each symbol here is a terminal symbol in the grammar.
*/
@@ -29,7 +29,7 @@
** and nonterminals. "int" is used otherwise.
** YYNOCODE is a number of type YYCODETYPE which corresponds
** to no legal terminal or nonterminal number. This
-** number is used to fill in empty slots of the hash
+** number is used to fill in empty slots of the hash
** table.
** YYFALLBACK If defined, this indicates that one or more tokens
** have fall-back values which should be used if the
@@ -38,7 +38,7 @@
** and nonterminal numbers. "unsigned char" is
** used if there are fewer than 250 rules and
** states combined. "int" is used otherwise.
-** ParseTOKENTYPE is the data type used for minor tokens given
+** ParseTOKENTYPE is the data type used for minor tokens given
** directly to the parser from the tokenizer.
** YYMINORTYPE is the data type used for all minor tokens.
** This is typically a union of many types, one of
@@ -62,7 +62,7 @@
/* Next are that tables used to determine what action to take based on the
** current state and lookahead token. These tables are used to implement
** functions that take a state number and lookahead value and return an
-** action integer.
+** action integer.
**
** Suppose the action integer is N. Then the action is determined as
** follows
@@ -87,7 +87,7 @@
** If the index value yy_shift_ofst[S]+X is out of range or if the value
** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
-** and that yy_default[S] should be used instead.
+** and that yy_default[S] should be used instead.
**
** The formula above is for computing the action when the lookahead is
** a terminal symbol. If the lookahead is a non-terminal (as occurs after
@@ -111,7 +111,7 @@
/* The next table maps tokens into fallback tokens. If a construct
** like the following:
-**
+**
** %fallback ID X Y Z.
**
** appears in the grammer, then ID becomes a fallback token for X, Y,
@@ -158,15 +158,15 @@ typedef struct yyParser yyParser;
#ifndef NDEBUG
#include <stdio.h>
-static FILE *yyTraceFILE = 0;
-static char *yyTracePrompt = 0;
+static FILE *yyTraceFILE = NULL;
+static char *yyTracePrompt = NULL;
#endif /* NDEBUG */
#ifndef NDEBUG
-/*
+/*
** Turn parser tracing on by giving a stream to which to write the trace
** and a prompt to preface each trace message. Tracing is turned off
-** by making either argument NULL
+** by making either argument NULL
**
** Inputs:
** <ul>
@@ -180,18 +180,20 @@ static char *yyTracePrompt = 0;
** Outputs:
** None.
*/
+#if 0
void ParseTrace(FILE *TraceFILE, char *zTracePrompt){
yyTraceFILE = TraceFILE;
yyTracePrompt = zTracePrompt;
if( yyTraceFILE==0 ) yyTracePrompt = 0;
else if( yyTracePrompt==0 ) yyTraceFILE = 0;
}
+#endif
#endif /* NDEBUG */
#ifndef NDEBUG
/* For tracing shifts, the names of all terminals and nonterminals
** are required. The following table supplies these names */
-static const char *yyTokenName[] = {
+static const char *yyTokenName[] = {
%%
};
#endif /* NDEBUG */
@@ -208,9 +210,10 @@ static const char *yyRuleName[] = {
** This function returns the symbolic name associated with a token
** value.
*/
+#if 0
const char *ParseTokenName(int tokenType){
#ifndef NDEBUG
- if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
+ if( tokenType>0 && (size_t)tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
return yyTokenName[tokenType];
}else{
return "Unknown";
@@ -219,8 +222,9 @@ const char *ParseTokenName(int tokenType){
return "";
#endif
}
+#endif
-/*
+/*
** This function allocates a new parser.
** The only argument is a pointer to a function which works like
** malloc.
@@ -251,7 +255,7 @@ static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
/* Here is inserted the actions which take place when a
** terminal or non-terminal is destroyed. This can happen
** when the symbol is popped from the stack during a
- ** reduce or during error processing or when a parser is
+ ** reduce or during error processing or when a parser is
** being destroyed before it is finished parsing.
**
** Note: during a reduce, the only symbols destroyed are those
@@ -289,7 +293,7 @@ static int yy_pop_parser_stack(yyParser *pParser){
return yymajor;
}
-/*
+/*
** Deallocate and destroy a parser. Destructors are all called for
** all stack elements before shutting the parser down.
**
@@ -306,7 +310,7 @@ void ParseFree(
void (*freeProc)(void*) /* Function used to reclaim memory */
){
yyParser *pParser = (yyParser*)p;
- if( pParser==0 ) return;
+ if( pParser==NULL ) return;
while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
(*freeProc)((void*)pParser);
}
@@ -325,7 +329,7 @@ static int yy_find_shift_action(
){
int i;
int stateno = pParser->yystack[pParser->yyidx].stateno;
-
+
/* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
i = yy_shift_ofst[stateno];
if( i==YY_SHIFT_USE_DFLT ){
@@ -335,7 +339,7 @@ static int yy_find_shift_action(
return YY_NO_ACTION;
}
i += iLookAhead;
- if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
+ if( i<0 || (size_t)i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
#ifdef YYFALLBACK
int iFallback; /* Fallback token */
if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
@@ -369,7 +373,7 @@ static int yy_find_reduce_action(
){
int i;
int stateno = pParser->yystack[pParser->yyidx].stateno;
-
+
i = yy_reduce_ofst[stateno];
if( i==YY_REDUCE_USE_DFLT ){
return yy_default[stateno];
@@ -378,7 +382,7 @@ static int yy_find_reduce_action(
return YY_NO_ACTION;
}
i += iLookAhead;
- if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
+ if( i<0 || (size_t)i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
return yy_default[stateno];
}else{
return yy_action[i];
@@ -455,8 +459,8 @@ static void yy_reduce(
ParseARG_FETCH;
yymsp = &yypParser->yystack[yypParser->yyidx];
#ifndef NDEBUG
- if( yyTraceFILE && yyruleno>=0
- && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
+ if( yyTraceFILE && yyruleno>=0
+ && (size_t)yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
yyRuleName[yyruleno]);
}
@@ -512,6 +516,8 @@ static void yy_syntax_error(
YYMINORTYPE yyminor /* The minor type of the error token */
){
ParseARG_FETCH;
+ UNUSED(yymajor);
+ UNUSED(yyminor);
#define TOKEN (yyminor.yy0)
%%
ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
@@ -608,7 +614,7 @@ void Parse(
#ifdef YYERRORSYMBOL
/* A syntax error has occurred.
** The response to an error depends upon whether or not the
- ** grammar defines an error token "ERROR".
+ ** grammar defines an error token "ERROR".
**
** This is what we do if the grammar does define ERROR:
**
diff --git a/src/lighttpd-angel.c b/src/lighttpd-angel.c
new file mode 100644
index 0000000..948ca01
--- /dev/null
+++ b/src/lighttpd-angel.c
@@ -0,0 +1,158 @@
+/**
+ * angel process for lighttpd
+ *
+ * the purpose is the run as root all the time and handle:
+ * - restart on crash
+ * - spawn on HUP to allow graceful restart
+ * - ...
+ *
+ * it has to stay safe and small to be trustable
+ */
+
+#include <sys/wait.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <signal.h>
+
+#define BINPATH SBIN_DIR"/lighttpd"
+
+static siginfo_t last_sigterm_info;
+static siginfo_t last_sighup_info;
+
+static volatile sig_atomic_t start_process = 1;
+static volatile pid_t pid = -1;
+
+#define UNUSED(x) ( (void)(x) )
+
+static void sigaction_handler(int sig, siginfo_t *si, void *context) {
+ int exitcode;
+
+ UNUSED(context);
+ switch (sig) {
+ case SIGINT:
+ case SIGTERM:
+ memcpy(&last_sigterm_info, si, sizeof(*si));
+
+ /** forward the sig to the child */
+ kill(pid, sig);
+ break;
+ case SIGHUP: /** do a graceful restart */
+ memcpy(&last_sighup_info, si, sizeof(*si));
+
+ /** do a graceful shutdown on the main process and start a new child */
+ kill(pid, SIGINT);
+
+ usleep(5 * 1000); /** wait 5 microsec */
+
+ start_process = 1;
+ break;
+ case SIGCHLD:
+ /** a child died, de-combie it */
+ wait(&exitcode);
+ break;
+ }
+}
+
+int main(int argc, char **argv) {
+ int is_shutdown = 0;
+ struct sigaction act;
+
+ UNUSED(argc);
+
+ /**
+ * we are running as root BEWARE
+ */
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &act, NULL);
+ sigaction(SIGUSR1, &act, NULL);
+
+ act.sa_sigaction = sigaction_handler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO;
+
+ sigaction(SIGINT, &act, NULL);
+ sigaction(SIGTERM, &act, NULL);
+ sigaction(SIGHUP, &act, NULL);
+ sigaction(SIGALRM, &act, NULL);
+ sigaction(SIGCHLD, &act, NULL);
+
+ /* check that the compiled in path has the right user,
+ *
+ * BEWARE: there is a race between the check here and the exec later
+ */
+
+ while (!is_shutdown) {
+ int exitcode = 0;
+
+ if (start_process) {
+ pid = fork();
+
+ if (0 == pid) {
+ /* i'm the child */
+
+ argv[0] = BINPATH;
+
+ execvp(BINPATH, argv);
+
+ exit(1);
+ } else if (-1 == pid) {
+ /** error */
+
+ return -1;
+ }
+
+ /* I'm the angel */
+ start_process = 0;
+ }
+
+ if ((pid_t)-1 == waitpid(pid, &exitcode, 0)) {
+ switch (errno) {
+ case EINTR:
+ /* someone sent a signal ...
+ * do we have to shutdown or restart the process */
+ break;
+ case ECHILD:
+ /**
+ * make sure we are not in a race between the signal handler
+ * and the process restart */
+ if (!start_process) is_shutdown = 1;
+ break;
+ default:
+ break;
+ }
+ } else {
+ /** process went away */
+
+ if (WIFEXITED(exitcode)) {
+ /** normal exit */
+
+ is_shutdown = 1;
+
+ fprintf(stderr, "%s.%d: child (pid=%d) exited normally with exitcode: %d\n",
+ __FILE__, __LINE__,
+ pid,
+ WEXITSTATUS(exitcode));
+
+ } else if (WIFSIGNALED(exitcode)) {
+ /** got a signal */
+
+ fprintf(stderr, "%s.%d: child (pid=%d) exited unexpectedly with signal %d, restarting\n",
+ __FILE__, __LINE__,
+ pid,
+ WTERMSIG(exitcode));
+
+ start_process = 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
diff --git a/src/log.c b/src/log.c
index 402e302..10db635 100644
--- a/src/log.c
+++ b/src/log.c
@@ -1,4 +1,6 @@
-#define _GNU_SOURCE
+#include "base.h"
+#include "log.h"
+#include "array.h"
#include <sys/types.h>
@@ -12,206 +14,319 @@
#include <stdarg.h>
#include <stdio.h>
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
#ifdef HAVE_SYSLOG_H
-#include <syslog.h>
+# include <syslog.h>
#endif
-#include "log.h"
-#include "array.h"
-
#ifdef HAVE_VALGRIND_VALGRIND_H
-#include <valgrind/valgrind.h>
+# include <valgrind/valgrind.h>
#endif
#ifndef O_LARGEFILE
# define O_LARGEFILE 0
#endif
-/**
+/* Close fd and _try_ to get a /dev/null for it instead.
+ * close() alone may trigger some bugs when a
+ * process opens another file and gets fd = STDOUT_FILENO or STDERR_FILENO
+ * and later tries to just print on stdout/stderr
+ *
+ * Returns 0 on success and -1 on failure (fd gets closed in all cases)
+ */
+int openDevNull(int fd) {
+ int tmpfd;
+ close(fd);
+#if defined(__WIN32)
+ /* Cygwin should work with /dev/null */
+ tmpfd = open("nul", O_RDWR);
+#else
+ tmpfd = open("/dev/null", O_RDWR);
+#endif
+ if (tmpfd != -1 && tmpfd != fd) {
+ dup2(tmpfd, fd);
+ close(tmpfd);
+ }
+ return (tmpfd != -1) ? 0 : -1;
+}
+
+int open_logfile_or_pipe(server *srv, const char* logfile) {
+ int fd;
+
+ if (logfile[0] == '|') {
+#ifdef HAVE_FORK
+ /* create write pipe and spawn process */
+
+ int to_log_fds[2];
+
+ if (pipe(to_log_fds)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno));
+ return -1;
+ }
+
+ /* fork, execve */
+ switch (fork()) {
+ case 0:
+ /* child */
+ close(STDIN_FILENO);
+
+ /* dup the filehandle to STDIN */
+ if (to_log_fds[0] != STDIN_FILENO) {
+ if (STDIN_FILENO != dup2(to_log_fds[0], STDIN_FILENO)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "dup2 failed: ", strerror(errno));
+ exit(-1);
+ }
+ close(to_log_fds[0]);
+ }
+ close(to_log_fds[1]);
+
+#ifndef FD_CLOEXEC
+ {
+ int i;
+ /* we don't need the client socket */
+ for (i = 3; i < 256; i++) {
+ close(i);
+ }
+ }
+#endif
+
+ /* close old stderr */
+ openDevNull(STDERR_FILENO);
+
+ /* exec the log-process (skip the | ) */
+ execl("/bin/sh", "sh", "-c", logfile + 1, NULL);
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "spawning log process failed: ", strerror(errno),
+ logfile + 1);
+
+ exit(-1);
+ break;
+ case -1:
+ /* error */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed: ", strerror(errno));
+ return -1;
+ default:
+ close(to_log_fds[0]);
+ fd = to_log_fds[1];
+ break;
+ }
+
+#else
+ return -1;
+#endif
+ } else if (-1 == (fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
+ log_error_write(srv, __FILE__, __LINE__, "SSSS",
+ "opening errorlog '", logfile,
+ "' failed: ", strerror(errno));
+
+ return -1;
+ }
+
+#ifdef FD_CLOEXEC
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
+
+ return fd;
+}
+
+
+/**
* open the errorlog
- *
- * we have 3 possibilities:
+ *
+ * we have 4 possibilities:
* - stderr (default)
- * - syslog
+ * - syslog
* - logfile
- *
+ * - pipe
+ *
* if the open failed, report to the user and die
- *
+ *
*/
int log_error_open(server *srv) {
- int fd;
- int close_stderr = 1;
-
#ifdef HAVE_SYSLOG_H
/* perhaps someone wants to use syslog() */
openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON);
#endif
- srv->errorlog_mode = ERRORLOG_STDERR;
-
+
+ srv->errorlog_mode = ERRORLOG_FD;
+ srv->errorlog_fd = STDERR_FILENO;
+
if (srv->srvconf.errorlog_use_syslog) {
srv->errorlog_mode = ERRORLOG_SYSLOG;
} else if (!buffer_is_empty(srv->srvconf.errorlog_file)) {
const char *logfile = srv->srvconf.errorlog_file->ptr;
-
- if (-1 == (srv->errorlog_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
- log_error_write(srv, __FILE__, __LINE__, "SSSS",
- "opening errorlog '", logfile,
- "' failed: ", strerror(errno));
-
+
+ if (-1 == (srv->errorlog_fd = open_logfile_or_pipe(srv, logfile))) {
return -1;
}
-#ifdef FD_CLOEXEC
- /* close fd on exec (cgi) */
- fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC);
-#endif
- srv->errorlog_mode = ERRORLOG_FILE;
+ srv->errorlog_mode = (logfile[0] == '|') ? ERRORLOG_PIPE : ERRORLOG_FILE;
}
-
+
log_error_write(srv, __FILE__, __LINE__, "s", "server started");
-
-#ifdef HAVE_VALGRIND_VALGRIND_H
- /* don't close stderr for debugging purposes if run in valgrind */
- if (RUNNING_ON_VALGRIND) close_stderr = 0;
+
+ if (srv->errorlog_mode == ERRORLOG_FD && !srv->srvconf.dont_daemonize) {
+ /* We can only log to stderr in dont-daemonize mode;
+ * if we do daemonize and no errorlog file is specified, we log into /dev/null
+ */
+ srv->errorlog_fd = -1;
+ }
+
+ if (!buffer_is_empty(srv->srvconf.breakagelog_file)) {
+ int breakage_fd;
+ const char *logfile = srv->srvconf.breakagelog_file->ptr;
+
+ if (srv->errorlog_mode == ERRORLOG_FD) {
+ srv->errorlog_fd = dup(STDERR_FILENO);
+#ifdef FD_CLOEXEC
+ fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC);
#endif
- if (srv->errorlog_mode == ERRORLOG_STDERR) close_stderr = 0;
-
- /* move stderr to /dev/null */
- if (close_stderr &&
- -1 != (fd = open("/dev/null", O_WRONLY))) {
- close(STDERR_FILENO);
- dup2(fd, STDERR_FILENO);
- close(fd);
+ }
+
+ if (-1 == (breakage_fd = open_logfile_or_pipe(srv, logfile))) {
+ return -1;
+ }
+
+ if (STDERR_FILENO != breakage_fd) {
+ dup2(breakage_fd, STDERR_FILENO);
+ close(breakage_fd);
+ }
+ } else if (!srv->srvconf.dont_daemonize) {
+ /* move stderr to /dev/null */
+ openDevNull(STDERR_FILENO);
}
return 0;
}
-/**
+/**
* open the errorlog
- *
+ *
* if the open failed, report to the user and die
* if no filename is given, use syslog instead
- *
+ *
*/
int log_error_cycle(server *srv) {
- /* only cycle if we are not in syslog-mode */
-
+ /* only cycle if the error log is a file */
+
if (srv->errorlog_mode == ERRORLOG_FILE) {
const char *logfile = srv->srvconf.errorlog_file->ptr;
/* already check of opening time */
-
+
int new_fd;
-
- if (-1 == (new_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
+
+ if (-1 == (new_fd = open_logfile_or_pipe(srv, logfile))) {
/* write to old log */
- log_error_write(srv, __FILE__, __LINE__, "SSSSS",
+ log_error_write(srv, __FILE__, __LINE__, "SSSSS",
"cycling errorlog '", logfile,
"' failed: ", strerror(errno),
", falling back to syslog()");
-
+
close(srv->errorlog_fd);
srv->errorlog_fd = -1;
-#ifdef HAVE_SYSLOG_H
+#ifdef HAVE_SYSLOG_H
srv->errorlog_mode = ERRORLOG_SYSLOG;
#endif
} else {
/* ok, new log is open, close the old one */
close(srv->errorlog_fd);
srv->errorlog_fd = new_fd;
+#ifdef FD_CLOEXEC
+ /* close fd on exec (cgi) */
+ fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC);
+#endif
}
}
-
- log_error_write(srv, __FILE__, __LINE__, "s", "logfiles cycled");
-
+
return 0;
}
int log_error_close(server *srv) {
- log_error_write(srv, __FILE__, __LINE__, "s", "server stopped");
-
switch(srv->errorlog_mode) {
+ case ERRORLOG_PIPE:
case ERRORLOG_FILE:
- close(srv->errorlog_fd);
+ case ERRORLOG_FD:
+ if (-1 != srv->errorlog_fd) {
+ /* don't close STDERR */
+ if (STDERR_FILENO != srv->errorlog_fd)
+ close(srv->errorlog_fd);
+ srv->errorlog_fd = -1;
+ }
break;
case ERRORLOG_SYSLOG:
#ifdef HAVE_SYSLOG_H
closelog();
#endif
break;
- case ERRORLOG_STDERR:
- break;
}
-
+
return 0;
}
int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
va_list ap;
-
+
switch(srv->errorlog_mode) {
+ case ERRORLOG_PIPE:
case ERRORLOG_FILE:
- case ERRORLOG_STDERR:
+ case ERRORLOG_FD:
+ if (-1 == srv->errorlog_fd) return 0;
/* cache the generated timestamp */
if (srv->cur_ts != srv->last_generated_debug_ts) {
buffer_prepare_copy(srv->ts_debug_str, 255);
strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1;
-
+
srv->last_generated_debug_ts = srv->cur_ts;
}
buffer_copy_string_buffer(srv->errorlog_buf, srv->ts_debug_str);
- BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ": (");
+ buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(": ("));
break;
case ERRORLOG_SYSLOG:
/* syslog is generating its own timestamps */
- BUFFER_COPY_STRING_CONST(srv->errorlog_buf, "(");
+ buffer_copy_string_len(srv->errorlog_buf, CONST_STR_LEN("("));
break;
}
-
+
buffer_append_string(srv->errorlog_buf, filename);
- BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ".");
+ buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN("."));
buffer_append_long(srv->errorlog_buf, line);
- BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ") ");
-
-
+ buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(") "));
+
+
for(va_start(ap, fmt); *fmt; fmt++) {
int d;
char *s;
buffer *b;
off_t o;
-
+
switch(*fmt) {
case 's': /* string */
s = va_arg(ap, char *);
buffer_append_string(srv->errorlog_buf, s);
- BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
+ buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(" "));
break;
case 'b': /* buffer */
b = va_arg(ap, buffer *);
buffer_append_string_buffer(srv->errorlog_buf, b);
- BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
+ buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(" "));
break;
case 'd': /* int */
d = va_arg(ap, int);
buffer_append_long(srv->errorlog_buf, d);
- BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
+ buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(" "));
break;
case 'o': /* off_t */
o = va_arg(ap, off_t);
buffer_append_off_t(srv->errorlog_buf, o);
- BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
+ buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(" "));
break;
case 'x': /* int (hex) */
d = va_arg(ap, int);
- BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "0x");
+ buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN("0x"));
buffer_append_long_hex(srv->errorlog_buf, d);
- BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
+ buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN(" "));
break;
case 'S': /* string */
s = va_arg(ap, char *);
@@ -225,9 +340,18 @@ int log_error_write(server *srv, const char *filename, unsigned int line, const
d = va_arg(ap, int);
buffer_append_long(srv->errorlog_buf, d);
break;
+ case 'O': /* off_t */
+ o = va_arg(ap, off_t);
+ buffer_append_off_t(srv->errorlog_buf, o);
+ break;
+ case 'X': /* int (hex) */
+ d = va_arg(ap, int);
+ buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN("0x"));
+ buffer_append_long_hex(srv->errorlog_buf, d);
+ break;
case '(':
case ')':
- case '<':
+ case '<':
case '>':
case ',':
case ' ':
@@ -236,21 +360,19 @@ int log_error_write(server *srv, const char *filename, unsigned int line, const
}
}
va_end(ap);
-
+
switch(srv->errorlog_mode) {
+ case ERRORLOG_PIPE:
case ERRORLOG_FILE:
- BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
+ case ERRORLOG_FD:
+ buffer_append_string_len(srv->errorlog_buf, CONST_STR_LEN("\n"));
write(srv->errorlog_fd, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
break;
- case ERRORLOG_STDERR:
- BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
- write(STDERR_FILENO, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
- break;
case ERRORLOG_SYSLOG:
syslog(LOG_ERR, "%s", srv->errorlog_buf->ptr);
break;
}
-
+
return 0;
}
diff --git a/src/log.h b/src/log.h
index bffee3a..583288b 100644
--- a/src/log.h
+++ b/src/log.h
@@ -3,11 +3,18 @@
#include "server.h"
+/* Close fd and _try_ to get a /dev/null for it instead.
+ * Returns 0 on success and -1 on failure (fd gets closed in all cases)
+ */
+int openDevNull(int fd);
+
#define WP() log_error_write(srv, __FILE__, __LINE__, "");
+int open_logfile_or_pipe(server *srv, const char* logfile);
+
int log_error_open(server *srv);
int log_error_close(server *srv);
int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...);
int log_error_cycle(server *srv);
-
+
#endif
diff --git a/src/md5.c b/src/md5.c
index 8b688f6..16a8c27 100644
--- a/src/md5.c
+++ b/src/md5.c
@@ -24,7 +24,7 @@ documentation and/or software.
*/
#ifdef HAVE_CONFIG_H
-#include "config.h"
+# include "config.h"
#endif
#ifndef USE_OPENSSL
@@ -52,9 +52,9 @@ documentation and/or software.
#define S43 15
#define S44 21
-static void MD5Transform (UINT4 [4], unsigned char [64]);
+static void li_MD5Transform (UINT4 [4], const unsigned char [64]);
static void Encode (unsigned char *, UINT4 *, unsigned int);
-static void Decode (UINT4 *, unsigned char *, unsigned int);
+static void Decode (UINT4 *, const unsigned char *, unsigned int);
#ifdef HAVE_MEMCPY
#define MD5_memcpy(output, input, len) memcpy((output), (input), (len))
@@ -110,8 +110,7 @@ Rotation is separate from addition to prevent recomputation.
/* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
-void MD5_Init (context)
-MD5_CTX *context; /* context */
+void li_MD5_Init (li_MD5_CTX *context)
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.
@@ -126,12 +125,10 @@ MD5_CTX *context; /* context */
operation, processing another message block, and updating the
context.
*/
-void MD5_Update (context, input, inputLen)
-MD5_CTX *context; /* context */
-unsigned char *input; /* input block */
-unsigned int inputLen; /* length of input block */
+void li_MD5_Update (li_MD5_CTX *context, const void *_input, unsigned int inputLen)
{
unsigned int i, ndx, partLen;
+ const unsigned char *input = (const unsigned char*) _input;
/* Compute number of bytes mod 64 */
ndx = (unsigned int)((context->count[0] >> 3) & 0x3F);
@@ -150,10 +147,10 @@ unsigned int inputLen; /* length of input block */
if (inputLen >= partLen) {
MD5_memcpy
((POINTER)&context->buffer[ndx], (POINTER)input, partLen);
- MD5Transform (context->state, context->buffer);
+ li_MD5Transform (context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
- MD5Transform (context->state, &input[i]);
+ li_MD5Transform (context->state, &input[i]);
ndx = 0;
}
@@ -169,9 +166,7 @@ unsigned int inputLen; /* length of input block */
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
the message digest and zeroizing the context.
*/
-void MD5_Final (digest, context)
-unsigned char digest[16]; /* message digest */
-MD5_CTX *context; /* context */
+void li_MD5_Final (unsigned char digest[16], li_MD5_CTX *context)
{
unsigned char bits[8];
unsigned int ndx, padLen;
@@ -183,10 +178,10 @@ MD5_CTX *context; /* context */
*/
ndx = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (ndx < 56) ? (56 - ndx) : (120 - ndx);
- MD5_Update (context, PADDING, padLen);
+ li_MD5_Update (context, PADDING, padLen);
/* Append length (before padding) */
- MD5_Update (context, bits, 8);
+ li_MD5_Update (context, bits, 8);
/* Store state in digest */
Encode (digest, context->state, 16);
@@ -198,9 +193,7 @@ MD5_CTX *context; /* context */
/* MD5 basic transformation. Transforms state based on block.
*/
-static void MD5Transform (state, block)
-UINT4 state[4];
-unsigned char block[64];
+static void li_MD5Transform (UINT4 state[4], const unsigned char block[64])
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
@@ -293,10 +286,7 @@ unsigned char block[64];
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
a multiple of 4.
*/
-static void Encode (output, input, len)
-unsigned char *output;
-UINT4 *input;
-unsigned int len;
+static void Encode (unsigned char *output, UINT4 *input, unsigned int len)
{
unsigned int i, j;
@@ -311,10 +301,7 @@ unsigned int len;
/* Decodes input (unsigned char) into output (UINT4). Assumes len is
a multiple of 4.
*/
-static void Decode (output, input, len)
-UINT4 *output;
-unsigned char *input;
-unsigned int len;
+static void Decode (UINT4 *output, const unsigned char *input, unsigned int len)
{
unsigned int i, j;
@@ -326,10 +313,7 @@ unsigned int len;
/* Note: Replace "for loop" with standard memcpy if possible.
*/
#ifndef HAVE_MEMCPY
-static void MD5_memcpy (output, input, len)
-POINTER output;
-POINTER input;
-unsigned int len;
+static void MD5_memcpy (POINTER output, POINTER input, unsigned int len)
{
unsigned int i;
@@ -341,10 +325,7 @@ unsigned int len;
/* Note: Replace "for loop" with standard memset if possible.
*/
#ifndef HAVE_MEMSET
-static void MD5_memset (output, value, len)
-POINTER output;
-int value;
-unsigned int len;
+static void MD5_memset (POINTER output, int value, unsigned int len)
{
unsigned int i;
diff --git a/src/md5.h b/src/md5.h
index a1c0d76..669a826 100644
--- a/src/md5.h
+++ b/src/md5.h
@@ -39,9 +39,8 @@ typedef struct {
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
-} MD5_CTX;
-
-void MD5_Init (MD5_CTX *);
-void MD5_Update (MD5_CTX *, unsigned char *, unsigned int);
-void MD5_Final (unsigned char [16], MD5_CTX *);
+} li_MD5_CTX;
+void li_MD5_Init (li_MD5_CTX *);
+void li_MD5_Update (li_MD5_CTX *, const void *, unsigned int);
+void li_MD5_Final (unsigned char [16], li_MD5_CTX *);
diff --git a/src/mod_access.c b/src/mod_access.c
index f3f7071..3902435 100644
--- a/src/mod_access.c
+++ b/src/mod_access.c
@@ -1,83 +1,83 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
#include "base.h"
#include "log.h"
#include "buffer.h"
#include "plugin.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
typedef struct {
array *access_deny;
} plugin_config;
typedef struct {
PLUGIN_DATA;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
INIT_FUNC(mod_access_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
return p;
}
FREE_FUNC(mod_access_free) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
-
+
array_free(s->access_deny);
-
+
free(s);
}
free(p->config_storage);
}
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
SETDEFAULTS_FUNC(mod_access_set_defaults) {
plugin_data *p = p_d;
size_t i = 0;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "url.access-deny", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
s->access_deny = array_init();
-
+
cv[0].destination = s->access_deny;
-
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
}
-
+
return HANDLER_GO_ON;
}
@@ -88,80 +88,105 @@ static int mod_access_patch_connection(server *srv, connection *con, plugin_data
plugin_config *s = p->config_storage[0];
PATCH(access_deny);
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.access-deny"))) {
PATCH(access_deny);
}
}
}
-
+
return 0;
}
#undef PATCH
+/**
+ * URI handler
+ *
+ * we will get called twice:
+ * - after the clean up of the URL and
+ * - after the pathinfo checks are done
+ *
+ * this handles the issue of trailing slashes
+ */
URIHANDLER_FUNC(mod_access_uri_handler) {
plugin_data *p = p_d;
int s_len;
size_t k;
-
+
if (con->uri.path->used == 0) return HANDLER_GO_ON;
-
+
mod_access_patch_connection(srv, con, p);
-
+
s_len = con->uri.path->used - 1;
-
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "-- mod_access_uri_handler called");
+ }
+
for (k = 0; k < p->conf.access_deny->used; k++) {
data_string *ds = (data_string *)p->conf.access_deny->data[k];
int ct_len = ds->value->used - 1;
-
+ int denied = 0;
+
+
if (ct_len > s_len) continue;
-
if (ds->value->used == 0) continue;
/* if we have a case-insensitive FS we have to lower-case the URI here too */
if (con->conf.force_lowercase_filenames) {
if (0 == strncasecmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
- con->http_status = 403;
-
- return HANDLER_FINISHED;
+ denied = 1;
}
} else {
if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
- con->http_status = 403;
-
- return HANDLER_FINISHED;
+ denied = 1;
+ }
+ }
+
+ if (denied) {
+ con->http_status = 403;
+ con->mode = DIRECT;
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "url denied as we match:", ds->value);
}
+
+ return HANDLER_FINISHED;
}
}
-
+
/* not found */
return HANDLER_GO_ON;
}
+int mod_access_plugin_init(plugin *p);
int mod_access_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("access");
-
+
p->init = mod_access_init;
p->set_defaults = mod_access_set_defaults;
- p->handle_uri_clean = mod_access_uri_handler;
+ p->handle_uri_clean = mod_access_uri_handler;
+ p->handle_subrequest_start = mod_access_uri_handler;
p->cleanup = mod_access_free;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_accesslog.c b/src/mod_accesslog.c
index d77c889..6d6c173 100644
--- a/src/mod_accesslog.c
+++ b/src/mod_accesslog.c
@@ -1,4 +1,12 @@
-#define _GNU_SOURCE
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+
+#include "plugin.h"
+
+#include "inet_ntop_cache.h"
+
+#include "sys-socket.h"
#include <sys/types.h>
#include <sys/stat.h>
@@ -13,23 +21,13 @@
#include <stdio.h>
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-
-#include "plugin.h"
-
-#include "inet_ntop_cache.h"
-
-#include "sys-socket.h"
-
#ifdef HAVE_SYSLOG_H
# include <syslog.h>
#endif
typedef struct {
char key;
- enum {
+ enum {
FORMAT_UNSET,
FORMAT_UNSUPPORTED,
FORMAT_PERCENT,
@@ -41,7 +39,7 @@ typedef struct {
FORMAT_STATUS,
FORMAT_BYTES_OUT_NO_HEADER,
FORMAT_HEADER,
-
+
FORMAT_REMOTE_ADDR,
FORMAT_LOCAL_ADDR,
FORMAT_COOKIE,
@@ -59,20 +57,20 @@ typedef struct {
FORMAT_CONNECTION_STATUS,
FORMAT_BYTES_IN,
FORMAT_BYTES_OUT,
-
+
FORMAT_RESPONSE_HEADER
} type;
} format_mapping;
/**
- *
- *
+ *
+ *
* "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
- *
+ *
*/
-const format_mapping fmap[] =
-{
+static const format_mapping fmap[] =
+{
{ '%', FORMAT_PERCENT },
{ 'h', FORMAT_REMOTE_HOST },
{ 'l', FORMAT_REMOTE_IDENT },
@@ -82,7 +80,7 @@ const format_mapping fmap[] =
{ 's', FORMAT_STATUS },
{ 'b', FORMAT_BYTES_OUT_NO_HEADER },
{ 'i', FORMAT_HEADER },
-
+
{ 'a', FORMAT_REMOTE_ADDR },
{ 'A', FORMAT_LOCAL_ADDR },
{ 'B', FORMAT_BYTES_OUT_NO_HEADER },
@@ -103,23 +101,23 @@ const format_mapping fmap[] =
{ 'X', FORMAT_CONNECTION_STATUS },
{ 'I', FORMAT_BYTES_IN },
{ 'O', FORMAT_BYTES_OUT },
-
+
{ 'o', FORMAT_RESPONSE_HEADER },
-
+
{ '\0', FORMAT_UNSET }
};
typedef struct {
enum { FIELD_UNSET, FIELD_STRING, FIELD_FORMAT } type;
-
+
buffer *string;
int field;
} format_field;
typedef struct {
format_field **ptr;
-
+
size_t used;
size_t size;
} format_fields;
@@ -128,226 +126,312 @@ typedef struct {
buffer *access_logfile;
buffer *format;
unsigned short use_syslog;
-
-
+
+
int log_access_fd;
time_t last_generated_accesslog_ts;
time_t *last_generated_accesslog_ts_ptr;
-
-
+
+
buffer *access_logbuffer;
buffer *ts_accesslog_str;
-
+ buffer *ts_accesslog_fmt_str;
+ unsigned short append_tz_offset;
+
format_fields *parsed_format;
} plugin_config;
typedef struct {
PLUGIN_DATA;
-
+
plugin_config **config_storage;
- plugin_config conf;
+ plugin_config conf;
} plugin_data;
INIT_FUNC(mod_accesslog_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
return p;
}
-int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
+static void accesslog_append_escaped(buffer *dest, buffer *str) {
+ char *ptr, *start, *end;
+
+ /* replaces non-printable chars with \xHH where HH is the hex representation of the byte */
+ /* exceptions: " => \", \ => \\, whitespace chars => \n \t etc. */
+ if (str->used == 0) return;
+ buffer_prepare_append(dest, str->used - 1);
+
+ for (ptr = start = str->ptr, end = str->ptr + str->used - 1; ptr < end; ptr++) {
+ char const c = *ptr;
+ if (c >= ' ' && c <= '~' && c != '"' && c != '\\') {
+ /* nothing to change, add later as one block */
+ } else {
+ /* copy previous part */
+ if (start < ptr) {
+ buffer_append_string_len(dest, start, ptr - start);
+ }
+ start = ptr + 1;
+
+ switch (c) {
+ case '"':
+ BUFFER_APPEND_STRING_CONST(dest, "\\\"");
+ break;
+ case '\\':
+ BUFFER_APPEND_STRING_CONST(dest, "\\\\");
+ break;
+ case '\b':
+ BUFFER_APPEND_STRING_CONST(dest, "\\b");
+ break;
+ case '\n':
+ BUFFER_APPEND_STRING_CONST(dest, "\\n");
+ break;
+ case '\r':
+ BUFFER_APPEND_STRING_CONST(dest, "\\r");
+ break;
+ case '\t':
+ BUFFER_APPEND_STRING_CONST(dest, "\\t");
+ break;
+ case '\v':
+ BUFFER_APPEND_STRING_CONST(dest, "\\v");
+ break;
+ default: {
+ /* non printable char => \xHH */
+ char hh[5] = {'\\','x',0,0,0};
+ char h = c / 16;
+ hh[2] = (h > 9) ? (h - 10 + 'A') : (h + '0');
+ h = c % 16;
+ hh[3] = (h > 9) ? (h - 10 + 'A') : (h + '0');
+ buffer_append_string_len(dest, &hh[0], 4);
+ }
+ break;
+ }
+ }
+ }
+
+ if (start < end) {
+ buffer_append_string_len(dest, start, end - start);
+ }
+}
+
+static int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
size_t i, j, k = 0, start = 0;
-
+
+ if (format->used == 0) return -1;
+
for (i = 0; i < format->used - 1; i++) {
-
switch(format->ptr[i]) {
case '%':
- if (start != i) {
- /* copy the string */
+ if (i > 0 && start != i) {
+ /* copy the string before this % */
if (fields->size == 0) {
fields->size = 16;
fields->used = 0;
- fields->ptr = malloc(fields->size * sizeof(format_fields * ));
+ fields->ptr = malloc(fields->size * sizeof(format_field * ));
} else if (fields->used == fields->size) {
fields->size += 16;
- fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
+ fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_field * ));
}
-
- fields->ptr[fields->used] = malloc(sizeof(format_fields));
+
+ fields->ptr[fields->used] = malloc(sizeof(format_field));
fields->ptr[fields->used]->type = FIELD_STRING;
fields->ptr[fields->used]->string = buffer_init();
-
+
buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
-
+
fields->used++;
}
-
-
+
/* we need a new field */
-
+
if (fields->size == 0) {
fields->size = 16;
fields->used = 0;
- fields->ptr = malloc(fields->size * sizeof(format_fields * ));
+ fields->ptr = malloc(fields->size * sizeof(format_field * ));
} else if (fields->used == fields->size) {
fields->size += 16;
- fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
+ fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_field * ));
}
-
+
/* search for the terminating command */
switch (format->ptr[i+1]) {
case '>':
case '<':
- /* only for s */
-
+ /* after the } has to be a character */
+ if (format->ptr[i+2] == '\0') {
+ log_error_write(srv, __FILE__, __LINE__, "s", "%< and %> have to be followed by a format-specifier");
+ return -1;
+ }
+
+
for (j = 0; fmap[j].key != '\0'; j++) {
if (fmap[j].key != format->ptr[i+2]) continue;
-
+
/* found key */
-
- fields->ptr[fields->used] = malloc(sizeof(format_fields));
+
+ fields->ptr[fields->used] = malloc(sizeof(format_field));
fields->ptr[fields->used]->type = FIELD_FORMAT;
fields->ptr[fields->used]->field = fmap[j].type;
fields->ptr[fields->used]->string = NULL;
-
+
fields->used++;
-
+
break;
}
-
+
if (fmap[j].key == '\0') {
- log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
+ log_error_write(srv, __FILE__, __LINE__, "s", "%< and %> have to be followed by a valid format-specifier");
return -1;
}
-
+
start = i + 3;
-
+ i = start - 1; /* skip the string */
+
break;
case '{':
/* go forward to } */
-
+
for (k = i+2; k < format->used - 1; k++) {
if (format->ptr[k] == '}') break;
}
-
+
if (k == format->used - 1) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
+ log_error_write(srv, __FILE__, __LINE__, "s", "%{ has to be terminated by a }");
return -1;
}
+
+ /* after the } has to be a character */
if (format->ptr[k+1] == '\0') {
- log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
+ log_error_write(srv, __FILE__, __LINE__, "s", "%{...} has to be followed by a format-specifier");
+ return -1;
+ }
+
+ if (k == i + 2) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "%{...} has to be contain a string");
return -1;
}
-
+
for (j = 0; fmap[j].key != '\0'; j++) {
if (fmap[j].key != format->ptr[k+1]) continue;
-
+
/* found key */
-
- fields->ptr[fields->used] = malloc(sizeof(format_fields));
+
+ fields->ptr[fields->used] = malloc(sizeof(format_field));
fields->ptr[fields->used]->type = FIELD_FORMAT;
fields->ptr[fields->used]->field = fmap[j].type;
fields->ptr[fields->used]->string = buffer_init();
-
+
buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + i + 2, k - (i + 2));
-
+
fields->used++;
-
+
break;
}
-
+
if (fmap[j].key == '\0') {
- log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
+ log_error_write(srv, __FILE__, __LINE__, "s", "%{...} has to be followed by a valid format-specifier");
return -1;
}
-
+
start = k + 2;
-
+ i = start - 1; /* skip the string */
+
break;
default:
+ /* after the % has to be a character */
+ if (format->ptr[i+1] == '\0') {
+ log_error_write(srv, __FILE__, __LINE__, "s", "% has to be followed by a format-specifier");
+ return -1;
+ }
+
for (j = 0; fmap[j].key != '\0'; j++) {
if (fmap[j].key != format->ptr[i+1]) continue;
-
+
/* found key */
-
- fields->ptr[fields->used] = malloc(sizeof(format_fields));
+
+ fields->ptr[fields->used] = malloc(sizeof(format_field));
fields->ptr[fields->used]->type = FIELD_FORMAT;
fields->ptr[fields->used]->field = fmap[j].type;
fields->ptr[fields->used]->string = NULL;
-
+
fields->used++;
-
+
break;
}
-
+
if (fmap[j].key == '\0') {
- log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
+ log_error_write(srv, __FILE__, __LINE__, "s", "% has to be followed by a valid format-specifier");
return -1;
}
-
+
start = i + 2;
-
+ i = start - 1; /* skip the string */
+
break;
}
-
+
break;
}
}
-
+
if (start < i) {
/* copy the string */
if (fields->size == 0) {
fields->size = 16;
fields->used = 0;
- fields->ptr = malloc(fields->size * sizeof(format_fields * ));
+ fields->ptr = malloc(fields->size * sizeof(format_field * ));
} else if (fields->used == fields->size) {
fields->size += 16;
- fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
+ fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_field * ));
}
-
- fields->ptr[fields->used] = malloc(sizeof(format_fields));
+
+ fields->ptr[fields->used] = malloc(sizeof(format_field));
fields->ptr[fields->used]->type = FIELD_STRING;
fields->ptr[fields->used]->string = buffer_init();
-
+
buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
-
+
fields->used++;
}
-
+
return 0;
}
FREE_FUNC(mod_accesslog_free) {
plugin_data *p = p_d;
size_t i;
-
+
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
if (!s) continue;
-
+
if (s->access_logbuffer->used) {
if (s->use_syslog) {
# ifdef HAVE_SYSLOG_H
- syslog(LOG_INFO, "%*s", s->access_logbuffer->used - 1, s->access_logbuffer->ptr);
+ if (s->access_logbuffer->used > 2) {
+ syslog(LOG_INFO, "%*s", (int) s->access_logbuffer->used - 2, s->access_logbuffer->ptr);
+ }
# endif
} else if (s->log_access_fd != -1) {
write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
}
}
-
+
if (s->log_access_fd != -1) close(s->log_access_fd);
-
+
buffer_free(s->ts_accesslog_str);
+ buffer_free(s->ts_accesslog_fmt_str);
buffer_free(s->access_logbuffer);
buffer_free(s->format);
buffer_free(s->access_logfile);
-
+
if (s->parsed_format) {
size_t j;
for (j = 0; j < s->parsed_format->used; j++) {
@@ -357,82 +441,108 @@ FREE_FUNC(mod_accesslog_free) {
free(s->parsed_format->ptr);
free(s->parsed_format);
}
-
+
free(s);
}
-
+
free(p->config_storage);
}
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
SETDEFAULTS_FUNC(log_access_open) {
plugin_data *p = p_d;
size_t i = 0;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "accesslog.filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "accesslog.use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
{ "accesslog.format", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
s->access_logfile = buffer_init();
s->format = buffer_init();
s->access_logbuffer = buffer_init();
s->ts_accesslog_str = buffer_init();
+ s->ts_accesslog_fmt_str = buffer_init();
s->log_access_fd = -1;
s->last_generated_accesslog_ts = 0;
s->last_generated_accesslog_ts_ptr = &(s->last_generated_accesslog_ts);
-
-
+
+
cv[0].destination = s->access_logfile;
cv[1].destination = &(s->use_syslog);
cv[2].destination = s->format;
-
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
-
+
if (i == 0 && buffer_is_empty(s->format)) {
/* set a default logfile string */
-
- buffer_copy_string(s->format, "%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"");
+
+ buffer_copy_string_len(s->format, CONST_STR_LEN("%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""));
}
-
+
/* parse */
-
+
if (s->format->used) {
+ size_t j, count;
+
s->parsed_format = calloc(1, sizeof(*(s->parsed_format)));
-
+
if (-1 == accesslog_parse_format(srv, s->parsed_format, s->format)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
"parsing accesslog-definition failed:", s->format);
return HANDLER_ERROR;
}
+
+ /* make sure they didn't try to send the timestamp in twice...
+ * also, save the format string in a different variable (this
+ * will save a few conditionals later)
+ */
+ count = 0;
+ for (j = 0; j < s->parsed_format->used; j++) {
+ if (FIELD_FORMAT == s->parsed_format->ptr[j]->type) {
+ if (FORMAT_TIMESTAMP == s->parsed_format->ptr[j]->field) {
+ if (!buffer_is_empty(s->parsed_format->ptr[j]->string)) {
+ buffer_copy_string(s->ts_accesslog_fmt_str, s->parsed_format->ptr[j]->string->ptr);
+ }
+
+ if (++count > 1) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "you may not use the timestamp twice in the same access log:", s->format);
+
+ return HANDLER_ERROR;
+ }
+ }
+ }
+ }
+
#if 0
- /* debugging */
+ /* debugging */
for (j = 0; j < s->parsed_format->used; j++) {
switch (s->parsed_format->ptr[j]->type) {
case FIELD_FORMAT:
- log_error_write(srv, __FILE__, __LINE__, "ssds",
+ log_error_write(srv, __FILE__, __LINE__, "ssds",
"config:", "format", s->parsed_format->ptr[j]->field,
- s->parsed_format->ptr[j]->string ?
+ s->parsed_format->ptr[j]->string ?
s->parsed_format->ptr[j]->string->ptr : "" );
break;
case FIELD_STRING:
@@ -444,81 +554,29 @@ SETDEFAULTS_FUNC(log_access_open) {
}
#endif
}
-
+
+ s->append_tz_offset = 0;
+ if (buffer_is_empty(s->ts_accesslog_fmt_str)) {
+#if defined(HAVE_STRUCT_TM_GMTOFF)
+ BUFFER_COPY_STRING_CONST(s->ts_accesslog_fmt_str, "[%d/%b/%Y:%H:%M:%S ");
+ s->append_tz_offset = 1;
+#else
+ BUFFER_COPY_STRING_CONST(s->ts_accesslog_fmt_str, "[%d/%b/%Y:%H:%M:%S +0000]");
+#endif
+ }
+
if (s->use_syslog) {
/* ignore the next checks */
continue;
}
-
- if (buffer_is_empty(s->access_logfile)) continue;
-
- if (s->access_logfile->ptr[0] == '|') {
-#ifdef HAVE_FORK
- /* create write pipe and spawn process */
-
- int to_log_fds[2];
- pid_t pid;
-
- if (pipe(to_log_fds)) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno));
- return HANDLER_ERROR;
- }
-
- /* fork, execve */
- switch (pid = fork()) {
- case 0:
- /* child */
-
- close(STDIN_FILENO);
- dup2(to_log_fds[0], STDIN_FILENO);
- close(to_log_fds[0]);
- /* not needed */
- close(to_log_fds[1]);
-
- /* we don't need the client socket */
- for (i = 3; i < 256; i++) {
- close(i);
- }
-
- /* exec the log-process (skip the | )
- *
- */
-
- execl("/bin/sh", "sh", "-c", s->access_logfile->ptr + 1, NULL);
- log_error_write(srv, __FILE__, __LINE__, "sss",
- "spawning log-process failed: ", strerror(errno),
- s->access_logfile->ptr + 1);
-
- exit(-1);
- break;
- case -1:
- /* error */
- log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed: ", strerror(errno));
- break;
- default:
- close(to_log_fds[0]);
-
- s->log_access_fd = to_log_fds[1];
-
- break;
- }
-#else
- return -1;
-#endif
- } else if (-1 == (s->log_access_fd =
- open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
-
- log_error_write(srv, __FILE__, __LINE__, "ssb",
- "opening access-log failed:",
- strerror(errno), s->access_logfile);
-
+ if (s->access_logfile->used < 2) continue;
+
+ if (-1 == (s->log_access_fd = open_logfile_or_pipe(srv, s->access_logfile->ptr)))
return HANDLER_ERROR;
- }
- fcntl(s->log_access_fd, F_SETFD, FD_CLOEXEC);
-
+
}
-
+
return HANDLER_GO_ON;
}
@@ -527,38 +585,44 @@ SIGHUP_FUNC(log_access_cycle) {
size_t i;
if (!p->config_storage) return HANDLER_GO_ON;
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
if (s->access_logbuffer->used) {
if (s->use_syslog) {
#ifdef HAVE_SYSLOG_H
- syslog(LOG_INFO, "%*s", s->access_logbuffer->used - 1, s->access_logbuffer->ptr);
+ if (s->access_logbuffer->used > 2) {
+ /* syslog appends a \n on its own */
+ syslog(LOG_INFO, "%*s", (int) s->access_logbuffer->used - 2, s->access_logbuffer->ptr);
+ }
#endif
} else if (s->log_access_fd != -1) {
write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
}
-
+
buffer_reset(s->access_logbuffer);
}
-
+
if (s->use_syslog == 0 &&
- !buffer_is_empty(s->access_logfile) &&
+ s->access_logfile->used > 1 &&
s->access_logfile->ptr[0] != '|') {
-
+
close(s->log_access_fd);
-
- if (-1 == (s->log_access_fd =
+
+ if (-1 == (s->log_access_fd =
open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
-
+
log_error_write(srv, __FILE__, __LINE__, "ss", "cycling access-log failed:", strerror(errno));
-
+
return HANDLER_ERROR;
}
+#ifdef FD_CLOEXEC
+ fcntl(s->log_access_fd, F_SETFD, FD_CLOEXEC);
+#endif
}
}
-
+
return HANDLER_GO_ON;
}
@@ -567,43 +631,48 @@ SIGHUP_FUNC(log_access_cycle) {
static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(access_logfile);
PATCH(format);
PATCH(log_access_fd);
PATCH(last_generated_accesslog_ts_ptr);
PATCH(access_logbuffer);
PATCH(ts_accesslog_str);
+ PATCH(ts_accesslog_fmt_str);
+ PATCH(append_tz_offset);
PATCH(parsed_format);
PATCH(use_syslog);
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.filename"))) {
PATCH(access_logfile);
PATCH(log_access_fd);
- PATCH(last_generated_accesslog_ts_ptr);
PATCH(access_logbuffer);
- PATCH(ts_accesslog_str);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.format"))) {
PATCH(format);
PATCH(parsed_format);
+ PATCH(last_generated_accesslog_ts_ptr);
+ PATCH(ts_accesslog_str);
+ PATCH(ts_accesslog_fmt_str);
+ PATCH(append_tz_offset);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.use-syslog"))) {
PATCH(use_syslog);
+ PATCH(access_logbuffer);
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -612,17 +681,20 @@ REQUESTDONE_FUNC(log_access_write) {
plugin_data *p = p_d;
buffer *b;
size_t j;
-
+
int newts = 0;
data_string *ds;
-
+
mod_accesslog_patch_connection(srv, con, p);
-
+
+ /* No output device, nothing to do */
+ if (!p->conf.use_syslog && p->conf.log_access_fd == -1) return HANDLER_GO_ON;
+
b = p->conf.access_logbuffer;
if (b->used == 0) {
- buffer_copy_string(b, "");
+ buffer_copy_string_len(b, CONST_STR_LEN(""));
}
-
+
for (j = 0; j < p->conf.parsed_format->used; j++) {
switch(p->conf.parsed_format->ptr[j]->type) {
case FIELD_STRING:
@@ -631,122 +703,131 @@ REQUESTDONE_FUNC(log_access_write) {
case FIELD_FORMAT:
switch(p->conf.parsed_format->ptr[j]->field) {
case FORMAT_TIMESTAMP:
-
+
/* cache the generated timestamp */
if (srv->cur_ts != *(p->conf.last_generated_accesslog_ts_ptr)) {
struct tm tm;
#if defined(HAVE_STRUCT_TM_GMTOFF)
long scd, hrs, min;
#endif
-
+
buffer_prepare_copy(p->conf.ts_accesslog_str, 255);
#if defined(HAVE_STRUCT_TM_GMTOFF)
# ifdef HAVE_LOCALTIME_R
localtime_r(&(srv->cur_ts), &tm);
- strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, "[%d/%b/%Y:%H:%M:%S ", &tm);
-# else
- strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, "[%d/%b/%Y:%H:%M:%S ", localtime_r(&(srv->cur_ts)));
-# endif
+ strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, p->conf.ts_accesslog_fmt_str->ptr, &tm);
+# else /* HAVE_LOCALTIME_R */
+ strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, p->conf.ts_accesslog_fmt_str->ptr, localtime_r(&(srv->cur_ts)));
+# endif /* HAVE_LOCALTIME_R */
p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
-
- buffer_append_string(p->conf.ts_accesslog_str, tm.tm_gmtoff >= 0 ? "+" : "-");
-
- scd = abs(tm.tm_gmtoff);
- hrs = scd / 3600;
- min = (scd % 3600) / 60;
-
- /* hours */
- if (hrs < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
- buffer_append_long(p->conf.ts_accesslog_str, hrs);
-
- if (min < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
- buffer_append_long(p->conf.ts_accesslog_str, min);
- BUFFER_APPEND_STRING_CONST(p->conf.ts_accesslog_str, "]");
-#else
-#ifdef HAVE_GMTIME_R
+
+ if (p->conf.append_tz_offset) {
+ buffer_append_string_len(p->conf.ts_accesslog_str, tm.tm_gmtoff >= 0 ? "+" : "-", 1);
+
+ scd = abs(tm.tm_gmtoff);
+ hrs = scd / 3600;
+ min = (scd % 3600) / 60;
+
+ /* hours */
+ if (hrs < 10) buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("0"));
+ buffer_append_long(p->conf.ts_accesslog_str, hrs);
+
+ if (min < 10) buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("0"));
+ buffer_append_long(p->conf.ts_accesslog_str, min);
+ buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("]"));
+ }
+#else /* HAVE_STRUCT_TM_GMTOFF */
+# ifdef HAVE_GMTIME_R
gmtime_r(&(srv->cur_ts), &tm);
- strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, "[%d/%b/%Y:%H:%M:%S +0000]", &tm);
-#else
- strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, "[%d/%b/%Y:%H:%M:%S +0000]", gmtime(&(srv->cur_ts)));
-#endif
+ strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, p->conf.ts_accesslog_fmt_str->ptr, &tm);
+# else /* HAVE_GMTIME_R */
+ strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, p->conf.ts_accesslog_fmt_str->ptr, gmtime(&(srv->cur_ts)));
+# endif /* HAVE_GMTIME_R */
p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
-#endif
-
+#endif /* HAVE_STRUCT_TM_GMTOFF */
+
*(p->conf.last_generated_accesslog_ts_ptr) = srv->cur_ts;
newts = 1;
}
-
+
buffer_append_string_buffer(b, p->conf.ts_accesslog_str);
-
+
break;
case FORMAT_REMOTE_HOST:
-
+
/* handle inet_ntop cache */
-
+
buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
-
+
break;
case FORMAT_REMOTE_IDENT:
/* ident */
- BUFFER_APPEND_STRING_CONST(b, "-");
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
break;
case FORMAT_REMOTE_USER:
if (con->authed_user->used > 1) {
buffer_append_string_buffer(b, con->authed_user);
} else {
- BUFFER_APPEND_STRING_CONST(b, "-");
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
}
break;
case FORMAT_REQUEST_LINE:
if (con->request.request_line->used) {
- buffer_append_string_buffer(b, con->request.request_line);
+ accesslog_append_escaped(b, con->request.request_line);
}
break;
case FORMAT_STATUS:
buffer_append_long(b, con->http_status);
break;
-
+
case FORMAT_BYTES_OUT_NO_HEADER:
if (con->bytes_written > 0) {
- buffer_append_off_t(b,
+ buffer_append_off_t(b,
con->bytes_written - con->bytes_header <= 0 ? 0 : con->bytes_written - con->bytes_header);
} else {
- BUFFER_APPEND_STRING_CONST(b, "-");
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
}
break;
case FORMAT_HEADER:
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, p->conf.parsed_format->ptr[j]->string->ptr))) {
- buffer_append_string_buffer(b, ds->value);
+ accesslog_append_escaped(b, ds->value);
} else {
- BUFFER_APPEND_STRING_CONST(b, "-");
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
}
break;
case FORMAT_RESPONSE_HEADER:
if (NULL != (ds = (data_string *)array_get_element(con->response.headers, p->conf.parsed_format->ptr[j]->string->ptr))) {
- buffer_append_string_buffer(b, ds->value);
+ accesslog_append_escaped(b, ds->value);
} else {
- BUFFER_APPEND_STRING_CONST(b, "-");
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
+ }
+ break;
+ case FORMAT_ENV:
+ if (NULL != (ds = (data_string *)array_get_element(con->environment, p->conf.parsed_format->ptr[j]->string->ptr))) {
+ accesslog_append_escaped(b, ds->value);
+ } else {
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
}
break;
case FORMAT_FILENAME:
if (con->physical.path->used > 1) {
buffer_append_string_buffer(b, con->physical.path);
} else {
- BUFFER_APPEND_STRING_CONST(b, "-");
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
}
break;
case FORMAT_BYTES_OUT:
if (con->bytes_written > 0) {
buffer_append_off_t(b, con->bytes_written);
} else {
- BUFFER_APPEND_STRING_CONST(b, "-");
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
}
break;
case FORMAT_BYTES_IN:
if (con->bytes_read > 0) {
buffer_append_off_t(b, con->bytes_read);
} else {
- BUFFER_APPEND_STRING_CONST(b, "-");
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
}
break;
case FORMAT_TIME_USED:
@@ -756,36 +837,52 @@ REQUESTDONE_FUNC(log_access_write) {
if (con->server_name->used > 1) {
buffer_append_string_buffer(b, con->server_name);
} else {
- BUFFER_APPEND_STRING_CONST(b, "-");
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
}
break;
case FORMAT_HTTP_HOST:
if (con->uri.authority->used > 1) {
- buffer_append_string_buffer(b, con->uri.authority);
+ accesslog_append_escaped(b, con->uri.authority);
} else {
- BUFFER_APPEND_STRING_CONST(b, "-");
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
}
break;
case FORMAT_REQUEST_PROTOCOL:
- buffer_append_string(b,
- con->request.http_version == HTTP_VERSION_1_1 ? "HTTP/1.1" : "HTTP/1.0");
+ buffer_append_string_len(b,
+ con->request.http_version == HTTP_VERSION_1_1 ? "HTTP/1.1" : "HTTP/1.0", 8);
break;
case FORMAT_REQUEST_METHOD:
buffer_append_string(b, get_http_method_name(con->request.http_method));
break;
+ case FORMAT_PERCENT:
+ buffer_append_string_len(b, CONST_STR_LEN("%"));
+ break;
case FORMAT_SERVER_PORT:
- buffer_append_long(b, srv->srvconf.port);
+ {
+ const char *colon;
+ buffer *srvtoken = ((server_socket*)(con->srv_socket))->srv_token;
+ if (srvtoken->ptr[0] == '[') {
+ colon = strstr(srvtoken->ptr, "]:");
+ } else {
+ colon = strchr(srvtoken->ptr, ':');
+ }
+ if (colon) {
+ buffer_append_string(b, colon+1);
+ } else {
+ buffer_append_long(b, srv->srvconf.port);
+ }
+ }
break;
case FORMAT_QUERY_STRING:
- buffer_append_string_buffer(b, con->uri.query);
+ accesslog_append_escaped(b, con->uri.query);
break;
case FORMAT_URL:
- buffer_append_string_buffer(b, con->uri.path_raw);
+ accesslog_append_escaped(b, con->uri.path_raw);
break;
case FORMAT_CONNECTION_STATUS:
switch(con->keep_alive) {
- case 0: buffer_append_string(b, "-"); break;
- default: buffer_append_string(b, "+"); break;
+ case 0: buffer_append_string_len(b, CONST_STR_LEN("-")); break;
+ default: buffer_append_string_len(b, CONST_STR_LEN("+")); break;
}
break;
default:
@@ -794,9 +891,8 @@ REQUESTDONE_FUNC(log_access_write) {
{ 'A', FORMAT_LOCAL_ADDR },
{ 'C', FORMAT_COOKIE },
{ 'D', FORMAT_TIME_USED_MS },
- { 'e', FORMAT_ENV },
*/
-
+
break;
}
break;
@@ -804,39 +900,43 @@ REQUESTDONE_FUNC(log_access_write) {
break;
}
}
-
- BUFFER_APPEND_STRING_CONST(b, "\n");
+
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
if (p->conf.use_syslog || /* syslog doesn't cache */
- (p->conf.access_logfile->used && p->conf.access_logfile->ptr[0] != '|') || /* pipes don't cache */
+ (p->conf.access_logfile->used && p->conf.access_logfile->ptr[0] == '|') || /* pipes don't cache */
newts ||
b->used > BUFFER_MAX_REUSE_SIZE) {
if (p->conf.use_syslog) {
#ifdef HAVE_SYSLOG_H
- syslog(LOG_INFO, "%*s", b->used - 1, b->ptr);
+ if (b->used > 2) {
+ /* syslog appends a \n on its own */
+ syslog(LOG_INFO, "%*s", (int) b->used - 2, b->ptr);
+ }
#endif
} else if (p->conf.log_access_fd != -1) {
write(p->conf.log_access_fd, b->ptr, b->used - 1);
}
buffer_reset(b);
}
-
+
return HANDLER_GO_ON;
}
+int mod_accesslog_plugin_init(plugin *p);
int mod_accesslog_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("accesslog");
-
+
p->init = mod_accesslog_init;
p->set_defaults= log_access_open;
p->cleanup = mod_accesslog_free;
-
+
p->handle_request_done = log_access_write;
p->handle_sighup = log_access_cycle;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_alias.c b/src/mod_alias.c
index 23570e4..5b7b510 100644
--- a/src/mod_alias.c
+++ b/src/mod_alias.c
@@ -1,14 +1,14 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
#include "base.h"
#include "log.h"
#include "buffer.h"
#include "plugin.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
/* plugin config for all request/connections */
typedef struct {
array *alias;
@@ -16,44 +16,46 @@ typedef struct {
typedef struct {
PLUGIN_DATA;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
/* init the plugin data */
INIT_FUNC(mod_alias_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
-
-
+
+
+
return p;
}
/* detroy the plugin data */
FREE_FUNC(mod_alias_free) {
plugin_data *p = p_d;
-
+
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
size_t i;
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
-
+
+ if(!s) continue;
+
array_free(s->alias);
-
+
free(s);
}
free(p->config_storage);
}
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
@@ -62,25 +64,25 @@ FREE_FUNC(mod_alias_free) {
SETDEFAULTS_FUNC(mod_alias_set_defaults) {
plugin_data *p = p_d;
size_t i = 0;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "alias.url", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
- s->alias = array_init();
+ s->alias = array_init();
cv[0].destination = s->alias;
-
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
@@ -101,16 +103,15 @@ SETDEFAULTS_FUNC(mod_alias_set_defaults) {
}
/* 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);
+ log_error_write(srv, __FILE__, __LINE__, "SBSBS",
+ "url.alias: `", key, "' will never match as `", prefix, "' matched first");
return HANDLER_ERROR;
}
}
}
}
}
-
+
return HANDLER_GO_ON;
}
@@ -119,27 +120,27 @@ SETDEFAULTS_FUNC(mod_alias_set_defaults) {
static int mod_alias_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(alias);
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("alias.url"))) {
PATCH(alias);
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -149,51 +150,54 @@ PHYSICALPATH_FUNC(mod_alias_physical_handler) {
int uri_len, basedir_len;
char *uri_ptr;
size_t k;
-
+
if (con->physical.path->used == 0) return HANDLER_GO_ON;
-
+
mod_alias_patch_connection(srv, con, p);
-
+
/* not to include the tailing slash */
basedir_len = (con->physical.basedir->used - 1) - 1;
uri_len = con->physical.path->used - 1 - basedir_len;
uri_ptr = con->physical.path->ptr + basedir_len;
-
+
for (k = 0; k < p->conf.alias->used; k++) {
data_string *ds = (data_string *)p->conf.alias->data[k];
int alias_len = ds->key->used - 1;
-
+
if (alias_len > uri_len) continue;
if (ds->key->used == 0) continue;
-
- if (0 == strncmp(uri_ptr, ds->key->ptr, alias_len)) {
+
+ if (0 == (con->conf.force_lowercase_filenames ?
+ strncasecmp(uri_ptr, ds->key->ptr, alias_len) :
+ strncmp(uri_ptr, ds->key->ptr, alias_len))) {
/* matched */
-
+
buffer_copy_string_buffer(con->physical.basedir, ds->value);
buffer_copy_string_buffer(srv->tmp_buf, ds->value);
buffer_append_string(srv->tmp_buf, uri_ptr + alias_len);
buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
-
+
return HANDLER_GO_ON;
}
}
-
+
/* not found */
return HANDLER_GO_ON;
}
/* this function is called at dlopen() time and inits the callbacks */
+int mod_alias_plugin_init(plugin *p);
int mod_alias_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("alias");
-
+
p->init = mod_alias_init;
p->handle_physical= mod_alias_physical_handler;
p->set_defaults = mod_alias_set_defaults;
p->cleanup = mod_alias_free;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_auth.c b/src/mod_auth.c
index 9b791d4..d981892 100644
--- a/src/mod_auth.c
+++ b/src/mod_auth.c
@@ -1,3 +1,8 @@
+#include "plugin.h"
+#include "http_auth.h"
+#include "log.h"
+#include "response.h"
+
#include <sys/types.h>
#include <sys/stat.h>
@@ -7,89 +12,84 @@
#include <fcntl.h>
#include <unistd.h>
-#include "plugin.h"
-#include "http_auth.h"
-#include "log.h"
-#include "response.h"
-
handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
/**
* the basic and digest auth framework
- *
+ *
* - config handling
* - protocol handling
- *
- * http_auth.c
- * http_auth_digest.c
- *
+ *
+ * http_auth.c
+ * http_auth_digest.c
+ *
* do the real work
*/
INIT_FUNC(mod_auth_init) {
mod_auth_plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
p->tmp_buf = buffer_init();
-
+
p->auth_user = buffer_init();
#ifdef USE_LDAP
p->ldap_filter = buffer_init();
#endif
-
+
return p;
}
FREE_FUNC(mod_auth_free) {
mod_auth_plugin_data *p = p_d;
-
+
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
-
+
buffer_free(p->tmp_buf);
buffer_free(p->auth_user);
#ifdef USE_LDAP
buffer_free(p->ldap_filter);
#endif
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
mod_auth_plugin_config *s = p->config_storage[i];
-
+
if (!s) continue;
-
+
array_free(s->auth_require);
buffer_free(s->auth_plain_groupfile);
buffer_free(s->auth_plain_userfile);
buffer_free(s->auth_htdigest_userfile);
buffer_free(s->auth_htpasswd_userfile);
buffer_free(s->auth_backend_conf);
-
+
buffer_free(s->auth_ldap_hostname);
buffer_free(s->auth_ldap_basedn);
buffer_free(s->auth_ldap_binddn);
buffer_free(s->auth_ldap_bindpw);
buffer_free(s->auth_ldap_filter);
buffer_free(s->auth_ldap_cafile);
-
+
#ifdef USE_LDAP
buffer_free(s->ldap_filter_pre);
buffer_free(s->ldap_filter_post);
-
+
if (s->ldap) ldap_unbind_s(s->ldap);
#endif
-
+
free(s);
}
free(p->config_storage);
}
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
@@ -113,24 +113,25 @@ static int mod_auth_patch_connection(server *srv, connection *con, mod_auth_plug
PATCH(auth_ldap_filter);
PATCH(auth_ldap_cafile);
PATCH(auth_ldap_starttls);
+ PATCH(auth_ldap_allow_empty_pw);
#ifdef USE_LDAP
- PATCH(ldap);
+ p->anon_conf = s;
PATCH(ldap_filter_pre);
PATCH(ldap_filter_post);
#endif
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend"))) {
PATCH(auth_backend);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.groupfile"))) {
@@ -148,22 +149,30 @@ static int mod_auth_patch_connection(server *srv, connection *con, mod_auth_plug
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.hostname"))) {
PATCH(auth_ldap_hostname);
#ifdef USE_LDAP
- PATCH(ldap);
- PATCH(ldap_filter_pre);
- PATCH(ldap_filter_post);
+ p->anon_conf = s;
#endif
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.base-dn"))) {
PATCH(auth_ldap_basedn);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.filter"))) {
PATCH(auth_ldap_filter);
+#ifdef USE_LDAP
+ PATCH(ldap_filter_pre);
+ PATCH(ldap_filter_post);
+#endif
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.ca-file"))) {
PATCH(auth_ldap_cafile);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.starttls"))) {
PATCH(auth_ldap_starttls);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.bind-dn"))) {
+ PATCH(auth_ldap_binddn);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.bind-pw"))) {
+ PATCH(auth_ldap_bindpw);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.allow-empty-pw"))) {
+ PATCH(auth_ldap_allow_empty_pw);
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -172,116 +181,121 @@ static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
size_t k;
int auth_required = 0, auth_satisfied = 0;
char *http_authorization = NULL;
+ const char *auth_type = NULL;
data_string *ds;
mod_auth_plugin_data *p = p_d;
array *req;
-
+
/* select the right config */
mod_auth_patch_connection(srv, con, p);
-
+
if (p->conf.auth_require == NULL) return HANDLER_GO_ON;
-
+
/*
* AUTH
- *
+ *
*/
-
+
/* do we have to ask for auth ? */
-
+
auth_required = 0;
auth_satisfied = 0;
-
+
/* search auth-directives for path */
for (k = 0; k < p->conf.auth_require->used; k++) {
- buffer *req = p->conf.auth_require->data[k]->key;
+ buffer *require = p->conf.auth_require->data[k]->key;
- if (req->used == 0) continue;
- if (con->uri.path->used < req->used) continue;
+ if (require->used == 0) continue;
+ if (con->uri.path->used < require->used) continue;
/* if we have a case-insensitive FS we have to lower-case the URI here too */
if (con->conf.force_lowercase_filenames) {
- if (0 == strncasecmp(con->uri.path->ptr, req->ptr, req->used - 1)) {
+ if (0 == strncasecmp(con->uri.path->ptr, require->ptr, require->used - 1)) {
auth_required = 1;
break;
}
} else {
- if (0 == strncmp(con->uri.path->ptr, req->ptr, req->used - 1)) {
+ if (0 == strncmp(con->uri.path->ptr, require->ptr, require->used - 1)) {
auth_required = 1;
break;
}
}
}
-
+
/* nothing to do for us */
if (auth_required == 0) return HANDLER_GO_ON;
-
+
req = ((data_array *)(p->conf.auth_require->data[k]))->value;
-
+
/* try to get Authorization-header */
-
+
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Authorization"))) {
http_authorization = ds->value->ptr;
}
-
+
if (ds && ds->value && ds->value->used) {
char *auth_realm;
data_string *method;
-
+
method = (data_string *)array_get_element(req, "method");
-
+
/* parse auth-header */
if (NULL != (auth_realm = strchr(http_authorization, ' '))) {
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))) {
+ auth_type = "Basic";
+
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))) {
+ auth_type = "Digest";
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;
-
+ con->mode = DIRECT;
+
/* a field was missing */
-
+
return HANDLER_FINISHED;
}
}
} else {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"unknown authentification type:",
http_authorization);
}
}
}
-
+
if (!auth_satisfied) {
data_string *method, *realm;
method = (data_string *)array_get_element(req, "method");
realm = (data_string *)array_get_element(req, "realm");
-
+
con->http_status = 401;
-
+ con->mode = DIRECT;
+
if (0 == strcmp(method->value->ptr, "basic")) {
- buffer_copy_string(p->tmp_buf, "Basic realm=\"");
+ buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("Basic realm=\""));
buffer_append_string_buffer(p->tmp_buf, realm->value);
- buffer_append_string(p->tmp_buf, "\"");
-
+ buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("\""));
+
response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
} else if (0 == strcmp(method->value->ptr, "digest")) {
char hh[33];
http_auth_digest_generate_nonce(srv, p, srv->tmp_buf, hh);
-
- buffer_copy_string(p->tmp_buf, "Digest realm=\"");
+
+ buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("Digest realm=\""));
buffer_append_string_buffer(p->tmp_buf, realm->value);
- buffer_append_string(p->tmp_buf, "\", nonce=\"");
+ buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("\", nonce=\""));
buffer_append_string(p->tmp_buf, hh);
- buffer_append_string(p->tmp_buf, "\", qop=\"auth\"");
-
+ buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("\", qop=\"auth\""));
+
response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
} else {
/* evil */
@@ -289,35 +303,47 @@ static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
return HANDLER_FINISHED;
} else {
/* the REMOTE_USER header */
-
+
buffer_copy_string_buffer(con->authed_user, p->auth_user);
+
+ /* AUTH_TYPE environment */
+
+ if (NULL == (ds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
+ ds = data_string_init();
+ }
+
+ buffer_copy_string(ds->key, "AUTH_TYPE");
+ buffer_copy_string(ds->value, auth_type);
+
+ array_insert_unique(con->environment, (data_unset *)ds);
}
-
+
return HANDLER_GO_ON;
}
SETDEFAULTS_FUNC(mod_auth_set_defaults) {
mod_auth_plugin_data *p = p_d;
size_t i;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "auth.backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "auth.backend.plain.groupfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.plain.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.require", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.ldap.hostname", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.ldap.base-dn", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.ldap.filter", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.ldap.ca-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.ldap.starttls", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.ldap.bind-dn", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
+ { "auth.backend.plain.groupfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "auth.backend.plain.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "auth.require", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "auth.backend.ldap.hostname", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { "auth.backend.ldap.base-dn", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
+ { "auth.backend.ldap.filter", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
+ { "auth.backend.ldap.ca-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
+ { "auth.backend.ldap.starttls", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
+ { "auth.backend.ldap.bind-dn", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
{ "auth.backend.ldap.bind-pw", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
- { "auth.backend.htdigest.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.backend.htpasswd.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "auth.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
+ { "auth.backend.ldap.allow-empty-pw", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
+ { "auth.backend.htdigest.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
+ { "auth.backend.htpasswd.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
+ { "auth.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
for (i = 0; i < srv->config_context->used; i++) {
@@ -325,14 +351,14 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) {
size_t n;
data_array *da;
array *ca;
-
+
s = calloc(1, sizeof(mod_auth_plugin_config));
s->auth_plain_groupfile = buffer_init();
s->auth_plain_userfile = buffer_init();
s->auth_htdigest_userfile = buffer_init();
s->auth_htpasswd_userfile = buffer_init();
s->auth_backend_conf = buffer_init();
-
+
s->auth_ldap_hostname = buffer_init();
s->auth_ldap_basedn = buffer_init();
s->auth_ldap_binddn = buffer_init();
@@ -341,15 +367,15 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) {
s->auth_ldap_cafile = buffer_init();
s->auth_ldap_starttls = 0;
s->auth_debug = 0;
-
+
s->auth_require = array_init();
-
+
#ifdef USE_LDAP
s->ldap_filter_pre = buffer_init();
s->ldap_filter_post = buffer_init();
s->ldap = NULL;
#endif
-
+
cv[0].destination = s->auth_backend_conf;
cv[1].destination = s->auth_plain_groupfile;
cv[2].destination = s->auth_plain_userfile;
@@ -359,19 +385,20 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) {
cv[6].destination = s->auth_ldap_filter;
cv[7].destination = s->auth_ldap_cafile;
cv[8].destination = &(s->auth_ldap_starttls);
- cv[9].destination = s->auth_ldap_binddn;
- cv[10].destination = s->auth_ldap_bindpw;
- cv[11].destination = s->auth_htdigest_userfile;
- cv[12].destination = s->auth_htpasswd_userfile;
- cv[13].destination = &(s->auth_debug);
-
+ cv[9].destination = s->auth_ldap_binddn;
+ cv[10].destination = s->auth_ldap_bindpw;
+ cv[11].destination = &(s->auth_ldap_allow_empty_pw);
+ cv[12].destination = s->auth_htdigest_userfile;
+ cv[13].destination = s->auth_htpasswd_userfile;
+ cv[14].destination = &(s->auth_debug);
+
p->config_storage[i] = s;
ca = ((data_config *)srv->config_context->data[i])->value;
-
+
if (0 != config_insert_values_global(srv, ca, cv)) {
return HANDLER_ERROR;
}
-
+
if (s->auth_backend_conf->used) {
if (0 == strcmp(s->auth_backend_conf->ptr, "htpasswd")) {
s->auth_backend = AUTH_BACKEND_HTPASSWD;
@@ -383,30 +410,48 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) {
s->auth_backend = AUTH_BACKEND_LDAP;
} else {
log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not supported:", s->auth_backend_conf);
-
+
return HANDLER_ERROR;
}
}
+#ifdef USE_LDAP
+ if (s->auth_ldap_filter->used) {
+ char *dollar;
+
+ /* parse filter */
+
+ if (NULL == (dollar = strchr(s->auth_ldap_filter->ptr, '$'))) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.filter is missing a replace-operator '$'");
+
+ return HANDLER_ERROR;
+ }
+
+ buffer_copy_string_len(s->ldap_filter_pre, s->auth_ldap_filter->ptr, dollar - s->auth_ldap_filter->ptr);
+ buffer_copy_string(s->ldap_filter_post, dollar+1);
+ }
+#endif
+
/* no auth.require for this section */
if (NULL == (da = (data_array *)array_get_element(ca, "auth.require"))) continue;
-
+
if (da->type != TYPE_ARRAY) continue;
-
+
for (n = 0; n < da->value->used; n++) {
size_t m;
data_array *da_file = (data_array *)da->value->data[n];
const char *method, *realm, *require;
-
+
if (da->value->data[n]->type != TYPE_ARRAY) {
- log_error_write(srv, __FILE__, __LINE__, "sssbs",
- "unexpected type for key: ", "auth.require", "[", da->value->data[n]->key, "](string)");
-
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "auth.require should contain an array as in:",
+ "auth.require = ( \"...\" => ( ..., ...) )");
+
return HANDLER_ERROR;
}
-
+
method = realm = require = NULL;
-
+
for (m = 0; m < da_file->value->used; m++) {
if (da_file->value->data[m]->type == TYPE_STRING) {
if (0 == strcmp(da_file->value->data[m]->key->ptr, "method")) {
@@ -416,206 +461,174 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) {
} else if (0 == strcmp(da_file->value->data[m]->key->ptr, "require")) {
require = ((data_string *)(da_file->value->data[m]))->value->ptr;
} else {
- log_error_write(srv, __FILE__, __LINE__, "sssbs", "unexpected type for key: ", "auth.require", "[", da_file->value->data[m]->key, "](string)");
+ log_error_write(srv, __FILE__, __LINE__, "ssbs",
+ "the field is unknown in:",
+ "auth.require = ( \"...\" => ( ..., -> \"",
+ da_file->value->data[m]->key,
+ "\" <- => \"...\" ) )");
+
return HANDLER_ERROR;
}
} else {
- log_error_write(srv, __FILE__, __LINE__, "sssbs", "unexpected type for key: ", "auth.require", "[", da_file->value->data[m]->key, "](string)");
-
+ log_error_write(srv, __FILE__, __LINE__, "ssbs",
+ "a string was expected for:",
+ "auth.require = ( \"...\" => ( ..., -> \"",
+ da_file->value->data[m]->key,
+ "\" <- => \"...\" ) )");
+
return HANDLER_ERROR;
}
}
-
+
if (method == NULL) {
- log_error_write(srv, __FILE__, __LINE__, "sssss", "missing entry for key: ", "auth.require", "[", "method", "](string)");
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "the method field is missing in:",
+ "auth.require = ( \"...\" => ( ..., \"method\" => \"...\" ) )");
return HANDLER_ERROR;
} else {
if (0 != strcmp(method, "basic") &&
0 != strcmp(method, "digest")) {
- log_error_write(srv, __FILE__, __LINE__, "s", "auth.require->method has to be either 'basic' or 'digest'");
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "method has to be either \"basic\" or \"digest\" in",
+ "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
return HANDLER_ERROR;
}
}
-
+
if (realm == NULL) {
- log_error_write(srv, __FILE__, __LINE__, "sssss", "missing entry for key: ", "auth.require", "[", "realm", "](string)");
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "the realm field is missing in:",
+ "auth.require = ( \"...\" => ( ..., \"realm\" => \"...\" ) )");
return HANDLER_ERROR;
}
-
+
if (require == NULL) {
- log_error_write(srv, __FILE__, __LINE__, "sssss", "missing entry for key: ", "auth.require", "[", "require", "](string)");
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "the require field is missing in:",
+ "auth.require = ( \"...\" => ( ..., \"require\" => \"...\" ) )");
return HANDLER_ERROR;
}
-
+
if (method && realm && require) {
data_string *ds;
data_array *a;
-
+
a = data_array_init();
buffer_copy_string_buffer(a->key, da_file->key);
-
+
ds = data_string_init();
-
- buffer_copy_string(ds->key, "method");
+
+ buffer_copy_string_len(ds->key, CONST_STR_LEN("method"));
buffer_copy_string(ds->value, method);
-
+
array_insert_unique(a->value, (data_unset *)ds);
-
+
ds = data_string_init();
-
- buffer_copy_string(ds->key, "realm");
+
+ buffer_copy_string_len(ds->key, CONST_STR_LEN("realm"));
buffer_copy_string(ds->value, realm);
-
+
array_insert_unique(a->value, (data_unset *)ds);
-
+
ds = data_string_init();
-
- buffer_copy_string(ds->key, "require");
+
+ buffer_copy_string_len(ds->key, CONST_STR_LEN("require"));
buffer_copy_string(ds->value, require);
-
+
array_insert_unique(a->value, (data_unset *)ds);
-
+
array_insert_unique(s->auth_require, (data_unset *)a);
}
}
-
- switch(s->auth_backend) {
- case AUTH_BACKEND_PLAIN:
- if (s->auth_plain_userfile->used) {
- int fd;
- /* try to read */
- if (-1 == (fd = open(s->auth_plain_userfile->ptr, O_RDONLY))) {
- log_error_write(srv, __FILE__, __LINE__, "sbss",
- "opening auth.backend.plain.userfile:", s->auth_plain_userfile,
- "failed:", strerror(errno));
- return HANDLER_ERROR;
- }
- close(fd);
- }
- break;
- case AUTH_BACKEND_HTPASSWD:
- if (s->auth_htpasswd_userfile->used) {
- int fd;
- /* try to read */
- if (-1 == (fd = open(s->auth_htpasswd_userfile->ptr, O_RDONLY))) {
- log_error_write(srv, __FILE__, __LINE__, "sbss",
- "opening auth.backend.htpasswd.userfile:", s->auth_htpasswd_userfile,
- "failed:", strerror(errno));
- return HANDLER_ERROR;
- }
- close(fd);
- }
- break;
- case AUTH_BACKEND_HTDIGEST:
- if (s->auth_htdigest_userfile->used) {
- int fd;
- /* try to read */
- if (-1 == (fd = open(s->auth_htdigest_userfile->ptr, O_RDONLY))) {
- log_error_write(srv, __FILE__, __LINE__, "sbss",
- "opening auth.backend.htdigest.userfile:", s->auth_htdigest_userfile,
- "failed:", strerror(errno));
- return HANDLER_ERROR;
- }
- close(fd);
- }
- break;
+
+ switch(s->auth_ldap_hostname->used) {
case AUTH_BACKEND_LDAP: {
handler_t ret = auth_ldap_init(srv, s);
if (ret == HANDLER_ERROR)
return (ret);
- break;
+ break;
}
- default:
- break;
- }
- }
+ default:
+ break;
+ }
+ }
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s) {
#ifdef USE_LDAP
- int ret;
-#if 0
- if (s->auth_ldap_basedn->used == 0) {
- log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.base-dn has to be set");
-
- return HANDLER_ERROR;
- }
+ int ret;
+#if 0
+ if (s->auth_ldap_basedn->used == 0) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.base-dn has to be set");
+
+ return HANDLER_ERROR;
+ }
#endif
-
- if (s->auth_ldap_filter->used) {
- char *dollar;
-
- /* parse filter */
-
- if (NULL == (dollar = strchr(s->auth_ldap_filter->ptr, '$'))) {
- log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.filter is missing a replace-operator '$'");
-
+
+ if (s->auth_ldap_hostname->used) {
+ /* free old context */
+ if (NULL != s->ldap) ldap_unbind_s(s->ldap);
+
+ if (NULL == (s->ldap = ldap_init(s->auth_ldap_hostname->ptr, LDAP_PORT))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
+
+ return HANDLER_ERROR;
+ }
+
+ ret = LDAP_VERSION3;
+ if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(s->ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
+
+ return HANDLER_ERROR;
+ }
+
+ if (s->auth_ldap_starttls) {
+ /* if no CA file is given, it is ok, as we will use encryption
+ * if the server requires a CAfile it will tell us */
+ if (!buffer_is_empty(s->auth_ldap_cafile)) {
+ if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
+ s->auth_ldap_cafile->ptr))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "Loading CA certificate failed:", ldap_err2string(ret));
+
return HANDLER_ERROR;
}
-
- buffer_copy_string_len(s->ldap_filter_pre, s->auth_ldap_filter->ptr, dollar - s->auth_ldap_filter->ptr);
- buffer_copy_string(s->ldap_filter_post, dollar+1);
}
-
- if (s->auth_ldap_hostname->used) {
- if (NULL == (s->ldap = ldap_init(s->auth_ldap_hostname->ptr, LDAP_PORT))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
-
- return HANDLER_ERROR;
- }
-
- ret = LDAP_VERSION3;
- if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(s->ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
-
- return HANDLER_ERROR;
- }
- if (s->auth_ldap_starttls) {
- /* if no CA file is given, it is ok, as we will use encryption
- * if the server requires a CAfile it will tell us */
- if (!buffer_is_empty(s->auth_ldap_cafile)) {
- if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
- s->auth_ldap_cafile->ptr))) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "Loading CA certificate failed:", ldap_err2string(ret));
-
- return HANDLER_ERROR;
- }
- }
-
- if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(s->ldap, NULL, NULL))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
-
- return HANDLER_ERROR;
- }
- }
-
-
- /* 1. */
- if (s->auth_ldap_binddn->used) {
- if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, s->auth_ldap_binddn->ptr, s->auth_ldap_bindpw->ptr))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
-
- return HANDLER_ERROR;
- }
- } else {
- if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, NULL, NULL))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
-
- return HANDLER_ERROR;
- }
- }
+ if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(s->ldap, NULL, NULL))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
+
+ return HANDLER_ERROR;
+ }
+ }
+
+
+ /* 1. */
+ if (s->auth_ldap_binddn->used) {
+ if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, s->auth_ldap_binddn->ptr, s->auth_ldap_bindpw->ptr))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
+
+ return HANDLER_ERROR;
}
+ } else {
+ if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, NULL, NULL))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
+
+ return HANDLER_ERROR;
+ }
+ }
+ }
+ return HANDLER_GO_ON;
#else
- log_error_write(srv, __FILE__, __LINE__, "s", "no ldap support available");
- return HANDLER_ERROR;
+ UNUSED(s);
+ log_error_write(srv, __FILE__, __LINE__, "s", "no ldap support available");
+ return HANDLER_ERROR;
#endif
- return HANDLER_GO_ON;
}
+int mod_auth_plugin_init(plugin *p);
int mod_auth_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("auth");
@@ -623,8 +636,8 @@ int mod_auth_plugin_init(plugin *p) {
p->set_defaults = mod_auth_set_defaults;
p->handle_uri_clean = mod_auth_uri_handler;
p->cleanup = mod_auth_free;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_cgi.c b/src/mod_cgi.c
index 9480032..5e65f4b 100644
--- a/src/mod_cgi.c
+++ b/src/mod_cgi.c
@@ -1,14 +1,23 @@
+#include "server.h"
+#include "stat_cache.h"
+#include "keyvalue.h"
+#include "log.h"
+#include "connections.h"
+#include "joblist.h"
+#include "http_chunk.h"
+
+#include "plugin.h"
+
#include <sys/types.h>
+
#ifdef __WIN32
-#include <winsock2.h>
+# include <winsock2.h>
#else
-#include <sys/socket.h>
-#include <sys/wait.h>
-#include <sys/mman.h>
-
-#include <netinet/in.h>
-
-#include <arpa/inet.h>
+# include <sys/socket.h>
+# include <sys/wait.h>
+# include <sys/mman.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
#endif
#include <unistd.h>
@@ -23,24 +32,17 @@
#include <stdio.h>
#include <fcntl.h>
-#include "server.h"
-#include "keyvalue.h"
-#include "log.h"
-#include "connections.h"
-#include "joblist.h"
-#include "http_chunk.h"
-
-#include "plugin.h"
-
#ifdef HAVE_SYS_FILIO_H
# include <sys/filio.h>
#endif
+#include "version.h"
+
enum {EOL_UNSET, EOL_N, EOL_RN};
typedef struct {
char **ptr;
-
+
size_t size;
size_t used;
} char_array;
@@ -53,47 +55,48 @@ typedef struct {
typedef struct {
array *cgi;
+ unsigned short execute_x_only;
} plugin_config;
typedef struct {
PLUGIN_DATA;
buffer_pid_t cgi_pid;
-
+
buffer *tmp_buf;
buffer *parse_response;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
typedef struct {
pid_t pid;
int fd;
int fde_ndx; /* index into the fd-event buffer */
-
+
connection *remote_conn; /* dumb pointer */
plugin_data *plugin_data; /* dumb pointer */
-
+
buffer *response;
buffer *response_header;
} handler_ctx;
-static handler_ctx * cgi_handler_ctx_init() {
+static handler_ctx * cgi_handler_ctx_init(void) {
handler_ctx *hctx = calloc(1, sizeof(*hctx));
assert(hctx);
-
+
hctx->response = buffer_init();
hctx->response_header = buffer_init();
-
+
return hctx;
}
static void cgi_handler_ctx_free(handler_ctx *hctx) {
buffer_free(hctx->response);
buffer_free(hctx->response_header);
-
+
free(hctx);
}
@@ -101,14 +104,14 @@ enum {FDEVENT_HANDLED_UNSET, FDEVENT_HANDLED_FINISHED, FDEVENT_HANDLED_NOT_FINIS
INIT_FUNC(mod_cgi_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
assert(p);
-
+
p->tmp_buf = buffer_init();
p->parse_response = buffer_init();
-
+
return p;
}
@@ -116,62 +119,65 @@ INIT_FUNC(mod_cgi_init) {
FREE_FUNC(mod_cgi_free) {
plugin_data *p = p_d;
buffer_pid_t *r = &(p->cgi_pid);
-
+
UNUSED(srv);
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
-
+
array_free(s->cgi);
-
+
free(s);
}
free(p->config_storage);
}
-
+
if (r->ptr) free(r->ptr);
-
+
buffer_free(p->tmp_buf);
buffer_free(p->parse_response);
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
plugin_data *p = p_d;
size_t i = 0;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "cgi.assign", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "cgi.execute-x-only", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET}
};
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
assert(s);
-
+
s->cgi = array_init();
-
+ s->execute_x_only = 0;
+
cv[0].destination = s->cgi;
-
+ cv[1].destination = &(s->execute_x_only);
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
}
-
+
return HANDLER_GO_ON;
}
@@ -180,13 +186,13 @@ static int cgi_pid_add(server *srv, plugin_data *p, pid_t pid) {
int m = -1;
size_t i;
buffer_pid_t *r = &(p->cgi_pid);
-
+
UNUSED(srv);
for (i = 0; i < r->used; i++) {
if (r->ptr[i] > m) m = r->ptr[i];
}
-
+
if (r->size == 0) {
r->size = 16;
r->ptr = malloc(sizeof(*r->ptr) * r->size);
@@ -194,93 +200,96 @@ static int cgi_pid_add(server *srv, plugin_data *p, pid_t pid) {
r->size += 16;
r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
}
-
+
r->ptr[r->used++] = pid;
-
+
return m;
}
static int cgi_pid_del(server *srv, plugin_data *p, pid_t pid) {
size_t i;
buffer_pid_t *r = &(p->cgi_pid);
-
+
UNUSED(srv);
for (i = 0; i < r->used; i++) {
if (r->ptr[i] == pid) break;
}
-
+
if (i != r->used) {
/* found */
-
+
if (i != r->used - 1) {
r->ptr[i] = r->ptr[r->used - 1];
}
r->used--;
}
-
+
return 0;
}
-static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
+static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
char *ns;
const char *s;
int line = 0;
-
+
UNUSED(srv);
-
+
buffer_copy_string_buffer(p->parse_response, in);
-
- for (s = p->parse_response->ptr;
- NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n')));
- s = ns + (eol == EOL_RN ? 2 : 1), line++) {
+
+ for (s = p->parse_response->ptr;
+ NULL != (ns = strchr(s, '\n'));
+ s = ns + 1, line++) {
const char *key, *value;
int key_len;
data_string *ds;
-
+
+ /* strip the \n */
ns[0] = '\0';
-
- if (line == 0 &&
+
+ if (ns > s && ns[-1] == '\r') ns[-1] = '\0';
+
+ if (line == 0 &&
0 == strncmp(s, "HTTP/1.", 7)) {
/* non-parsed header ... we parse them anyway */
-
+
if ((s[7] == '1' ||
s[7] == '0') &&
s[8] == ' ') {
int status;
/* after the space should be a status code for us */
-
+
status = strtol(s+9, NULL, 10);
-
- if (con->http_status >= 100 &&
- con->http_status < 1000) {
+
+ if (status >= 100 &&
+ status < 1000) {
/* we expected 3 digits and didn't got them */
con->parsed_response |= HTTP_STATUS;
con->http_status = status;
}
}
} else {
-
+ /* parse the headers */
key = s;
if (NULL == (value = strchr(s, ':'))) {
/* we expect: "<key>: <value>\r\n" */
continue;
}
-
+
key_len = value - key;
value += 1;
-
+
/* skip LWS */
while (*value == ' ' || *value == '\t') value++;
-
+
if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
ds = data_response_init();
}
buffer_copy_string_len(ds->key, key, key_len);
buffer_copy_string(ds->value, value);
-
+
array_insert_unique(con->response.headers, (data_unset *)ds);
-
+
switch(key_len) {
case 4:
if (0 == strncasecmp(key, "Date", key_len)) {
@@ -315,13 +324,13 @@ static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buff
}
}
}
-
+
/* CGI/1.1 rev 03 - 7.2.1.2 */
if ((con->parsed_response & HTTP_LOCATION) &&
!(con->parsed_response & HTTP_STATUS)) {
con->http_status = 302;
}
-
+
return 0;
}
@@ -329,11 +338,22 @@ static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buff
static int cgi_demux_response(server *srv, handler_ctx *hctx) {
plugin_data *p = hctx->plugin_data;
connection *con = hctx->remote_conn;
-
+
while(1) {
int n;
-
- buffer_prepare_copy(hctx->response, 1024);
+ int toread;
+
+#if defined(__WIN32)
+ buffer_prepare_copy(hctx->response, 4 * 1024);
+#else
+ if (ioctl(con->fd, FIONREAD, &toread) || toread == 0 || toread <= 4*1024) {
+ buffer_prepare_copy(hctx->response, 4 * 1024);
+ } else {
+ if (toread > MAX_READ_LIMIT) toread = MAX_READ_LIMIT;
+ buffer_prepare_copy(hctx->response, toread + 1);
+ }
+#endif
+
if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
if (errno == EAGAIN || errno == EINTR) {
/* would block, wait for signal */
@@ -343,125 +363,153 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) {
log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
return FDEVENT_HANDLED_ERROR;
}
-
+
if (n == 0) {
/* read finished */
-
+
con->file_finished = 1;
-
+
/* send final chunk */
http_chunk_append_mem(srv, con, NULL, 0);
joblist_append(srv, con);
-
+
return FDEVENT_HANDLED_FINISHED;
}
-
+
hctx->response->ptr[n] = '\0';
hctx->response->used = n+1;
-
+
/* split header from body */
-
+
if (con->file_started == 0) {
- char *c;
- int in_header = 0;
- int header_end = 0;
- int cp, eol = EOL_UNSET;
- size_t used = 0;
-
+ int is_header = 0;
+ int is_header_end = 0;
+ size_t last_eol = 0;
+ size_t i;
+
buffer_append_string_buffer(hctx->response_header, hctx->response);
+
+ /**
+ * we have to handle a few cases:
+ *
+ * nph:
+ *
+ * HTTP/1.0 200 Ok\n
+ * Header: Value\n
+ * \n
+ *
+ * CGI:
+ * Header: Value\n
+ * Status: 200\n
+ * \n
+ *
+ * and different mixes of \n and \r\n combinations
+ *
+ * Some users also forget about CGI and just send a response and hope
+ * we handle it. No headers, no header-content seperator
+ *
+ */
/* nph (non-parsed headers) */
- if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
-
- /* search for the \r\n\r\n or \n\n in the string */
- for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
- if (*c == ':') in_header = 1;
- else if (*c == '\n') {
- if (in_header == 0) {
- /* got a response without a response header */
-
- c = NULL;
- header_end = 1;
- break;
- }
-
- if (eol == EOL_UNSET) eol = EOL_N;
-
- if (*(c+1) == '\n') {
- header_end = 1;
- break;
- }
-
- } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
- if (in_header == 0) {
- /* got a response without a response header */
-
- c = NULL;
- header_end = 1;
+ if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) is_header = 1;
+
+ for (i = 0; !is_header_end && i < hctx->response_header->used - 1; i++) {
+ char c = hctx->response_header->ptr[i];
+
+ switch (c) {
+ case ':':
+ /* we found a colon
+ *
+ * looks like we have a normal header
+ */
+ is_header = 1;
+ break;
+ case '\n':
+ /* EOL */
+ if (is_header == 0) {
+ /* we got a EOL but we don't seem to got a HTTP header */
+
+ is_header_end = 1;
+
break;
}
-
- if (eol == EOL_UNSET) eol = EOL_RN;
-
- if (used > 3 &&
- *(c+2) == '\r' &&
- *(c+3) == '\n') {
- header_end = 1;
+
+ /**
+ * check if we saw a \n(\r)?\n sequence
+ */
+ if (last_eol > 0 &&
+ ((i - last_eol == 1) ||
+ (i - last_eol == 2 && hctx->response_header->ptr[i - 1] == '\r'))) {
+ is_header_end = 1;
break;
}
-
- /* skip the \n */
- c++;
- cp++;
- used--;
+
+ last_eol = i;
+
+ break;
}
}
-
- if (header_end) {
- if (c == NULL) {
+
+ if (is_header_end) {
+ if (!is_header) {
/* no header, but a body */
-
+
if (con->request.http_version == HTTP_VERSION_1_1) {
con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
}
-
+
http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
joblist_append(srv, con);
} else {
- size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
- size_t blen = hctx->response_header->used - hlen - 1;
-
- /* a small hack: terminate after at the second \r */
- hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
- hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
-
- /* parse the response header */
- cgi_response_parse(srv, con, p, hctx->response_header, eol);
+ const char *bstart;
+ size_t blen;
+
+ /**
+ * i still points to the char after the terminating EOL EOL
+ *
+ * put it on the last \n again
+ */
+ i--;
+
+ /* the body starts after the EOL */
+ bstart = hctx->response_header->ptr + (i + 1);
+ blen = (hctx->response_header->used - 1) - (i + 1);
+
+ /* string the last \r?\n */
+ if (i > 0 && (hctx->response_header->ptr[i - 1] == '\r')) {
+ i--;
+ }
+
+ hctx->response_header->ptr[i] = '\0';
+ hctx->response_header->used = i + 1; /* the string + \0 */
+ /* parse the response header */
+ cgi_response_parse(srv, con, p, hctx->response_header);
+
/* enable chunked-transfer-encoding */
if (con->request.http_version == HTTP_VERSION_1_1 &&
!(con->parsed_response & HTTP_CONTENT_LENGTH)) {
con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
}
-
- if ((hctx->response->used != hlen) && blen > 0) {
- http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
+
+ if (blen > 0) {
+ http_chunk_append_mem(srv, con, bstart, blen + 1);
joblist_append(srv, con);
}
}
-
+
con->file_started = 1;
}
} else {
http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
joblist_append(srv, con);
}
-
-#if 0
+
+#if 0
log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
#endif
}
-
+
return FDEVENT_HANDLED_NOT_FINISHED;
}
@@ -470,42 +518,42 @@ static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) {
pid_t pid;
plugin_data *p;
connection *con;
-
+
if (NULL == hctx) return HANDLER_GO_ON;
-
+
p = hctx->plugin_data;
con = hctx->remote_conn;
-
+
if (con->mode != p->id) return HANDLER_GO_ON;
#ifndef __WIN32
-
+
/* the connection to the browser went away, but we still have a connection
- * to the CGI script
+ * to the CGI script
*
* close cgi-connection
*/
-
+
if (hctx->fd != -1) {
/* close connection to the cgi-script */
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
fdevent_unregister(srv->ev, hctx->fd);
-
+
if (close(hctx->fd)) {
log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
}
-
+
hctx->fd = -1;
hctx->fde_ndx = -1;
}
-
+
pid = hctx->pid;
-
+
con->plugin_ctx[p->id] = NULL;
-
+
/* is this a good idea ? */
cgi_handler_ctx_free(hctx);
-
+
/* if waitpid hasn't been called by response.c yet, do it here */
if (pid) {
/* check if the CGI-script is already gone */
@@ -519,19 +567,19 @@ static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) {
case -1:
/* */
if (errno == EINTR) break;
-
- /*
- * errno == ECHILD happens if _subrequest catches the process-status before
+
+ /*
+ * errno == ECHILD happens if _subrequest catches the process-status before
* we have read the response of the cgi process
- *
+ *
* -> catch status
* -> WAIT_FOR_EVENT
* -> read response
* -> we get here with waitpid == ECHILD
- *
+ *
*/
- if (errno == ECHILD) return HANDLER_FINISHED;
-
+ if (errno == ECHILD) return HANDLER_GO_ON;
+
log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
return HANDLER_ERROR;
default:
@@ -540,80 +588,83 @@ static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) {
connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
con->http_status = 500;
con->mode = DIRECT;
+ } else {
+ con->file_finished = 1;
}
-
+
if (WIFEXITED(status)) {
#if 0
log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", pid);
#endif
- pid = 0;
-
- return HANDLER_FINISHED;
+ return HANDLER_GO_ON;
} else {
log_error_write(srv, __FILE__, __LINE__, "sd", "cgi died, pid:", pid);
- pid = 0;
- return HANDLER_FINISHED;
+ return HANDLER_GO_ON;
}
}
-
-
+
+
kill(pid, SIGTERM);
-
+
/* cgi-script is still alive, queue the PID for removal */
cgi_pid_add(srv, p, pid);
}
-#endif
- return HANDLER_FINISHED;
+#endif
+ return HANDLER_GO_ON;
}
static handler_t cgi_connection_close_callback(server *srv, connection *con, void *p_d) {
plugin_data *p = p_d;
-
+
return cgi_connection_close(srv, con->plugin_ctx[p->id]);
}
-static handler_t cgi_handle_fdevent(void *s, void *ctx, int revents) {
- server *srv = (server *)s;
+static handler_t cgi_handle_fdevent(server *srv, void *ctx, int revents) {
handler_ctx *hctx = ctx;
connection *con = hctx->remote_conn;
-
+
joblist_append(srv, con);
-
+
if (hctx->fd == -1) {
log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "invalid cgi-fd");
-
+
return HANDLER_ERROR;
}
-
+
if (revents & FDEVENT_IN) {
switch (cgi_demux_response(srv, hctx)) {
case FDEVENT_HANDLED_NOT_FINISHED:
break;
case FDEVENT_HANDLED_FINISHED:
/* we are done */
-
+
#if 0
log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "finished");
#endif
cgi_connection_close(srv, hctx);
-
- /* if we get a IN|HUP and have read everything don't exec the close twice */
+
+ /* if we get a IN|HUP and have read everything don't exec the close twice */
return HANDLER_FINISHED;
case FDEVENT_HANDLED_ERROR:
- connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
- con->http_status = 500;
- con->mode = DIRECT;
-
+ /* Send an error if we haven't sent any data yet */
+ if (0 == con->file_started) {
+ connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
+ con->http_status = 500;
+ con->mode = DIRECT;
+ } else {
+ con->file_finished = 1;
+ }
+
log_error_write(srv, __FILE__, __LINE__, "s", "demuxer failed: ");
break;
}
}
-
+
if (revents & FDEVENT_OUT) {
/* nothing to do */
}
-
+
/* perhaps this issue is already handled */
if (revents & FDEVENT_HUP) {
/* check if we still have a unfinished header package which is a body in reality */
@@ -623,57 +674,54 @@ static handler_t cgi_handle_fdevent(void *s, void *ctx, int revents) {
http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
joblist_append(srv, con);
}
-
+
if (con->file_finished == 0) {
http_chunk_append_mem(srv, con, NULL, 0);
joblist_append(srv, con);
}
-
+
con->file_finished = 1;
-
+
if (chunkqueue_is_empty(con->write_queue)) {
/* there is nothing left to write */
connection_set_state(srv, con, CON_STATE_RESPONSE_END);
} else {
/* used the write-handler to finish the request on demand */
-
+
}
-
+
# if 0
log_error_write(srv, __FILE__, __LINE__, "sddd", "got HUP from cgi", con->fd, hctx->fd, revents);
# endif
-
+
/* rtsigs didn't liked the close */
cgi_connection_close(srv, hctx);
} else if (revents & FDEVENT_ERR) {
con->file_finished = 1;
-
+
/* kill all connections to the cgi process */
cgi_connection_close(srv, hctx);
#if 1
log_error_write(srv, __FILE__, __LINE__, "s", "cgi-FDEVENT_ERR");
-#endif
+#endif
return HANDLER_ERROR;
}
-
+
return HANDLER_FINISHED;
}
-static int cgi_env_add(char_array *env, const char *key, size_t key_len, const char *val) {
- int val_len;
+static int cgi_env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
char *dst;
-
+
if (!key || !val) return -1;
-
- val_len = strlen(val);
-
- dst = malloc(key_len + val_len + 3);
+
+ dst = malloc(key_len + val_len + 2);
memcpy(dst, key, key_len);
dst[key_len] = '=';
- /* add the \0 from the value */
- memcpy(dst + key_len + 1, val, val_len + 1);
-
+ memcpy(dst + key_len + 1, val, val_len);
+ dst[key_len + 1 + val_len] = '\0';
+
if (env->size == 0) {
env->size = 16;
env->ptr = malloc(env->size * sizeof(*env->ptr));
@@ -681,45 +729,47 @@ static int cgi_env_add(char_array *env, const char *key, size_t key_len, const c
env->size += 16;
env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
}
-
+
env->ptr[env->used++] = dst;
-
+
return 0;
}
static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *cgi_handler) {
pid_t pid;
-
+
#ifdef HAVE_IPV6
char b2[INET6_ADDRSTRLEN + 1];
#endif
-
+
int to_cgi_fds[2];
int from_cgi_fds[2];
struct stat st;
-
-#ifndef __WIN32
-
+
+#ifndef __WIN32
+
if (cgi_handler->used > 1) {
/* stat the exec file */
if (-1 == (stat(cgi_handler->ptr, &st))) {
- log_error_write(srv, __FILE__, __LINE__, "sbss",
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
"stat for cgi-handler", cgi_handler,
"failed:", strerror(errno));
return -1;
}
}
-
+
if (pipe(to_cgi_fds)) {
log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
return -1;
}
-
+
if (pipe(from_cgi_fds)) {
+ close(to_cgi_fds[0]);
+ close(to_cgi_fds[1]);
log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
return -1;
}
-
+
/* fork, execve */
switch (pid = fork()) {
case 0: {
@@ -731,142 +781,193 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
size_t n;
char_array env;
char *c;
+ const char *s;
server_socket *srv_sock = con->srv_socket;
-
+
/* move stdout to from_cgi_fd[1] */
close(STDOUT_FILENO);
dup2(from_cgi_fds[1], STDOUT_FILENO);
close(from_cgi_fds[1]);
/* not needed */
close(from_cgi_fds[0]);
-
+
/* move the stdin to to_cgi_fd[0] */
close(STDIN_FILENO);
dup2(to_cgi_fds[0], STDIN_FILENO);
close(to_cgi_fds[0]);
/* not needed */
close(to_cgi_fds[1]);
-
- /* HACK:
- * this is not nice, but it works
- *
- * we feed the stderr of the CGI to our errorlog, if possible
- */
- if (srv->errorlog_mode == ERRORLOG_FILE) {
- close(STDERR_FILENO);
- dup2(srv->errorlog_fd, STDERR_FILENO);
- }
-
+
/* create environment */
env.ptr = NULL;
env.size = 0;
env.used = 0;
-
- cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), PACKAGE_NAME"/"PACKAGE_VERSION);
- cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"),
- con->server_name->used ?
- con->server_name->ptr :
+
+ if (buffer_is_empty(con->conf.server_tag)) {
+ cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_DESC));
+ } else {
+ cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_BUF_LEN(con->conf.server_tag));
+ }
+
+ if (!buffer_is_empty(con->server_name)) {
+ size_t len = con->server_name->used - 1;
+
+ if (con->server_name->ptr[0] == '[') {
+ const char *colon = strstr(con->server_name->ptr, "]:");
+ if (colon) len = (colon + 1) - con->server_name->ptr;
+ } else {
+ const char *colon = strchr(con->server_name->ptr, ':');
+ if (colon) len = colon - con->server_name->ptr;
+ }
+
+ cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), con->server_name->ptr, len);
+ } else {
#ifdef HAVE_IPV6
- inet_ntop(srv_sock->addr.plain.sa_family,
- srv_sock->addr.plain.sa_family == AF_INET6 ?
+ s = inet_ntop(srv_sock->addr.plain.sa_family,
+ srv_sock->addr.plain.sa_family == AF_INET6 ?
(const void *) &(srv_sock->addr.ipv6.sin6_addr) :
(const void *) &(srv_sock->addr.ipv4.sin_addr),
- b2, sizeof(b2)-1)
+ b2, sizeof(b2)-1);
#else
- inet_ntoa(srv_sock->addr.ipv4.sin_addr)
+ s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
#endif
- );
- cgi_env_add(&env, CONST_STR_LEN("GATEWAY_INTERFACE"), "CGI/1.1");
-
- cgi_env_add(&env, CONST_STR_LEN("SERVER_PROTOCOL"), get_http_version_name(con->request.http_version));
-
- ltostr(buf,
+ cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
+ }
+ cgi_env_add(&env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
+
+ s = get_http_version_name(con->request.http_version);
+
+ cgi_env_add(&env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
+
+ LI_ltostr(buf,
#ifdef HAVE_IPV6
ntohs(srv_sock->addr.plain.sa_family == AF_INET6 ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
#else
ntohs(srv_sock->addr.ipv4.sin_port)
#endif
);
- cgi_env_add(&env, CONST_STR_LEN("SERVER_PORT"), buf);
-
- cgi_env_add(&env, CONST_STR_LEN("SERVER_ADDR"),
+ cgi_env_add(&env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
+
+ switch (srv_sock->addr.plain.sa_family) {
#ifdef HAVE_IPV6
- inet_ntop(srv_sock->addr.plain.sa_family,
- srv_sock->addr.plain.sa_family == AF_INET6 ?
- (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
- (const void *) &(srv_sock->addr.ipv4.sin_addr),
- b2, sizeof(b2)-1)
+ case AF_INET6:
+ s = inet_ntop(srv_sock->addr.plain.sa_family,
+ (const void *) &(srv_sock->addr.ipv6.sin6_addr),
+ b2, sizeof(b2)-1);
+ break;
+ case AF_INET:
+ s = inet_ntop(srv_sock->addr.plain.sa_family,
+ (const void *) &(srv_sock->addr.ipv4.sin_addr),
+ b2, sizeof(b2)-1);
+ break;
#else
- inet_ntoa(srv_sock->addr.ipv4.sin_addr)
+ case AF_INET:
+ s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
+ break;
#endif
- );
-
- cgi_env_add(&env, CONST_STR_LEN("REQUEST_METHOD"), get_http_method_name(con->request.http_method));
- if (con->request.pathinfo->used) {
- cgi_env_add(&env, CONST_STR_LEN("PATH_INFO"), con->request.pathinfo->ptr);
+ default:
+ s = "";
+ break;
}
- cgi_env_add(&env, CONST_STR_LEN("REDIRECT_STATUS"), "200");
- cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), con->uri.query->used ? con->uri.query->ptr : "");
- cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), con->request.orig_uri->used ? con->request.orig_uri->ptr : "");
-
-
- cgi_env_add(&env, CONST_STR_LEN("REMOTE_ADDR"),
+ cgi_env_add(&env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
+
+ s = get_http_method_name(con->request.http_method);
+ cgi_env_add(&env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
+
+ if (!buffer_is_empty(con->request.pathinfo)) {
+ cgi_env_add(&env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
+ }
+ cgi_env_add(&env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200"));
+ if (!buffer_is_empty(con->uri.query)) {
+ cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
+ }
+ if (!buffer_is_empty(con->request.orig_uri)) {
+ cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
+ }
+
+
+ switch (con->dst_addr.plain.sa_family) {
#ifdef HAVE_IPV6
- inet_ntop(con->dst_addr.plain.sa_family,
- con->dst_addr.plain.sa_family == AF_INET6 ?
- (const void *) &(con->dst_addr.ipv6.sin6_addr) :
- (const void *) &(con->dst_addr.ipv4.sin_addr),
- b2, sizeof(b2)-1)
+ case AF_INET6:
+ s = inet_ntop(con->dst_addr.plain.sa_family,
+ (const void *) &(con->dst_addr.ipv6.sin6_addr),
+ b2, sizeof(b2)-1);
+ break;
+ case AF_INET:
+ s = inet_ntop(con->dst_addr.plain.sa_family,
+ (const void *) &(con->dst_addr.ipv4.sin_addr),
+ b2, sizeof(b2)-1);
+ break;
#else
- inet_ntoa(con->dst_addr.ipv4.sin_addr)
+ case AF_INET:
+ s = inet_ntoa(con->dst_addr.ipv4.sin_addr);
+ break;
#endif
- );
+ default:
+ s = "";
+ break;
+ }
+ cgi_env_add(&env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
- ltostr(buf,
+ LI_ltostr(buf,
#ifdef HAVE_IPV6
ntohs(con->dst_addr.plain.sa_family == AF_INET6 ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
#else
ntohs(con->dst_addr.ipv4.sin_port)
#endif
);
- cgi_env_add(&env, CONST_STR_LEN("REMOTE_PORT"), buf);
-
- if (con->authed_user->used) {
+ cgi_env_add(&env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
+
+ if (!buffer_is_empty(con->authed_user)) {
cgi_env_add(&env, CONST_STR_LEN("REMOTE_USER"),
- con->authed_user->ptr);
+ CONST_BUF_LEN(con->authed_user));
}
-
+
+#ifdef USE_OPENSSL
+ if (srv_sock->is_ssl) {
+ cgi_env_add(&env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
+ }
+#endif
+
/* request.content_length < SSIZE_MAX, see request.c */
- ltostr(buf, con->request.content_length);
- cgi_env_add(&env, CONST_STR_LEN("CONTENT_LENGTH"), buf);
- cgi_env_add(&env, CONST_STR_LEN("SCRIPT_FILENAME"), con->physical.path->ptr);
- cgi_env_add(&env, CONST_STR_LEN("SCRIPT_NAME"), con->uri.path->ptr);
-
+ LI_ltostr(buf, con->request.content_length);
+ cgi_env_add(&env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
+ cgi_env_add(&env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
+ cgi_env_add(&env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
+ cgi_env_add(&env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir));
+
/* for valgrind */
- cgi_env_add(&env, CONST_STR_LEN("LD_PRELOAD"), getenv("LD_PRELOAD"));
- cgi_env_add(&env, CONST_STR_LEN("LD_LIBRARY_PATH"), getenv("LD_LIBRARY_PATH"));
+ if (NULL != (s = getenv("LD_PRELOAD"))) {
+ cgi_env_add(&env, CONST_STR_LEN("LD_PRELOAD"), s, strlen(s));
+ }
+
+ if (NULL != (s = getenv("LD_LIBRARY_PATH"))) {
+ cgi_env_add(&env, CONST_STR_LEN("LD_LIBRARY_PATH"), s, strlen(s));
+ }
#ifdef __CYGWIN__
/* CYGWIN needs SYSTEMROOT */
- cgi_env_add(&env, CONST_STR_LEN("SYSTEMROOT"), getenv("SYSTEMROOT"));
+ if (NULL != (s = getenv("SYSTEMROOT"))) {
+ cgi_env_add(&env, CONST_STR_LEN("SYSTEMROOT"), s, strlen(s));
+ }
#endif
-
+
for (n = 0; n < con->request.headers->used; n++) {
data_string *ds;
-
+
ds = (data_string *)con->request.headers->data[n];
-
+
if (ds->value->used && ds->key->used) {
size_t j;
-
+
buffer_reset(p->tmp_buf);
-
+
if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
- buffer_copy_string(p->tmp_buf, "HTTP_");
+ buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("HTTP_"));
p->tmp_buf->used--; /* strip \0 after HTTP_ */
}
-
+
buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
-
+
for (j = 0; j < ds->key->used - 1; j++) {
char cr = '_';
if (light_isalpha(ds->key->ptr[j])) {
@@ -879,56 +980,62 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
p->tmp_buf->ptr[p->tmp_buf->used++] = cr;
}
p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
-
- cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), ds->value->ptr);
+
+ cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
}
}
-
+
for (n = 0; n < con->environment->used; n++) {
data_string *ds;
-
+
ds = (data_string *)con->environment->data[n];
-
+
if (ds->value->used && ds->key->used) {
size_t j;
-
+
buffer_reset(p->tmp_buf);
-
+
buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
-
+
for (j = 0; j < ds->key->used - 1; j++) {
- p->tmp_buf->ptr[p->tmp_buf->used++] =
- isalpha((unsigned char)ds->key->ptr[j]) ?
- toupper((unsigned char)ds->key->ptr[j]) : '_';
+ char cr = '_';
+ if (light_isalpha(ds->key->ptr[j])) {
+ /* upper-case */
+ cr = ds->key->ptr[j] & ~32;
+ } else if (light_isdigit(ds->key->ptr[j])) {
+ /* copy */
+ cr = ds->key->ptr[j];
+ }
+ p->tmp_buf->ptr[p->tmp_buf->used++] = cr;
}
p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
-
- cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), ds->value->ptr);
+
+ cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
}
}
-
+
if (env.size == env.used) {
env.size += 16;
env.ptr = realloc(env.ptr, env.size * sizeof(*env.ptr));
}
-
+
env.ptr[env.used] = NULL;
-
+
/* set up args */
argc = 3;
args = malloc(sizeof(*args) * argc);
i = 0;
-
+
if (cgi_handler->used > 1) {
args[i++] = cgi_handler->ptr;
}
args[i++] = con->physical.path->ptr;
- args[i++] = NULL;
+ args[i ] = NULL;
/* search for the last / */
if (NULL != (c = strrchr(con->physical.path->ptr, '/'))) {
*c = '\0';
-
+
/* change to the physical directory */
if (-1 == chdir(con->physical.path->ptr)) {
log_error_write(srv, __FILE__, __LINE__, "ssb", "chdir failed:", strerror(errno), con->physical.path);
@@ -940,12 +1047,12 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
for (i = 3; i < 256; i++) {
if (i != srv->errorlog_fd) close(i);
}
-
+
/* exec the cgi */
execve(args[0], args, env.ptr);
-
- log_error_write(srv, __FILE__, __LINE__, "sss", "CGI failed:", strerror(errno), args[0]);
-
+
+ /* log_error_write(srv, __FILE__, __LINE__, "sss", "CGI failed:", strerror(errno), args[0]); */
+
/* */
SEGFAULT();
break;
@@ -953,15 +1060,23 @@ 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));
+ close(from_cgi_fds[0]);
+ close(from_cgi_fds[1]);
+ close(to_cgi_fds[0]);
+ close(to_cgi_fds[1]);
+ return -1;
break;
default: {
handler_ctx *hctx;
/* father */
-
+
+ close(from_cgi_fds[1]);
+ close(to_cgi_fds[0]);
+
if (con->request.content_length) {
chunkqueue *cq = con->request_content_queue;
chunk *c;
-
+
assert(chunkqueue_length(cq) == (off_t)con->request.content_length);
/* there is content to send */
@@ -976,22 +1091,26 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
if (-1 == c->file.fd && /* open the file if not already open */
-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
-
+
+ close(from_cgi_fds[0]);
+ close(to_cgi_fds[1]);
return -1;
}
c->file.mmap.length = c->file.length;
-
- if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.mmap.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
- log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
+
+ if (MAP_FAILED == (c->file.mmap.start = mmap(NULL, c->file.mmap.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
+ log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
strerror(errno), c->file.name, c->file.fd);
+ close(from_cgi_fds[0]);
+ close(to_cgi_fds[1]);
return -1;
}
close(c->file.fd);
c->file.fd = -1;
-
+
/* chunk_reset() or chunk_free() will cleanup for us */
}
@@ -999,8 +1118,9 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
switch(errno) {
case ENOSPC:
con->http_status = 507;
-
break;
+ case EINTR:
+ continue;
default:
con->http_status = 403;
break;
@@ -1012,8 +1132,9 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
switch(errno) {
case ENOSPC:
con->http_status = 507;
-
break;
+ case EINTR:
+ continue;
default:
con->http_status = 403;
break;
@@ -1028,55 +1149,54 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
c->offset += r;
cq->bytes_out += r;
} else {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "write() failed due to: ", strerror(errno));
+ con->http_status = 500;
break;
}
chunkqueue_remove_finished_chunks(cq);
}
}
-
- close(from_cgi_fds[1]);
-
- close(to_cgi_fds[0]);
+
close(to_cgi_fds[1]);
-
+
/* register PID and wait for them asyncronously */
con->mode = p->id;
buffer_reset(con->physical.path);
-
+
hctx = cgi_handler_ctx_init();
-
+
hctx->remote_conn = con;
hctx->plugin_data = p;
hctx->pid = pid;
hctx->fd = from_cgi_fds[0];
hctx->fde_ndx = -1;
-
+
con->plugin_ctx[p->id] = hctx;
-
+
fdevent_register(srv->ev, hctx->fd, cgi_handle_fdevent, hctx);
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
-
+ fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
+
if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
-
+
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
fdevent_unregister(srv->ev, hctx->fd);
-
+
log_error_write(srv, __FILE__, __LINE__, "sd", "cgi close:", hctx->fd);
-
+
close(hctx->fd);
-
+
cgi_handler_ctx_free(hctx);
-
+
con->plugin_ctx[p->id] = NULL;
-
+
return -1;
}
-
+
break;
}
}
-
+
return 0;
#else
return -1;
@@ -1088,27 +1208,30 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(cgi);
-
+ PATCH(execute_x_only);
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.assign"))) {
PATCH(cgi);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.execute-x-only"))) {
+ PATCH(execute_x_only);
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -1117,24 +1240,32 @@ URIHANDLER_FUNC(cgi_is_handled) {
size_t k, s_len;
plugin_data *p = p_d;
buffer *fn = con->physical.path;
-
- if (fn->used == 0) return HANDLER_ERROR;
-
+ stat_cache_entry *sce = NULL;
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+ if (fn->used == 0) return HANDLER_GO_ON;
+
mod_cgi_patch_connection(srv, con, p);
-
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) return HANDLER_GO_ON;
+ if (!S_ISREG(sce->st.st_mode)) return HANDLER_GO_ON;
+ if (p->conf.execute_x_only == 1 && (sce->st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) return HANDLER_GO_ON;
+
s_len = fn->used - 1;
-
+
for (k = 0; k < p->conf.cgi->used; k++) {
data_string *ds = (data_string *)p->conf.cgi->data[k];
size_t ct_len = ds->key->used - 1;
-
+
if (ds->key->used == 0) continue;
if (s_len < ct_len) continue;
-
+
if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
if (cgi_create_env(srv, con, p, ds->value)) {
+ con->mode = DIRECT;
con->http_status = 500;
-
+
buffer_reset(con->physical.path);
return HANDLER_FINISHED;
}
@@ -1142,7 +1273,7 @@ URIHANDLER_FUNC(cgi_is_handled) {
break;
}
}
-
+
return HANDLER_GO_ON;
}
@@ -1154,7 +1285,7 @@ TRIGGER_FUNC(cgi_trigger) {
for (ndx = 0; ndx < p->cgi_pid.used; ndx++) {
int status;
-
+
switch(waitpid(p->cgi_pid.ptr[ndx], &status, WNOHANG)) {
case 0:
/* not finished yet */
@@ -1163,8 +1294,17 @@ TRIGGER_FUNC(cgi_trigger) {
#endif
break;
case -1:
+ if (errno == ECHILD) {
+ /* someone else called waitpid... remove the pid to stop looping the error each time */
+ log_error_write(srv, __FILE__, __LINE__, "s", "cgi child vanished, probably someone else called waitpid");
+
+ cgi_pid_del(srv, p, p->cgi_pid.ptr[ndx]);
+ ndx--;
+ continue;
+ }
+
log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
-
+
return HANDLER_ERROR;
default:
@@ -1172,35 +1312,52 @@ 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]);
- /* del modified the buffer structure
+ /* del modified the buffer structure
* and copies the last entry to the current one
* -> recheck the current index
*/
ndx--;
}
}
-#endif
+#endif
return HANDLER_GO_ON;
}
+/*
+ * - HANDLER_GO_ON : not our job
+ * - HANDLER_FINISHED: got response header
+ * - HANDLER_WAIT_FOR_EVENT: waiting for response header
+ */
SUBREQUEST_FUNC(mod_cgi_handle_subrequest) {
int status;
plugin_data *p = p_d;
handler_ctx *hctx = con->plugin_ctx[p->id];
-
+
if (con->mode != p->id) return HANDLER_GO_ON;
if (NULL == hctx) return HANDLER_GO_ON;
-
+
#if 0
log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", hctx, hctx->pid);
-#endif
- if (hctx->pid == 0) return HANDLER_FINISHED;
-#ifndef __WIN32
+#endif
+
+ if (hctx->pid == 0) {
+ /* cgi already dead */
+ if (!con->file_started) return HANDLER_WAIT_FOR_EVENT;
+ return HANDLER_FINISHED;
+ }
+
+#ifndef __WIN32
switch(waitpid(hctx->pid, &status, WNOHANG)) {
case 0:
/* we only have for events here if we don't have the header yet,
@@ -1210,61 +1367,61 @@ SUBREQUEST_FUNC(mod_cgi_handle_subrequest) {
return HANDLER_WAIT_FOR_EVENT;
case -1:
if (errno == EINTR) return HANDLER_WAIT_FOR_EVENT;
-
+
if (errno == ECHILD && con->file_started == 0) {
/*
- * second round but still not response
+ * second round but still not response
*/
- return HANDLER_WAIT_FOR_EVENT;
+ return HANDLER_WAIT_FOR_EVENT;
}
-
+
log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
con->mode = DIRECT;
con->http_status = 500;
-
+
hctx->pid = 0;
-
+
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
fdevent_unregister(srv->ev, hctx->fd);
-
+
if (close(hctx->fd)) {
log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
}
-
+
cgi_handler_ctx_free(hctx);
-
+
con->plugin_ctx[p->id] = NULL;
-
+
return HANDLER_FINISHED;
default:
- /* cgi process exited cleanly
- *
- * check if we already got the response
+ /* cgi process exited
*/
-
- if (!con->file_started) return HANDLER_WAIT_FOR_EVENT;
-
+
+ hctx->pid = 0;
+
+ /* we already have response headers? just continue */
+ if (con->file_started) return HANDLER_FINISHED;
+
if (WIFEXITED(status)) {
- /* nothing */
- } else {
- log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
-
- con->mode = DIRECT;
- con->http_status = 500;
-
+ /* clean exit - just continue */
+ return HANDLER_WAIT_FOR_EVENT;
}
-
- hctx->pid = 0;
-
+
+ /* cgi proc died, and we didn't get any data yet - send error message and close cgi con */
+ log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
+
+ con->http_status = 500;
+ con->mode = DIRECT;
+
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
fdevent_unregister(srv->ev, hctx->fd);
-
+
if (close(hctx->fd)) {
log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
}
-
+
cgi_handler_ctx_free(hctx);
-
+
con->plugin_ctx[p->id] = NULL;
return HANDLER_FINISHED;
}
@@ -1274,6 +1431,7 @@ SUBREQUEST_FUNC(mod_cgi_handle_subrequest) {
}
+int mod_cgi_plugin_init(plugin *p);
int mod_cgi_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("cgi");
@@ -1288,8 +1446,8 @@ int mod_cgi_plugin_init(plugin *p) {
p->init = mod_cgi_init;
p->cleanup = mod_cgi_free;
p->set_defaults = mod_fastcgi_set_defaults;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_cml.c b/src/mod_cml.c
index 0be9747..f83eb80 100644
--- a/src/mod_cml.c
+++ b/src/mod_cml.c
@@ -1,12 +1,3 @@
-#include <sys/stat.h>
-#include <time.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdio.h>
-
#include "buffer.h"
#include "server.h"
#include "log.h"
@@ -17,55 +8,62 @@
#include "mod_cml.h"
+#include <sys/stat.h>
+#include <time.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+
/* init the plugin data */
INIT_FUNC(mod_cml_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
p->basedir = buffer_init();
p->baseurl = buffer_init();
- p->session_id = buffer_init();
p->trigger_handler = buffer_init();
-
+
return p;
}
/* detroy the plugin data */
FREE_FUNC(mod_cml_free) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
-
+
buffer_free(s->ext);
-
+
buffer_free(s->mc_namespace);
buffer_free(s->power_magnet);
array_free(s->mc_hosts);
-
+
#if defined(HAVE_MEMCACHE_H)
if (s->mc) mc_free(s->mc);
#endif
-
+
free(s);
}
free(p->config_storage);
}
-
+
buffer_free(p->trigger_handler);
- buffer_free(p->session_id);
buffer_free(p->basedir);
buffer_free(p->baseurl);
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
@@ -74,22 +72,22 @@ FREE_FUNC(mod_cml_free) {
SETDEFAULTS_FUNC(mod_cml_set_defaults) {
plugin_data *p = p_d;
size_t i = 0;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "cml.extension", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ "cml.memcache-hosts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ "cml.memcache-namespace", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
{ "cml.power-magnet", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = malloc(srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = malloc(sizeof(plugin_config));
s->ext = buffer_init();
s->mc_hosts = array_init();
@@ -98,42 +96,42 @@ SETDEFAULTS_FUNC(mod_cml_set_defaults) {
#if defined(HAVE_MEMCACHE_H)
s->mc = NULL;
#endif
-
+
cv[0].destination = s->ext;
cv[1].destination = s->mc_hosts;
cv[2].destination = s->mc_namespace;
cv[3].destination = s->power_magnet;
-
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
-
+
if (s->mc_hosts->used) {
#if defined(HAVE_MEMCACHE_H)
size_t k;
s->mc = mc_new();
-
+
for (k = 0; k < s->mc_hosts->used; k++) {
data_string *ds = (data_string *)s->mc_hosts->data[k];
-
+
if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "connection to host failed:",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "connection to host failed:",
ds->value);
-
+
return HANDLER_ERROR;
}
}
#else
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"memcache support is not compiled in but cml.memcache-hosts is set, aborting");
return HANDLER_ERROR;
#endif
}
}
-
+
return HANDLER_GO_ON;
}
@@ -142,26 +140,26 @@ SETDEFAULTS_FUNC(mod_cml_set_defaults) {
static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(ext);
#if defined(HAVE_MEMCACHE_H)
PATCH(mc);
#endif
PATCH(mc_namespace);
PATCH(power_magnet);
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.extension"))) {
PATCH(ext);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-hosts"))) {
@@ -175,191 +173,68 @@ static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p
}
}
}
-
+
return 0;
}
#undef PATCH
-
-int cache_get_cookie_session_id(server *srv, connection *con, plugin_data *p) {
- data_unset *d;
-
- UNUSED(srv);
-
- if (NULL != (d = array_get_element(con->request.headers, "Cookie"))) {
- data_string *ds = (data_string *)d;
- size_t key = 0, value = 0;
- size_t is_key = 1, is_sid = 0;
- size_t i;
-
- /* found COOKIE */
- if (!DATA_IS_STRING(d)) return -1;
- if (ds->value->used == 0) return -1;
-
- if (ds->value->ptr[0] == '\0' ||
- ds->value->ptr[0] == '=' ||
- ds->value->ptr[0] == ';') return -1;
-
- buffer_reset(p->session_id);
- for (i = 0; i < ds->value->used; i++) {
- switch(ds->value->ptr[i]) {
- case '=':
- if (is_key) {
- if (0 == strncmp(ds->value->ptr + key, "PHPSESSID", i - key)) {
- /* found PHP-session-id-key */
- is_sid = 1;
- }
- value = i + 1;
-
- is_key = 0;
- }
-
- break;
- case ';':
- if (is_sid) {
- buffer_copy_string_len(p->session_id, ds->value->ptr + value, i - value);
- }
-
- is_sid = 0;
- key = i + 1;
- value = 0;
- is_key = 1;
- break;
- case ' ':
- if (is_key == 1 && key == i) key = i + 1;
- if (is_key == 0 && value == i) value = i + 1;
- break;
- case '\0':
- if (is_sid) {
- buffer_copy_string_len(p->session_id, ds->value->ptr + value, i - value);
- }
- /* fin */
- break;
- }
- }
- }
-
- return !buffer_is_empty(p->session_id);
-}
-
-int cache_get_url_session_id(server *srv, connection *con, plugin_data *p) {
- size_t key = 0, value = 0;
- size_t is_key = 1, is_sid = 0;
- size_t i;
-
- UNUSED(srv);
- buffer_reset(p->session_id);
- for (i = 0; i < con->uri.query->used; i++) {
- switch(con->uri.query->ptr[i]) {
- case '=':
- if (is_key) {
- if (0 == strncmp(con->uri.query->ptr + key, "PHPSESSID", i - key)) {
- /* found PHP-session-id-key */
- is_sid = 1;
- }
- value = i + 1;
-
- is_key = 0;
- }
-
- break;
- case '&':
- if (is_sid) {
- buffer_copy_string_len(p->session_id, con->uri.query->ptr + value, i - value);
- }
-
- is_sid = 0;
- key = i + 1;
- value = 0;
- is_key = 1;
- break;
- case ' ':
- if (is_key == 1 && key == i) key = i + 1;
- if (is_key == 0 && value == i) value = i + 1;
- break;
- case '\0':
- if (is_sid) {
- buffer_copy_string_len(p->session_id, con->uri.query->ptr + value, i - value);
- }
- /* fin */
- break;
- }
- }
-
- return !buffer_is_empty(p->session_id);
-}
-
-int cache_get_session_id(server *srv, connection *con, plugin_data *p) {
-
- return cache_get_cookie_session_id(srv, con, p) ||
- cache_get_url_session_id(srv, con, p);
-
-}
-
-int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) {
+static int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) {
buffer *b;
char *c;
- int ret;
/* cleanup basedir */
b = p->baseurl;
buffer_copy_string_buffer(b, con->uri.path);
for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
-
+
if (*c == '/') {
b->used = c - b->ptr + 2;
*(c+1) = '\0';
}
-
+
b = p->basedir;
buffer_copy_string_buffer(b, con->physical.path);
for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
-
+
if (*c == '/') {
b->used = c - b->ptr + 2;
*(c+1) = '\0';
}
-
+
/* prepare variables
- * - session-id
* - cookie-based
* - get-param-based
*/
-
- cache_get_session_id(srv, con, p);
-
return cache_parse_lua(srv, con, p, cml_file);
-
}
URIHANDLER_FUNC(mod_cml_power_magnet) {
plugin_data *p = p_d;
-
+
mod_cml_patch_connection(srv, con, p);
-
+
buffer_reset(p->basedir);
buffer_reset(p->baseurl);
- buffer_reset(p->session_id);
buffer_reset(p->trigger_handler);
if (buffer_is_empty(p->conf.power_magnet)) return HANDLER_GO_ON;
-
- /*
+
+ /*
* power-magnet:
* cml.power-magnet = server.docroot + "/rewrite.cml"
*
* is called on EACH request, take the original REQUEST_URI and modifies the
- * request header as neccesary.
+ * request header as neccesary.
*
* First use:
* if file_exists("/maintainance.html") {
* output_include = ( "/maintainance.html" )
- * return CACHE_HIT
+ * return CACHE_HIT
* }
*
* as we only want to rewrite HTML like requests we should cover it in a conditional
- *
+ *
* */
switch(cache_call_lua(srv, con, p, p->conf.power_magnet)) {
@@ -388,21 +263,20 @@ URIHANDLER_FUNC(mod_cml_power_magnet) {
URIHANDLER_FUNC(mod_cml_is_handled) {
plugin_data *p = p_d;
-
+
if (buffer_is_empty(con->physical.path)) return HANDLER_ERROR;
-
+
mod_cml_patch_connection(srv, con, p);
-
+
buffer_reset(p->basedir);
buffer_reset(p->baseurl);
- buffer_reset(p->session_id);
buffer_reset(p->trigger_handler);
if (buffer_is_empty(p->conf.ext)) return HANDLER_GO_ON;
-
+
if (!buffer_is_equal_right_len(con->physical.path, p->conf.ext, p->conf.ext->used - 1)) {
return HANDLER_GO_ON;
- }
+ }
switch(cache_call_lua(srv, con, p, con->physical.path)) {
case -1:
@@ -431,18 +305,19 @@ URIHANDLER_FUNC(mod_cml_is_handled) {
}
}
+int mod_cml_plugin_init(plugin *p);
int mod_cml_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("cache");
-
+
p->init = mod_cml_init;
p->cleanup = mod_cml_free;
p->set_defaults = mod_cml_set_defaults;
-
+
p->handle_subrequest_start = mod_cml_is_handled;
p->handle_physical = mod_cml_power_magnet;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_cml.h b/src/mod_cml.h
index a2e9df4..1afd708 100644
--- a/src/mod_cml.h
+++ b/src/mod_cml.h
@@ -16,10 +16,10 @@
typedef struct {
buffer *ext;
-
+
array *mc_hosts;
buffer *mc_namespace;
-#if defined(HAVE_MEMCACHE_H)
+#if defined(HAVE_MEMCACHE_H)
struct memcache *mc;
#endif
buffer *power_magnet;
@@ -27,17 +27,15 @@ typedef struct {
typedef struct {
PLUGIN_DATA;
-
+
buffer *basedir;
buffer *baseurl;
-
+
buffer *trigger_handler;
-
- buffer *session_id;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn);
diff --git a/src/mod_cml_funcs.c b/src/mod_cml_funcs.c
index 46a1f16..9d859c7 100644
--- a/src/mod_cml_funcs.c
+++ b/src/mod_cml_funcs.c
@@ -1,3 +1,12 @@
+#include "buffer.h"
+#include "server.h"
+#include "log.h"
+#include "plugin.h"
+#include "response.h"
+
+#include "mod_cml.h"
+#include "mod_cml_funcs.h"
+
#include <sys/stat.h>
#include <time.h>
@@ -8,20 +17,7 @@
#include <dirent.h>
#include <stdio.h>
-#include "buffer.h"
-#include "server.h"
-#include "log.h"
-#include "plugin.h"
-#include "response.h"
-
-#include "mod_cml.h"
-#include "mod_cml_funcs.h"
-
-#ifdef USE_OPENSSL
-# include <openssl/md5.h>
-#else
-# include "md5.h"
-#endif
+#include "md5.h"
#define HASHLEN 16
typedef unsigned char HASH[HASHLEN];
@@ -30,41 +26,41 @@ typedef char HASHHEX[HASHHEXLEN+1];
#ifdef USE_OPENSSL
#define IN const
#else
-#define IN
+#define IN
#endif
#define OUT
#ifdef HAVE_LUA_H
int f_crypto_md5(lua_State *L) {
- MD5_CTX Md5Ctx;
+ li_MD5_CTX Md5Ctx;
HASH HA1;
buffer b;
char hex[33];
int n = lua_gettop(L);
-
+
b.ptr = hex;
b.used = 0;
b.size = sizeof(hex);
-
+
if (n != 1) {
lua_pushstring(L, "md5: expected one argument");
lua_error(L);
}
-
+
if (!lua_isstring(L, 1)) {
lua_pushstring(L, "md5: argument has to be a string");
lua_error(L);
}
-
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)lua_tostring(L, 1), lua_strlen(L, 1));
- MD5_Final(HA1, &Md5Ctx);
-
+
+ li_MD5_Init(&Md5Ctx);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)lua_tostring(L, 1), lua_strlen(L, 1));
+ li_MD5_Final(HA1, &Md5Ctx);
+
buffer_copy_string_hex(&b, (char *)HA1, 16);
-
+
lua_pushstring(L, b.ptr);
-
+
return 1;
}
@@ -72,37 +68,37 @@ int f_crypto_md5(lua_State *L) {
int f_file_mtime(lua_State *L) {
struct stat st;
int n = lua_gettop(L);
-
+
if (n != 1) {
lua_pushstring(L, "file_mtime: expected one argument");
lua_error(L);
}
-
+
if (!lua_isstring(L, 1)) {
lua_pushstring(L, "file_mtime: argument has to be a string");
lua_error(L);
}
-
+
if (-1 == stat(lua_tostring(L, 1), &st)) {
lua_pushnil(L);
return 1;
}
-
+
lua_pushnumber(L, st.st_mtime);
-
+
return 1;
}
-int f_dir_files_iter(lua_State *L) {
+static int f_dir_files_iter(lua_State *L) {
DIR *d;
struct dirent *de;
-
+
d = lua_touserdata(L, lua_upvalueindex(1));
-
+
if (NULL == (de = readdir(d))) {
/* EOF */
closedir(d);
-
+
return 0;
} else {
lua_pushstring(L, de->d_name);
@@ -113,75 +109,75 @@ int f_dir_files_iter(lua_State *L) {
int f_dir_files(lua_State *L) {
DIR *d;
int n = lua_gettop(L);
-
+
if (n != 1) {
lua_pushstring(L, "dir_files: expected one argument");
lua_error(L);
}
-
+
if (!lua_isstring(L, 1)) {
lua_pushstring(L, "dir_files: argument has to be a string");
lua_error(L);
}
-
- /* check if there is a valid DIR handle on the stack */
+
+ /* check if there is a valid DIR handle on the stack */
if (NULL == (d = opendir(lua_tostring(L, 1)))) {
lua_pushnil(L);
return 1;
}
-
+
/* push d into registry */
lua_pushlightuserdata(L, d);
lua_pushcclosure(L, f_dir_files_iter, 1);
-
+
return 1;
}
int f_file_isreg(lua_State *L) {
struct stat st;
int n = lua_gettop(L);
-
+
if (n != 1) {
lua_pushstring(L, "file_isreg: expected one argument");
lua_error(L);
}
-
+
if (!lua_isstring(L, 1)) {
lua_pushstring(L, "file_isreg: argument has to be a string");
lua_error(L);
}
-
+
if (-1 == stat(lua_tostring(L, 1), &st)) {
lua_pushnil(L);
return 1;
}
-
+
lua_pushnumber(L, S_ISREG(st.st_mode));
-
+
return 1;
}
int f_file_isdir(lua_State *L) {
struct stat st;
int n = lua_gettop(L);
-
+
if (n != 1) {
lua_pushstring(L, "file_isreg: expected one argument");
lua_error(L);
}
-
+
if (!lua_isstring(L, 1)) {
lua_pushstring(L, "file_isreg: argument has to be a string");
lua_error(L);
}
-
+
if (-1 == stat(lua_tostring(L, 1), &st)) {
lua_pushnil(L);
return 1;
}
-
+
lua_pushnumber(L, S_ISDIR(st.st_mode));
-
+
return 1;
}
@@ -192,33 +188,33 @@ int f_memcache_exists(lua_State *L) {
char *r;
int n = lua_gettop(L);
struct memcache *mc;
-
+
if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
lua_pushstring(L, "where is my userdata ?");
lua_error(L);
}
-
+
mc = lua_touserdata(L, lua_upvalueindex(1));
-
+
if (n != 1) {
lua_pushstring(L, "expected one argument");
lua_error(L);
}
-
+
if (!lua_isstring(L, 1)) {
lua_pushstring(L, "argument has to be a string");
lua_error(L);
}
-
- if (NULL == (r = mc_aget(mc,
- lua_tostring(L, 1), lua_strlen(L, 1)))) {
-
+
+ if (NULL == (r = mc_aget(mc,
+ (char*) lua_tostring(L, 1), lua_strlen(L, 1)))) {
+
lua_pushboolean(L, 0);
return 1;
}
-
+
free(r);
-
+
lua_pushboolean(L, 1);
return 1;
}
@@ -226,74 +222,74 @@ int f_memcache_exists(lua_State *L) {
int f_memcache_get_string(lua_State *L) {
char *r;
int n = lua_gettop(L);
-
+
struct memcache *mc;
-
+
if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
lua_pushstring(L, "where is my userdata ?");
lua_error(L);
}
-
+
mc = lua_touserdata(L, lua_upvalueindex(1));
-
-
+
+
if (n != 1) {
lua_pushstring(L, "expected one argument");
lua_error(L);
}
-
+
if (!lua_isstring(L, 1)) {
lua_pushstring(L, "argument has to be a string");
lua_error(L);
}
-
- if (NULL == (r = mc_aget(mc,
- lua_tostring(L, 1), lua_strlen(L, 1)))) {
+
+ if (NULL == (r = mc_aget(mc,
+ (char*) lua_tostring(L, 1), lua_strlen(L, 1)))) {
lua_pushnil(L);
return 1;
}
-
+
lua_pushstring(L, r);
-
+
free(r);
-
+
return 1;
}
int f_memcache_get_long(lua_State *L) {
char *r;
int n = lua_gettop(L);
-
+
struct memcache *mc;
-
+
if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
lua_pushstring(L, "where is my userdata ?");
lua_error(L);
}
-
+
mc = lua_touserdata(L, lua_upvalueindex(1));
-
-
+
+
if (n != 1) {
lua_pushstring(L, "expected one argument");
lua_error(L);
}
-
+
if (!lua_isstring(L, 1)) {
lua_pushstring(L, "argument has to be a string");
lua_error(L);
}
-
- if (NULL == (r = mc_aget(mc,
- lua_tostring(L, 1), lua_strlen(L, 1)))) {
+
+ if (NULL == (r = mc_aget(mc,
+ (char*) lua_tostring(L, 1), lua_strlen(L, 1)))) {
lua_pushnil(L);
return 1;
}
-
+
lua_pushnumber(L, strtol(r, NULL, 10));
-
+
free(r);
-
+
return 1;
}
#endif
diff --git a/src/mod_cml_funcs.h b/src/mod_cml_funcs.h
index 42e067c..f0695d7 100644
--- a/src/mod_cml_funcs.h
+++ b/src/mod_cml_funcs.h
@@ -2,7 +2,7 @@
#define _MOD_CML_FUNCS_H_
#ifdef HAVE_CONFIG_H
-#include "config.h"
+# include "config.h"
#endif
#ifdef HAVE_LUA_H
diff --git a/src/mod_cml_lua.c b/src/mod_cml_lua.c
index 4e780e1..9f4e27a 100644
--- a/src/mod_cml_lua.c
+++ b/src/mod_cml_lua.c
@@ -1,8 +1,3 @@
-#include <assert.h>
-#include <stdio.h>
-#include <errno.h>
-#include <time.h>
-
#include "mod_cml.h"
#include "mod_cml_funcs.h"
#include "log.h"
@@ -10,11 +5,11 @@
#include "stat_cache.h"
-#ifdef USE_OPENSSL
-# include <openssl/md5.h>
-#else
-# include "md5.h"
-#endif
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <time.h>
+#include <string.h>
#define HASHLEN 16
typedef unsigned char HASH[HASHLEN];
@@ -23,7 +18,7 @@ typedef char HASHHEX[HASHHEXLEN+1];
#ifdef USE_OPENSSL
#define IN const
#else
-#define IN
+#define IN
#endif
#define OUT
@@ -31,6 +26,7 @@ typedef char HASHHEX[HASHHEXLEN+1];
#include <lua.h>
#include <lualib.h>
+#include <lauxlib.h>
typedef struct {
stream st;
@@ -39,11 +35,11 @@ typedef struct {
static const char * load_file(lua_State *L, void *data, size_t *size) {
readme *rm = data;
-
+
UNUSED(L);
-
+
if (rm->done) return 0;
-
+
*size = rm->st.size;
rm->done = 1;
return rm->st.start;
@@ -51,47 +47,47 @@ static const char * load_file(lua_State *L, void *data, size_t *size) {
static int lua_to_c_get_string(lua_State *L, const char *varname, buffer *b) {
int curelem;
-
+
lua_pushstring(L, varname);
-
+
curelem = lua_gettop(L);
lua_gettable(L, LUA_GLOBALSINDEX);
-
+
/* it should be a table */
if (!lua_isstring(L, curelem)) {
lua_settop(L, curelem - 1);
-
+
return -1;
}
-
+
buffer_copy_string(b, lua_tostring(L, curelem));
-
+
lua_pop(L, 1);
-
+
assert(curelem - 1 == lua_gettop(L));
-
+
return 0;
}
static int lua_to_c_is_table(lua_State *L, const char *varname) {
int curelem;
-
+
lua_pushstring(L, varname);
-
+
curelem = lua_gettop(L);
lua_gettable(L, LUA_GLOBALSINDEX);
-
+
/* it should be a table */
if (!lua_istable(L, curelem)) {
lua_settop(L, curelem - 1);
-
+
return 0;
}
-
+
lua_settop(L, curelem - 1);
-
+
assert(curelem - 1 == lua_gettop(L));
-
+
return 1;
}
@@ -99,88 +95,148 @@ static int c_to_lua_push(lua_State *L, int tbl, const char *key, size_t key_len,
lua_pushlstring(L, key, key_len);
lua_pushlstring(L, val, val_len);
lua_settable(L, tbl);
-
+
return 0;
}
-int split_query_string(lua_State *L, int tbl, buffer *qrystr) {
+static int cache_export_get_params(lua_State *L, int tbl, buffer *qrystr) {
size_t is_key = 1;
size_t i;
char *key = NULL, *val = NULL;
-
+
key = qrystr->ptr;
-
+
/* we need the \0 */
for (i = 0; i < qrystr->used; i++) {
switch(qrystr->ptr[i]) {
case '=':
if (is_key) {
val = qrystr->ptr + i + 1;
-
+
qrystr->ptr[i] = '\0';
-
+
is_key = 0;
}
-
+
break;
case '&':
case '\0': /* fin symbol */
if (!is_key) {
/* we need at least a = since the last & */
-
- c_to_lua_push(L, tbl,
+
+ /* terminate the value */
+ qrystr->ptr[i] = '\0';
+
+ c_to_lua_push(L, tbl,
key, strlen(key),
val, strlen(val));
}
-
+
key = qrystr->ptr + i + 1;
val = NULL;
is_key = 1;
break;
}
}
-
+
return 0;
}
+#if 0
+int cache_export_cookie_params(server *srv, connection *con, plugin_data *p) {
+ data_unset *d;
+
+ UNUSED(srv);
+
+ if (NULL != (d = array_get_element(con->request.headers, "Cookie"))) {
+ data_string *ds = (data_string *)d;
+ size_t key = 0, value = 0;
+ size_t is_key = 1, is_sid = 0;
+ size_t i;
+
+ /* found COOKIE */
+ if (!DATA_IS_STRING(d)) return -1;
+ if (ds->value->used == 0) return -1;
+
+ if (ds->value->ptr[0] == '\0' ||
+ ds->value->ptr[0] == '=' ||
+ ds->value->ptr[0] == ';') return -1;
+
+ buffer_reset(p->session_id);
+ for (i = 0; i < ds->value->used; i++) {
+ switch(ds->value->ptr[i]) {
+ case '=':
+ if (is_key) {
+ if (0 == strncmp(ds->value->ptr + key, "PHPSESSID", i - key)) {
+ /* found PHP-session-id-key */
+ is_sid = 1;
+ }
+ value = i + 1;
+
+ is_key = 0;
+ }
+
+ break;
+ case ';':
+ if (is_sid) {
+ buffer_copy_string_len(p->session_id, ds->value->ptr + value, i - value);
+ }
+
+ is_sid = 0;
+ key = i + 1;
+ value = 0;
+ is_key = 1;
+ break;
+ case ' ':
+ if (is_key == 1 && key == i) key = i + 1;
+ if (is_key == 0 && value == i) value = i + 1;
+ break;
+ case '\0':
+ if (is_sid) {
+ buffer_copy_string_len(p->session_id, ds->value->ptr + value, i - value);
+ }
+ /* fin */
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+#endif
int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
- lua_State *L;
+ lua_State *L;
readme rm;
int ret = -1;
buffer *b = buffer_init();
int header_tbl = 0;
-
+
rm.done = 0;
stream_open(&rm.st, fn);
-
+
/* push the lua file to the interpreter and see what happends */
- L = lua_open();
-
- luaopen_base(L);
- luaopen_table(L);
- luaopen_string(L);
- luaopen_math(L);
- luaopen_io(L);
-
+ L = luaL_newstate();
+ luaL_openlibs(L);
+
/* register functions */
lua_register(L, "md5", f_crypto_md5);
lua_register(L, "file_mtime", f_file_mtime);
lua_register(L, "file_isreg", f_file_isreg);
lua_register(L, "file_isdir", f_file_isreg);
lua_register(L, "dir_files", f_dir_files);
-
+
#ifdef HAVE_MEMCACHE_H
lua_pushliteral(L, "memcache_get_long");
lua_pushlightuserdata(L, p->conf.mc);
lua_pushcclosure(L, f_memcache_get_long, 1);
lua_settable(L, LUA_GLOBALSINDEX);
-
+
lua_pushliteral(L, "memcache_get_string");
lua_pushlightuserdata(L, p->conf.mc);
lua_pushcclosure(L, f_memcache_get_string, 1);
lua_settable(L, LUA_GLOBALSINDEX);
-
+
lua_pushliteral(L, "memcache_exists");
lua_pushlightuserdata(L, p->conf.mc);
lua_pushcclosure(L, f_memcache_exists, 1);
@@ -190,11 +246,11 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
lua_pushliteral(L, "request");
lua_newtable(L);
lua_settable(L, LUA_GLOBALSINDEX);
-
+
lua_pushliteral(L, "request");
header_tbl = lua_gettop(L);
lua_gettable(L, LUA_GLOBALSINDEX);
-
+
c_to_lua_push(L, header_tbl, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
@@ -202,84 +258,84 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
if (!buffer_is_empty(con->request.pathinfo)) {
c_to_lua_push(L, header_tbl, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
}
-
+
c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(p->basedir));
c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(p->baseurl));
-
+
/* register GET parameter */
lua_pushliteral(L, "get");
lua_newtable(L);
lua_settable(L, LUA_GLOBALSINDEX);
-
+
lua_pushliteral(L, "get");
header_tbl = lua_gettop(L);
lua_gettable(L, LUA_GLOBALSINDEX);
-
-
+
buffer_copy_string_buffer(b, con->uri.query);
- split_query_string(L, header_tbl, b);
+ cache_export_get_params(L, header_tbl, b);
buffer_reset(b);
-
+
+ /* 2 default constants */
lua_pushliteral(L, "CACHE_HIT");
lua_pushnumber(L, 0);
lua_settable(L, LUA_GLOBALSINDEX);
-
+
lua_pushliteral(L, "CACHE_MISS");
lua_pushnumber(L, 1);
lua_settable(L, LUA_GLOBALSINDEX);
-
+
/* load lua program */
if (lua_load(L, load_file, &rm, fn->ptr) || lua_pcall(L,0,1,0)) {
log_error_write(srv, __FILE__, __LINE__, "s",
lua_tostring(L,-1));
-
+
goto error;
}
-
+
/* get return value */
ret = (int)lua_tonumber(L, -1);
lua_pop(L, 1);
-
- /* fetch the data from lua */
+
+ /* fetch the data from lua */
lua_to_c_get_string(L, "trigger_handler", p->trigger_handler);
-
+
if (0 == lua_to_c_get_string(L, "output_contenttype", b)) {
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(b));
}
-
+
if (ret == 0) {
/* up to now it is a cache-hit, check if all files exist */
-
+
int curelem;
time_t mtime = 0;
-
+
if (!lua_to_c_is_table(L, "output_include")) {
log_error_write(srv, __FILE__, __LINE__, "s",
"output_include is missing or not a table");
ret = -1;
-
+
goto error;
}
-
+
lua_pushstring(L, "output_include");
-
+
curelem = lua_gettop(L);
lua_gettable(L, LUA_GLOBALSINDEX);
/* HOW-TO build a etag ?
- * as we don't just have one file we have to take the stat()
+ * as we don't just have one file we have to take the stat()
* from all base files, merge them and build the etag from
* it later.
- *
+ *
* The mtime of the content is the mtime of the freshest base file
- *
+ *
* */
-
+
lua_pushnil(L); /* first key */
while (lua_next(L, curelem) != 0) {
stat_cache_entry *sce = NULL;
/* key' is at index -2 and value' at index -1 */
-
+
if (lua_isstring(L, -1)) {
const char *s = lua_tostring(L, -1);
@@ -299,18 +355,18 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
/* a file is missing, call the handler to generate it */
if (!buffer_is_empty(p->trigger_handler)) {
ret = 1; /* cache-miss */
-
+
log_error_write(srv, __FILE__, __LINE__, "s",
"a file is missing, calling handler");
-
+
break;
} else {
/* handler not set -> 500 */
ret = -1;
-
+
log_error_write(srv, __FILE__, __LINE__, "s",
"a file missing and no handler set");
-
+
break;
}
break;
@@ -328,12 +384,12 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
"not a string");
break;
}
-
+
lua_pop(L, 1); /* removes value'; keeps key' for next iteration */
}
-
+
lua_settop(L, curelem - 1);
-
+
if (ret == 0) {
data_string *ds;
char timebuf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
@@ -345,9 +401,9 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
/* no Last-Modified specified */
if ((mtime) && (NULL == ds)) {
-
+
strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime));
-
+
response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), timebuf, sizeof(timebuf) - 1);
@@ -363,9 +419,9 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
tbuf.used = 0;
tbuf.ptr = NULL;
}
-
+
if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, &tbuf)) {
- /* ok, the client already has our content,
+ /* ok, the client already has our content,
* no need to send it again */
chunkqueue_reset(con->write_queue);
@@ -375,28 +431,32 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
chunkqueue_reset(con->write_queue);
}
}
-
+
if (ret == 1 && !buffer_is_empty(p->trigger_handler)) {
/* cache-miss */
buffer_copy_string_buffer(con->uri.path, p->baseurl);
buffer_append_string_buffer(con->uri.path, p->trigger_handler);
-
+
buffer_copy_string_buffer(con->physical.path, p->basedir);
buffer_append_string_buffer(con->physical.path, p->trigger_handler);
-
+
chunkqueue_reset(con->write_queue);
}
-
+
error:
lua_close(L);
-
+
stream_close(&rm.st);
buffer_free(b);
-
+
return ret /* cache-error */;
}
#else
int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
+ UNUSED(srv);
+ UNUSED(con);
+ UNUSED(p);
+ UNUSED(fn);
/* error */
return -1;
}
diff --git a/src/mod_compress.c b/src/mod_compress.c
index fc78220..e4f53da 100644
--- a/src/mod_compress.c
+++ b/src/mod_compress.c
@@ -1,14 +1,3 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <fcntl.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-
#include "base.h"
#include "log.h"
#include "buffer.h"
@@ -20,6 +9,17 @@
#include "crc32.h"
#include "etag.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
#if defined HAVE_ZLIB_H && defined HAVE_LIBZ
# define USE_ZLIB
# include <zlib.h>
@@ -40,112 +40,202 @@
#define HTTP_ACCEPT_ENCODING_DEFLATE BV(2)
#define HTTP_ACCEPT_ENCODING_COMPRESS BV(3)
#define HTTP_ACCEPT_ENCODING_BZIP2 BV(4)
+#define HTTP_ACCEPT_ENCODING_X_GZIP BV(5)
+#define HTTP_ACCEPT_ENCODING_X_BZIP2 BV(6)
#ifdef __WIN32
-#define mkdir(x,y) mkdir(x)
+# define mkdir(x,y) mkdir(x)
#endif
typedef struct {
buffer *compress_cache_dir;
array *compress;
off_t compress_max_filesize; /** max filesize in kb */
+ int allowed_encodings;
} plugin_config;
typedef struct {
PLUGIN_DATA;
buffer *ofn;
buffer *b;
-
+
plugin_config **config_storage;
- plugin_config conf;
+ plugin_config conf;
} plugin_data;
INIT_FUNC(mod_compress_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
p->ofn = buffer_init();
p->b = buffer_init();
-
+
return p;
}
FREE_FUNC(mod_compress_free) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
-
+
buffer_free(p->ofn);
buffer_free(p->b);
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
if (!s) continue;
-
+
array_free(s->compress);
buffer_free(s->compress_cache_dir);
-
+
free(s);
}
free(p->config_storage);
}
-
-
+
+
free(p);
-
+
return HANDLER_GO_ON;
}
+/* 0 on success, -1 for error */
+static 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 */
+static 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;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "compress.cache-dir", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "compress.filetype", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
{ "compress.max-filesize", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
+ { "compress.allowed-encodings", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+ array *encodings_arr = array_init();
+
s = calloc(1, sizeof(plugin_config));
s->compress_cache_dir = buffer_init();
s->compress = array_init();
s->compress_max_filesize = 0;
-
+ s->allowed_encodings = 0;
+
cv[0].destination = s->compress_cache_dir;
cv[1].destination = s->compress;
cv[2].destination = &(s->compress_max_filesize);
-
+ cv[3].destination = encodings_arr; /* temp array for allowed encodings list */
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
-
+
+ if (encodings_arr->used) {
+ size_t j = 0;
+ for (j = 0; j < encodings_arr->used; j++) {
+ data_string *ds = (data_string *)encodings_arr->data[j];
+#ifdef USE_ZLIB
+ if (NULL != strstr(ds->value->ptr, "gzip"))
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_GZIP | HTTP_ACCEPT_ENCODING_X_GZIP;
+ if (NULL != strstr(ds->value->ptr, "x-gzip"))
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_X_GZIP;
+ if (NULL != strstr(ds->value->ptr, "deflate"))
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
+ /*
+ if (NULL != strstr(ds->value->ptr, "compress"))
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_COMPRESS;
+ */
+#endif
+#ifdef USE_BZ2LIB
+ if (NULL != strstr(ds->value->ptr, "bzip2"))
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_BZIP2 | HTTP_ACCEPT_ENCODING_X_BZIP2;
+ if (NULL != strstr(ds->value->ptr, "x-bzip2"))
+ s->allowed_encodings |= HTTP_ACCEPT_ENCODING_X_BZIP2;
+#endif
+ }
+ } else {
+ /* default encodings */
+ s->allowed_encodings = 0
+#ifdef USE_ZLIB
+ | HTTP_ACCEPT_ENCODING_GZIP | HTTP_ACCEPT_ENCODING_X_GZIP | HTTP_ACCEPT_ENCODING_DEFLATE
+#endif
+#ifdef USE_BZ2LIB
+ | HTTP_ACCEPT_ENCODING_BZIP2 | HTTP_ACCEPT_ENCODING_X_BZIP2
+#endif
+ ;
+ }
+
+ array_free(encodings_arr);
+
if (!buffer_is_empty(s->compress_cache_dir)) {
struct stat st;
+ mkdir_recursive(s->compress_cache_dir->ptr);
+
if (0 != stat(s->compress_cache_dir->ptr, &st)) {
- log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir",
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir",
s->compress_cache_dir, strerror(errno));
-
+
return HANDLER_ERROR;
}
}
}
-
+
return HANDLER_GO_ON;
-
+
}
#ifdef USE_ZLIB
@@ -153,32 +243,32 @@ static int deflate_file_to_buffer_gzip(server *srv, connection *con, plugin_data
unsigned char *c;
unsigned long crc;
z_stream z;
-
+
UNUSED(srv);
UNUSED(con);
z.zalloc = Z_NULL;
z.zfree = Z_NULL;
z.opaque = Z_NULL;
-
- if (Z_OK != deflateInit2(&z,
+
+ if (Z_OK != deflateInit2(&z,
Z_DEFAULT_COMPRESSION,
- Z_DEFLATED,
+ Z_DEFLATED,
-MAX_WBITS, /* supress zlib-header */
8,
Z_DEFAULT_STRATEGY)) {
return -1;
}
-
+
z.next_in = (unsigned char *)start;
z.avail_in = st_size;
z.total_in = 0;
-
-
+
+
buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12 + 18);
-
+
/* write gzip header */
-
+
c = (unsigned char *)p->b->ptr;
c[0] = 0x1f;
c[1] = 0x8b;
@@ -190,24 +280,24 @@ static int deflate_file_to_buffer_gzip(server *srv, connection *con, plugin_data
c[7] = (mtime >> 24) & 0xff;
c[8] = 0x00; /* extra flags */
c[9] = 0x03; /* UNIX */
-
+
p->b->used = 10;
z.next_out = (unsigned char *)p->b->ptr + p->b->used;
z.avail_out = p->b->size - p->b->used - 8;
z.total_out = 0;
-
+
if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
deflateEnd(&z);
return -1;
}
-
+
/* trailer */
p->b->used += z.total_out;
-
+
crc = generate_crc32c(start, st_size);
-
+
c = (unsigned char *)p->b->ptr + p->b->used;
-
+
c[0] = (crc >> 0) & 0xff;
c[1] = (crc >> 8) & 0xff;
c[2] = (crc >> 16) & 0xff;
@@ -221,51 +311,51 @@ static int deflate_file_to_buffer_gzip(server *srv, connection *con, plugin_data
if (Z_OK != deflateEnd(&z)) {
return -1;
}
-
+
return 0;
}
static int deflate_file_to_buffer_deflate(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
z_stream z;
-
+
UNUSED(srv);
UNUSED(con);
z.zalloc = Z_NULL;
z.zfree = Z_NULL;
z.opaque = Z_NULL;
-
- if (Z_OK != deflateInit2(&z,
+
+ if (Z_OK != deflateInit2(&z,
Z_DEFAULT_COMPRESSION,
- Z_DEFLATED,
+ Z_DEFLATED,
-MAX_WBITS, /* supress zlib-header */
8,
Z_DEFAULT_STRATEGY)) {
return -1;
}
-
+
z.next_in = start;
z.avail_in = st_size;
z.total_in = 0;
-
+
buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12);
-
+
z.next_out = (unsigned char *)p->b->ptr;
z.avail_out = p->b->size;
z.total_out = 0;
-
+
if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
deflateEnd(&z);
return -1;
}
-
+
/* trailer */
p->b->used += z.total_out;
-
+
if (Z_OK != deflateEnd(&z)) {
return -1;
}
-
+
return 0;
}
@@ -274,48 +364,48 @@ static int deflate_file_to_buffer_deflate(server *srv, connection *con, plugin_d
#ifdef USE_BZ2LIB
static int deflate_file_to_buffer_bzip2(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
bz_stream bz;
-
+
UNUSED(srv);
UNUSED(con);
bz.bzalloc = NULL;
bz.bzfree = NULL;
bz.opaque = NULL;
-
- if (BZ_OK != BZ2_bzCompressInit(&bz,
+
+ if (BZ_OK != BZ2_bzCompressInit(&bz,
9, /* blocksize = 900k */
0, /* no output */
0)) { /* workFactor: default */
return -1;
}
-
+
bz.next_in = (char *)start;
bz.avail_in = st_size;
bz.total_in_lo32 = 0;
bz.total_in_hi32 = 0;
-
+
buffer_prepare_copy(p->b, (bz.avail_in * 1.1) + 12);
-
+
bz.next_out = p->b->ptr;
bz.avail_out = p->b->size;
bz.total_out_lo32 = 0;
bz.total_out_hi32 = 0;
-
+
if (BZ_STREAM_END != BZ2_bzCompress(&bz, BZ_FINISH)) {
BZ2_bzCompressEnd(&bz);
return -1;
}
-
+
/* file is too large for now */
if (bz.total_out_hi32) return -1;
-
+
/* trailer */
p->b->used = bz.total_out_lo32;
-
+
if (BZ_OK != BZ2_bzCompressEnd(&bz)) {
return -1;
}
-
+
return 0;
}
#endif
@@ -326,64 +416,52 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
void *start;
const char *filename = fn->ptr;
ssize_t r;
-
+
/* overflow */
if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
-
- /* don't mmap files > 128Mb
- *
+
+ /* don't mmap files > 128Mb
+ *
* we could use a sliding window, but currently there is no need for it
*/
-
+
if (sce->st.st_size > 128 * 1024 * 1024) return -1;
-
+
buffer_reset(p->ofn);
buffer_copy_string_buffer(p->ofn, p->conf.compress_cache_dir);
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);
}
-
+
switch(type) {
case HTTP_ACCEPT_ENCODING_GZIP:
- buffer_append_string(p->ofn, "-gzip-");
+ case HTTP_ACCEPT_ENCODING_X_GZIP:
+ buffer_append_string_len(p->ofn, CONST_STR_LEN("-gzip-"));
break;
case HTTP_ACCEPT_ENCODING_DEFLATE:
- buffer_append_string(p->ofn, "-deflate-");
+ buffer_append_string_len(p->ofn, CONST_STR_LEN("-deflate-"));
break;
case HTTP_ACCEPT_ENCODING_BZIP2:
- buffer_append_string(p->ofn, "-bzip2-");
+ case HTTP_ACCEPT_ENCODING_X_BZIP2:
+ buffer_append_string_len(p->ofn, CONST_STR_LEN("-bzip2-"));
break;
default:
log_error_write(srv, __FILE__, __LINE__, "sd", "unknown compression type", type);
return -1;
}
-
+
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 */
@@ -391,45 +469,75 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache hit");
#endif
buffer_copy_string_buffer(con->physical.path, p->ofn);
-
+
return 0;
}
-
+
log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cachefile", p->ofn, "failed", strerror(errno));
-
+
return -1;
}
#if 0
log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache miss");
-#endif
+#endif
if (-1 == (ifd = open(filename, O_RDONLY | O_BINARY))) {
log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
-
+
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;
}
-
-
+
+#ifdef USE_MMAP
if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
-
+
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;
}
-
+#else
+ start = malloc(sce->st.st_size);
+ if (NULL == start || sce->st.st_size != read(ifd, start, sce->st.st_size)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "reading", fn, "failed", strerror(errno));
+
+ close(ofd);
+ close(ifd);
+ free(start);
+
+ /* 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;
+ }
+#endif
+
switch(type) {
#ifdef USE_ZLIB
- case HTTP_ACCEPT_ENCODING_GZIP:
+ case HTTP_ACCEPT_ENCODING_GZIP:
+ case HTTP_ACCEPT_ENCODING_X_GZIP:
ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
break;
- case HTTP_ACCEPT_ENCODING_DEFLATE:
+ case HTTP_ACCEPT_ENCODING_DEFLATE:
ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
break;
#endif
#ifdef USE_BZ2LIB
- case HTTP_ACCEPT_ENCODING_BZIP2:
+ case HTTP_ACCEPT_ENCODING_BZIP2:
+ case HTTP_ACCEPT_ENCODING_X_BZIP2:
ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
break;
#endif
@@ -437,26 +545,38 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
ret = -1;
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;
+ }
}
-
+
+#ifdef USE_MMAP
munmap(start, sce->st.st_size);
+#else
+ free(start);
+#endif
+
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);
-
+
return 0;
}
@@ -465,43 +585,55 @@ static int deflate_file_to_buffer(server *srv, connection *con, plugin_data *p,
int ret = -1;
void *start;
buffer *b;
-
+
/* overflow */
if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
-
+
/* don't mmap files > 128M
- *
+ *
* we could use a sliding window, but currently there is no need for it
*/
-
+
if (sce->st.st_size > 128 * 1024 * 1024) return -1;
-
-
+
+
if (-1 == (ifd = open(fn->ptr, O_RDONLY | O_BINARY))) {
log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
-
+
return -1;
}
-
-
+
+#ifdef USE_MMAP
if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
-
+
+ close(ifd);
+ return -1;
+ }
+#else
+ start = malloc(sce->st.st_size);
+ if (NULL == start || sce->st.st_size != read(ifd, start, sce->st.st_size)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbss", "reading", fn, "failed", strerror(errno));
+
close(ifd);
+ free(start);
return -1;
}
-
+#endif
+
switch(type) {
#ifdef USE_ZLIB
- case HTTP_ACCEPT_ENCODING_GZIP:
+ case HTTP_ACCEPT_ENCODING_GZIP:
+ case HTTP_ACCEPT_ENCODING_X_GZIP:
ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
break;
- case HTTP_ACCEPT_ENCODING_DEFLATE:
+ case HTTP_ACCEPT_ENCODING_DEFLATE:
ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
break;
#endif
#ifdef USE_BZ2LIB
- case HTTP_ACCEPT_ENCODING_BZIP2:
+ case HTTP_ACCEPT_ENCODING_BZIP2:
+ case HTTP_ACCEPT_ENCODING_X_BZIP2:
ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
break;
#endif
@@ -509,21 +641,25 @@ static int deflate_file_to_buffer(server *srv, connection *con, plugin_data *p,
ret = -1;
break;
}
-
+
+#ifdef USE_MMAP
munmap(start, sce->st.st_size);
+#else
+ free(start);
+#endif
close(ifd);
-
+
if (ret != 0) return -1;
-
+
chunkqueue_reset(con->write_queue);
b = chunkqueue_get_append_buffer(con->write_queue);
buffer_copy_memory(b, p->b->ptr, p->b->used + 1);
-
+
buffer_reset(con->physical.path);
-
+
con->file_finished = 1;
con->file_started = 1;
-
+
return 0;
}
@@ -537,41 +673,62 @@ static int mod_compress_patch_connection(server *srv, connection *con, plugin_da
PATCH(compress_cache_dir);
PATCH(compress);
PATCH(compress_max_filesize);
-
+ PATCH(allowed_encodings);
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.cache-dir"))) {
PATCH(compress_cache_dir);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.filetype"))) {
PATCH(compress);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.max-filesize"))) {
PATCH(compress_max_filesize);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.allowed-encodings"))) {
+ PATCH(allowed_encodings);
}
}
}
-
+
return 0;
}
#undef PATCH
+static int mod_compress_contains_encoding(const char *headervalue, const char *encoding) {
+ const char *m;
+ for ( ;; ) {
+ m = strstr(headervalue, encoding);
+ if (NULL == m) return 0;
+ if (m == headervalue || m[-1] == ' ' || m[-1] == ',') return 1;
+
+ /* only partial match, search for next value */
+ m = strchr(m, ',');
+ if (NULL == m) return 0;
+ headervalue = m + 1;
+ }
+}
+
PHYSICALPATH_FUNC(mod_compress_physical) {
plugin_data *p = p_d;
size_t m;
off_t max_fsize;
stat_cache_entry *sce = NULL;
-
+ buffer *mtime = NULL;
+ buffer *content_type;
+
+ 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 &&
+ if (con->request.http_method != HTTP_METHOD_GET &&
con->request.http_method != HTTP_METHOD_POST) {
return HANDLER_GO_ON;
}
@@ -579,123 +736,188 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
if (buffer_is_empty(con->physical.path)) {
return HANDLER_GO_ON;
}
-
+
mod_compress_patch_connection(srv, con, p);
-
+
max_fsize = p->conf.compress_max_filesize;
- stat_cache_get_entry(srv, con, con->physical.path, &sce);
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- handling file as static file");
+ }
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+ con->http_status = 403;
+
+ log_error_write(srv, __FILE__, __LINE__, "sbsb",
+ "not a regular file:", con->uri.path,
+ "->", con->physical.path);
+
+ return HANDLER_FINISHED;
+ }
+
+ /* we only handle regular files */
+#ifdef HAVE_LSTAT
+ if ((sce->is_symlink == 1) && !con->conf.follow_symlink) {
+ return HANDLER_GO_ON;
+ }
+#endif
+ if (!S_ISREG(sce->st.st_mode)) {
+ return HANDLER_GO_ON;
+ }
/* don't compress files that are too large as we need to much time to handle them */
if (max_fsize && (sce->st.st_size >> 10) > max_fsize) return HANDLER_GO_ON;
-
+
+ /* don't try to compress files less than 128 bytes
+ *
+ * - extra overhead for compression
+ * - mmap() fails for st_size = 0 :)
+ */
+ if (sce->st.st_size < 128) return HANDLER_GO_ON;
+
/* check if mimetype is in compress-config */
+ content_type = NULL;
+ if (sce->content_type->ptr) {
+ char *c;
+ if ( (c = strchr(sce->content_type->ptr, ';')) != NULL) {
+ content_type = srv->tmp_buf;
+ buffer_copy_string_len(content_type, sce->content_type->ptr, c - sce->content_type->ptr);
+ }
+ }
+
for (m = 0; m < p->conf.compress->used; m++) {
data_string *compress_ds = (data_string *)p->conf.compress->data[m];
-
+
if (!compress_ds) {
log_error_write(srv, __FILE__, __LINE__, "sbb", "evil", con->physical.path, con->uri.path);
-
+
return HANDLER_GO_ON;
}
-
- if (buffer_is_equal(compress_ds->value, sce->content_type)) {
+
+ if (buffer_is_equal(compress_ds->value, sce->content_type)
+ || (content_type && buffer_is_equal(compress_ds->value, content_type))) {
/* mimetype found */
data_string *ds;
-
+
/* the response might change according to Accept-Encoding */
response_header_insert(srv, con, CONST_STR_LEN("Vary"), CONST_STR_LEN("Accept-Encoding"));
-
+
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Accept-Encoding"))) {
int accept_encoding = 0;
char *value = ds->value->ptr;
- int srv_encodings = 0;
int matched_encodings = 0;
-
+ int use_etag = sce->etag != NULL && sce->etag->ptr != NULL;
+
/* get client side support encodings */
- if (NULL != strstr(value, "gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP;
- if (NULL != strstr(value, "deflate")) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE;
- if (NULL != strstr(value, "compress")) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS;
- if (NULL != strstr(value, "bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2;
- if (NULL != strstr(value, "identity")) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY;
-
- /* get server side supported ones */
-#ifdef USE_BZ2LIB
- srv_encodings |= HTTP_ACCEPT_ENCODING_BZIP2;
-#endif
#ifdef USE_ZLIB
- srv_encodings |= HTTP_ACCEPT_ENCODING_GZIP;
- srv_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
+ if (mod_compress_contains_encoding(value, "gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP;
+ if (mod_compress_contains_encoding(value, "x-gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_X_GZIP;
+ if (mod_compress_contains_encoding(value, "deflate")) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE;
+ if (mod_compress_contains_encoding(value, "compress")) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS;
#endif
-
+#ifdef USE_BZ2LIB
+ if (mod_compress_contains_encoding(value, "bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2;
+ if (mod_compress_contains_encoding(value, "x-bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_X_BZIP2;
+#endif
+ if (mod_compress_contains_encoding(value, "identity")) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY;
+
/* find matching entries */
- matched_encodings = accept_encoding & srv_encodings;
-
+ matched_encodings = accept_encoding & p->conf.allowed_encodings;
+
if (matched_encodings) {
- const char *dflt_gzip = "gzip";
- const char *dflt_deflate = "deflate";
- const char *dflt_bzip2 = "bzip2";
-
+ static const char dflt_gzip[] = "gzip";
+ static const char dflt_x_gzip[] = "x-gzip";
+ static const char dflt_deflate[] = "deflate";
+ static const char dflt_bzip2[] = "bzip2";
+ static const char dflt_x_bzip2[] = "x-bzip2";
+
const char *compression_name = NULL;
int compression_type = 0;
-
+
+ mtime = strftime_cache_get(srv, sce->st.st_mtime);
+
+ /* try matching original etag of uncompressed version */
+ if (use_etag) {
+ etag_mutate(con->physical.etag, sce->etag);
+ if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
+ response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
+ response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
+ return HANDLER_FINISHED;
+ }
+ }
+
/* select best matching encoding */
if (matched_encodings & HTTP_ACCEPT_ENCODING_BZIP2) {
compression_type = HTTP_ACCEPT_ENCODING_BZIP2;
compression_name = dflt_bzip2;
+ } else if (matched_encodings & HTTP_ACCEPT_ENCODING_X_BZIP2) {
+ compression_type = HTTP_ACCEPT_ENCODING_X_BZIP2;
+ compression_name = dflt_x_bzip2;
} else if (matched_encodings & HTTP_ACCEPT_ENCODING_GZIP) {
compression_type = HTTP_ACCEPT_ENCODING_GZIP;
compression_name = dflt_gzip;
+ } else if (matched_encodings & HTTP_ACCEPT_ENCODING_X_GZIP) {
+ compression_type = HTTP_ACCEPT_ENCODING_X_GZIP;
+ compression_name = dflt_x_gzip;
} else if (matched_encodings & HTTP_ACCEPT_ENCODING_DEFLATE) {
compression_type = HTTP_ACCEPT_ENCODING_DEFLATE;
compression_name = dflt_deflate;
}
-
- /* deflate it */
- if (p->conf.compress_cache_dir->used) {
- if (0 == deflate_file_to_file(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));
+ if (use_etag) {
+ /* try matching etag of compressed version */
+ buffer_copy_string_buffer(srv->tmp_buf, sce->etag);
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("-"));
+ buffer_append_string(srv->tmp_buf, compression_name);
+ etag_mutate(con->physical.etag, srv->tmp_buf);
+ }
- return HANDLER_GO_ON;
- }
- } else if (0 == deflate_file_to_buffer(srv, con, p,
- con->physical.path, sce, compression_type)) {
-
+ if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
-
+ response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
+ if (use_etag) {
+ response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
+ }
return HANDLER_FINISHED;
}
- break;
+
+ /* deflate it */
+ if (use_etag && p->conf.compress_cache_dir->used) {
+ if (0 != deflate_file_to_file(srv, con, p, con->physical.path, sce, compression_type))
+ return HANDLER_GO_ON;
+ } else {
+ if (0 != deflate_file_to_buffer(srv, con, p, con->physical.path, sce, compression_type))
+ return HANDLER_GO_ON;
+ }
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
+ response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
+ if (use_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));
+ /* let mod_staticfile handle the cached compressed files, physical path was modified */
+ return (use_etag && p->conf.compress_cache_dir->used) ? HANDLER_GO_ON : HANDLER_FINISHED;
}
}
}
}
-
+
return HANDLER_GO_ON;
}
+int mod_compress_plugin_init(plugin *p);
int mod_compress_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("compress");
-
+
p->init = mod_compress_init;
p->set_defaults = mod_compress_setdefaults;
p->handle_subrequest_start = mod_compress_physical;
p->cleanup = mod_compress_free;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c
index 69eb1e9..cd317ec 100644
--- a/src/mod_dirlisting.c
+++ b/src/mod_dirlisting.c
@@ -1,13 +1,3 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dirent.h>
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <time.h>
-
#include "base.h"
#include "log.h"
#include "buffer.h"
@@ -18,6 +8,16 @@
#include "stat_cache.h"
#include "stream.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+
/**
* this is a dirlisting for a lighttpd plugin
*/
@@ -31,6 +31,8 @@
#include <attr/attributes.h>
#endif
+#include "version.h"
+
/* plugin config for all request/connections */
typedef struct {
@@ -52,27 +54,31 @@ typedef struct {
unsigned short hide_dot_files;
unsigned short show_readme;
unsigned short hide_readme_file;
+ unsigned short encode_readme;
unsigned short show_header;
unsigned short hide_header_file;
-
+ unsigned short encode_header;
+ unsigned short auto_layout;
+
excludes_buffer *excludes;
buffer *external_css;
buffer *encoding;
+ buffer *set_footer;
} plugin_config;
typedef struct {
PLUGIN_DATA;
-
+
buffer *tmp_buf;
buffer *content_charset;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
-excludes_buffer *excludes_buffer_init(void) {
+static excludes_buffer *excludes_buffer_init(void) {
excludes_buffer *exb;
exb = calloc(1, sizeof(*exb));
@@ -80,7 +86,7 @@ excludes_buffer *excludes_buffer_init(void) {
return exb;
}
-int excludes_buffer_append(excludes_buffer *exb, buffer *string) {
+static int excludes_buffer_append(excludes_buffer *exb, buffer *string) {
#ifdef HAVE_PCRE_H
size_t i;
const char *errptr;
@@ -127,7 +133,7 @@ int excludes_buffer_append(excludes_buffer *exb, buffer *string) {
#endif
}
-void excludes_buffer_free(excludes_buffer *exb) {
+static void excludes_buffer_free(excludes_buffer *exb) {
#ifdef HAVE_PCRE_H
size_t i;
@@ -146,44 +152,45 @@ void excludes_buffer_free(excludes_buffer *exb) {
/* init the plugin data */
INIT_FUNC(mod_dirlisting_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
p->tmp_buf = buffer_init();
p->content_charset = buffer_init();
-
+
return p;
}
/* detroy the plugin data */
FREE_FUNC(mod_dirlisting_free) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
-
+
if (!s) continue;
-
+
excludes_buffer_free(s->excludes);
buffer_free(s->external_css);
buffer_free(s->encoding);
-
+ buffer_free(s->set_footer);
+
free(s);
}
free(p->config_storage);
}
-
+
buffer_free(p->tmp_buf);
buffer_free(p->content_charset);
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
@@ -191,7 +198,7 @@ static int parse_config_entry(server *srv, plugin_config *s, array *ca, const ch
data_unset *du;
if (NULL != (du = array_get_element(ca, option))) {
- data_array *da = (data_array *)du;
+ data_array *da;
size_t j;
if (du->type != TYPE_ARRAY) {
@@ -215,10 +222,10 @@ static int parse_config_entry(server *srv, plugin_config *s, array *ca, const ch
if (0 != excludes_buffer_append(s->excludes,
((data_string *)(da->value->data[j]))->value)) {
#ifdef HAVE_PCRE_H
- log_error_write(srv, __FILE__, __LINE__, "sb",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
"pcre-compile failed for", ((data_string *)(da->value->data[j]))->value);
#else
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"pcre support is missing, please install libpcre and the headers");
#endif
}
@@ -230,33 +237,53 @@ static int parse_config_entry(server *srv, plugin_config *s, array *ca, const ch
/* handle plugin config and check values */
+#define CONFIG_EXCLUDE "dir-listing.exclude"
+#define CONFIG_ACTIVATE "dir-listing.activate"
+#define CONFIG_HIDE_DOTFILES "dir-listing.hide-dotfiles"
+#define CONFIG_EXTERNAL_CSS "dir-listing.external-css"
+#define CONFIG_ENCODING "dir-listing.encoding"
+#define CONFIG_SHOW_README "dir-listing.show-readme"
+#define CONFIG_HIDE_README_FILE "dir-listing.hide-readme-file"
+#define CONFIG_SHOW_HEADER "dir-listing.show-header"
+#define CONFIG_HIDE_HEADER_FILE "dir-listing.hide-header-file"
+#define CONFIG_DIR_LISTING "server.dir-listing"
+#define CONFIG_SET_FOOTER "dir-listing.set-footer"
+#define CONFIG_ENCODE_README "dir-listing.encode-readme"
+#define CONFIG_ENCODE_HEADER "dir-listing.encode-header"
+#define CONFIG_AUTO_LAYOUT "dir-listing.auto-layout"
+
+
SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
plugin_data *p = p_d;
size_t i = 0;
-
- config_values_t cv[] = {
- { "dir-listing.exclude", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "dir-listing.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { "dir-listing.hide-dotfiles", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { "dir-listing.external-css", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
- { "dir-listing.encoding", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
- { "dir-listing.show-readme", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
- { "dir-listing.hide-readme-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
- { "dir-listing.show-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
- { "dir-listing.hide-header-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
- { "server.dir-listing", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
-
+
+ config_values_t cv[] = {
+ { CONFIG_EXCLUDE, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { CONFIG_ACTIVATE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { CONFIG_HIDE_DOTFILES, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { CONFIG_EXTERNAL_CSS, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { CONFIG_ENCODING, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { CONFIG_SHOW_README, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
+ { CONFIG_HIDE_README_FILE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
+ { CONFIG_SHOW_HEADER, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
+ { CONFIG_HIDE_HEADER_FILE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
+ { CONFIG_DIR_LISTING, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
+ { CONFIG_SET_FOOTER, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
+ { CONFIG_ENCODE_README, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
+ { CONFIG_ENCODE_HEADER, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
+ { CONFIG_AUTO_LAYOUT, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
+
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
array *ca;
-
+
s = calloc(1, sizeof(plugin_config));
s->excludes = excludes_buffer_init();
s->dir_listing = 0;
@@ -266,8 +293,13 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
s->hide_readme_file = 0;
s->show_header = 0;
s->hide_header_file = 0;
+ s->encode_readme = 1;
+ s->encode_header = 1;
+ s->auto_layout = 1;
+
s->encoding = buffer_init();
-
+ s->set_footer = buffer_init();
+
cv[0].destination = s->excludes;
cv[1].destination = &(s->dir_listing);
cv[2].destination = &(s->hide_dot_files);
@@ -278,6 +310,10 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
cv[7].destination = &(s->show_header);
cv[8].destination = &(s->hide_header_file);
cv[9].destination = &(s->dir_listing); /* old name */
+ cv[10].destination = s->set_footer;
+ cv[11].destination = &(s->encode_readme);
+ cv[12].destination = &(s->encode_header);
+ cv[13].destination = &(s->auto_layout);
p->config_storage[i] = s;
ca = ((data_config *)srv->config_context->data[i])->value;
@@ -286,7 +322,7 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
return HANDLER_ERROR;
}
- parse_config_entry(srv, s, ca, "dir-listing.exclude");
+ parse_config_entry(srv, s, ca, CONFIG_EXCLUDE);
}
return HANDLER_GO_ON;
@@ -307,42 +343,54 @@ static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_
PATCH(show_header);
PATCH(hide_header_file);
PATCH(excludes);
-
+ PATCH(set_footer);
+ PATCH(encode_readme);
+ PATCH(encode_header);
+ PATCH(auto_layout);
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
- if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.activate")) ||
- buffer_is_equal_string(du->key, CONST_STR_LEN("server.dir-listing"))) {
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_ACTIVATE)) ||
+ buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_DIR_LISTING))) {
PATCH(dir_listing);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-dotfiles"))) {
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_HIDE_DOTFILES))) {
PATCH(hide_dot_files);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.external-css"))) {
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_EXTERNAL_CSS))) {
PATCH(external_css);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.encoding"))) {
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_ENCODING))) {
PATCH(encoding);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-readme"))) {
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_SHOW_README))) {
PATCH(show_readme);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-readme-file"))) {
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_HIDE_README_FILE))) {
PATCH(hide_readme_file);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-header"))) {
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_SHOW_HEADER))) {
PATCH(show_header);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-header-file"))) {
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_HIDE_HEADER_FILE))) {
PATCH(hide_header_file);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.excludes"))) {
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_SET_FOOTER))) {
+ PATCH(set_footer);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_EXCLUDE))) {
PATCH(excludes);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_ENCODE_README))) {
+ PATCH(encode_readme);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_ENCODE_HEADER))) {
+ PATCH(encode_header);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_AUTO_LAYOUT))) {
+ PATCH(auto_layout);
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -421,7 +469,7 @@ static int http_list_directory_sizefmt(char *buf, off_t size) {
u++;
}
- out += ltostr(out, size);
+ out += LI_ltostr(out, size);
out[0] = '.';
out[1] = remain + '0';
out[2] = *u;
@@ -432,85 +480,87 @@ static int http_list_directory_sizefmt(char *buf, off_t size) {
static void http_list_directory_header(server *srv, connection *con, plugin_data *p, buffer *out) {
UNUSED(srv);
-
- BUFFER_APPEND_STRING_CONST(out,
- "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
- "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n"
- "<head>\n"
- "<title>Index of "
- );
- buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_MINIMAL_XML);
- BUFFER_APPEND_STRING_CONST(out, "</title>\n");
- if (p->conf.external_css->used > 1) {
- BUFFER_APPEND_STRING_CONST(out, "<link rel=\"stylesheet\" type=\"text/css\" href=\"");
- buffer_append_string_buffer(out, p->conf.external_css);
- BUFFER_APPEND_STRING_CONST(out, "\" />\n");
- } else {
- BUFFER_APPEND_STRING_CONST(out,
- "<style type=\"text/css\">\n"
- "a, a:active {text-decoration: none; color: blue;}\n"
- "a:visited {color: #48468F;}\n"
- "a:hover, a:focus {text-decoration: underline; color: red;}\n"
- "body {background-color: #F5F5F5;}\n"
- "h2 {margin-bottom: 12px;}\n"
- "table {margin-left: 12px;}\n"
- "th, td {"
- " font-family: \"Courier New\", Courier, monospace;"
- " font-size: 10pt;"
- " text-align: left;"
- "}\n"
- "th {"
- " font-weight: bold;"
- " padding-right: 14px;"
- " padding-bottom: 3px;"
- "}\n"
- );
- BUFFER_APPEND_STRING_CONST(out,
- "td {padding-right: 14px;}\n"
- "td.s, th.s {text-align: right;}\n"
- "div.list {"
- " background-color: white;"
- " border-top: 1px solid #646464;"
- " border-bottom: 1px solid #646464;"
- " padding-top: 10px;"
- " padding-bottom: 14px;"
- "}\n"
- "div.foot {"
- " font-family: \"Courier New\", Courier, monospace;"
- " font-size: 10pt;"
- " color: #787878;"
- " padding-top: 4px;"
- "}\n"
- "</style>\n"
- );
- }
+ if (p->conf.auto_layout) {
+ buffer_append_string_len(out, CONST_STR_LEN(
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n"
+ "<head>\n"
+ "<title>Index of "
+ ));
+ buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_MINIMAL_XML);
+ buffer_append_string_len(out, CONST_STR_LEN("</title>\n"));
+
+ if (p->conf.external_css->used > 1) {
+ buffer_append_string_len(out, CONST_STR_LEN("<link rel=\"stylesheet\" type=\"text/css\" href=\""));
+ buffer_append_string_buffer(out, p->conf.external_css);
+ buffer_append_string_len(out, CONST_STR_LEN("\" />\n"));
+ } else {
+ buffer_append_string_len(out, CONST_STR_LEN(
+ "<style type=\"text/css\">\n"
+ "a, a:active {text-decoration: none; color: blue;}\n"
+ "a:visited {color: #48468F;}\n"
+ "a:hover, a:focus {text-decoration: underline; color: red;}\n"
+ "body {background-color: #F5F5F5;}\n"
+ "h2 {margin-bottom: 12px;}\n"
+ "table {margin-left: 12px;}\n"
+ "th, td {"
+ " font: 90% monospace;"
+ " text-align: left;"
+ "}\n"
+ "th {"
+ " font-weight: bold;"
+ " padding-right: 14px;"
+ " padding-bottom: 3px;"
+ "}\n"
+ "td {padding-right: 14px;}\n"
+ "td.s, th.s {text-align: right;}\n"
+ "div.list {"
+ " background-color: white;"
+ " border-top: 1px solid #646464;"
+ " border-bottom: 1px solid #646464;"
+ " padding-top: 10px;"
+ " padding-bottom: 14px;"
+ "}\n"
+ "div.foot {"
+ " font: 90% monospace;"
+ " color: #787878;"
+ " padding-top: 4px;"
+ "}\n"
+ "</style>\n"
+ ));
+ }
- BUFFER_APPEND_STRING_CONST(out, "</head>\n<body>\n");
+ buffer_append_string_len(out, CONST_STR_LEN("</head>\n<body>\n"));
+ }
/* HEADER.txt */
if (p->conf.show_header) {
stream s;
/* if we have a HEADER file, display it in <pre class="header"></pre> */
-
+
buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
BUFFER_APPEND_SLASH(p->tmp_buf);
- BUFFER_APPEND_STRING_CONST(p->tmp_buf, "HEADER.txt");
-
+ buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("HEADER.txt"));
+
if (-1 != stream_open(&s, p->tmp_buf)) {
- BUFFER_APPEND_STRING_CONST(out, "<pre class=\"header\">");
- buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
- BUFFER_APPEND_STRING_CONST(out, "</pre>");
+ if (p->conf.encode_header) {
+ buffer_append_string_len(out, CONST_STR_LEN("<pre class=\"header\">"));
+ buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
+ buffer_append_string_len(out, CONST_STR_LEN("</pre>"));
+ } else {
+ buffer_append_string_len(out, s.start, s.size);
+ }
}
stream_close(&s);
}
- BUFFER_APPEND_STRING_CONST(out, "<h2>Index of ");
+ buffer_append_string_len(out, CONST_STR_LEN("<h2>Index of "));
buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_MINIMAL_XML);
- BUFFER_APPEND_STRING_CONST(out,
+ buffer_append_string_len(out, CONST_STR_LEN(
"</h2>\n"
"<div class=\"list\">\n"
- "<table cellpadding=\"0\" cellspacing=\"0\">\n"
+ "<table summary=\"Directory Listing\" cellpadding=\"0\" cellspacing=\"0\">\n"
"<thead>"
"<tr>"
"<th class=\"n\">Name</th>"
@@ -526,49 +576,57 @@ static void http_list_directory_header(server *srv, connection *con, plugin_data
"<td class=\"s\">- &nbsp;</td>"
"<td class=\"t\">Directory</td>"
"</tr>\n"
- );
+ ));
}
static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) {
UNUSED(srv);
-
- BUFFER_APPEND_STRING_CONST(out,
+
+ buffer_append_string_len(out, CONST_STR_LEN(
"</tbody>\n"
"</table>\n"
"</div>\n"
- );
-
+ ));
+
if (p->conf.show_readme) {
stream s;
/* if we have a README file, display it in <pre class="readme"></pre> */
-
+
buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
BUFFER_APPEND_SLASH(p->tmp_buf);
- BUFFER_APPEND_STRING_CONST(p->tmp_buf, "README.txt");
-
+ buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("README.txt"));
+
if (-1 != stream_open(&s, p->tmp_buf)) {
- BUFFER_APPEND_STRING_CONST(out, "<pre class=\"readme\">");
- buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
- BUFFER_APPEND_STRING_CONST(out, "</pre>");
+ if (p->conf.encode_readme) {
+ buffer_append_string_len(out, CONST_STR_LEN("<pre class=\"readme\">"));
+ buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
+ buffer_append_string_len(out, CONST_STR_LEN("</pre>"));
+ } else {
+ buffer_append_string_len(out, s.start, s.size);
+ }
}
stream_close(&s);
}
-
- BUFFER_APPEND_STRING_CONST(out,
- "<div class=\"foot\">"
- );
- if (buffer_is_empty(con->conf.server_tag)) {
- BUFFER_APPEND_STRING_CONST(out, PACKAGE_NAME "/" PACKAGE_VERSION);
- } else {
- buffer_append_string_buffer(out, con->conf.server_tag);
- }
+ if(p->conf.auto_layout) {
+ buffer_append_string_len(out, CONST_STR_LEN(
+ "<div class=\"foot\">"
+ ));
+
+ if (p->conf.set_footer->used > 1) {
+ buffer_append_string_buffer(out, p->conf.set_footer);
+ } else if (buffer_is_empty(con->conf.server_tag)) {
+ buffer_append_string_len(out, CONST_STR_LEN(PACKAGE_DESC));
+ } else {
+ buffer_append_string_buffer(out, con->conf.server_tag);
+ }
- BUFFER_APPEND_STRING_CONST(out,
- "</div>\n"
- "</body>\n"
- "</html>\n"
- );
+ buffer_append_string_len(out, CONST_STR_LEN(
+ "</div>\n"
+ "</body>\n"
+ "</html>\n"
+ ));
+ }
}
static int http_list_directory(server *srv, connection *con, plugin_data *p, buffer *dir) {
@@ -595,15 +653,16 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
#endif
if (dir->used == 0) return -1;
-
+
i = dir->used - 1;
#ifdef HAVE_PATHCONF
- if (-1 == (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) {
+ if (0 >= (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) {
+ /* some broken fs (fuse) return 0 instead of -1 */
#ifdef NAME_MAX
name_max = NAME_MAX;
#else
- name_max = 256; /* stupid default */
+ name_max = 255; /* stupid default */
#endif
}
#elif defined __WIN32
@@ -611,14 +670,14 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
#else
name_max = NAME_MAX;
#endif
-
+
path = malloc(dir->used + name_max);
assert(path);
strcpy(path, dir->ptr);
path_file = path + i;
if (NULL == (dp = opendir(path))) {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
"opendir failed:", dir, strerror(errno));
free(path);
@@ -633,7 +692,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
assert(files.ent);
files.size = DIRLIST_BLOB_SIZE;
files.used = 0;
-
+
while ((dent = readdir(dp)) != NULL) {
unsigned short exclude_match = 0;
@@ -686,12 +745,12 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
#endif
i = strlen(dent->d_name);
-
+
/* NOTE: the manual says, d_name is never more than NAME_MAX
* so this should actually not be a buffer-overflow-risk
*/
if (i > (size_t)name_max) continue;
-
+
memcpy(path_file, dent->d_name, i + 1);
if (stat(path, &st) != 0)
continue;
@@ -721,13 +780,13 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
if (files.used) http_dirls_sort(files.ent, files.used);
out = chunkqueue_get_append_buffer(con->write_queue);
- BUFFER_COPY_STRING_CONST(out, "<?xml version=\"1.0\" encoding=\"");
+ buffer_copy_string_len(out, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\""));
if (buffer_is_empty(p->conf.encoding)) {
- BUFFER_APPEND_STRING_CONST(out, "iso-8859-1");
+ buffer_append_string_len(out, CONST_STR_LEN("iso-8859-1"));
} else {
buffer_append_string_buffer(out, p->conf.encoding);
}
- BUFFER_APPEND_STRING_CONST(out, "\"?>\n");
+ buffer_append_string_len(out, CONST_STR_LEN("\"?>\n"));
http_list_directory_header(srv, con, p, out);
/* directories */
@@ -740,14 +799,14 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
#else
strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
#endif
-
- BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
+
+ buffer_append_string_len(out, CONST_STR_LEN("<tr><td class=\"n\"><a href=\""));
buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
- BUFFER_APPEND_STRING_CONST(out, "/\">");
+ buffer_append_string_len(out, CONST_STR_LEN("/\">"));
buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_MINIMAL_XML);
- BUFFER_APPEND_STRING_CONST(out, "</a>/</td><td class=\"m\">");
+ buffer_append_string_len(out, CONST_STR_LEN("</a>/</td><td class=\"m\">"));
buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1);
- BUFFER_APPEND_STRING_CONST(out, "</td><td class=\"s\">- &nbsp;</td><td class=\"t\">Directory</td></tr>\n");
+ buffer_append_string_len(out, CONST_STR_LEN("</td><td class=\"s\">- &nbsp;</td><td class=\"t\">Directory</td></tr>\n"));
free(tmp);
}
@@ -758,7 +817,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
content_type = NULL;
#ifdef HAVE_XATTR
-
+
if (con->conf.use_xattr) {
memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
attrlen = sizeof(attrval) - 1;
@@ -768,7 +827,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
}
}
#endif
-
+
if (content_type == NULL) {
content_type = "application/octet-stream";
for (k = 0; k < con->conf.mimetypes->used; k++) {
@@ -788,7 +847,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
}
}
}
-
+
#ifdef HAVE_LOCALTIME_R
localtime_r(&(tmp->mtime), &tm);
strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
@@ -797,17 +856,17 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
#endif
http_list_directory_sizefmt(sizebuf, tmp->size);
- BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
+ buffer_append_string_len(out, CONST_STR_LEN("<tr><td class=\"n\"><a href=\""));
buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
- BUFFER_APPEND_STRING_CONST(out, "\">");
+ buffer_append_string_len(out, CONST_STR_LEN("\">"));
buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_MINIMAL_XML);
- BUFFER_APPEND_STRING_CONST(out, "</a></td><td class=\"m\">");
+ buffer_append_string_len(out, CONST_STR_LEN("</a></td><td class=\"m\">"));
buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1);
- BUFFER_APPEND_STRING_CONST(out, "</td><td class=\"s\">");
+ buffer_append_string_len(out, CONST_STR_LEN("</td><td class=\"s\">"));
buffer_append_string(out, sizebuf);
- BUFFER_APPEND_STRING_CONST(out, "</td><td class=\"t\">");
+ buffer_append_string_len(out, CONST_STR_LEN("</td><td class=\"t\">"));
buffer_append_string(out, content_type);
- BUFFER_APPEND_STRING_CONST(out, "</td></tr>\n");
+ buffer_append_string_len(out, CONST_STR_LEN("</td></tr>\n"));
free(tmp);
}
@@ -820,11 +879,11 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
/* Insert possible charset to Content-Type */
if (buffer_is_empty(p->conf.encoding)) {
- response_header_insert(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
} else {
- buffer_copy_string(p->content_charset, "text/html; charset=");
+ buffer_copy_string_len(p->content_charset, CONST_STR_LEN("text/html; charset="));
buffer_append_string_buffer(p->content_charset, p->conf.encoding);
- response_header_insert(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->content_charset));
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->content_charset));
}
con->file_finished = 1;
@@ -837,52 +896,65 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
URIHANDLER_FUNC(mod_dirlisting_subrequest) {
plugin_data *p = p_d;
stat_cache_entry *sce = NULL;
-
+
UNUSED(srv);
-
+
+ /* we only handle GET, POST and HEAD */
+ switch(con->request.http_method) {
+ case HTTP_METHOD_GET:
+ case HTTP_METHOD_POST:
+ case HTTP_METHOD_HEAD:
+ break;
+ default:
+ return HANDLER_GO_ON;
+ }
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
if (con->physical.path->used == 0) return HANDLER_GO_ON;
if (con->uri.path->used == 0) return HANDLER_GO_ON;
if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
-
+
mod_dirlisting_patch_connection(srv, con, p);
if (!p->conf.dir_listing) return HANDLER_GO_ON;
-
+
if (con->conf.log_request_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "-- handling the request as Dir-Listing");
log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path);
}
-
+
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
- fprintf(stderr, "%s.%d: %s\n", __FILE__, __LINE__, con->physical.path->ptr);
+ log_error_write(srv, __FILE__, __LINE__, "SB", "stat_cache_get_entry failed: ", con->physical.path);
SEGFAULT();
}
-
+
if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
-
+
if (http_list_directory(srv, con, p, con->physical.path)) {
/* dirlisting failed */
con->http_status = 403;
}
-
+
buffer_reset(con->physical.path);
-
+
/* not found */
return HANDLER_FINISHED;
}
/* this function is called at dlopen() time and inits the callbacks */
+int mod_dirlisting_plugin_init(plugin *p);
int mod_dirlisting_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("dirlisting");
-
+
p->init = mod_dirlisting_init;
p->handle_subrequest_start = mod_dirlisting_subrequest;
p->set_defaults = mod_dirlisting_set_defaults;
p->cleanup = mod_dirlisting_free;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_evasive.c b/src/mod_evasive.c
index b9d19ca..2907053 100644
--- a/src/mod_evasive.c
+++ b/src/mod_evasive.c
@@ -1,7 +1,3 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
#include "base.h"
#include "log.h"
#include "buffer.h"
@@ -10,6 +6,10 @@
#include "inet_ntop_cache.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
/**
* mod_evasive
*
@@ -27,72 +27,76 @@
typedef struct {
unsigned short max_conns;
+ unsigned short silent;
} plugin_config;
typedef struct {
PLUGIN_DATA;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
INIT_FUNC(mod_evasive_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
return p;
}
FREE_FUNC(mod_evasive_free) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
-
+
free(s);
}
free(p->config_storage);
}
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
SETDEFAULTS_FUNC(mod_evasive_set_defaults) {
plugin_data *p = p_d;
size_t i = 0;
-
- config_values_t cv[] = {
- { "evasive.max-conns-per-ip", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
+
+ config_values_t cv[] = {
+ { "evasive.max-conns-per-ip", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "evasive.silent", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
s->max_conns = 0;
-
+ s->silent = 0;
+
cv[0].destination = &(s->max_conns);
-
+ cv[1].destination = &(s->silent);
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
}
-
+
return HANDLER_GO_ON;
}
@@ -103,25 +107,28 @@ static int mod_evasive_patch_connection(server *srv, connection *con, plugin_dat
plugin_config *s = p->config_storage[0];
PATCH(max_conns);
-
+ PATCH(silent);
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("evasive.max-conns-per-ip"))) {
PATCH(max_conns);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("evasive.silent"))) {
+ PATCH(silent);
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -132,47 +139,73 @@ URIHANDLER_FUNC(mod_evasive_uri_handler) {
size_t j;
if (con->uri.path->used == 0) return HANDLER_GO_ON;
-
+
mod_evasive_patch_connection(srv, con, p);
-
- /* no limit set, nothing to block */
+
+ /* no limit set, nothing to block */
if (p->conf.max_conns == 0) return HANDLER_GO_ON;
+ switch (con->dst_addr.plain.sa_family) {
+ case AF_INET:
+#ifdef HAVE_IPV6
+ case AF_INET6:
+#endif
+ break;
+ default: /* Address family not supported */
+ return HANDLER_GO_ON;
+ };
+
for (j = 0; j < srv->conns->used; j++) {
connection *c = srv->conns->ptr[j];
/* check if other connections are already actively serving data for the same IP
* we can only ban connections which are already behind the 'read request' state
* */
- if (c->dst_addr.ipv4.sin_addr.s_addr == con->dst_addr.ipv4.sin_addr.s_addr &&
- c->state > CON_STATE_REQUEST_END) {
- conns_by_ip++;
-
- if (conns_by_ip > p->conf.max_conns) {
+ if (c->dst_addr.plain.sa_family != con->dst_addr.plain.sa_family) continue;
+ if (c->state <= CON_STATE_REQUEST_END) continue;
+
+ switch (con->dst_addr.plain.sa_family) {
+ case AF_INET:
+ if (c->dst_addr.ipv4.sin_addr.s_addr != con->dst_addr.ipv4.sin_addr.s_addr) continue;
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ if (0 != memcmp(c->dst_addr.ipv6.sin6_addr.s6_addr, con->dst_addr.ipv6.sin6_addr.s6_addr, 16)) continue;
+ break;
+#endif
+ default: /* Address family not supported, should never be reached */
+ continue;
+ };
+ conns_by_ip++;
+
+ if (conns_by_ip > p->conf.max_conns) {
+ if (!p->conf.silent) {
log_error_write(srv, __FILE__, __LINE__, "ss",
inet_ntop_cache_get_ip(srv, &(con->dst_addr)),
"turned away. Too many connections.");
-
- con->http_status = 403;
- return HANDLER_FINISHED;
}
+
+ con->http_status = 403;
+ con->mode = DIRECT;
+ return HANDLER_FINISHED;
}
}
-
+
return HANDLER_GO_ON;
}
+int mod_evasive_plugin_init(plugin *p);
int mod_evasive_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("evasive");
-
+
p->init = mod_evasive_init;
p->set_defaults = mod_evasive_set_defaults;
p->handle_uri_clean = mod_evasive_uri_handler;
p->cleanup = mod_evasive_free;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_evhost.c b/src/mod_evhost.c
index bc8adb6..7aabf6e 100644
--- a/src/mod_evhost.c
+++ b/src/mod_evhost.c
@@ -1,16 +1,16 @@
-#include <string.h>
-#include <errno.h>
-#include <ctype.h>
-
#include "plugin.h"
#include "log.h"
#include "response.h"
#include "stat_cache.h"
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
typedef struct {
/* unparsed pieces */
buffer *path_pieces_raw;
-
+
/* pieces for path creation */
size_t len;
buffer **path_pieces;
@@ -21,14 +21,14 @@ typedef struct {
buffer *tmp_buf;
plugin_config **config_storage;
- plugin_config conf;
+ plugin_config conf;
} plugin_data;
INIT_FUNC(mod_evhost_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
p->tmp_buf = buffer_init();
return p;
@@ -36,34 +36,34 @@ INIT_FUNC(mod_evhost_init) {
FREE_FUNC(mod_evhost_free) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
if (!s) continue;
-
+
if(s->path_pieces) {
size_t j;
for (j = 0; j < s->len; j++) {
buffer_free(s->path_pieces[j]);
}
-
+
free(s->path_pieces);
}
-
+
buffer_free(s->path_pieces_raw);
-
+
free(s);
}
free(p->config_storage);
}
-
+
buffer_free(p->tmp_buf);
free(p);
@@ -73,30 +73,30 @@ FREE_FUNC(mod_evhost_free) {
static void mod_evhost_parse_pattern(plugin_config *s) {
char *ptr = s->path_pieces_raw->ptr,*pos;
-
+
s->path_pieces = NULL;
-
+
for(pos=ptr;*ptr;ptr++) {
if(*ptr == '%') {
s->path_pieces = realloc(s->path_pieces,(s->len+2) * sizeof(*s->path_pieces));
s->path_pieces[s->len] = buffer_init();
s->path_pieces[s->len+1] = buffer_init();
-
+
buffer_copy_string_len(s->path_pieces[s->len],pos,ptr-pos);
pos = ptr + 2;
-
+
buffer_copy_string_len(s->path_pieces[s->len+1],ptr++,2);
-
+
s->len += 2;
}
}
-
+
if(*pos != '\0') {
s->path_pieces = realloc(s->path_pieces,(s->len+1) * sizeof(*s->path_pieces));
s->path_pieces[s->len] = buffer_init();
-
- buffer_append_memory(s->path_pieces[s->len],pos,ptr-pos);
-
+
+ buffer_copy_string_len(s->path_pieces[s->len],pos,ptr-pos);
+
s->len += 1;
}
}
@@ -104,9 +104,9 @@ static void mod_evhost_parse_pattern(plugin_config *s) {
SETDEFAULTS_FUNC(mod_evhost_set_defaults) {
plugin_data *p = p_d;
size_t i;
-
+
/**
- *
+ *
* #
* # define a pattern for the host url finding
* # %% => % sign
@@ -115,50 +115,52 @@ SETDEFAULTS_FUNC(mod_evhost_set_defaults) {
* # %2 => domain name without tld
* # %3 => subdomain 1 name
* # %4 => subdomain 2 name
+ * # %_ => fqdn (without port info)
* #
* evhost.path-pattern = "/home/ckruse/dev/www/%3/htdocs/"
- *
+ *
*/
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "evhost.path-pattern", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
s->path_pieces_raw = buffer_init();
s->path_pieces = NULL;
s->len = 0;
-
+
cv[0].destination = s->path_pieces_raw;
-
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
-
+
if (s->path_pieces_raw->used != 0) {
mod_evhost_parse_pattern(s);
}
}
-
+
return HANDLER_GO_ON;
}
/**
- * assign the different parts of the domain to array-indezes
- * - %0 - full hostname (authority w/o port)
+ * assign the different parts of the domain to array-indezes (sub2.sub1.domain.tld)
+ * - %0 - domain.tld
* - %1 - tld
- * - %2 - domain.tld
- * - %3 -
+ * - %2 - domain
+ * - %3 - sub1
+ * - ...
*/
static int mod_evhost_parse_host(connection *con,array *host) {
@@ -168,7 +170,7 @@ static int mod_evhost_parse_host(connection *con,array *host) {
int first = 1;
data_string *ds;
int i;
-
+
/* first, find the domain + tld */
for(;ptr > con->uri.authority->ptr;ptr--) {
if(*ptr == '.') {
@@ -179,45 +181,45 @@ static int mod_evhost_parse_host(connection *con,array *host) {
first = 1;
}
}
-
+
ds = data_string_init();
- buffer_copy_string(ds->key,"%0");
-
+ buffer_copy_string_len(ds->key,CONST_STR_LEN("%0"));
+
/* if we stopped at a dot, skip the dot */
if (*ptr == '.') ptr++;
buffer_copy_string_len(ds->value, ptr, colon-ptr);
-
+
array_insert_unique(host,(data_unset *)ds);
-
+
/* if the : is not the start of the authority, go on parsing the hostname */
-
+
if (colon != con->uri.authority->ptr) {
for(ptr = colon - 1, i = 1; ptr > con->uri.authority->ptr; ptr--) {
if(*ptr == '.') {
if (ptr != colon - 1) {
/* is something between the dots */
ds = data_string_init();
- buffer_copy_string(ds->key,"%");
+ buffer_copy_string_len(ds->key,CONST_STR_LEN("%"));
buffer_append_long(ds->key, i++);
buffer_copy_string_len(ds->value,ptr+1,colon-ptr-1);
-
+
array_insert_unique(host,(data_unset *)ds);
}
colon = ptr;
}
}
-
+
/* if the . is not the first charactor of the hostname */
if (colon != ptr) {
ds = data_string_init();
- buffer_copy_string(ds->key,"%");
- buffer_append_long(ds->key, i++);
+ buffer_copy_string_len(ds->key,CONST_STR_LEN("%"));
+ buffer_append_long(ds->key, i /* ++ */);
buffer_copy_string_len(ds->value,ptr,colon-ptr);
-
+
array_insert_unique(host,(data_unset *)ds);
}
}
-
+
return 0;
}
@@ -226,29 +228,29 @@ static int mod_evhost_parse_host(connection *con,array *host) {
static int mod_evhost_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(path_pieces);
PATCH(len);
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("evhost.path-pattern"))) {
PATCH(path_pieces);
PATCH(len);
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -261,32 +263,42 @@ static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d)
register char *ptr;
int not_good = 0;
stat_cache_entry *sce = NULL;
-
+
/* not authority set */
if (con->uri.authority->used == 0) return HANDLER_GO_ON;
-
+
mod_evhost_patch_connection(srv, con, p);
-
+
/* missing even default(global) conf */
if (0 == p->conf.len) {
return HANDLER_GO_ON;
}
parsed_host = array_init();
-
+
mod_evhost_parse_host(con, parsed_host);
-
+
/* build document-root */
buffer_reset(p->tmp_buf);
-
+
for (i = 0; i < p->conf.len; i++) {
ptr = p->conf.path_pieces[i]->ptr;
if (*ptr == '%') {
data_string *ds;
-
+
if (*(ptr+1) == '%') {
/* %% */
- BUFFER_APPEND_STRING_CONST(p->tmp_buf,"%");
+ buffer_append_string_len(p->tmp_buf,CONST_STR_LEN("%"));
+ } else if (*(ptr+1) == '_' ) {
+ /* %_ == full hostname */
+ char *colon = strchr(con->uri.authority->ptr, ':');
+
+ if(colon == NULL) {
+ buffer_append_string_buffer(p->tmp_buf, con->uri.authority); /* adds fqdn */
+ } else {
+ /* strip the port out of the authority-part of the URI scheme */
+ buffer_append_string_len(p->tmp_buf, con->uri.authority->ptr, colon - con->uri.authority->ptr); /* adds fqdn */
+ }
} else if (NULL != (ds = (data_string *)array_get_element(parsed_host,p->conf.path_pieces[i]->ptr))) {
if (ds->value->used) {
buffer_append_string_buffer(p->tmp_buf,ds->value);
@@ -298,11 +310,11 @@ static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d)
buffer_append_string_buffer(p->tmp_buf,p->conf.path_pieces[i]);
}
}
-
+
BUFFER_APPEND_SLASH(p->tmp_buf);
-
+
array_free(parsed_host);
-
+
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
not_good = 1;
@@ -310,14 +322,15 @@ static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d)
log_error_write(srv, __FILE__, __LINE__, "sb", "not a directory:", p->tmp_buf);
not_good = 1;
}
-
+
if (!not_good) {
buffer_copy_string_buffer(con->physical.doc_root, p->tmp_buf);
}
-
+
return HANDLER_GO_ON;
}
+int mod_evhost_plugin_init(plugin *p);
int mod_evhost_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("evhost");
@@ -325,9 +338,9 @@ int mod_evhost_plugin_init(plugin *p) {
p->set_defaults = mod_evhost_set_defaults;
p->handle_docroot = mod_evhost_uri_handler;
p->cleanup = mod_evhost_free;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_expire.c b/src/mod_expire.c
index 619b542..734cb93 100644
--- a/src/mod_expire.c
+++ b/src/mod_expire.c
@@ -1,8 +1,3 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
#include "base.h"
#include "log.h"
#include "buffer.h"
@@ -11,9 +6,14 @@
#include "plugin.h"
#include "stat_cache.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
/**
- * this is a expire module for a lighttpd
- *
+ * this is a expire module for a lighttpd
+ *
* set 'Expires:' HTTP Headers on demand
*/
@@ -27,80 +27,83 @@ typedef struct {
typedef struct {
PLUGIN_DATA;
-
+
buffer *expire_tstmp;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
/* init the plugin data */
INIT_FUNC(mod_expire_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
p->expire_tstmp = buffer_init();
-
+
buffer_prepare_copy(p->expire_tstmp, 255);
-
+
return p;
}
/* detroy the plugin data */
FREE_FUNC(mod_expire_free) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
-
+
buffer_free(p->expire_tstmp);
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
-
+ if (!s) continue;
+
array_free(s->expire_url);
-
free(s);
}
free(p->config_storage);
}
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
-static int mod_expire_get_offset(server *srv, plugin_data *p, buffer *expire, int *offset) {
+static int mod_expire_get_offset(server *srv, plugin_data *p, buffer *expire, time_t *offset) {
char *ts;
int type = -1;
- int retts = 0;
-
+ time_t retts = 0;
+
UNUSED(p);
- /*
+ /*
* parse
- *
- * '(access|modification) [plus] {<num> <type>}*'
- *
+ *
+ * '(access|now|modification) [plus] {<num> <type>}*'
+ *
* e.g. 'access 1 years'
*/
-
+
if (expire->used == 0) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"empty:");
return -1;
}
-
+
ts = expire->ptr;
-
+
if (0 == strncmp(ts, "access ", 7)) {
type = 0;
ts += 7;
+ } else if (0 == strncmp(ts, "now ", 4)) {
+ type = 0;
+ ts += 4;
} else if (0 == strncmp(ts, "modification ", 13)) {
type = 1;
ts += 13;
@@ -110,44 +113,47 @@ static int mod_expire_get_offset(server *srv, plugin_data *p, buffer *expire, in
"invalid <base>:", ts);
return -1;
}
-
+
if (0 == strncmp(ts, "plus ", 5)) {
/* skip the optional plus */
ts += 5;
}
-
- /* the rest is just <number> (years|months|days|hours|minutes|seconds) */
+
+ /* the rest is just <number> (years|months|weeks|days|hours|minutes|seconds) */
while (1) {
char *space, *err;
int num;
-
+
if (NULL == (space = strchr(ts, ' '))) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"missing space after <num>:", ts);
return -1;
}
-
+
num = strtol(ts, &err, 10);
if (*err != ' ') {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"missing <type> after <num>:", ts);
return -1;
}
-
+
ts = space + 1;
-
+
if (NULL != (space = strchr(ts, ' '))) {
int slen;
/* */
-
+
slen = space - ts;
-
- if (slen == 5 &&
+
+ if (slen == 5 &&
0 == strncmp(ts, "years", slen)) {
num *= 60 * 60 * 24 * 30 * 12;
} else if (slen == 6 &&
0 == strncmp(ts, "months", slen)) {
num *= 60 * 60 * 24 * 30;
+ } else if (slen == 5 &&
+ 0 == strncmp(ts, "weeks", slen)) {
+ num *= 60 * 60 * 24 * 7;
} else if (slen == 4 &&
0 == strncmp(ts, "days", slen)) {
num *= 60 * 60 * 24;
@@ -161,19 +167,21 @@ static int mod_expire_get_offset(server *srv, plugin_data *p, buffer *expire, in
0 == strncmp(ts, "seconds", slen)) {
num *= 1;
} else {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"unknown type:", ts);
return -1;
}
-
+
retts += num;
-
+
ts = space + 1;
} else {
if (0 == strcmp(ts, "years")) {
num *= 60 * 60 * 24 * 30 * 12;
} else if (0 == strcmp(ts, "months")) {
num *= 60 * 60 * 24 * 30;
+ } else if (0 == strcmp(ts, "weeks")) {
+ num *= 60 * 60 * 24 * 7;
} else if (0 == strcmp(ts, "days")) {
num *= 60 * 60 * 24;
} else if (0 == strcmp(ts, "hours")) {
@@ -183,19 +191,19 @@ static int mod_expire_get_offset(server *srv, plugin_data *p, buffer *expire, in
} else if (0 == strcmp(ts, "seconds")) {
num *= 1;
} else {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"unknown type:", ts);
return -1;
}
-
+
retts += num;
-
+
break;
}
}
-
+
if (offset != NULL) *offset = retts;
-
+
return type;
}
@@ -205,43 +213,43 @@ static int mod_expire_get_offset(server *srv, plugin_data *p, buffer *expire, in
SETDEFAULTS_FUNC(mod_expire_set_defaults) {
plugin_data *p = p_d;
size_t i = 0, k;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "expire.url", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
s->expire_url = array_init();
-
+
cv[0].destination = s->expire_url;
-
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
-
+
for (k = 0; k < s->expire_url->used; k++) {
data_string *ds = (data_string *)s->expire_url->data[k];
-
+
/* parse lines */
if (-1 == mod_expire_get_offset(srv, p, ds->value, NULL)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
"parsing expire.url failed:", ds->value);
return HANDLER_ERROR;
}
}
}
-
-
+
+
return HANDLER_GO_ON;
}
@@ -250,27 +258,27 @@ SETDEFAULTS_FUNC(mod_expire_set_defaults) {
static int mod_expire_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(expire_url);
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("expire.url"))) {
PATCH(expire_url);
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -279,83 +287,84 @@ URIHANDLER_FUNC(mod_expire_path_handler) {
plugin_data *p = p_d;
int s_len;
size_t k;
-
+
if (con->uri.path->used == 0) return HANDLER_GO_ON;
-
+
mod_expire_patch_connection(srv, con, p);
-
+
s_len = con->uri.path->used - 1;
-
+
for (k = 0; k < p->conf.expire_url->used; k++) {
data_string *ds = (data_string *)p->conf.expire_url->data[k];
int ct_len = ds->key->used - 1;
-
+
if (ct_len > s_len) continue;
if (ds->key->used == 0) continue;
-
+
if (0 == strncmp(con->uri.path->ptr, ds->key->ptr, ct_len)) {
- int ts;
- time_t t;
+ time_t ts, expires;
size_t len;
stat_cache_entry *sce = NULL;
-
+
stat_cache_get_entry(srv, con, con->physical.path, &sce);
-
+
switch(mod_expire_get_offset(srv, p, ds->value, &ts)) {
case 0:
/* access */
- t = (ts + srv->cur_ts);
+ expires = (ts + srv->cur_ts);
break;
case 1:
/* modification */
-
- t = (ts + sce->st.st_mtime);
+
+ expires = (ts + sce->st.st_mtime);
break;
default:
/* -1 is handled at parse-time */
break;
}
-
-
- if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1,
- "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(t))))) {
+
+ /* expires should be at least srv->cur_ts */
+ if (expires < srv->cur_ts) expires = srv->cur_ts;
+
+ if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1,
+ "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(expires))))) {
/* could not set expire header, out of mem */
-
+
return HANDLER_GO_ON;
-
}
-
+
p->expire_tstmp->used = len + 1;
-
- /* HTTP/1.0 */
+
+ /* HTTP/1.0 */
response_header_overwrite(srv, con, CONST_STR_LEN("Expires"), CONST_BUF_LEN(p->expire_tstmp));
- /* HTTP/1.1 */
- buffer_copy_string(p->expire_tstmp, "max-age=");
- buffer_append_long(p->expire_tstmp, ts);
-
- response_header_overwrite(srv, con, CONST_STR_LEN("Cache-Control"), CONST_BUF_LEN(p->expire_tstmp));
-
+ /* HTTP/1.1 */
+ buffer_copy_string_len(p->expire_tstmp, CONST_STR_LEN("max-age="));
+ buffer_append_long(p->expire_tstmp, expires - srv->cur_ts); /* as expires >= srv->cur_ts the difference is >= 0 */
+
+ response_header_append(srv, con, CONST_STR_LEN("Cache-Control"), CONST_BUF_LEN(p->expire_tstmp));
+
return HANDLER_GO_ON;
}
}
-
+
/* not found */
return HANDLER_GO_ON;
}
/* this function is called at dlopen() time and inits the callbacks */
+int mod_expire_plugin_init(plugin *p);
int mod_expire_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("expire");
-
+
p->init = mod_expire_init;
p->handle_subrequest_start = mod_expire_path_handler;
p->set_defaults = mod_expire_set_defaults;
p->cleanup = mod_expire_free;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_extforward.c b/src/mod_extforward.c
new file mode 100644
index 0000000..828bbfe
--- /dev/null
+++ b/src/mod_extforward.c
@@ -0,0 +1,517 @@
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+
+#include "plugin.h"
+
+#include "inet_ntop_cache.h"
+#include "configfile.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <errno.h>
+
+/**
+ * mod_extforward.c for lighttpd, by comman.kang <at> gmail <dot> com
+ * extended, modified by Lionel Elie Mamane (LEM), lionel <at> mamane <dot> lu
+ * support chained proxies by glen@delfi.ee, #1528
+ *
+ * Config example:
+ *
+ * Trust proxy 10.0.0.232 and 10.0.0.232
+ * extforward.forwarder = ( "10.0.0.232" => "trust",
+ * "10.0.0.233" => "trust" )
+ *
+ * Trust all proxies (NOT RECOMMENDED!)
+ * extforward.forwarder = ( "all" => "trust")
+ *
+ * Note that "all" has precedence over specific entries,
+ * so "all except" setups will not work.
+ *
+ * In case you have chained proxies, you can add all their IP's to the
+ * config. However "all" has effect only on connecting IP, as the
+ * X-Forwarded-For header can not be trusted.
+ *
+ * Note: The effect of this module is variable on $HTTP["remotip"] directives and
+ * other module's remote ip dependent actions.
+ * Things done by modules before we change the remoteip or after we reset it will match on the proxy's IP.
+ * Things done in between these two moments will match on the real client's IP.
+ * The moment things are done by a module depends on in which hook it does things and within the same hook
+ * on whether they are before/after us in the module loading order
+ * (order in the server.modules directive in the config file).
+ *
+ * Tested behaviours:
+ *
+ * mod_access: Will match on the real client.
+ *
+ * mod_accesslog:
+ * In order to see the "real" ip address in access log ,
+ * you'll have to load mod_extforward after mod_accesslog.
+ * like this:
+ *
+ * server.modules = (
+ * .....
+ * mod_accesslog,
+ * mod_extforward
+ * )
+ *
+ * Known issues:
+ * seems causing segfault with mod_ssl and $HTTP{"socket"} directives
+ * LEM 2006.05.26: Fixed segfault $SERVER["socket"] directive. Untested with SSL.
+ *
+ * ChangeLog:
+ * 2005.12.19 Initial Version
+ * 2005.12.19 fixed conflict with conditional directives
+ * 2006.05.26 LEM: IPv6 support
+ * 2006.05.26 LEM: Fix a segfault with $SERVER["socket"] directive.
+ * 2006.05.26 LEM: Run at uri_raw time, as we don't need to see the URI
+ * In this manner, we run before mod_access and $HTTP["remoteip"] directives work!
+ * 2006.05.26 LEM: Clean config_cond cache of tests whose result we probably change.
+ */
+
+
+/* plugin config for all request/connections */
+
+typedef struct {
+ array *forwarder;
+ array *headers;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+
+/* context , used for restore remote ip */
+
+typedef struct {
+ sock_addr saved_remote_addr;
+ buffer *saved_remote_addr_buf;
+} handler_ctx;
+
+
+static handler_ctx * handler_ctx_init(sock_addr oldaddr, buffer *oldaddr_buf) {
+ handler_ctx * hctx;
+ hctx = calloc(1, sizeof(*hctx));
+ hctx->saved_remote_addr = oldaddr;
+ hctx->saved_remote_addr_buf = oldaddr_buf;
+ return hctx;
+}
+
+static void handler_ctx_free(handler_ctx *hctx) {
+ free(hctx);
+}
+
+/* init the plugin data */
+INIT_FUNC(mod_extforward_init) {
+ plugin_data *p;
+ p = calloc(1, sizeof(*p));
+ return p;
+}
+
+/* destroy the plugin data */
+FREE_FUNC(mod_extforward_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (!s) continue;
+
+ array_free(s->forwarder);
+ array_free(s->headers);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_extforward_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "extforward.forwarder", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "extforward.headers", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->forwarder = array_init();
+ s->headers = array_init();
+
+ cv[0].destination = s->forwarder;
+ cv[1].destination = s->headers;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_extforward_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(forwarder);
+ PATCH(headers);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("extforward.forwarder"))) {
+ PATCH(forwarder);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("extforward.headers"))) {
+ PATCH(headers);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+
+static void put_string_into_array_len(array *ary, const char *str, int len)
+{
+ data_string *tempdata;
+ if (len == 0)
+ return;
+ tempdata = data_string_init();
+ buffer_copy_string_len(tempdata->value,str,len);
+ array_insert_unique(ary,(data_unset *)tempdata);
+}
+/*
+ extract a forward array from the environment
+*/
+static array *extract_forward_array(buffer *pbuffer)
+{
+ array *result = array_init();
+ if (pbuffer->used > 0) {
+ char *base, *curr;
+ /* state variable, 0 means not in string, 1 means in string */
+ int in_str = 0;
+ for (base = pbuffer->ptr, curr = pbuffer->ptr; *curr; curr++) {
+ if (in_str) {
+ if ((*curr > '9' || *curr < '0') && *curr != '.' && *curr != ':' && (*curr < 'a' || *curr > 'f') && (*curr < 'A' || *curr > 'F')) {
+ /* found an separator , insert value into result array */
+ put_string_into_array_len(result, base, curr - base);
+ /* change state to not in string */
+ in_str = 0;
+ }
+ } else {
+ if ((*curr >= '0' && *curr <= '9') || *curr == ':' || (*curr >= 'a' && *curr <= 'f') || (*curr >= 'A' && *curr <= 'F')) {
+ /* found leading char of an IP address, move base pointer and change state */
+ base = curr;
+ in_str = 1;
+ }
+ }
+ }
+ /* if breaking out while in str, we got to the end of string, so add it */
+ if (in_str) {
+ put_string_into_array_len(result, base, curr - base);
+ }
+ }
+ return result;
+}
+
+#define IP_TRUSTED 1
+#define IP_UNTRUSTED 0
+/*
+ * check whether ip is trusted, return 1 for trusted , 0 for untrusted
+ */
+static int is_proxy_trusted(const char *ipstr, plugin_data *p)
+{
+ data_string* allds = (data_string *)array_get_element(p->conf.forwarder, "all");
+
+ if (allds) {
+ if (strcasecmp(allds->value->ptr, "trust") == 0) {
+ return IP_TRUSTED;
+ } else {
+ return IP_UNTRUSTED;
+ }
+ }
+
+ return (data_string *)array_get_element(p->conf.forwarder, ipstr) ? IP_TRUSTED : IP_UNTRUSTED;
+}
+
+/*
+ * Return char *ip of last address of proxy that is not trusted.
+ * Do not accept "all" keyword here.
+ */
+static const char *last_not_in_array(array *a, plugin_data *p)
+{
+ array *forwarder = p->conf.forwarder;
+ int i;
+
+ for (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;
+}
+
+static struct addrinfo *ipstr_to_sockaddr(server *srv, const char *host) {
+ struct addrinfo hints, *res0;
+ int result;
+
+ memset(&hints, 0, sizeof(hints));
+#ifndef AI_NUMERICSERV
+ /**
+ * quoting $ man getaddrinfo
+ *
+ * NOTES
+ * AI_ADDRCONFIG, AI_ALL, and AI_V4MAPPED are available since glibc 2.3.3.
+ * AI_NUMERICSERV is available since glibc 2.3.4.
+ */
+#define AI_NUMERICSERV 0
+#endif
+ hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
+
+ errno = 0;
+ result = getaddrinfo(host, NULL, &hints, &res0);
+
+ if (result != 0) {
+ log_error_write(srv, __FILE__, __LINE__, "SSSs(S)",
+ "could not resolve hostname ", host, " because ", gai_strerror(result), strerror(errno));
+
+ return NULL;
+ } else if (res0 == NULL) {
+ log_error_write(srv, __FILE__, __LINE__, "SSS",
+ "Problem in resolving hostname ", host, ": succeeded, but no information returned");
+ }
+
+ return res0;
+}
+
+
+
+static void clean_cond_cache(server *srv, connection *con) {
+ config_cond_cache_reset_item(srv, con, COMP_HTTP_REMOTE_IP);
+}
+
+URIHANDLER_FUNC(mod_extforward_uri_handler) {
+ plugin_data *p = p_d;
+ data_string *forwarded = NULL;
+#ifdef HAVE_IPV6
+ char b2[INET6_ADDRSTRLEN + 1];
+ struct addrinfo *addrlist = NULL;
+#endif
+ const char *dst_addr_str = NULL;
+ array *forward_array = NULL;
+ const char *real_remote_addr = NULL;
+#ifdef HAVE_IPV6
+#endif
+
+ if (!con->request.headers) return HANDLER_GO_ON;
+
+ mod_extforward_patch_connection(srv, con, p);
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "-- mod_extforward_uri_handler called");
+ }
+
+ if (p->conf.headers->used) {
+ data_string *ds;
+ size_t k;
+
+ for(k = 0; k < p->conf.headers->used; k++) {
+ ds = (data_string *) p->conf.headers->data[k];
+ if (NULL != (forwarded = (data_string*) array_get_element(con->request.headers, ds->value->ptr))) break;
+ }
+ } else {
+ forwarded = (data_string *) array_get_element(con->request.headers,"X-Forwarded-For");
+ if (NULL == forwarded) forwarded = (data_string *) array_get_element(con->request.headers, "Forwarded-For");
+ }
+
+ if (NULL == forwarded) {
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "no forward header found, skipping");
+ }
+
+ return HANDLER_GO_ON;
+ }
+
+#ifdef HAVE_IPV6
+ dst_addr_str = inet_ntop(con->dst_addr.plain.sa_family,
+ con->dst_addr.plain.sa_family == AF_INET6 ?
+ (struct sockaddr *)&(con->dst_addr.ipv6.sin6_addr) :
+ (struct sockaddr *)&(con->dst_addr.ipv4.sin_addr),
+ b2, (sizeof b2) - 1);
+#else
+ dst_addr_str = inet_ntoa(con->dst_addr.ipv4.sin_addr);
+#endif
+
+ /* if the remote ip itself is not trusted, then do nothing */
+ if (IP_UNTRUSTED == is_proxy_trusted(dst_addr_str, p)) {
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "remote address", dst_addr_str, "is NOT a trusted proxy, skipping");
+ }
+
+ return HANDLER_GO_ON;
+ }
+
+ /* build forward_array from forwarded data_string */
+ forward_array = extract_forward_array(forwarded->value);
+ real_remote_addr = last_not_in_array(forward_array, p);
+
+ if (real_remote_addr != NULL) { /* parsed */
+ sock_addr sock;
+ struct addrinfo *addrs_left;
+ server_socket *srv_sock = con->srv_socket;
+ data_string *forwarded_proto = (data_string *)array_get_element(con->request.headers, "X-Forwarded-Proto");
+
+ if (forwarded_proto && !strcmp(forwarded_proto->value->ptr, "https")) {
+ srv_sock->is_proxy_ssl = 1;
+ } else {
+ srv_sock->is_proxy_ssl = 0;
+ }
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "using address:", real_remote_addr);
+ }
+#ifdef HAVE_IPV6
+ addrlist = ipstr_to_sockaddr(srv, real_remote_addr);
+ sock.plain.sa_family = AF_UNSPEC;
+ for (addrs_left = addrlist; addrs_left != NULL; addrs_left = addrs_left -> ai_next) {
+ sock.plain.sa_family = addrs_left->ai_family;
+ if (sock.plain.sa_family == AF_INET) {
+ sock.ipv4.sin_addr = ((struct sockaddr_in*)addrs_left->ai_addr)->sin_addr;
+ break;
+ } else if (sock.plain.sa_family == AF_INET6) {
+ sock.ipv6.sin6_addr = ((struct sockaddr_in6*)addrs_left->ai_addr)->sin6_addr;
+ break;
+ }
+ }
+#else
+ UNUSED(addrs_left);
+ sock.ipv4.sin_addr.s_addr = inet_addr(real_remote_addr);
+ sock.plain.sa_family = (sock.ipv4.sin_addr.s_addr == 0xFFFFFFFF) ? AF_UNSPEC : AF_INET;
+#endif
+ if (sock.plain.sa_family != AF_UNSPEC) {
+ /* we found the remote address, modify current connection and save the old address */
+ if (con->plugin_ctx[p->id]) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "patching an already patched connection!");
+ handler_ctx_free(con->plugin_ctx[p->id]);
+ con->plugin_ctx[p->id] = NULL;
+ }
+ /* save old address */
+ con->plugin_ctx[p->id] = handler_ctx_init(con->dst_addr, con->dst_addr_buf);
+ /* patch connection address */
+ con->dst_addr = sock;
+ con->dst_addr_buf = buffer_init();
+ buffer_copy_string(con->dst_addr_buf, real_remote_addr);
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "patching con->dst_addr_buf for the accesslog:", real_remote_addr);
+ }
+ /* Now, clean the conf_cond cache, because we may have changed the results of tests */
+ clean_cond_cache(srv, con);
+ }
+#ifdef HAVE_IPV6
+ if (addrlist != NULL ) freeaddrinfo(addrlist);
+#endif
+ }
+ array_free(forward_array);
+
+ /* not found */
+ return HANDLER_GO_ON;
+}
+
+CONNECTION_FUNC(mod_extforward_restore) {
+ plugin_data *p = p_d;
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+
+ if (!hctx) return HANDLER_GO_ON;
+
+ con->dst_addr = hctx->saved_remote_addr;
+ buffer_free(con->dst_addr_buf);
+
+ con->dst_addr_buf = hctx->saved_remote_addr_buf;
+
+ handler_ctx_free(hctx);
+
+ con->plugin_ctx[p->id] = NULL;
+
+ /* Now, clean the conf_cond cache, because we may have changed the results of tests */
+ clean_cond_cache(srv, con);
+
+ return HANDLER_GO_ON;
+}
+
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_extforward_plugin_init(plugin *p);
+int mod_extforward_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("extforward");
+
+ p->init = mod_extforward_init;
+ p->handle_uri_raw = mod_extforward_uri_handler;
+ p->handle_request_done = mod_extforward_restore;
+ p->connection_reset = mod_extforward_restore;
+ p->set_defaults = mod_extforward_set_defaults;
+ p->cleanup = mod_extforward_free;
+
+ p->data = NULL;
+
+ return 0;
+}
+
diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c
index 8b1be0a..de6bfd1 100644
--- a/src/mod_fastcgi.c
+++ b/src/mod_fastcgi.c
@@ -1,13 +1,3 @@
-#include <sys/types.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <assert.h>
-#include <signal.h>
-
#include "buffer.h"
#include "server.h"
#include "keyvalue.h"
@@ -23,8 +13,28 @@
#include "inet_ntop_cache.h"
#include "stat_cache.h"
+#include "status_counter.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+#include <signal.h>
+
+#ifdef HAVE_FASTCGI_FASTCGI_H
+# include <fastcgi/fastcgi.h>
+#else
+# ifdef HAVE_FASTCGI_H
+# include <fastcgi.h>
+# else
+# include "fastcgi.h"
+# endif
+#endif /* HAVE_FASTCGI_FASTCGI_H */
-#include <fastcgi.h>
#include <stdio.h>
#ifdef HAVE_SYS_FILIO_H
@@ -33,11 +43,6 @@
#include "sys-socket.h"
-
-#ifndef UNIX_PATH_MAX
-# define UNIX_PATH_MAX 108
-#endif
-
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
@@ -45,42 +50,52 @@
#include <sys/wait.h>
#endif
+#include "version.h"
+
+#define FCGI_ENV_ADD_CHECK(ret, con) \
+ if (ret == -1) { \
+ con->http_status = 400; \
+ con->file_finished = 1; \
+ return -1; \
+ };
/*
- *
+ *
* TODO:
- *
+ *
* - add timeout for a connect to a non-fastcgi process
* (use state_timestamp + state)
- *
+ *
*/
typedef struct fcgi_proc {
size_t id; /* id will be between 1 and max_procs */
- buffer *socket; /* config.socket + "-" + id */
+ buffer *unixsocket; /* config.socket + "-" + id */
unsigned port; /* config.port + pno */
-
+
+ buffer *connection_name; /* either tcp:<host>:<port> or unix:<socket> for debugging purposes */
+
pid_t pid; /* PID of the spawned process (0 if not spawned locally) */
size_t load; /* number of requests waiting on this process */
- time_t last_used; /* see idle_timeout */
size_t requests; /* see max_requests */
struct fcgi_proc *prev, *next; /* see first */
-
- time_t disabled_until; /* this proc is disabled until, use something else until than */
-
+
+ time_t disabled_until; /* this proc is disabled until, use something else until then */
+
int is_local;
- enum {
- PROC_STATE_UNSET, /* init-phase */
- PROC_STATE_RUNNING, /* alive */
- PROC_STATE_DIED_WAIT_FOR_PID,
- PROC_STATE_KILLED, /* was killed as we don't have the load anymore */
- PROC_STATE_DIED, /* marked as dead, should be restarted */
- PROC_STATE_DISABLED /* proc disabled as it resulted in an error */
- } state;
+ enum {
+ PROC_STATE_UNSET, /* init-phase */
+ PROC_STATE_RUNNING, /* alive */
+ PROC_STATE_OVERLOADED, /* listen-queue is full,
+ don't send anything to this proc for the next 2 seconds */
+ PROC_STATE_DIED_WAIT_FOR_PID, /* */
+ PROC_STATE_DIED, /* marked as dead, should be restarted */
+ PROC_STATE_KILLED /* was killed as we don't have the load anymore */
+ } state;
} fcgi_proc;
typedef struct {
@@ -91,69 +106,56 @@ typedef struct {
* sorted by lowest load
*
* whenever a job is done move it up in the list
- * until it is sorted, move it down as soon as the
+ * until it is sorted, move it down as soon as the
* job is started
*/
- fcgi_proc *first;
- fcgi_proc *unused_procs;
+ fcgi_proc *first;
+ fcgi_proc *unused_procs;
- /*
+ /*
* spawn at least min_procs, at max_procs.
*
- * as soon as the load of the first entry
+ * as soon as the load of the first entry
* is max_load_per_proc we spawn a new one
- * and add it to the first entry and give it
+ * and add it to the first entry and give it
* the load
- *
+ *
*/
- unsigned short min_procs;
unsigned short max_procs;
size_t num_procs; /* how many procs are started */
- size_t active_procs; /* how many of them are really running */
+ size_t active_procs; /* how many of them are really running, i.e. state = PROC_STATE_RUNNING */
- unsigned short max_load_per_proc;
-
- /*
- * kick the process from the list if it was not
- * used for idle_timeout until min_procs is
- * reached. this helps to get the processlist
- * small again we had a small peak load.
- *
- */
-
- unsigned short idle_timeout;
-
/*
* time after a disabled remote connection is tried to be re-enabled
- *
- *
+ *
+ *
*/
-
+
unsigned short disable_time;
/*
- * same fastcgi processes get a little bit larger
- * than wanted. max_requests_per_proc kills a
+ * some fastcgi processes get a little bit larger
+ * than wanted. max_requests_per_proc kills a
* process after a number of handled requests.
*
*/
size_t max_requests_per_proc;
-
+
/* config */
- /*
- * host:port
+ /*
+ * host:port
*
- * if host is one of the local IP adresses the
+ * 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
- *
- */
- buffer *host;
+ * if port is not 0, and host is not specified,
+ * "localhost" (INADDR_LOOPBACK) is assumed.
+ *
+ */
+ buffer *host;
unsigned short port;
/*
@@ -166,27 +168,27 @@ typedef struct {
*/
buffer *unixsocket;
- /* if socket is local we can start the fastcgi
+ /* if socket is local we can start the fastcgi
* process ourself
*
* bin-path is the path to the binary
*
* check min_procs and max_procs for the number
- * of process to start-up
+ * of process to start up
*/
- buffer *bin_path;
-
- /* bin-path is set bin-environment is taken to
+ buffer *bin_path;
+
+ /* bin-path is set bin-environment is taken to
* create the environement before starting the
* FastCGI process
- *
+ *
*/
array *bin_env;
-
+
array *bin_env_copy;
-
+
/*
- * docroot-translation between URL->phys and the
+ * docroot-translation between URL->phys and the
* remote host
*
* reasons:
@@ -205,7 +207,7 @@ typedef struct {
unsigned short mode;
/*
- * check_local tell you if the phys file is stat()ed
+ * check_local tells you if the phys file is stat()ed
* or not. FastCGI doesn't care if the service is
* remote. If the web-server side doesn't contain
* the fastcgi-files we should not stat() for them
@@ -215,44 +217,59 @@ typedef struct {
/*
* append PATH_INFO to SCRIPT_FILENAME
- *
- * php needs this if cgi.fix_pathinfo is provied
- *
+ *
+ * php needs this if cgi.fix_pathinfo is provided
+ *
*/
-
+
unsigned short break_scriptfilename_for_php;
/*
+ * workaround for program when prefix="/"
+ *
+ * rule to build PATH_INFO is hardcoded for when check_local is disabled
+ * enable this option to use the workaround
+ *
+ */
+
+ unsigned short fix_root_path_name;
+
+ /*
* If the backend includes X-LIGHTTPD-send-file in the response
* we use the value as filename and ignore the content.
*
*/
unsigned short allow_xsendfile;
-
+
ssize_t load; /* replace by host->load */
size_t max_id; /* corresponds most of the time to
num_procs.
-
+
only if a process is killed max_id waits for the process itself
- to die and decrements its afterwards */
+ to die and decrements it afterwards */
buffer *strip_request_uri;
+
+ unsigned short kill_signal; /* we need a setting for this as libfcgi
+ applications prefer SIGUSR1 while the
+ rest of the world would use SIGTERM
+ *sigh* */
} fcgi_extension_host;
/*
* one extension can have multiple hosts assigned
- * one host can spawn additional processes on the same
+ * one host can spawn additional processes on the same
* socket (if we control it)
*
* ext -> host -> procs
* 1:n 1:n
*
- * if the fastcgi process is remote that whole goes down
+ * if the fastcgi process is remote that whole goes down
* to
*
* ext -> host -> procs
- * 1:n 1:1
+ * 1:n 1:1
*
* in case of PHP and FCGI_CHILDREN we have again a procs
* but we don't control it directly.
@@ -262,8 +279,11 @@ typedef struct {
typedef struct {
buffer *key; /* like .php */
+ int note_is_sent;
+ int last_used_ndx;
+
fcgi_extension_host **hosts;
-
+
size_t used;
size_t size;
} fcgi_extension;
@@ -277,20 +297,16 @@ typedef struct {
typedef struct {
- fcgi_exts *exts;
-
- int debug;
-} plugin_config;
+ fcgi_exts *exts;
-typedef struct {
- size_t *ptr;
- size_t used;
- size_t size;
-} buffer_uint;
+ array *ext_mapping;
+
+ unsigned int debug;
+} plugin_config;
typedef struct {
char **ptr;
-
+
size_t size;
size_t used;
} char_array;
@@ -298,45 +314,44 @@ typedef struct {
/* generic plugin data, shared between all connections */
typedef struct {
PLUGIN_DATA;
- buffer_uint fcgi_request_id;
-
+
buffer *fcgi_env;
-
+
buffer *path;
buffer *parse_response;
buffer *statuskey;
-
+
plugin_config **config_storage;
-
+
plugin_config conf; /* this is only used as long as no handler_ctx is setup */
} plugin_data;
/* connection specific data */
-typedef enum {
+typedef enum {
FCGI_STATE_UNSET,
- FCGI_STATE_INIT,
- FCGI_STATE_CONNECT_DELAYED,
- FCGI_STATE_PREPARE_WRITE,
- FCGI_STATE_WRITE,
- FCGI_STATE_READ
+ FCGI_STATE_INIT,
+ FCGI_STATE_CONNECT_DELAYED,
+ FCGI_STATE_PREPARE_WRITE,
+ FCGI_STATE_WRITE,
+ FCGI_STATE_READ
} fcgi_connection_state_t;
typedef struct {
fcgi_proc *proc;
fcgi_extension_host *host;
fcgi_extension *ext;
-
+
fcgi_connection_state_t state;
time_t state_timestamp;
-
+
int reconnects; /* number of reconnect attempts */
-
+
chunkqueue *rb; /* read queue */
chunkqueue *wb; /* write queue */
-
+
buffer *response_header;
-
+
size_t request_id;
int fd; /* fd to the fastcgi process */
int fde_ndx; /* index into the fd-event buffer */
@@ -345,75 +360,107 @@ typedef struct {
int got_proc;
int send_content_body;
-
+
plugin_config conf;
-
+
connection *remote_conn; /* dumb pointer */
plugin_data *plugin_data; /* dumb pointer */
} handler_ctx;
/* ok, we need a prototype */
-static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents);
+static handler_t fcgi_handle_fdevent(server *srv, void *ctx, int revents);
+
+static void reset_signals(void) {
+#ifdef SIGTTOU
+ signal(SIGTTOU, SIG_DFL);
+#endif
+#ifdef SIGTTIN
+ signal(SIGTTIN, SIG_DFL);
+#endif
+#ifdef SIGTSTP
+ signal(SIGTSTP, SIG_DFL);
+#endif
+ signal(SIGHUP, SIG_DFL);
+ signal(SIGPIPE, SIG_DFL);
+ signal(SIGUSR1, SIG_DFL);
+}
-int fcgi_proclist_sort_down(server *srv, fcgi_extension_host *host, fcgi_proc *proc);
+static void fastcgi_status_copy_procname(buffer *b, fcgi_extension_host *host, fcgi_proc *proc) {
+ buffer_copy_string_len(b, CONST_STR_LEN("fastcgi.backend."));
+ buffer_append_string_buffer(b, host->id);
+ if (proc) {
+ buffer_append_string_len(b, CONST_STR_LEN("."));
+ buffer_append_long(b, proc->id);
+ }
+}
-data_integer *status_counter_get_counter(server *srv, const char *s, size_t len) {
- data_integer *di;
+static void fcgi_proc_load_inc(server *srv, handler_ctx *hctx) {
+ plugin_data *p = hctx->plugin_data;
+ hctx->proc->load++;
- if (NULL == (di = (data_integer *)array_get_element(srv->status, s))) {
- /* not found, create it */
+ status_counter_inc(srv, CONST_STR_LEN("fastcgi.active-requests"));
- if (NULL == (di = (data_integer *)array_get_unused_element(srv->status, TYPE_INTEGER))) {
- di = data_integer_init();
- }
- buffer_copy_string_len(di->key, s, len);
- di->value = 0;
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string_len(p->statuskey, CONST_STR_LEN(".load"));
- array_insert_unique(srv->status, (data_unset *)di);
- }
- return di;
+ status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
}
-/* dummies of the statistic framework functions
- * they will be moved to a statistics.c later */
-int status_counter_inc(server *srv, const char *s, size_t len) {
- data_integer *di = status_counter_get_counter(srv, s, len);
+static void fcgi_proc_load_dec(server *srv, handler_ctx *hctx) {
+ plugin_data *p = hctx->plugin_data;
+ hctx->proc->load--;
- di->value++;
+ status_counter_dec(srv, CONST_STR_LEN("fastcgi.active-requests"));
- return 0;
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string_len(p->statuskey, CONST_STR_LEN(".load"));
+
+ status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
}
-int status_counter_dec(server *srv, const char *s, size_t len) {
- data_integer *di = status_counter_get_counter(srv, s, len);
+static void fcgi_host_assign(server *srv, handler_ctx *hctx, fcgi_extension_host *host) {
+ plugin_data *p = hctx->plugin_data;
+ hctx->host = host;
+ hctx->host->load++;
- if (di->value > 0) di->value--;
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, NULL);
+ buffer_append_string_len(p->statuskey, CONST_STR_LEN(".load"));
- return 0;
+ status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->host->load);
}
-int status_counter_set(server *srv, const char *s, size_t len, int val) {
- data_integer *di = status_counter_get_counter(srv, s, len);
+static void fcgi_host_reset(server *srv, handler_ctx *hctx) {
+ plugin_data *p = hctx->plugin_data;
+ hctx->host->load--;
- di->value = val;
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, NULL);
+ buffer_append_string_len(p->statuskey, CONST_STR_LEN(".load"));
- return 0;
+ status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->host->load);
+
+ hctx->host = NULL;
}
-int fastcgi_status_copy_procname(buffer *b, fcgi_extension_host *host, fcgi_proc *proc) {
- buffer_copy_string(b, "fastcgi.backend.");
- buffer_append_string_buffer(b, host->id);
- buffer_append_string(b, ".");
- buffer_append_long(b, proc->id);
+static void fcgi_host_disable(server *srv, handler_ctx *hctx) {
+ plugin_data *p = hctx->plugin_data;
- return 0;
+ if (hctx->host->disable_time || hctx->proc->is_local) {
+ if (hctx->proc->state == PROC_STATE_RUNNING) hctx->host->active_procs--;
+ hctx->proc->disabled_until = srv->cur_ts + hctx->host->disable_time;
+ hctx->proc->state = hctx->proc->is_local ? PROC_STATE_DIED_WAIT_FOR_PID : PROC_STATE_DIED;
+
+ if (p->conf.debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "backend disabled for", hctx->host->disable_time, "seconds");
+ }
+ }
}
-int fastcgi_status_init(server *srv, buffer *b, fcgi_extension_host *host, fcgi_proc *proc) {
+static int fastcgi_status_init(server *srv, buffer *b, fcgi_extension_host *host, fcgi_proc *proc) {
#define CLEAN(x) \
fastcgi_status_copy_procname(b, host, proc); \
- buffer_append_string(b, x); \
+ buffer_append_string_len(b, CONST_STR_LEN(x)); \
status_counter_set(srv, CONST_BUF_LEN(b), 0);
CLEAN(".disabled");
@@ -422,37 +469,50 @@ int fastcgi_status_init(server *srv, buffer *b, fcgi_extension_host *host, fcgi_
CLEAN(".connected");
CLEAN(".load");
-#undef CLEAN
+#undef CLEAN
+
+#define CLEAN(x) \
+ fastcgi_status_copy_procname(b, host, NULL); \
+ buffer_append_string_len(b, CONST_STR_LEN(x)); \
+ status_counter_set(srv, CONST_BUF_LEN(b), 0);
+
+ CLEAN(".load");
+
+#undef CLEAN
return 0;
}
-static handler_ctx * handler_ctx_init() {
+static handler_ctx * handler_ctx_init(void) {
handler_ctx * hctx;
-
+
hctx = calloc(1, sizeof(*hctx));
assert(hctx);
-
+
hctx->fde_ndx = -1;
-
+
hctx->response_header = buffer_init();
-
+
hctx->request_id = 0;
hctx->state = FCGI_STATE_INIT;
hctx->proc = NULL;
-
+
hctx->fd = -1;
-
+
hctx->reconnects = 0;
hctx->send_content_body = 1;
hctx->rb = chunkqueue_init();
hctx->wb = chunkqueue_init();
-
+
return hctx;
}
-static void handler_ctx_free(handler_ctx *hctx) {
+static void handler_ctx_free(server *srv, handler_ctx *hctx) {
+ if (hctx->host) {
+ fcgi_host_reset(srv, hctx);
+ }
+
buffer_free(hctx->response_header);
chunkqueue_free(hctx->rb);
@@ -461,29 +521,31 @@ static void handler_ctx_free(handler_ctx *hctx) {
free(hctx);
}
-fcgi_proc *fastcgi_process_init() {
+static fcgi_proc *fastcgi_process_init(void) {
fcgi_proc *f;
f = calloc(1, sizeof(*f));
- f->socket = buffer_init();
-
+ f->unixsocket = buffer_init();
+ f->connection_name = buffer_init();
+
f->prev = NULL;
f->next = NULL;
-
+
return f;
}
-void fastcgi_process_free(fcgi_proc *f) {
+static void fastcgi_process_free(fcgi_proc *f) {
if (!f) return;
-
+
fastcgi_process_free(f->next);
-
- buffer_free(f->socket);
-
+
+ buffer_free(f->unixsocket);
+ buffer_free(f->connection_name);
+
free(f);
}
-fcgi_extension_host *fastcgi_host_init() {
+static fcgi_extension_host *fastcgi_host_init(void) {
fcgi_extension_host *f;
f = calloc(1, sizeof(*f));
@@ -496,13 +558,13 @@ fcgi_extension_host *fastcgi_host_init() {
f->bin_env = array_init();
f->bin_env_copy = array_init();
f->strip_request_uri = buffer_init();
-
+
return f;
}
-void fastcgi_host_free(fcgi_extension_host *h) {
+static void fastcgi_host_free(fcgi_extension_host *h) {
if (!h) return;
-
+
buffer_free(h->id);
buffer_free(h->host);
buffer_free(h->unixsocket);
@@ -511,53 +573,53 @@ void fastcgi_host_free(fcgi_extension_host *h) {
buffer_free(h->strip_request_uri);
array_free(h->bin_env);
array_free(h->bin_env_copy);
-
+
fastcgi_process_free(h->first);
fastcgi_process_free(h->unused_procs);
-
+
free(h);
-
+
}
-fcgi_exts *fastcgi_extensions_init() {
+static fcgi_exts *fastcgi_extensions_init(void) {
fcgi_exts *f;
f = calloc(1, sizeof(*f));
-
+
return f;
}
-void fastcgi_extensions_free(fcgi_exts *f) {
+static void fastcgi_extensions_free(fcgi_exts *f) {
size_t i;
-
+
if (!f) return;
-
+
for (i = 0; i < f->used; i++) {
fcgi_extension *fe;
size_t j;
-
+
fe = f->exts[i];
-
+
for (j = 0; j < fe->used; j++) {
fcgi_extension_host *h;
-
+
h = fe->hosts[j];
-
+
fastcgi_host_free(h);
}
-
+
buffer_free(fe->key);
free(fe->hosts);
-
+
free(fe);
}
-
+
free(f->exts);
-
+
free(f);
}
-int fastcgi_extension_insert(fcgi_exts *ext, buffer *key, fcgi_extension_host *fh) {
+static int fastcgi_extension_insert(fcgi_exts *ext, buffer *key, fcgi_extension_host *fh) {
fcgi_extension *fe;
size_t i;
@@ -574,6 +636,7 @@ int fastcgi_extension_insert(fcgi_exts *ext, buffer *key, fcgi_extension_host *f
fe = calloc(1, sizeof(*fe));
assert(fe);
fe->key = buffer_init();
+ fe->last_used_ndx = -1;
buffer_copy_string_buffer(fe->key, key);
/* */
@@ -602,105 +665,116 @@ int fastcgi_extension_insert(fcgi_exts *ext, buffer *key, fcgi_extension_host *f
assert(fe->hosts);
}
- fe->hosts[fe->used++] = fh;
+ fe->hosts[fe->used++] = fh;
return 0;
-
+
}
INIT_FUNC(mod_fastcgi_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
p->fcgi_env = buffer_init();
-
+
p->path = buffer_init();
p->parse_response = buffer_init();
p->statuskey = buffer_init();
-
+
return p;
}
FREE_FUNC(mod_fastcgi_free) {
plugin_data *p = p_d;
- buffer_uint *r = &(p->fcgi_request_id);
-
+
UNUSED(srv);
- if (r->ptr) free(r->ptr);
-
buffer_free(p->fcgi_env);
buffer_free(p->path);
buffer_free(p->parse_response);
buffer_free(p->statuskey);
-
+
if (p->config_storage) {
size_t i, j, n;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
fcgi_exts *exts;
-
+
if (!s) continue;
-
+
exts = s->exts;
for (j = 0; j < exts->used; j++) {
fcgi_extension *ex;
-
+
ex = exts->exts[j];
-
+
for (n = 0; n < ex->used; n++) {
fcgi_proc *proc;
fcgi_extension_host *host;
-
+
host = ex->hosts[n];
-
+
for (proc = host->first; proc; proc = proc->next) {
- if (proc->pid != 0) kill(proc->pid, SIGTERM);
-
- if (proc->is_local &&
- !buffer_is_empty(proc->socket)) {
- unlink(proc->socket->ptr);
+ if (proc->pid != 0) {
+ kill(proc->pid, host->kill_signal);
+ }
+
+ if (proc->is_local &&
+ !buffer_is_empty(proc->unixsocket)) {
+ unlink(proc->unixsocket->ptr);
}
}
-
+
for (proc = host->unused_procs; proc; proc = proc->next) {
- if (proc->pid != 0) kill(proc->pid, SIGTERM);
-
- if (proc->is_local &&
- !buffer_is_empty(proc->socket)) {
- unlink(proc->socket->ptr);
+ if (proc->pid != 0) {
+ kill(proc->pid, host->kill_signal);
+ }
+ if (proc->is_local &&
+ !buffer_is_empty(proc->unixsocket)) {
+ unlink(proc->unixsocket->ptr);
}
}
}
}
-
+
fastcgi_extensions_free(s->exts);
-
+ array_free(s->ext_mapping);
+
free(s);
}
free(p->config_storage);
}
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
char *dst;
-
+ size_t i;
+
if (!key || !val) return -1;
-
+
dst = malloc(key_len + val_len + 3);
memcpy(dst, key, key_len);
dst[key_len] = '=';
- /* add the \0 from the value */
- memcpy(dst + key_len + 1, val, val_len + 1);
-
+ memcpy(dst + key_len + 1, val, val_len);
+ dst[key_len + 1 + val_len] = '\0';
+
+ for (i = 0; i < env->used; i++) {
+ if (0 == strncmp(dst, env->ptr[i], key_len + 1)) {
+ /* don't care about free as we are in a forked child which is going to exec(...) */
+ /* free(env->ptr[i]); */
+ env->ptr[i] = dst;
+ return 0;
+ }
+ }
+
if (env->size == 0) {
env->size = 16;
env->ptr = malloc(env->size * sizeof(*env->ptr));
@@ -708,9 +782,9 @@ static int env_add(char_array *env, const char *key, size_t key_len, const char
env->size += 16;
env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
}
-
+
env->ptr[env->used++] = dst;
-
+
return 0;
}
@@ -729,15 +803,15 @@ static int parse_binpath(char_array *env, buffer *b) {
if (env->size == 0) {
env->size = 16;
env->ptr = malloc(env->size * sizeof(*env->ptr));
- } else if (env->size == env->used) {
+ } else if (env->size == env->used) {
env->size += 16;
env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
}
-
+
b->ptr[i] = '\0';
env->ptr[env->used++] = start;
-
+
start = b->ptr + i + 1;
break;
default:
@@ -770,7 +844,7 @@ static int parse_binpath(char_array *env, buffer *b) {
return 0;
}
-static int fcgi_spawn_connection(server *srv,
+static int fcgi_spawn_connection(server *srv,
plugin_data *p,
fcgi_extension_host *host,
fcgi_proc *proc) {
@@ -782,33 +856,37 @@ static int fcgi_spawn_connection(server *srv,
#endif
struct sockaddr_in fcgi_addr_in;
struct sockaddr *fcgi_addr;
-
+
socklen_t servlen;
-
+
#ifndef HAVE_FORK
return -1;
#endif
-
+
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "sdb",
- "new proc, socket:", proc->port, proc->socket);
+ "new proc, socket:", proc->port, proc->unixsocket);
}
-
- if (!buffer_is_empty(proc->socket)) {
+
+ if (!buffer_is_empty(proc->unixsocket)) {
memset(&fcgi_addr, 0, sizeof(fcgi_addr));
-
+
#ifdef HAVE_SYS_UN_H
fcgi_addr_un.sun_family = AF_UNIX;
- strcpy(fcgi_addr_un.sun_path, proc->socket->ptr);
-
+ strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
+
#ifdef SUN_LEN
servlen = SUN_LEN(&fcgi_addr_un);
#else
/* stevens says: */
- servlen = proc->socket->used - 1 + sizeof(fcgi_addr_un.sun_family);
+ servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
#endif
socket_type = AF_UNIX;
fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
+
+ buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("unix:"));
+ buffer_append_string_buffer(proc->connection_name, proc->unixsocket);
+
#else
log_error_write(srv, __FILE__, __LINE__, "s",
"ERROR: Unix Domain sockets are not supported.");
@@ -816,103 +894,112 @@ static int fcgi_spawn_connection(server *srv,
#endif
} else {
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 usefull default */
- fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
-
-
+
+ /* set a useful default */
+ fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+
if (NULL == (he = gethostbyname(host->host->ptr))) {
- log_error_write(srv, __FILE__, __LINE__,
- "sdb", "gethostbyname failed: ",
+ log_error_write(srv, __FILE__, __LINE__,
+ "sdb", "gethostbyname failed: ",
h_errno, host->host);
return -1;
}
-
+
if (he->h_addrtype != AF_INET) {
log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
return -1;
}
-
+
if (he->h_length != sizeof(struct in_addr)) {
log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
return -1;
}
-
+
memcpy(&(fcgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
-
+
}
fcgi_addr_in.sin_port = htons(proc->port);
servlen = sizeof(fcgi_addr_in);
-
+
socket_type = AF_INET;
fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
+
+ buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("tcp:"));
+ if (!buffer_is_empty(host->host)) {
+ buffer_append_string_buffer(proc->connection_name, host->host);
+ } else {
+ buffer_append_string_len(proc->connection_name, CONST_STR_LEN("localhost"));
+ }
+ buffer_append_string_len(proc->connection_name, CONST_STR_LEN(":"));
+ buffer_append_long(proc->connection_name, proc->port);
}
-
+
if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"failed:", strerror(errno));
return -1;
}
-
+
if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
- /* server is not up, spawn in */
+ /* server is not up, spawn it */
pid_t child;
int val;
-
- if (!buffer_is_empty(proc->socket)) {
- unlink(proc->socket->ptr);
+
+ if (errno != ENOENT &&
+ !buffer_is_empty(proc->unixsocket)) {
+ unlink(proc->unixsocket->ptr);
}
-
+
close(fcgi_fd);
-
+
/* reopen socket */
if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"socket failed:", strerror(errno));
return -1;
}
-
+
val = 1;
if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"socketsockopt failed:", strerror(errno));
return -1;
}
-
+
/* create socket */
if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
- log_error_write(srv, __FILE__, __LINE__, "sbds",
- "bind failed for:",
- proc->socket,
- proc->port,
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "bind failed for:",
+ proc->connection_name,
strerror(errno));
return -1;
}
-
+
if (-1 == listen(fcgi_fd, 1024)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"listen failed:", strerror(errno));
return -1;
}
-
-#ifdef HAVE_FORK
+
+#ifdef HAVE_FORK
switch ((child = fork())) {
case 0: {
size_t i = 0;
char *c;
char_array env;
char_array arg;
-
+
/* create environment */
env.ptr = NULL;
env.size = 0;
env.used = 0;
-
+
arg.ptr = NULL;
arg.size = 0;
arg.used = 0;
@@ -922,18 +1009,18 @@ static int fcgi_spawn_connection(server *srv,
dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
close(fcgi_fd);
}
-
+
/* we don't need the client socket */
for (i = 3; i < 256; i++) {
close(i);
}
-
+
/* build clean environment */
if (host->bin_env_copy->used) {
for (i = 0; i < host->bin_env_copy->used; i++) {
data_string *ds = (data_string *)host->bin_env_copy->data[i];
char *ge;
-
+
if (NULL != (ge = getenv(ds->value->ptr))) {
env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
}
@@ -941,39 +1028,39 @@ static int fcgi_spawn_connection(server *srv,
} else {
for (i = 0; environ[i]; i++) {
char *eq;
-
+
if (NULL != (eq = strchr(environ[i], '='))) {
env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
}
}
}
-
+
/* create environment */
for (i = 0; i < host->bin_env->used; i++) {
data_string *ds = (data_string *)host->bin_env->data[i];
-
+
env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
}
-
+
for (i = 0; i < env.used; i++) {
/* search for PHP_FCGI_CHILDREN */
if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
}
-
+
/* not found, add a default */
if (i == env.used) {
env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
}
-
+
env.ptr[env.used] = NULL;
parse_binpath(&arg, host->bin_path);
-
+
/* chdir into the base of the bin-path,
* search for the last / */
if (NULL != (c = strrchr(arg.ptr[0], '/'))) {
*c = '\0';
-
+
/* change to the physical directory */
if (-1 == chdir(arg.ptr[0])) {
*c = '/';
@@ -982,15 +1069,16 @@ static int fcgi_spawn_connection(server *srv,
*c = '/';
}
+ reset_signals();
/* exec the cgi */
execve(arg.ptr[0], arg.ptr, env.ptr);
-
- log_error_write(srv, __FILE__, __LINE__, "sbs",
- "execve failed for:", host->bin_path, strerror(errno));
-
+
+ /* log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "execve failed for:", host->bin_path, strerror(errno)); */
+
exit(errno);
-
+
break;
}
case -1:
@@ -998,17 +1086,17 @@ static int fcgi_spawn_connection(server *srv,
break;
default:
/* father */
-
+
/* wait */
select(0, NULL, NULL, NULL, &tv);
-
+
switch (waitpid(child, &status, WNOHANG)) {
case 0:
/* child still running after timeout, good */
break;
case -1:
/* no PID found ? should never happen */
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"pid not found:", strerror(errno));
return -1;
default:
@@ -1016,30 +1104,26 @@ static int fcgi_spawn_connection(server *srv,
"the fastcgi-backend", host->bin_path, "failed to start:");
/* the child should not terminate at all */
if (WIFEXITED(status)) {
- log_error_write(srv, __FILE__, __LINE__, "sdb",
- "child exited with status",
+ log_error_write(srv, __FILE__, __LINE__, "sdb",
+ "child exited with status",
WEXITSTATUS(status), host->bin_path);
- log_error_write(srv, __FILE__, __LINE__, "s",
- "if you try do run PHP as FastCGI backend make sure you use the FastCGI enabled version.\n"
- "You can find out if it is the right one by executing 'php -v' and it should display '(cgi-fcgi)' "
- "in the output, NOT (cgi) NOR (cli)\n"
- "For more information check http://www.lighttpd.net/documentation/fastcgi.html#preparing-php-as-a-fastcgi-program");
log_error_write(srv, __FILE__, __LINE__, "s",
- "If this is PHP on Gentoo add fastcgi to the USE flags");
+ "If you're trying to run your app as a FastCGI backend, make sure you're using the FastCGI-enabled version.\n"
+ "If this is PHP on Gentoo, add 'fastcgi' to the USE flags.");
} else if (WIFSIGNALED(status)) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "terminated by signal:",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "terminated by signal:",
WTERMSIG(status));
if (WTERMSIG(status) == 11) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "to be exact: it seg-fault, crashed, died, ... you get the idea." );
log_error_write(srv, __FILE__, __LINE__, "s",
- "If this is PHP try to remove the byte-code caches for now and try again.");
+ "to be exact: it segfaulted, crashed, died, ... you get the idea." );
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "If this is PHP, try removing the bytecode caches for now and try again.");
}
} else {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "child died somehow:",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child died somehow:",
status);
}
return -1;
@@ -1047,28 +1131,27 @@ static int fcgi_spawn_connection(server *srv,
/* register process */
proc->pid = child;
- proc->last_used = srv->cur_ts;
proc->is_local = 1;
-
+
break;
}
#endif
} else {
proc->is_local = 0;
proc->pid = 0;
-
+
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "sb",
- "(debug) socket is already used, won't spawn:",
- proc->socket);
+ "(debug) socket is already used; won't spawn:",
+ proc->connection_name);
}
}
-
+
proc->state = PROC_STATE_RUNNING;
host->active_procs++;
-
+
close(fcgi_fd);
-
+
return 0;
}
@@ -1078,216 +1161,216 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
data_unset *du;
size_t i = 0;
buffer *fcgi_mode = buffer_init();
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "fastcgi.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "fastcgi.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "fastcgi.debug", NULL, T_CONFIG_INT , T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "fastcgi.map-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
array *ca;
-
+
s = malloc(sizeof(plugin_config));
s->exts = fastcgi_extensions_init();
s->debug = 0;
-
+ s->ext_mapping = array_init();
+
cv[0].destination = s->exts;
cv[1].destination = &(s->debug);
-
+ cv[2].destination = s->ext_mapping;
+
p->config_storage[i] = s;
ca = ((data_config *)srv->config_context->data[i])->value;
-
+
if (0 != config_insert_values_global(srv, ca, cv)) {
return HANDLER_ERROR;
}
-
- /*
+
+ /*
* <key> = ( ... )
*/
-
+
if (NULL != (du = array_get_element(ca, "fastcgi.server"))) {
size_t j;
data_array *da = (data_array *)du;
-
+
if (du->type != TYPE_ARRAY) {
- log_error_write(srv, __FILE__, __LINE__, "sss",
+ log_error_write(srv, __FILE__, __LINE__, "sss",
"unexpected type for key: ", "fastcgi.server", "array of strings");
-
+
return HANDLER_ERROR;
}
-
-
- /*
- * fastcgi.server = ( "<ext>" => ( ... ),
+
+
+ /*
+ * fastcgi.server = ( "<ext>" => ( ... ),
* "<ext>" => ( ... ) )
*/
-
+
for (j = 0; j < da->value->used; j++) {
size_t n;
data_array *da_ext = (data_array *)da->value->data[j];
-
+
if (da->value->data[j]->type != TYPE_ARRAY) {
- log_error_write(srv, __FILE__, __LINE__, "sssbs",
- "unexpected type for key: ", "fastcgi.server",
+ log_error_write(srv, __FILE__, __LINE__, "sssbs",
+ "unexpected type for key: ", "fastcgi.server",
"[", da->value->data[j]->key, "](string)");
-
+
return HANDLER_ERROR;
}
-
- /*
- * da_ext->key == name of the extension
+
+ /*
+ * da_ext->key == name of the extension
*/
-
- /*
- * fastcgi.server = ( "<ext>" =>
- * ( "<host>" => ( ... ),
+
+ /*
+ * fastcgi.server = ( "<ext>" =>
+ * ( "<host>" => ( ... ),
* "<host>" => ( ... )
- * ),
+ * ),
* "<ext>" => ... )
*/
-
+
for (n = 0; n < da_ext->value->used; n++) {
data_array *da_host = (data_array *)da_ext->value->data[n];
-
+
fcgi_extension_host *host;
-
- config_values_t fcv[] = {
+
+ config_values_t fcv[] = {
{ "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ "docroot", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ "mode", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
{ "socket", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
{ "bin-path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
-
+
{ "check-local", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
{ "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
- { "min-procs-not-working", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 7 this is broken for now */
- { "max-procs", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
- { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
- { "idle-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
- { "disable-time", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
-
- { "bin-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
- { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
-
- { "broken-scriptfilename", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
- { "allow-x-send-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 15 */
- { "strip-request-uri", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 16 */
-
+ { "max-procs", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
+ { "disable-time", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
+
+ { "bin-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
+ { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
+
+ { "broken-scriptfilename", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
+ { "allow-x-send-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
+ { "strip-request-uri", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
+ { "kill-signal", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
+ { "fix-root-scriptname", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 15 */
+
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (da_host->type != TYPE_ARRAY) {
- log_error_write(srv, __FILE__, __LINE__, "ssSBS",
- "unexpected type for key:",
- "fastcgi.server",
+ log_error_write(srv, __FILE__, __LINE__, "ssSBS",
+ "unexpected type for key:",
+ "fastcgi.server",
"[", da_host->key, "](string)");
-
+
return HANDLER_ERROR;
}
-
+
host = fastcgi_host_init();
-
+
buffer_copy_string_buffer(host->id, da_host->key);
host->check_local = 1;
- host->min_procs = 4;
host->max_procs = 4;
- host->max_load_per_proc = 1;
- host->idle_timeout = 60;
host->mode = FCGI_RESPONDER;
- host->disable_time = 60;
+ host->disable_time = 1;
host->break_scriptfilename_for_php = 0;
host->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */
-
+ host->kill_signal = SIGTERM;
+ host->fix_root_path_name = 0;
+
fcv[0].destination = host->host;
fcv[1].destination = host->docroot;
fcv[2].destination = fcgi_mode;
fcv[3].destination = host->unixsocket;
fcv[4].destination = host->bin_path;
-
+
fcv[5].destination = &(host->check_local);
fcv[6].destination = &(host->port);
- fcv[7].destination = &(host->min_procs);
- fcv[8].destination = &(host->max_procs);
- fcv[9].destination = &(host->max_load_per_proc);
- fcv[10].destination = &(host->idle_timeout);
- fcv[11].destination = &(host->disable_time);
-
- fcv[12].destination = host->bin_env;
- fcv[13].destination = host->bin_env_copy;
- fcv[14].destination = &(host->break_scriptfilename_for_php);
- fcv[15].destination = &(host->allow_xsendfile);
- fcv[16].destination = host->strip_request_uri;
-
+ fcv[7].destination = &(host->max_procs);
+ fcv[8].destination = &(host->disable_time);
+
+ fcv[9].destination = host->bin_env;
+ fcv[10].destination = host->bin_env_copy;
+ fcv[11].destination = &(host->break_scriptfilename_for_php);
+ fcv[12].destination = &(host->allow_xsendfile);
+ fcv[13].destination = host->strip_request_uri;
+ fcv[14].destination = &(host->kill_signal);
+ fcv[15].destination = &(host->fix_root_path_name);
+
if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
return HANDLER_ERROR;
}
-
- if ((!buffer_is_empty(host->host) || host->port) &&
+
+ if ((!buffer_is_empty(host->host) || host->port) &&
!buffer_is_empty(host->unixsocket)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "either host+port or socket");
-
+ log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
+ "either host/port or socket have to be set in:",
+ da->key, "= (",
+ da_ext->key, " => (",
+ da_host->key, " ( ...");
+
return HANDLER_ERROR;
}
-
+
if (!buffer_is_empty(host->unixsocket)) {
/* unix domain socket */
-
- if (host->unixsocket->used > UNIX_PATH_MAX - 2) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "path of the unixdomain socket is too large");
+ struct sockaddr_un un;
+
+ if (host->unixsocket->used > sizeof(un.sun_path) - 2) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
+ "unixsocket is too long in:",
+ da->key, "= (",
+ da_ext->key, " => (",
+ da_host->key, " ( ...");
+
return HANDLER_ERROR;
}
} else {
/* tcp/ip */
-
- if (buffer_is_empty(host->host) &&
+
+ if (buffer_is_empty(host->host) &&
buffer_is_empty(host->bin_path)) {
- log_error_write(srv, __FILE__, __LINE__, "sbbbs",
- "missing key (string):",
- da->key,
- da_ext->key,
- da_host->key,
- "host");
-
+ log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
+ "host or binpath have to be set in:",
+ da->key, "= (",
+ da_ext->key, " => (",
+ da_host->key, " ( ...");
+
return HANDLER_ERROR;
} else if (host->port == 0) {
- log_error_write(srv, __FILE__, __LINE__, "sbbbs",
- "missing key (short):",
- da->key,
- da_ext->key,
- da_host->key,
- "port");
+ log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
+ "port has to be set in:",
+ da->key, "= (",
+ da_ext->key, " => (",
+ da_host->key, " ( ...");
+
return HANDLER_ERROR;
}
}
-
- if (!buffer_is_empty(host->bin_path)) {
+
+ if (!buffer_is_empty(host->bin_path)) {
/* a local socket + self spawning */
size_t pno;
- /* HACK: just to make sure the adaptive spawing is disabled */
- host->min_procs = host->max_procs;
-
- if (host->min_procs > host->max_procs) host->max_procs = host->min_procs;
- if (host->max_load_per_proc < 1) host->max_load_per_proc = 0;
-
if (s->debug) {
- log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
+ log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsd",
"--- fastcgi spawning local",
"\n\tproc:", host->bin_path,
"\n\tport:", host->port,
"\n\tsocket", host->unixsocket,
- "\n\tmin-procs:", host->min_procs,
"\n\tmax-procs:", host->max_procs);
}
-
- for (pno = 0; pno < host->min_procs; pno++) {
+
+ for (pno = 0; pno < host->max_procs; pno++) {
fcgi_proc *proc;
proc = fastcgi_process_init();
@@ -1297,19 +1380,19 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
if (buffer_is_empty(host->unixsocket)) {
proc->port = host->port + pno;
} else {
- buffer_copy_string_buffer(proc->socket, host->unixsocket);
- buffer_append_string(proc->socket, "-");
- buffer_append_long(proc->socket, pno);
+ buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
+ buffer_append_string_len(proc->unixsocket, CONST_STR_LEN("-"));
+ buffer_append_long(proc->unixsocket, pno);
}
-
+
if (s->debug) {
log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
"--- fastcgi spawning",
"\n\tport:", host->port,
"\n\tsocket", host->unixsocket,
- "\n\tcurrent:", pno, "/", host->min_procs);
+ "\n\tcurrent:", pno, "/", host->max_procs);
}
-
+
if (fcgi_spawn_connection(srv, p, host, proc)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"[ERROR]: spawning fcgi failed.");
@@ -1317,35 +1400,34 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
}
fastcgi_status_init(srv, p->statuskey, host, proc);
-
+
proc->next = host->first;
if (host->first) host->first->prev = proc;
-
+
host->first = proc;
}
} else {
fcgi_proc *proc;
-
+
proc = fastcgi_process_init();
proc->id = host->num_procs++;
host->max_id++;
host->active_procs++;
proc->state = PROC_STATE_RUNNING;
-
+
if (buffer_is_empty(host->unixsocket)) {
proc->port = host->port;
} else {
- buffer_copy_string_buffer(proc->socket, host->unixsocket);
+ buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
}
-
+
fastcgi_status_init(srv, p->statuskey, host, proc);
host->first = proc;
-
- host->min_procs = 1;
+
host->max_procs = 1;
}
-
+
if (!buffer_is_empty(fcgi_mode)) {
if (strcmp(fcgi_mode->ptr, "responder") == 0) {
host->mode = FCGI_RESPONDER;
@@ -1369,140 +1451,76 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
}
}
}
-
+
buffer_free(fcgi_mode);
-
+
return HANDLER_GO_ON;
}
static int fcgi_set_state(server *srv, handler_ctx *hctx, fcgi_connection_state_t state) {
hctx->state = state;
hctx->state_timestamp = srv->cur_ts;
-
- return 0;
-}
-
-static size_t fcgi_requestid_new(server *srv, plugin_data *p) {
- size_t m = 0;
- size_t i;
- buffer_uint *r = &(p->fcgi_request_id);
-
- UNUSED(srv);
-
- for (i = 0; i < r->used; i++) {
- if (r->ptr[i] > m) m = r->ptr[i];
- }
-
- if (r->size == 0) {
- r->size = 16;
- r->ptr = malloc(sizeof(*r->ptr) * r->size);
- } else if (r->used == r->size) {
- r->size += 16;
- r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
- }
-
- r->ptr[r->used++] = ++m;
-
- return m;
+ return 0;
}
-static int fcgi_requestid_del(server *srv, plugin_data *p, size_t request_id) {
- size_t i;
- buffer_uint *r = &(p->fcgi_request_id);
-
- UNUSED(srv);
- for (i = 0; i < r->used; i++) {
- if (r->ptr[i] == request_id) break;
- }
-
- if (i != r->used) {
- /* found */
-
- if (i != r->used - 1) {
- r->ptr[i] = r->ptr[r->used - 1];
- }
- r->used--;
- }
-
- return 0;
-}
-void fcgi_connection_close(server *srv, handler_ctx *hctx) {
+static void fcgi_connection_close(server *srv, handler_ctx *hctx) {
plugin_data *p;
connection *con;
-
+
if (NULL == hctx) return;
-
+
p = hctx->plugin_data;
con = hctx->remote_conn;
-
- if (con->mode != p->id) {
- WP();
- return;
- }
-
+
if (hctx->fd != -1) {
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
fdevent_unregister(srv->ev, hctx->fd);
close(hctx->fd);
srv->cur_fds--;
}
-
- if (hctx->request_id != 0) {
- fcgi_requestid_del(srv, p, hctx->request_id);
- }
if (hctx->host && hctx->proc) {
- hctx->host->load--;
-
if (hctx->got_proc) {
/* after the connect the process gets a load */
- hctx->proc->load--;
-
- status_counter_dec(srv, CONST_STR_LEN("fastcgi.active-requests"));
-
- fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
- buffer_append_string(p->statuskey, ".load");
-
- status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
+ fcgi_proc_load_dec(srv, hctx);
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sddb",
- "release proc:",
- hctx->fd,
- hctx->proc->pid, hctx->proc->socket);
+ log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
+ "released proc:",
+ "pid:", hctx->proc->pid,
+ "socket:", hctx->proc->connection_name,
+ "load:", hctx->proc->load);
}
}
-
- fcgi_proclist_sort_down(srv, hctx->host, hctx->proc);
}
-
- handler_ctx_free(hctx);
- con->plugin_ctx[p->id] = NULL;
+
+ handler_ctx_free(srv, hctx);
+ con->plugin_ctx[p->id] = NULL;
}
static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
plugin_data *p = hctx->plugin_data;
-
- /* child died
- *
- * 1.
- *
+
+ /* child died
+ *
+ * 1.
+ *
* connect was ok, connection was accepted
* but the php accept loop checks after the accept if it should die or not.
- *
- * if yes we can only detect it at a write()
- *
+ *
+ * if yes we can only detect it at a write()
+ *
* next step is resetting this attemp and setup a connection again
- *
- * if we have more then 5 reconnects for the same request, die
- *
- * 2.
- *
+ *
+ * if we have more than 5 reconnects for the same request, die
+ *
+ * 2.
+ *
* we have a connection but the child died by some other reason
- *
+ *
*/
if (hctx->fd != -1) {
@@ -1510,55 +1528,73 @@ static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
fdevent_unregister(srv->ev, hctx->fd);
close(hctx->fd);
srv->cur_fds--;
+ hctx->fd = -1;
}
-
- fcgi_requestid_del(srv, p, hctx->request_id);
-
+
fcgi_set_state(srv, hctx, FCGI_STATE_INIT);
-
+
hctx->request_id = 0;
hctx->reconnects++;
-
- if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sddb",
- "release proc:",
- hctx->fd,
- hctx->proc->pid, hctx->proc->socket);
+
+ if (p->conf.debug > 2) {
+ if (hctx->proc) {
+ log_error_write(srv, __FILE__, __LINE__, "sdb",
+ "release proc for reconnect:",
+ hctx->proc->pid, hctx->proc->connection_name);
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "release proc for reconnect:",
+ hctx->host->unixsocket);
+ }
}
- if (hctx->proc) {
- hctx->proc->load--;
- fcgi_proclist_sort_down(srv, hctx->host, hctx->proc);
+ if (hctx->proc && hctx->got_proc) {
+ fcgi_proc_load_dec(srv, hctx);
}
/* perhaps another host gives us more luck */
- hctx->host = NULL;
-
+ fcgi_host_reset(srv, hctx);
+
return 0;
}
static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d) {
plugin_data *p = p_d;
-
+
fcgi_connection_close(srv, con->plugin_ctx[p->id]);
-
+
return HANDLER_GO_ON;
}
static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
size_t len;
-
+
if (!key || !val) return -1;
-
+
len = key_len + val_len;
-
+
len += key_len > 127 ? 4 : 1;
len += val_len > 127 ? 4 : 1;
-
+
+ if (env->used + len >= FCGI_MAX_LENGTH) {
+ /**
+ * we can't append more headers, ignore it
+ */
+ return -1;
+ }
+
+ /**
+ * field length can be 31bit max
+ *
+ * HINT: this can't happen as FCGI_MAX_LENGTH is only 16bit
+ */
+ if (key_len > 0x7fffffff) key_len = 0x7fffffff;
+ if (val_len > 0x7fffffff) val_len = 0x7fffffff;
+
buffer_prepare_append(env, len);
-
+
if (key_len > 127) {
env->ptr[env->used++] = ((key_len >> 24) & 0xff) | 0x80;
env->ptr[env->used++] = (key_len >> 16) & 0xff;
@@ -1567,7 +1603,7 @@ static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char
} else {
env->ptr[env->used++] = (key_len >> 0) & 0xff;
}
-
+
if (val_len > 127) {
env->ptr[env->used++] = ((val_len >> 24) & 0xff) | 0x80;
env->ptr[env->used++] = (val_len >> 16) & 0xff;
@@ -1576,16 +1612,18 @@ static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char
} else {
env->ptr[env->used++] = (val_len >> 0) & 0xff;
}
-
+
memcpy(env->ptr + env->used, key, key_len);
env->used += key_len;
memcpy(env->ptr + env->used, val, val_len);
env->used += val_len;
-
+
return 0;
}
static int fcgi_header(FCGI_Header * header, unsigned char type, size_t request_id, int contentLength, unsigned char paddingLength) {
+ assert(contentLength <= FCGI_MAX_LENGTH);
+
header->version = FCGI_VERSION_1;
header->type = type;
header->requestIdB0 = request_id & 0xff;
@@ -1594,22 +1632,14 @@ static int fcgi_header(FCGI_Header * header, unsigned char type, size_t request_
header->contentLengthB1 = (contentLength >> 8) & 0xff;
header->paddingLength = paddingLength;
header->reserved = 0;
-
+
return 0;
}
-/**
- *
- * returns
- * -1 error
- * 0 connected
- * 1 not connected yet
- */
typedef enum {
- CONNECTION_UNSET,
CONNECTION_OK,
CONNECTION_DELAYED, /* retry after event, take same host */
- CONNECTION_OVERLOADED, /* disable for 1 seconds, take another backend */
+ CONNECTION_OVERLOADED, /* disable for 1 second, take another backend */
CONNECTION_DEAD /* disable for 60 seconds, take another backend */
} connection_result_t;
@@ -1620,67 +1650,89 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h
struct sockaddr_un fcgi_addr_un;
#endif
socklen_t servlen;
-
+
fcgi_extension_host *host = hctx->host;
fcgi_proc *proc = hctx->proc;
int fcgi_fd = hctx->fd;
-
+
memset(&fcgi_addr, 0, sizeof(fcgi_addr));
-
- if (!buffer_is_empty(proc->socket)) {
+
+ if (!buffer_is_empty(proc->unixsocket)) {
#ifdef HAVE_SYS_UN_H
/* use the unix domain socket */
fcgi_addr_un.sun_family = AF_UNIX;
- strcpy(fcgi_addr_un.sun_path, proc->socket->ptr);
+ strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
#ifdef SUN_LEN
servlen = SUN_LEN(&fcgi_addr_un);
#else
/* stevens says: */
- servlen = proc->socket->used - 1 + sizeof(fcgi_addr_un.sun_family);
+ servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
#endif
fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
+
+ if (buffer_is_empty(proc->connection_name)) {
+ /* on remote spawing we have to set the connection-name now */
+ buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("unix:"));
+ buffer_append_string_buffer(proc->connection_name, proc->unixsocket);
+ }
#else
- return -1;
+ return CONNECTION_DEAD;
#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-adress 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 CONNECTION_DEAD;
+ }
+ } else {
+ fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
}
fcgi_addr_in.sin_port = htons(proc->port);
servlen = sizeof(fcgi_addr_in);
-
+
fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
+
+ if (buffer_is_empty(proc->connection_name)) {
+ /* on remote spawing we have to set the connection-name now */
+ buffer_copy_string_len(proc->connection_name, CONST_STR_LEN("tcp:"));
+ if (!buffer_is_empty(host->host)) {
+ buffer_append_string_buffer(proc->connection_name, host->host);
+ } else {
+ buffer_append_string_len(proc->connection_name, CONST_STR_LEN("localhost"));
+ }
+ buffer_append_string_len(proc->connection_name, CONST_STR_LEN(":"));
+ buffer_append_long(proc->connection_name, proc->port);
+ }
}
-
+
if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
- if (errno == EINPROGRESS ||
+ if (errno == EINPROGRESS ||
errno == EALREADY ||
errno == EINTR) {
- if (hctx->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "connect delayed, will continue later:", host->host);
+ if (hctx->conf.debug > 2) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "connect delayed; will continue later:", proc->connection_name);
}
-
+
return CONNECTION_DELAYED;
} else if (errno == EAGAIN) {
if (hctx->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. "
- "Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections."
- "The load for this fastcgi backend is:", proc->load);
+ log_error_write(srv, __FILE__, __LINE__, "sbsd",
+ "This means that you have more incoming requests than your FastCGI backend can handle in parallel."
+ "It might help to spawn more FastCGI backends or PHP children; if not, decrease server.max-connections."
+ "The load for this FastCGI backend", proc->connection_name, "is", proc->load);
}
return CONNECTION_OVERLOADED;
} else {
- log_error_write(srv, __FILE__, __LINE__, "ssdb",
- "connect failed:",
- strerror(errno),
- proc->port, proc->socket);
+ log_error_write(srv, __FILE__, __LINE__, "sssb",
+ "connect failed:",
+ strerror(errno), "on",
+ proc->connection_name);
return CONNECTION_DEAD;
}
@@ -1688,7 +1740,7 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h
hctx->reconnects = 0;
if (hctx->conf.debug > 1) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"connect succeeded: ", fcgi_fd);
}
@@ -1697,21 +1749,21 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h
static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
size_t i;
-
+
for (i = 0; i < con->request.headers->used; i++) {
data_string *ds;
-
+
ds = (data_string *)con->request.headers->data[i];
-
+
if (ds->value->used && ds->key->used) {
size_t j;
buffer_reset(srv->tmp_buf);
-
+
if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
- BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
+ buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("HTTP_"));
srv->tmp_buf->used--;
}
-
+
buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
for (j = 0; j < ds->key->used - 1; j++) {
char c = '_';
@@ -1725,20 +1777,20 @@ static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_dat
srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
}
srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
-
- fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
+
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)),con);
}
}
-
+
for (i = 0; i < con->environment->used; i++) {
data_string *ds;
-
+
ds = (data_string *)con->environment->data[i];
-
+
if (ds->value->used && ds->key->used) {
size_t j;
buffer_reset(srv->tmp_buf);
-
+
buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
for (j = 0; j < ds->key->used - 1; j++) {
char c = '_';
@@ -1752,11 +1804,11 @@ static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_dat
srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
}
srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
-
- fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
+
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)), con);
}
}
-
+
return 0;
}
@@ -1765,24 +1817,24 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
FCGI_BeginRequestRecord beginRecord;
FCGI_Header header;
buffer *b;
-
+
char buf[32];
const char *s;
#ifdef HAVE_IPV6
char b2[INET6_ADDRSTRLEN + 1];
#endif
-
+
plugin_data *p = hctx->plugin_data;
fcgi_extension_host *host= hctx->host;
connection *con = hctx->remote_conn;
server_socket *srv_sock = con->srv_socket;
-
+
sock_addr our_addr;
socklen_t our_addr_len;
-
+
/* send FCGI_BEGIN_REQUEST */
-
+
fcgi_header(&(beginRecord.header), FCGI_BEGIN_REQUEST, request_id, sizeof(beginRecord.body), 0);
beginRecord.body.roleB0 = host->mode;
beginRecord.body.roleB1 = 0;
@@ -1790,76 +1842,89 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));
b = chunkqueue_get_append_buffer(hctx->wb);
-
+
buffer_copy_memory(b, (const char *)&beginRecord, sizeof(beginRecord));
-
+
/* send FCGI_PARAMS */
buffer_prepare_copy(p->fcgi_env, 1024);
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
-
+ if (buffer_is_empty(con->conf.server_tag)) {
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_DESC)),con)
+ } else {
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_BUF_LEN(con->conf.server_tag)),con)
+ }
+
if (con->server_name->used) {
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
+ size_t len = con->server_name->used - 1;
+
+ if (con->server_name->ptr[0] == '[') {
+ const char *colon = strstr(con->server_name->ptr, "]:");
+ if (colon) len = (colon + 1) - con->server_name->ptr;
+ } else {
+ const char *colon = strchr(con->server_name->ptr, ':');
+ if (colon) len = colon - con->server_name->ptr;
+ }
+
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), con->server_name->ptr, len),con)
} else {
#ifdef HAVE_IPV6
- s = inet_ntop(srv_sock->addr.plain.sa_family,
- srv_sock->addr.plain.sa_family == AF_INET6 ?
+ s = inet_ntop(srv_sock->addr.plain.sa_family,
+ srv_sock->addr.plain.sa_family == AF_INET6 ?
(const void *) &(srv_sock->addr.ipv6.sin6_addr) :
(const void *) &(srv_sock->addr.ipv4.sin_addr),
b2, sizeof(b2)-1);
#else
s = inet_ntoa(srv_sock->addr.ipv4.sin_addr);
#endif
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s)),con)
}
-
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
-
- ltostr(buf,
+
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1")),con)
+
+ LI_ltostr(buf,
#ifdef HAVE_IPV6
ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
#else
ntohs(srv_sock->addr.ipv4.sin_port)
#endif
);
-
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
-
+
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf)),con)
+
/* get the server-side of the connection to the client */
our_addr_len = sizeof(our_addr);
-
+
if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
} else {
s = inet_ntop_cache_get_ip(srv, &(our_addr));
}
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
-
- ltostr(buf,
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s)),con)
+
+ LI_ltostr(buf,
#ifdef HAVE_IPV6
ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
#else
ntohs(con->dst_addr.ipv4.sin_port)
#endif
);
-
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
-
+
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf)),con)
+
s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
-
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s)),con)
+
if (!buffer_is_empty(con->authed_user)) {
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_USER"),
- CONST_BUF_LEN(con->authed_user));
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_USER"), CONST_BUF_LEN(con->authed_user)),con)
}
-
+
if (con->request.content_length > 0 && host->mode != FCGI_AUTHORIZER) {
/* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
-
+
/* request.content_length < SSIZE_MAX, see request.c */
- ltostr(buf, con->request.content_length);
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
+ LI_ltostr(buf, con->request.content_length);
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf)),con)
}
if (host->mode != FCGI_AUTHORIZER) {
@@ -1870,22 +1935,22 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
* For AUTHORIZER mode these headers should be omitted.
*/
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
-
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path)),con)
+
if (!buffer_is_empty(con->request.pathinfo)) {
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
-
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo)),con)
+
/* PATH_TRANSLATED is only defined if PATH_INFO is set */
-
+
if (!buffer_is_empty(host->docroot)) {
buffer_copy_string_buffer(p->path, host->docroot);
} else {
- buffer_copy_string_buffer(p->path, con->physical.doc_root);
+ buffer_copy_string_buffer(p->path, con->physical.basedir);
}
buffer_append_string_buffer(p->path, con->request.pathinfo);
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_TRANSLATED"), CONST_BUF_LEN(p->path));
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_TRANSLATED"), CONST_BUF_LEN(p->path)),con)
} else {
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_STR_LEN(""));
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_STR_LEN("")),con)
}
}
@@ -1898,29 +1963,29 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
*/
if (!buffer_is_empty(host->docroot)) {
- /*
- * rewrite SCRIPT_FILENAME
- *
+ /*
+ * rewrite SCRIPT_FILENAME
+ *
*/
-
+
buffer_copy_string_buffer(p->path, host->docroot);
buffer_append_string_buffer(p->path, con->uri.path);
-
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
+
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path)),con)
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot)),con)
} else {
buffer_copy_string_buffer(p->path, con->physical.path);
-
- /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself
- *
+
+ /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself
+ *
* see src/sapi/cgi_main.c, init_request_info()
*/
if (host->break_scriptfilename_for_php) {
buffer_append_string_buffer(p->path, con->request.pathinfo);
}
-
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
+
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path)),con)
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir)),con)
}
if (host->strip_request_uri->used > 1) {
@@ -1928,57 +1993,54 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
/**
* /app1/index/list
*
- * stripping /app1 or /app1/ should lead to
+ * stripping /app1 or /app1/ should lead to
*
* /index/list
*
*/
if ('/' != host->strip_request_uri->ptr[host->strip_request_uri->used - 2]) {
/* fix the user-input to have / as last char */
- buffer_append_string(host->strip_request_uri, "/");
+ buffer_append_string_len(host->strip_request_uri, CONST_STR_LEN("/"));
}
if (con->request.orig_uri->used >= host->strip_request_uri->used &&
0 == strncmp(con->request.orig_uri->ptr, host->strip_request_uri->ptr, host->strip_request_uri->used - 1)) {
/* the left is the same */
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
+ fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
con->request.orig_uri->ptr + (host->strip_request_uri->used - 2),
- con->request.orig_uri->used - (host->strip_request_uri->used - 2));
+ con->request.orig_uri->used - (host->strip_request_uri->used - 2) - 1);
} else {
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)),con)
}
} else {
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)),con)
}
if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.uri));
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.uri)),con)
}
if (!buffer_is_empty(con->uri.query)) {
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query)),con)
} else {
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN("")),con)
}
-
+
s = get_http_method_name(con->request.http_method);
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s)),con)
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")),con) /* if php is compiled with --force-redirect */
s = get_http_version_name(con->request.http_version);
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
-
-#ifdef USE_OPENSSL
- if (srv_sock->is_ssl) {
- fcgi_env_add(p->fcgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
+ FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s)),con)
+
+ 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_request_headers(srv, con, p);
-
+
+ FCGI_ENV_ADD_CHECK(fcgi_env_add_request_headers(srv, con, p), con);
+
fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0);
buffer_append_memory(b, (const char *)&header, sizeof(header));
buffer_append_memory(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used);
-
+
fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);
buffer_append_memory(b, (const char *)&header, sizeof(header));
@@ -1996,9 +2058,9 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
off_t written = 0;
off_t weHave = 0;
- /* we announce toWrite octects
- * now take all the request_content chunk that we need to fill this request
- * */
+ /* we announce toWrite octets
+ * now take all the request_content chunks that we need to fill this request
+ * */
b = chunkqueue_get_append_buffer(hctx->wb);
fcgi_header(&(header), FCGI_STDIN, request_id, weWant, 0);
@@ -2006,12 +2068,12 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
hctx->wb->bytes_in += sizeof(header);
if (p->conf.debug > 10) {
- fprintf(stderr, "%s.%d: tosend: %lld / %lld\n", __FILE__, __LINE__, offset, req_cq->bytes_in);
+ log_error_write(srv, __FILE__, __LINE__, "soso", "tosend:", offset, "/", req_cq->bytes_in);
}
for (written = 0; written != weWant; ) {
if (p->conf.debug > 10) {
- fprintf(stderr, "%s.%d: chunk: %lld / %lld\n", __FILE__, __LINE__, written, weWant);
+ log_error_write(srv, __FILE__, __LINE__, "soso", "chunk:", written, "/", weWant);
}
switch (req_c->type) {
@@ -2021,16 +2083,14 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
if (weHave > weWant - written) weHave = weWant - written;
if (p->conf.debug > 10) {
- fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n",
- __FILE__, __LINE__,
- weHave,
- req_c->offset,
- req_c->file.length,
- req_c->file.name->ptr);
+ log_error_write(srv, __FILE__, __LINE__, "soSosOsb",
+ "sending", weHave, "bytes from (",
+ req_c->offset, "/", req_c->file.length, ")",
+ req_c->file.name);
}
assert(weHave != 0);
-
+
chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave);
req_c->offset += weHave;
@@ -2045,7 +2105,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
* - we reference the tempfile from the request-content-queue several times
* if the req_c is larger than FCGI_MAX_LENGTH
* - we can't simply cleanup the request-content-queue as soon as possible
- * as it would remove the tempfiles
+ * as it would remove the tempfiles
* - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last
* referencing chunk of the fastcgi-write-queue
*
@@ -2055,7 +2115,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
chunk *c;
if (p->conf.debug > 10) {
- fprintf(stderr, "%s.%d: next chunk\n", __FILE__, __LINE__);
+ log_error_write(srv, __FILE__, __LINE__, "s", "next chunk");
}
c = hctx->wb->last;
@@ -2082,10 +2142,10 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
req_c->offset += weHave;
req_cq->bytes_out += weHave;
written += weHave;
-
+
hctx->wb->bytes_in += weHave;
- if (req_c->offset == req_c->mem->used - 1) {
+ if (req_c->offset == (off_t) req_c->mem->used - 1) {
chunkqueue_remove_finished_chunks(req_cq);
req_c = req_cq->first;
@@ -2096,12 +2156,12 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
break;
}
}
-
+
b->used++; /* add virtual \0 */
offset += weWant;
}
}
-
+
b = chunkqueue_get_append_buffer(hctx->wb);
/* terminate STDIN */
fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0);
@@ -2110,65 +2170,53 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
hctx->wb->bytes_in += sizeof(header);
-#if 0
- for (i = 0; i < hctx->write_buffer->used; i++) {
- fprintf(stderr, "%02x ", hctx->write_buffer->ptr[i]);
- if ((i+1) % 16 == 0) {
- size_t j;
- for (j = i-15; j <= i; j++) {
- fprintf(stderr, "%c",
- isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
- }
- fprintf(stderr, "\n");
- }
- }
-#endif
-
return 0;
}
static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
char *s, *ns;
-
+
handler_ctx *hctx = con->plugin_ctx[p->id];
fcgi_extension_host *host= hctx->host;
-
+ int have_sendfile2 = 0;
+ off_t sendfile2_content_length = 0;
+
UNUSED(srv);
buffer_copy_string_buffer(p->parse_response, in);
-
+
/* search for \n */
for (s = p->parse_response->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) {
char *key, *value;
int key_len;
- data_string *ds;
-
+ data_string *ds = NULL;
+
/* a good day. Someone has read the specs and is sending a \r\n to us */
-
+
if (ns > p->parse_response->ptr &&
*(ns-1) == '\r') {
*(ns-1) = '\0';
}
-
+
ns[0] = '\0';
-
+
key = s;
if (NULL == (value = strchr(s, ':'))) {
/* we expect: "<key>: <value>\n" */
continue;
}
-
+
key_len = value - key;
-
+
value++;
/* strip WS */
while (*value == ' ' || *value == '\t') value++;
-
+
if (host->mode != FCGI_AUTHORIZER ||
!(con->http_status == 0 ||
con->http_status == 200)) {
/* authorizers shouldn't affect the response headers sent back to the client */
-
+
/* don't forward Status: */
if (0 != strncasecmp(key, "Status", key_len)) {
if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
@@ -2176,11 +2224,11 @@ static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buf
}
buffer_copy_string_len(ds->key, key, key_len);
buffer_copy_string(ds->value, value);
-
+
array_insert_unique(con->response.headers, (data_unset *)ds);
}
}
-
+
switch(key_len) {
case 4:
if (0 == strncasecmp(key, "Date", key_len)) {
@@ -2204,11 +2252,97 @@ static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buf
con->parsed_response |= HTTP_CONNECTION;
}
break;
+ case 11:
+ if (host->allow_xsendfile && 0 == strncasecmp(key, "X-Sendfile2", key_len)&& hctx->send_content_body) {
+ char *pos = value;
+ have_sendfile2 = 1;
+
+ while (*pos) {
+ char *filename, *range;
+ stat_cache_entry *sce;
+ off_t begin_range, end_range, range_len;
+
+ while (' ' == *pos) pos++;
+ if (!*pos) break;
+
+ filename = pos;
+ if (NULL == (range = strchr(pos, ' '))) {
+ /* missing range */
+ if (p->conf.debug) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "Couldn't find range after filename:", filename);
+ }
+ return 1;
+ }
+ buffer_copy_string_len(srv->tmp_buf, filename, range - filename);
+
+ /* find end of range */
+ for (pos = ++range; *pos && *pos != ' ' && *pos != ','; pos++) ;
+
+ buffer_urldecode_path(srv->tmp_buf);
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, srv->tmp_buf, &sce)) {
+ if (p->conf.debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "send-file error: couldn't get stat_cache entry for X-Sendfile2:",
+ srv->tmp_buf);
+ }
+ return 1;
+ } else if (!S_ISREG(sce->st.st_mode)) {
+ if (p->conf.debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "send-file error: wrong filetype for X-Sendfile2:",
+ srv->tmp_buf);
+ }
+ return 1;
+ }
+ /* found the file */
+
+ /* parse range */
+ begin_range = 0; end_range = sce->st.st_size - 1;
+ {
+ char *rpos = NULL;
+ errno = 0;
+ begin_range = strtoll(range, &rpos, 10);
+ if (errno != 0 || begin_range < 0 || rpos == range) goto range_failed;
+ if ('-' != *rpos++) goto range_failed;
+ if (rpos != pos) {
+ range = rpos;
+ end_range = strtoll(range, &rpos, 10);
+ if (errno != 0 || end_range < 0 || rpos == range) goto range_failed;
+ }
+ if (rpos != pos) goto range_failed;
+
+ goto range_success;
+
+range_failed:
+ if (p->conf.debug) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "Couldn't decode range after filename:", filename);
+ }
+ return 1;
+
+range_success: ;
+ }
+
+ /* no parameters accepted */
+
+ while (*pos == ' ') pos++;
+ if (*pos != '\0' && *pos != ',') return 1;
+
+ range_len = end_range - begin_range + 1;
+ if (range_len < 0) return 1;
+ if (range_len != 0) {
+ http_chunk_append_file(srv, con, srv->tmp_buf, begin_range, range_len);
+ }
+ sendfile2_content_length += range_len;
+
+ if (*pos == ',') pos++;
+ }
+ }
+ break;
case 14:
if (0 == strncasecmp(key, "Content-Length", key_len)) {
con->response.content_length = strtol(value, NULL, 10);
con->parsed_response |= HTTP_CONTENT_LENGTH;
-
+
if (con->response.content_length < 0) con->response.content_length = 0;
}
break;
@@ -2216,18 +2350,38 @@ static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buf
break;
}
}
-
+
+ if (have_sendfile2) {
+ data_string *dcls;
+
+ hctx->send_content_body = 0;
+ joblist_append(srv, con);
+
+ /* fix content-length */
+ if (NULL == (dcls = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
+ dcls = data_response_init();
+ }
+
+ buffer_copy_string_len(dcls->key, "Content-Length", sizeof("Content-Length")-1);
+ buffer_copy_off_t(dcls->value, sendfile2_content_length);
+ 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 = sendfile2_content_length;
+ }
+
/* CGI/1.1 rev 03 - 7.2.1.2 */
if ((con->parsed_response & HTTP_LOCATION) &&
!(con->parsed_response & HTTP_STATUS)) {
con->http_status = 302;
}
-
+
return 0;
}
typedef struct {
- buffer *b;
+ buffer *b;
size_t len;
int type;
int padding;
@@ -2236,8 +2390,8 @@ typedef struct {
static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_packet *packet) {
chunk * c;
- size_t offset = 0;
- size_t toread = 0;
+ size_t offset;
+ size_t toread;
FCGI_Header *header;
if (!hctx->rb->first) return -1;
@@ -2248,15 +2402,22 @@ static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_p
packet->padding = 0;
packet->request_id = 0;
+ offset = 0; toread = 8;
/* get at least the FastCGI header */
for (c = hctx->rb->first; c; c = c->next) {
+ size_t weHave = c->mem->used - c->offset - 1;
+
+ if (weHave > toread) weHave = toread;
+
if (packet->b->used == 0) {
- buffer_copy_string_len(packet->b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
+ buffer_copy_string_len(packet->b, c->mem->ptr + c->offset, weHave);
} else {
- buffer_append_string_len(packet->b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
+ buffer_append_string_len(packet->b, c->mem->ptr + c->offset, weHave);
}
+ toread -= weHave;
+ offset = weHave; /* skip offset bytes in chunk for "real" data */
- if (packet->b->used >= sizeof(*header) + 1) break;
+ if (0 == toread) break;
}
if ((packet->b->used == 0) ||
@@ -2264,23 +2425,22 @@ 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");
+ if (hctx->plugin_data->conf.debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sdsds", "FastCGI: header too small:", packet->b->used, "bytes <", sizeof(FCGI_Header), "bytes, waiting for more data");
+ }
return -1;
}
- /* we have at least a header, now check how much me have to fetch */
+ /* we have at least a header, now check how much me have to fetch */
header = (FCGI_Header *)(packet->b->ptr);
-
+
packet->len = (header->contentLengthB0 | (header->contentLengthB1 << 8)) + header->paddingLength;
packet->request_id = (header->requestIdB0 | (header->requestIdB1 << 8));
packet->type = header->type;
packet->padding = header->paddingLength;
- /* the first bytes in packet->b are the header */
- offset = sizeof(*header);
-
/* ->b should only be the content */
- buffer_copy_string(packet->b, ""); /* used == 1 */
+ buffer_copy_string_len(packet->b, CONST_STR_LEN("")); /* used == 1 */
if (packet->len) {
/* copy the content */
@@ -2289,15 +2449,15 @@ static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_p
size_t weHave = c->mem->used - c->offset - offset - 1;
if (weHave > weWant) weHave = weWant;
-
+
buffer_append_string_len(packet->b, c->mem->ptr + c->offset + offset, weHave);
- /* we only skipped the first 8 bytes as they are the fcgi header */
+ /* we only skipped the first bytes as they belonged to the fcgi header */
offset = 0;
}
if (packet->b->used < packet->len + 1) {
- /* we didn't got the full packet */
+ /* we didn't get the full packet */
buffer_free(packet->b);
return -1;
@@ -2321,7 +2481,7 @@ static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_p
}
chunkqueue_remove_finished_chunks(hctx->rb);
-
+
return 0;
}
@@ -2329,59 +2489,69 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
int fin = 0;
int toread;
ssize_t r;
-
+
plugin_data *p = hctx->plugin_data;
connection *con = hctx->remote_conn;
int fcgi_fd = hctx->fd;
fcgi_extension_host *host= hctx->host;
fcgi_proc *proc = hctx->proc;
-
- /*
- * check how much we have to read
+
+ /*
+ * check how much we have to read
*/
if (ioctl(hctx->fd, FIONREAD, &toread)) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ if (errno == EAGAIN) return 0;
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"unexpected end-of-file (perhaps the fastcgi process died):",
fcgi_fd);
return -1;
}
-
+
/* init read-buffer */
-
+
if (toread > 0) {
buffer *b;
+ chunk *cq_first = hctx->rb->first;
+ chunk *cq_last = hctx->rb->last;
b = chunkqueue_get_append_buffer(hctx->rb);
buffer_prepare_copy(b, toread + 1);
/* append to read-buffer */
if (-1 == (r = read(hctx->fd, b->ptr, toread))) {
- log_error_write(srv, __FILE__, __LINE__, "sds",
+ if (errno == EAGAIN) {
+ /* roll back the last chunk allocation,
+ and continue on next iteration */
+ buffer_free(hctx->rb->last->mem);
+ free(hctx->rb->last);
+ hctx->rb->first = cq_first;
+ hctx->rb->last = cq_last;
+ return 0;
+ }
+ log_error_write(srv, __FILE__, __LINE__, "sds",
"unexpected end-of-file (perhaps the fastcgi process died):",
fcgi_fd, strerror(errno));
return -1;
}
-
+
/* this should be catched by the b > 0 above */
assert(r);
b->used = r + 1; /* one extra for the fake \0 */
b->ptr[b->used - 1] = '\0';
} else {
- log_error_write(srv, __FILE__, __LINE__, "ssdsbsbsd",
+ log_error_write(srv, __FILE__, __LINE__, "ssdsb",
"unexpected end-of-file (perhaps the fastcgi process died):",
"pid:", proc->pid,
- "socket:", proc->socket,
- "host:", host->host,
- "port:", proc->port);
-
+ "socket:", proc->connection_name);
+
return -1;
}
/*
* parse the fastcgi packets and forward the content to the write-queue
*
- */
+ */
while (fin == 0) {
fastcgi_response_packet packet;
@@ -2400,9 +2570,9 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
char *c;
size_t blen;
data_string *ds;
-
- /* search for header terminator
- *
+
+ /* search for header terminator
+ *
* if we start with \r\n check if last packet terminated with \r\n
* if we start with \n check if last packet terminated with \n
* search for \r\n\r\n
@@ -2429,7 +2599,12 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
}
/* parse the response header */
- fcgi_response_parse(srv, con, p, hctx->response_header);
+ if (fcgi_response_parse(srv, con, p, hctx->response_header)) {
+ con->http_status = 502;
+ hctx->send_content_body = 0;
+ con->file_started = 1;
+ break;
+ }
con->file_started = 1;
@@ -2440,21 +2615,41 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
hctx->send_content_body = 0;
}
- if (host->allow_xsendfile &&
- NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file"))) {
+ if (host->allow_xsendfile && hctx->send_content_body &&
+ (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;
+ if (NULL == (dcls = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
+ dcls = data_response_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_off_t(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);
+ con->http_status = 502;
+ hctx->send_content_body = 0;
+ con->file_started = 1;
+ break;
}
}
-
- if (hctx->send_content_body && blen > 1) {
+
+ if (hctx->send_content_body && blen > 1) {
/* enable chunked-transfer-encoding */
if (con->request.http_version == HTTP_VERSION_1_1 &&
!(con->parsed_response & HTTP_CONTENT_LENGTH)) {
@@ -2476,264 +2671,169 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
}
break;
case FCGI_STDERR:
- log_error_write(srv, __FILE__, __LINE__, "sb",
+ if (packet.len == 0) break;
+
+ log_error_write(srv, __FILE__, __LINE__, "sb",
"FastCGI-stderr:", packet.b);
-
+
break;
case FCGI_END_REQUEST:
con->file_finished = 1;
-
+
if (host->mode != FCGI_AUTHORIZER ||
!(con->http_status == 0 ||
con->http_status == 200)) {
- /* send chunk-end if nesseary */
+ /* send chunk-end if necessary */
http_chunk_append_mem(srv, con, NULL, 0);
joblist_append(srv, con);
}
-
+
fin = 1;
break;
default:
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"FastCGI: header.type not handled: ", packet.type);
break;
}
buffer_free(packet.b);
}
-
- return fin;
-}
-
-int fcgi_proclist_sort_up(server *srv, fcgi_extension_host *host, fcgi_proc *proc) {
- fcgi_proc *p;
-
- UNUSED(srv);
-
- /* we have been the smallest of the current list
- * and we want to insert the node sorted as soon
- * possible
- *
- * 1 0 0 0 1 1 1
- * | ^
- * | |
- * +------+
- *
- */
-
- /* nothing to sort, only one element */
- if (host->first == proc && proc->next == NULL) return 0;
-
- for (p = proc; p->next && p->next->load < proc->load; p = p->next);
-
- /* no need to move something
- *
- * 1 2 2 2 3 3 3
- * ^
- * |
- * +
- *
- */
- if (p == proc) return 0;
-
- if (host->first == proc) {
- /* we have been the first elememt */
-
- host->first = proc->next;
- host->first->prev = NULL;
- }
-
- /* disconnect proc */
-
- if (proc->prev) proc->prev->next = proc->next;
- if (proc->next) proc->next->prev = proc->prev;
-
- /* proc should be right of p */
-
- proc->next = p->next;
- proc->prev = p;
- if (p->next) p->next->prev = proc;
- p->next = proc;
-#if 0
- for(p = host->first; p; p = p->next) {
- log_error_write(srv, __FILE__, __LINE__, "dd",
- p->pid, p->load);
- }
-#else
- UNUSED(srv);
-#endif
-
- return 0;
-}
-
-int fcgi_proclist_sort_down(server *srv, fcgi_extension_host *host, fcgi_proc *proc) {
- fcgi_proc *p;
-
- UNUSED(srv);
-
- /* we have been the smallest of the current list
- * and we want to insert the node sorted as soon
- * possible
- *
- * 0 0 0 0 1 0 1
- * ^ |
- * | |
- * +----------+
- *
- *
- * the basic is idea is:
- * - the last active fastcgi process should be still
- * in ram and is not swapped out yet
- * - processes that are not reused will be killed
- * after some time by the trigger-handler
- * - remember it as:
- * everything > 0 is hot
- * all unused procs are colder the more right they are
- * ice-cold processes are propably unused since more
- * than 'unused-timeout', are swaped out and won't be
- * reused in the next seconds anyway.
- *
- */
-
- /* nothing to sort, only one element */
- if (host->first == proc && proc->next == NULL) return 0;
-
- for (p = host->first; p != proc && p->load < proc->load; p = p->next);
-
-
- /* no need to move something
- *
- * 1 2 2 2 3 3 3
- * ^
- * |
- * +
- *
- */
- if (p == proc) return 0;
-
- /* we have to move left. If we are already the first element
- * we are done */
- if (host->first == proc) return 0;
-
- /* release proc */
- if (proc->prev) proc->prev->next = proc->next;
- if (proc->next) proc->next->prev = proc->prev;
-
- /* proc should be left of p */
- proc->next = p;
- proc->prev = p->prev;
- if (p->prev) p->prev->next = proc;
- p->prev = proc;
-
- if (proc->prev == NULL) host->first = proc;
-#if 0
- for(p = host->first; p; p = p->next) {
- log_error_write(srv, __FILE__, __LINE__, "dd",
- p->pid, p->load);
- }
-#else
- UNUSED(srv);
-#endif
- return 0;
+ return fin;
}
static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_host *host) {
fcgi_proc *proc;
-
+
for (proc = host->first; proc; proc = proc->next) {
- if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sbdbdddd",
- "proc:",
- host->host, proc->port,
- proc->socket,
+ int status;
+
+ if (p->conf.debug > 2) {
+ log_error_write(srv, __FILE__, __LINE__, "sbdddd",
+ "proc:",
+ proc->connection_name,
proc->state,
proc->is_local,
proc->load,
proc->pid);
}
-
- if (!proc->is_local) {
- /*
- * external servers might get disabled
- *
- * enable the server again, perhaps it is back again
- */
-
- if ((proc->state == PROC_STATE_DISABLED) &&
- (srv->cur_ts > proc->disabled_until)) {
- proc->state = PROC_STATE_RUNNING;
- host->active_procs++;
-
- fastcgi_status_copy_procname(p->statuskey, host, proc);
- buffer_append_string(p->statuskey, ".disabled");
- status_counter_set(srv, CONST_BUF_LEN(p->statuskey), 0);
+ /*
+ * if the remote side is overloaded, we check back after <n> seconds
+ *
+ */
+ switch (proc->state) {
+ case PROC_STATE_KILLED:
+ case PROC_STATE_UNSET:
+ /* this should never happen as long as adaptive spawing is disabled */
+ assert(0);
- log_error_write(srv, __FILE__, __LINE__, "sbdb",
- "fcgi-server re-enabled:",
- host->host, host->port,
- host->unixsocket);
- }
- } else {
- /* the child should not terminate at all */
- int status;
-
- if (proc->state == PROC_STATE_DIED_WAIT_FOR_PID) {
- switch(waitpid(proc->pid, &status, WNOHANG)) {
- case 0:
- /* child is still alive */
- break;
- case -1:
- break;
- default:
- if (WIFEXITED(status)) {
+ break;
+ case PROC_STATE_RUNNING:
+ break;
+ case PROC_STATE_OVERLOADED:
+ if (srv->cur_ts <= proc->disabled_until) break;
+
+ proc->state = PROC_STATE_RUNNING;
+ host->active_procs++;
+
+ log_error_write(srv, __FILE__, __LINE__, "sbdb",
+ "fcgi-server re-enabled:",
+ host->host, host->port,
+ host->unixsocket);
+ break;
+ case PROC_STATE_DIED_WAIT_FOR_PID:
+ /* non-local procs don't have PIDs to wait for */
+ if (!proc->is_local) {
+ proc->state = PROC_STATE_DIED;
+ } else {
+ /* the child should not terminate at all */
+
+ for ( ;; ) {
+ switch(waitpid(proc->pid, &status, WNOHANG)) {
+ case 0:
+ /* child is still alive */
+ if (srv->cur_ts <= proc->disabled_until) break;
+
+ proc->state = PROC_STATE_RUNNING;
+ host->active_procs++;
+
+ log_error_write(srv, __FILE__, __LINE__, "sbdb",
+ "fcgi-server re-enabled:",
+ host->host, host->port,
+ host->unixsocket);
+ break;
+ case -1:
+ if (errno == EINTR) continue;
+
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child died somehow, waitpid failed:",
+ errno);
+ proc->state = PROC_STATE_DIED;
+ break;
+ default:
+ if (WIFEXITED(status)) {
#if 0
- log_error_write(srv, __FILE__, __LINE__, "sdsd",
+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
"child exited, pid:", proc->pid,
"status:", WEXITSTATUS(status));
#endif
- } else if (WIFSIGNALED(status)) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "child signaled:",
+ } else if (WIFSIGNALED(status)) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child signaled:",
WTERMSIG(status));
- } else {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "child died somehow:",
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child died somehow:",
status);
+ }
+
+ proc->state = PROC_STATE_DIED;
+ break;
}
-
- proc->state = PROC_STATE_DIED;
break;
}
}
-
- /*
- * local servers might died, but we restart them
- *
- */
- if (proc->state == PROC_STATE_DIED &&
- proc->load == 0) {
+
+ /* fall through if we have a dead proc now */
+ if (proc->state != PROC_STATE_DIED) break;
+
+ case PROC_STATE_DIED:
+ /* local procs get restarted by us,
+ * remote ones hopefully by the admin */
+
+ if (!buffer_is_empty(host->bin_path)) {
+ /* we still have connections bound to this proc,
+ * let them terminate first */
+ if (proc->load != 0) break;
+
/* restart the child */
-
+
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
+ log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
"--- fastcgi spawning",
- "\n\tport:", host->port,
- "\n\tsocket", host->unixsocket,
- "\n\tcurrent:", 1, "/", host->min_procs);
+ "\n\tsocket", proc->connection_name,
+ "\n\tcurrent:", 1, "/", host->max_procs);
}
-
+
if (fcgi_spawn_connection(srv, p, host, proc)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"ERROR: spawning fcgi failed.");
return HANDLER_ERROR;
}
-
- fcgi_proclist_sort_down(srv, host, proc);
+ } else {
+ if (srv->cur_ts <= proc->disabled_until) break;
+
+ proc->state = PROC_STATE_RUNNING;
+ host->active_procs++;
+
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "fcgi-server re-enabled:",
+ proc->connection_name);
}
+ break;
}
}
-
+
return 0;
}
@@ -2741,18 +2841,22 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
plugin_data *p = hctx->plugin_data;
fcgi_extension_host *host= hctx->host;
connection *con = hctx->remote_conn;
-
+ fcgi_proc *proc;
+
int ret;
- /* sanity check */
- if (!host ||
- ((!host->host->used || !host->port) && !host->unixsocket->used)) {
- log_error_write(srv, __FILE__, __LINE__, "sxddd",
- "write-req: error",
- host,
- host->host->used,
- host->port,
- host->unixsocket->used);
+ /* 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) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "fatal error: host = NULL");
+ return HANDLER_ERROR;
+ }
+ if ((!host->port && !host->unixsocket->used)) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "fatal error: neither host->port nor host->unixsocket is set");
return HANDLER_ERROR;
}
@@ -2760,33 +2864,39 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
int socket_error;
socklen_t socket_error_len = sizeof(socket_error);
-
+
/* try to finish the connect() */
if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"getsockopt failed:", strerror(errno));
-
+
+ fcgi_host_disable(srv, hctx);
+
return HANDLER_ERROR;
}
if (socket_error != 0) {
if (!hctx->proc->is_local || p->conf.debug) {
/* local procs get restarted */
-
- log_error_write(srv, __FILE__, __LINE__, "sssd",
- "establishing connection failed:", strerror(socket_error),
- "port:", hctx->proc->port);
+
+ log_error_write(srv, __FILE__, __LINE__, "sssb",
+ "establishing connection failed:", strerror(socket_error),
+ "socket:", hctx->proc->connection_name);
}
-
- hctx->proc->disabled_until = srv->cur_ts + 10;
-
+
+ fcgi_host_disable(srv, hctx);
+ log_error_write(srv, __FILE__, __LINE__, "sdssdsd",
+ "backend is overloaded; we'll disable it for", hctx->host->disable_time, "seconds and send the request to another backend instead:",
+ "reconnects:", hctx->reconnects,
+ "load:", host->load);
+
fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
- buffer_append_string(p->statuskey, ".died");
+ buffer_append_string_len(p->statuskey, CONST_STR_LEN(".died"));
status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
-
+
return HANDLER_ERROR;
}
- /* go on with preparing the request */
+ /* go on with preparing the request */
hctx->state = FCGI_STATE_PREPARE_WRITE;
}
@@ -2797,89 +2907,105 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
break;
case FCGI_STATE_INIT:
/* do we have a running process for this host (max-procs) ? */
+ hctx->proc = NULL;
+
+ for (proc = hctx->host->first;
+ proc && proc->state != PROC_STATE_RUNNING;
+ proc = proc->next);
- for (hctx->proc = hctx->host->first;
- hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
- hctx->proc = hctx->proc->next);
-
- /* all childs are dead */
- if (hctx->proc == NULL) {
+ /* all children are dead */
+ if (proc == NULL) {
hctx->fde_ndx = -1;
-
+
return HANDLER_ERROR;
}
+ hctx->proc = proc;
+
+ /* check the other procs if they have a lower load */
+ for (proc = proc->next; proc; proc = proc->next) {
+ if (proc->state != PROC_STATE_RUNNING) continue;
+ if (proc->load < hctx->proc->load) hctx->proc = proc;
+ }
+
ret = host->unixsocket->used ? AF_UNIX : AF_INET;
-
+
if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
if (errno == EMFILE ||
errno == EINTR) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"wait for fd at connection:", con->fd);
-
+
return HANDLER_WAIT_FOR_FD;
}
-
- log_error_write(srv, __FILE__, __LINE__, "ssdd",
+
+ log_error_write(srv, __FILE__, __LINE__, "ssdd",
"socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
return HANDLER_ERROR;
}
hctx->fde_ndx = -1;
-
+
srv->cur_fds++;
-
+
fdevent_register(srv->ev, hctx->fd, fcgi_handle_fdevent, hctx);
-
+
if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"fcntl failed:", strerror(errno));
-
+
return HANDLER_ERROR;
}
-
+
if (hctx->proc->is_local) {
hctx->pid = hctx->proc->pid;
}
-
+
switch (fcgi_establish_connection(srv, hctx)) {
case CONNECTION_DELAYED:
/* connection is in progress, wait for an event and call getsockopt() below */
-
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
-
+
+ fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
+
fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT_DELAYED);
return HANDLER_WAIT_FOR_EVENT;
case CONNECTION_OVERLOADED:
/* cool down the backend, it is overloaded
* -> EAGAIN */
- log_error_write(srv, __FILE__, __LINE__, "ssdsdb",
- "backend is overloaded, we disable it for a 2 seconds and send the request to another backend instead:"
- "reconnects:", hctx->reconnects,
- "load:", host->load,
- host->unixsocket);
-
+ if (hctx->host->disable_time) {
+ log_error_write(srv, __FILE__, __LINE__, "sdssdsd",
+ "backend is overloaded; we'll disable it for", hctx->host->disable_time, "seconds and send the request to another backend instead:",
+ "reconnects:", hctx->reconnects,
+ "load:", host->load);
- hctx->proc->disabled_until = srv->cur_ts + 2;
+ hctx->proc->disabled_until = srv->cur_ts + hctx->host->disable_time;
+ if (hctx->proc->state == PROC_STATE_RUNNING) hctx->host->active_procs--;
+ hctx->proc->state = PROC_STATE_OVERLOADED;
+ }
fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
- buffer_append_string(p->statuskey, ".overloaded");
+ buffer_append_string_len(p->statuskey, CONST_STR_LEN(".overloaded"));
status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
-
+
return HANDLER_ERROR;
case CONNECTION_DEAD:
/* we got a hard error from the backend like
* - ECONNREFUSED for tcp-ip sockets
* - ENOENT for unix-domain-sockets
*
- * for check if the host is back in 10 seconds
+ * for check if the host is back in hctx->host->disable_time seconds
* */
-
- hctx->proc->disabled_until = srv->cur_ts + 10;
-
+
+ fcgi_host_disable(srv, hctx);
+
+ log_error_write(srv, __FILE__, __LINE__, "sdssdsd",
+ "backend died; we'll disable it for", hctx->host->disable_time, "seconds and send the request to another backend instead:",
+ "reconnects:", hctx->reconnects,
+ "load:", host->load);
+
fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
- buffer_append_string(p->statuskey, ".died");
+ buffer_append_string_len(p->statuskey, CONST_STR_LEN(".died"));
status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
@@ -2888,104 +3014,67 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
/* everything is ok, go on */
fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
-
- break;
- case CONNECTION_UNSET:
+
break;
}
-
+
case FCGI_STATE_PREPARE_WRITE:
/* ok, we have the connection */
-
- hctx->proc->load++;
- hctx->proc->last_used = srv->cur_ts;
+
+ fcgi_proc_load_inc(srv, hctx);
hctx->got_proc = 1;
-
+
status_counter_inc(srv, CONST_STR_LEN("fastcgi.requests"));
- status_counter_inc(srv, CONST_STR_LEN("fastcgi.active-requests"));
fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
- buffer_append_string(p->statuskey, ".connected");
+ buffer_append_string_len(p->statuskey, CONST_STR_LEN(".connected"));
status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
- fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
- buffer_append_string(p->statuskey, ".load");
-
- status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
-
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sddbdd",
- "got proc:",
- hctx->fd,
- hctx->proc->pid,
- hctx->proc->socket,
- hctx->proc->port,
- hctx->proc->load);
+ log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
+ "got proc:",
+ "pid:", hctx->proc->pid,
+ "socket:", hctx->proc->connection_name,
+ "load:", hctx->proc->load);
}
/* move the proc-list entry down the list */
- fcgi_proclist_sort_up(srv, hctx->host, hctx->proc);
-
if (hctx->request_id == 0) {
- hctx->request_id = fcgi_requestid_new(srv, p);
+ hctx->request_id = 1; /* always use id 1 as we don't use multiplexing */
} else {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"fcgi-request is already in use:", hctx->request_id);
}
-
+
/* fall through */
- fcgi_create_env(srv, hctx, hctx->request_id);
-
+ if (-1 == fcgi_create_env(srv, hctx, hctx->request_id)) return HANDLER_ERROR;
fcgi_set_state(srv, hctx, FCGI_STATE_WRITE);
-
/* fall through */
case FCGI_STATE_WRITE:
- ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
+ ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb, MAX_WRITE_LIMIT);
chunkqueue_remove_finished_chunks(hctx->wb);
-
+
if (ret < 0) {
switch(errno) {
+ case EPIPE:
case ENOTCONN:
- /* the connection got dropped after accept()
- *
- * this is most of the time a PHP which dies
- * after PHP_FCGI_MAX_REQUESTS
- *
- */
- if (hctx->wb->bytes_out == 0 &&
- hctx->reconnects < 5) {
- usleep(10000); /* take away the load of the webserver
- * to let the php a chance to restart
- */
-
- fcgi_reconnect(srv, hctx);
-
- return HANDLER_WAIT_FOR_FD;
- }
-
- /* not reconnected ... why
- *
- * far@#lighttpd report this for FreeBSD
- *
+ case ECONNRESET:
+ /* the connection got dropped after accept()
+ * we don't care about that - if you accept() it, you have to handle it.
*/
-
- log_error_write(srv, __FILE__, __LINE__, "ssdsd",
- "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
+
+ log_error_write(srv, __FILE__, __LINE__, "ssosb",
+ "connection was dropped after accept() (perhaps the fastcgi process died),",
"write-offset:", hctx->wb->bytes_out,
- "reconnect attempts:", hctx->reconnects);
-
+ "socket:", hctx->proc->connection_name);
+
return HANDLER_ERROR;
- case EAGAIN:
- case EINTR:
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
-
- return HANDLER_WAIT_FOR_EVENT;
default:
- log_error_write(srv, __FILE__, __LINE__, "ssd",
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
"write failed:", strerror(errno), errno);
-
+
return HANDLER_ERROR;
}
}
@@ -2993,11 +3082,11 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
/* we don't need the out event anymore */
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
+ fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
fcgi_set_state(srv, hctx, FCGI_STATE_READ);
} else {
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
-
+ fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
+
return HANDLER_WAIT_FOR_EVENT;
}
@@ -3009,7 +3098,7 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
return HANDLER_ERROR;
}
-
+
return HANDLER_WAIT_FOR_EVENT;
}
@@ -3018,58 +3107,68 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
* */
SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
plugin_data *p = p_d;
-
+
handler_ctx *hctx = con->plugin_ctx[p->id];
- fcgi_proc *proc;
fcgi_extension_host *host;
-
+
if (NULL == hctx) return HANDLER_GO_ON;
-
+
/* not my job */
if (con->mode != p->id) return HANDLER_GO_ON;
/* we don't have a host yet, choose one
- * -> this happens in the first round
+ * -> this happens in the first round
* and when the host died and we have to select a new one */
if (hctx->host == NULL) {
size_t k;
int ndx, used = -1;
- /* get best server */
- for (k = 0, ndx = -1; k < hctx->ext->used; k++) {
- host = hctx->ext->hosts[k];
-
- /* we should have at least one proc that can do somthing */
- if (host->active_procs == 0) continue;
-
- if (used == -1 || host->load < used) {
- used = host->load;
-
- ndx = k;
+ /* check if the next server has no load. */
+ ndx = hctx->ext->last_used_ndx + 1;
+ if(ndx >= (int) hctx->ext->used || ndx < 0) ndx = 0;
+ host = hctx->ext->hosts[ndx];
+ if (host->load > 0) {
+ /* get backend with the least load. */
+ for (k = 0, ndx = -1; k < hctx->ext->used; k++) {
+ host = hctx->ext->hosts[k];
+
+ /* we should have at least one proc that can do something */
+ if (host->active_procs == 0) continue;
+
+ if (used == -1 || host->load < used) {
+ used = host->load;
+
+ ndx = k;
+ }
}
}
-
+
/* found a server */
if (ndx == -1) {
/* all hosts are down */
fcgi_connection_close(srv, hctx);
-
+
con->http_status = 500;
con->mode = DIRECT;
return HANDLER_FINISHED;
}
+ hctx->ext->last_used_ndx = ndx;
host = hctx->ext->hosts[ndx];
-
- /*
- * if check-local is disabled, use the uri.path handler
- *
+
+ /*
+ * if check-local is disabled, use the uri.path handler
+ *
*/
-
+
/* init handler-context */
- hctx->host = host;
+
+ /* we put a connection on this host, move the other new connections to other hosts
+ *
+ * as soon as hctx->host is unassigned, decrease the load again */
+ fcgi_host_assign(srv, hctx, host);
hctx->proc = NULL;
} else {
host = hctx->host;
@@ -3078,49 +3177,10 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
/* ok, create the request */
switch(fcgi_write_request(srv, hctx)) {
case HANDLER_ERROR:
- proc = hctx->proc;
host = hctx->host;
-
+
if (hctx->state == FCGI_STATE_INIT ||
hctx->state == FCGI_STATE_CONNECT_DELAYED) {
- /* connect() or getsockopt() failed,
- * restart the request-handling
- */
- if (proc) {
- if (proc->is_local) {
-
- if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sbdb",
- "connect() to fastcgi failed, restarting the request-handling:",
- host->host,
- proc->port,
- proc->socket);
- }
-
- /*
- * several hctx might reference the same proc
- *
- * Only one of them should mark the proc as dead all the other
- * ones should just take a new one.
- *
- * If a new proc was started with the old struct this might lead
- * the mark a perfect proc as dead otherwise
- *
- */
- if (proc->state == PROC_STATE_RUNNING &&
- hctx->pid == proc->pid) {
- proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
- }
- } else {
- proc->state = PROC_STATE_DISABLED;
- }
- host->active_procs--;
- fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
- buffer_append_string(p->statuskey, ".disabled");
-
- status_counter_set(srv, CONST_BUF_LEN(p->statuskey), 1);
- }
-
fcgi_restart_dead_procs(srv, p, host);
/* cleanup this request and let the request handler start this request again */
@@ -3131,22 +3191,22 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
return HANDLER_WAIT_FOR_FD;
} else {
fcgi_connection_close(srv, hctx);
-
+
buffer_reset(con->physical.path);
con->mode = DIRECT;
- con->http_status = 500;
+ con->http_status = 503;
joblist_append(srv, con); /* in case we come from the event-handler */
return HANDLER_FINISHED;
}
} else {
fcgi_connection_close(srv, hctx);
-
+
buffer_reset(con->physical.path);
con->mode = DIRECT;
- con->http_status = 503;
+ if (con->http_status != 400) con->http_status = 503;
joblist_append(srv, con); /* really ? */
-
+
return HANDLER_FINISHED;
}
case HANDLER_WAIT_FOR_EVENT:
@@ -3163,12 +3223,11 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
}
}
-static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
- server *srv = (server *)s;
+static handler_t fcgi_handle_fdevent(server *srv, void *ctx, int revents) {
handler_ctx *hctx = ctx;
connection *con = hctx->remote_conn;
plugin_data *p = hctx->plugin_data;
-
+
fcgi_proc *proc = hctx->proc;
fcgi_extension_host *host= hctx->host;
@@ -3178,37 +3237,39 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
case 0:
break;
case 1:
-
- if (host->mode == FCGI_AUTHORIZER &&
+
+ if (host->mode == FCGI_AUTHORIZER &&
(con->http_status == 200 ||
con->http_status == 0)) {
/*
- * If we are here in AUTHORIZER mode then a request for autorizer
- * was proceeded already, and status 200 has been returned. We need
- * now to handle autorized request.
+ * If we are here in AUTHORIZER mode then a request for authorizer
+ * was processed already, and status 200 has been returned. We need
+ * now to handle authorized request.
*/
buffer_copy_string_buffer(con->physical.doc_root, host->docroot);
-
+ buffer_copy_string_buffer(con->physical.basedir, host->docroot);
+
buffer_copy_string_buffer(con->physical.path, host->docroot);
buffer_append_string_buffer(con->physical.path, con->uri.path);
fcgi_connection_close(srv, hctx);
-
+
con->mode = DIRECT;
+ con->http_status = 0;
con->file_started = 1; /* fcgi_extension won't touch the request afterwards */
} else {
/* we are done */
fcgi_connection_close(srv, hctx);
}
-
+
joblist_append(srv, con);
return HANDLER_FINISHED;
case -1:
if (proc->pid && proc->state != PROC_STATE_DIED) {
int status;
-
+
/* only fetch the zombie if it is not already done */
-
+
switch(waitpid(proc->pid, &status, WNOHANG)) {
case 0:
/* child is still alive */
@@ -3218,60 +3279,60 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
default:
/* the child should not terminate at all */
if (WIFEXITED(status)) {
- log_error_write(srv, __FILE__, __LINE__, "sdsd",
+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
"child exited, pid:", proc->pid,
"status:", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "child signaled:",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child signaled:",
WTERMSIG(status));
} else {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "child died somehow:",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child died somehow:",
status);
}
-
+
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
+ log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
"--- fastcgi spawning",
- "\n\tport:", host->port,
- "\n\tsocket", host->unixsocket,
- "\n\tcurrent:", 1, "/", host->min_procs);
+ "\n\tsocket", proc->connection_name,
+ "\n\tcurrent:", 1, "/", host->max_procs);
}
-
+
if (fcgi_spawn_connection(srv, p, host, proc)) {
- /* child died */
+ /* respawning failed, retry later */
proc->state = PROC_STATE_DIED;
- } else {
- fcgi_proclist_sort_down(srv, host, proc);
+
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "respawning failed, will retry later");
}
-
+
break;
}
}
if (con->file_started == 0) {
- /* nothing has been send out yet, try to use another child */
-
+ /* nothing has been sent out yet, try to use another child */
+
if (hctx->wb->bytes_out == 0 &&
hctx->reconnects < 5) {
fcgi_reconnect(srv, hctx);
-
- log_error_write(srv, __FILE__, __LINE__, "ssdsd",
- "response not received, request not sent, reconnecting.",
- "connection-fd:", con->fd,
- "fcgi-fd:", hctx->fd);
-
+
+ log_error_write(srv, __FILE__, __LINE__, "ssbsBSBs",
+ "response not received, request not sent",
+ "on socket:", proc->connection_name,
+ "for", con->uri.path, "?", con->uri.query, ", reconnecting");
+
return HANDLER_WAIT_FOR_FD;
}
-
- log_error_write(srv, __FILE__, __LINE__, "sosdsd",
+
+ log_error_write(srv, __FILE__, __LINE__, "sosbsBSBs",
"response not received, request sent:", hctx->wb->bytes_out,
- "connection-fd:", con->fd,
- "fcgi-fd:", hctx->fd);
-
+ "on socket:", proc->connection_name,
+ "for", con->uri.path, "?", con->uri.query, ", closing connection");
+
fcgi_connection_close(srv, hctx);
-
+
connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
buffer_reset(con->physical.path);
con->http_status = 500;
@@ -3279,76 +3340,72 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
} else {
/* response might have been already started, kill the connection */
fcgi_connection_close(srv, hctx);
-
- log_error_write(srv, __FILE__, __LINE__, "ssdsd",
- "response already sent out, termination connection",
- "connection-fd:", con->fd,
- "fcgi-fd:", hctx->fd);
-
+
+ log_error_write(srv, __FILE__, __LINE__, "ssbsBSBs",
+ "response already sent out, but backend returned error",
+ "on socket:", proc->connection_name,
+ "for", con->uri.path, "?", con->uri.query, ", terminating connection");
+
connection_set_state(srv, con, CON_STATE_ERROR);
}
/* */
-
-
+
+
joblist_append(srv, con);
return HANDLER_FINISHED;
}
}
-
+
if (revents & FDEVENT_OUT) {
if (hctx->state == FCGI_STATE_CONNECT_DELAYED ||
hctx->state == FCGI_STATE_WRITE) {
/* we are allowed to send something out
- *
- * 1. in a unfinished connect() call
- * 2. in a unfinished write() call (long POST request)
+ *
+ * 1. in an unfinished connect() call
+ * 2. in an unfinished write() call (long POST request)
*/
return mod_fastcgi_handle_subrequest(srv, con, p);
} else {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "got a FDEVENT_OUT and didn't know why:",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "got a FDEVENT_OUT and didn't know why:",
hctx->state);
}
}
-
+
/* perhaps this issue is already handled */
if (revents & FDEVENT_HUP) {
if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
/* getoptsock will catch this one (right ?)
- *
- * if we are in connect we might get a EINPROGRESS
- * in the first call and a FDEVENT_HUP in the
+ *
+ * if we are in connect we might get an EINPROGRESS
+ * in the first call and an FDEVENT_HUP in the
* second round
- *
+ *
* FIXME: as it is a bit ugly.
- *
+ *
*/
return mod_fastcgi_handle_subrequest(srv, con, p);
} else if (hctx->state == FCGI_STATE_READ &&
hctx->proc->port == 0) {
/* FIXME:
- *
+ *
* ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
* even if the FCGI_FIN packet is not received yet
*/
} else {
- log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
- "error: unexpected close of fastcgi connection for",
- con->uri.path,
- "(no fastcgi process on host: ",
- host->host,
- ", port: ",
- host->port,
- " ?)",
+ log_error_write(srv, __FILE__, __LINE__, "sBSbsbsd",
+ "error: unexpected close of fastcgi connection for",
+ con->uri.path, "?", con->uri.query,
+ "(no fastcgi process on socket:", proc->connection_name, "?)",
hctx->state);
-
+
connection_set_state(srv, con, CON_STATE_ERROR);
fcgi_connection_close(srv, hctx);
joblist_append(srv, con);
}
} else if (revents & FDEVENT_ERR) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"fcgi: got a FDEVENT_ERR. Don't know why.");
/* kill all connections to the fastcgi process */
@@ -3357,7 +3414,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
fcgi_connection_close(srv, hctx);
joblist_append(srv, con);
}
-
+
return HANDLER_FINISHED;
}
#define PATCH(x) \
@@ -3365,30 +3422,33 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(exts);
PATCH(debug);
-
+ PATCH(ext_mapping);
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.server"))) {
PATCH(exts);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.debug"))) {
PATCH(debug);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.map-extensions"))) {
+ PATCH(ext_mapping);
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -3401,152 +3461,217 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i
buffer *fn;
fcgi_extension *extension = NULL;
fcgi_extension_host *host = NULL;
-
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
/* Possibly, we processed already this request */
if (con->file_started == 1) return HANDLER_GO_ON;
fn = uri_path_handler ? con->uri.path : con->physical.path;
- if (fn->used == 0) {
- return HANDLER_ERROR;
- }
-
+ if (buffer_is_empty(fn)) return HANDLER_GO_ON;
+
s_len = fn->used - 1;
-
+
fcgi_patch_connection(srv, con, p);
-
- /* check if extension matches */
- for (k = 0; k < p->conf.exts->used; k++) {
+
+ /* fastcgi.map-extensions maps extensions to existing fastcgi.server entries
+ *
+ * fastcgi.map-extensions = ( ".php3" => ".php" )
+ *
+ * fastcgi.server = ( ".php" => ... )
+ *
+ * */
+
+ /* check if extension-mapping matches */
+ for (k = 0; k < p->conf.ext_mapping->used; k++) {
+ data_string *ds = (data_string *)p->conf.ext_mapping->data[k];
size_t ct_len; /* length of the config entry */
-
- extension = p->conf.exts->exts[k];
-
- if (extension->key->used == 0) continue;
-
- ct_len = extension->key->used - 1;
-
+
+ if (ds->key->used == 0) continue;
+
+ ct_len = ds->key->used - 1;
+
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;
- } else if (0 == strncmp(fn->ptr + s_len - ct_len, extension->key->ptr, ct_len)) {
- /* check extension in the form ".fcg" */
+
+ /* found a mapping */
+ if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
+ /* check if we know the extension */
+
+ /* we can reuse k here */
+ for (k = 0; k < p->conf.exts->used; k++) {
+ extension = p->conf.exts->exts[k];
+
+ if (buffer_is_equal(ds->value, extension->key)) {
+ break;
+ }
+ }
+
+ if (k == p->conf.exts->used) {
+ /* found nothign */
+ extension = NULL;
+ }
break;
}
}
-
- /* extension doesn't match */
- if (k == p->conf.exts->used) {
- return HANDLER_GO_ON;
+
+ if (extension == NULL) {
+ /* check if extension matches */
+ for (k = 0; k < p->conf.exts->used; k++) {
+ size_t ct_len; /* length of the config entry */
+ fcgi_extension *ext = p->conf.exts->exts[k];
+
+ if (ext->key->used == 0) continue;
+
+ ct_len = ext->key->used - 1;
+
+ /* check _url_ in the form "/fcgi_pattern" */
+ if (ext->key->ptr[0] == '/') {
+ if ((ct_len <= con->uri.path->used -1) &&
+ (strncmp(con->uri.path->ptr, ext->key->ptr, ct_len) == 0)) {
+ extension = ext;
+ break;
+ }
+ } else if ((ct_len <= s_len) && (0 == strncmp(fn->ptr + s_len - ct_len, ext->key->ptr, ct_len))) {
+ /* check extension in the form ".fcg" */
+ extension = ext;
+ break;
+ }
+ }
+ /* extension doesn't match */
+ if (NULL == extension) {
+ return HANDLER_GO_ON;
+ }
}
- /* get best server */
+ /* check if we have at least one server for this extension up and running */
for (k = 0; k < extension->used; k++) {
- host = extension->hosts[k];
-
- /* we should have at least one proc that can do somthing */
- if (host->active_procs == 0) {
- host = NULL;
+ fcgi_extension_host *h = extension->hosts[k];
+ /* we should have at least one proc that can do something */
+ if (h->active_procs == 0) {
continue;
}
- /* we found one host that is alive */
+ /* we found one host that is alive */
+ host = h;
break;
}
-
+
if (!host) {
/* sorry, we don't have a server alive for this ext */
buffer_reset(con->physical.path);
con->http_status = 500;
-
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "no fcgi-handler found for:",
- fn);
-
+
+ /* only send the 'no handler' once */
+ if (!extension->note_is_sent) {
+ extension->note_is_sent = 1;
+
+ log_error_write(srv, __FILE__, __LINE__, "sBSbsbs",
+ "all handlers for", con->uri.path, "?", con->uri.query,
+ "on", extension->key,
+ "are down.");
+ }
+
return HANDLER_FINISHED;
}
- /*
- * if check-local is disabled, use the uri.path handler
- *
+ /* a note about no handler is not sent yet */
+ extension->note_is_sent = 0;
+
+ /*
+ * if check-local is disabled, use the uri.path handler
+ *
*/
-
+
/* init handler-context */
if (uri_path_handler) {
if (host->check_local == 0) {
handler_ctx *hctx;
char *pathinfo;
-
+
hctx = handler_ctx_init();
-
+
hctx->remote_conn = con;
hctx->plugin_data = p;
hctx->proc = NULL;
hctx->ext = extension;
-
+
hctx->conf.exts = p->conf.exts;
hctx->conf.debug = p->conf.debug;
-
+
con->plugin_ctx[p->id] = hctx;
-
+
con->mode = p->id;
-
+
if (con->conf.log_request_handling) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"handling it in mod_fastcgi");
}
-
- /* the prefix is the SCRIPT_NAME,
- * everthing from start to the next slash
- * this is important for check-local = "disable"
- *
- * if prefix = /admin.fcgi
- *
- * /admin.fcgi/foo/bar
- *
- * SCRIPT_NAME = /admin.fcgi
- * PATH_INFO = /foo/bar
- *
- * if prefix = /fcgi-bin/
- *
- * /fcgi-bin/foo/bar
- *
- * SCRIPT_NAME = /fcgi-bin/foo
- * PATH_INFO = /bar
- *
- */
-
- /* the rewrite is only done for /prefix/? matches */
- if (extension->key->ptr[0] == '/' &&
- con->uri.path->used > extension->key->used &&
- NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
- /* rewrite uri.path and pathinfo */
-
- buffer_copy_string(con->request.pathinfo, pathinfo);
-
- con->uri.path->used -= con->request.pathinfo->used - 1;
- con->uri.path->ptr[con->uri.path->used - 1] = '\0';
+
+ /* do not split path info for authorizer */
+ if (host->mode != FCGI_AUTHORIZER) {
+ /* the prefix is the SCRIPT_NAME,
+ * everything from start to the next slash
+ * this is important for check-local = "disable"
+ *
+ * if prefix = /admin.fcgi
+ *
+ * /admin.fcgi/foo/bar
+ *
+ * SCRIPT_NAME = /admin.fcgi
+ * PATH_INFO = /foo/bar
+ *
+ * if prefix = /fcgi-bin/
+ *
+ * /fcgi-bin/foo/bar
+ *
+ * SCRIPT_NAME = /fcgi-bin/foo
+ * PATH_INFO = /bar
+ *
+ * if prefix = /, and fix-root-path-name is enable
+ *
+ * /fcgi-bin/foo/bar
+ *
+ * SCRIPT_NAME = /fcgi-bin/foo
+ * PATH_INFO = /bar
+ *
+ */
+
+ /* the rewrite is only done for /prefix/? matches */
+ if (host->fix_root_path_name && extension->key->ptr[0] == '/' && extension->key->ptr[1] == '\0') {
+ buffer_copy_string(con->request.pathinfo, con->uri.path->ptr);
+ con->uri.path->used = 1;
+ con->uri.path->ptr[con->uri.path->used - 1] = '\0';
+ } else if (extension->key->ptr[0] == '/' &&
+ con->uri.path->used > extension->key->used &&
+ NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
+ /* rewrite uri.path and pathinfo */
+
+ buffer_copy_string(con->request.pathinfo, pathinfo);
+
+ con->uri.path->used -= con->request.pathinfo->used - 1;
+ con->uri.path->ptr[con->uri.path->used - 1] = '\0';
+ }
}
}
} else {
handler_ctx *hctx;
hctx = handler_ctx_init();
-
+
hctx->remote_conn = con;
hctx->plugin_data = p;
hctx->proc = NULL;
hctx->ext = extension;
-
+
hctx->conf.exts = p->conf.exts;
hctx->conf.debug = p->conf.debug;
-
+
con->plugin_ctx[p->id] = hctx;
-
+
con->mode = p->id;
-
+
if (con->conf.log_request_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
}
@@ -3568,19 +3693,19 @@ static handler_t fcgi_check_extension_2(server *srv, connection *con, void *p_d)
JOBLIST_FUNC(mod_fastcgi_handle_joblist) {
plugin_data *p = p_d;
handler_ctx *hctx = con->plugin_ctx[p->id];
-
+
if (hctx == NULL) return HANDLER_GO_ON;
if (hctx->fd != -1) {
switch (hctx->state) {
case FCGI_STATE_READ:
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
-
+ fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
+
break;
case FCGI_STATE_CONNECT_DELAYED:
case FCGI_STATE_WRITE:
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
-
+ fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
+
break;
case FCGI_STATE_INIT:
/* at reconnect */
@@ -3597,7 +3722,7 @@ JOBLIST_FUNC(mod_fastcgi_handle_joblist) {
static handler_t fcgi_connection_close_callback(server *srv, connection *con, void *p_d) {
plugin_data *p = p_d;
-
+
fcgi_connection_close(srv, con->plugin_ctx[p->id]);
return HANDLER_GO_ON;
@@ -3606,17 +3731,17 @@ static handler_t fcgi_connection_close_callback(server *srv, connection *con, vo
TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
plugin_data *p = p_d;
size_t i, j, n;
-
-
+
+
/* perhaps we should kill a connect attempt after 10-15 seconds
- *
- * currently we wait for the TCP timeout which is on Linux 180 seconds
- *
- *
- *
+ *
+ * currently we wait for the TCP timeout which is 180 seconds on Linux
+ *
+ *
+ *
*/
- /* check all childs if they are still up */
+ /* check all children if they are still up */
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *conf;
@@ -3630,118 +3755,21 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
fcgi_extension *ex;
ex = exts->exts[j];
-
+
for (n = 0; n < ex->used; n++) {
-
+
fcgi_proc *proc;
- unsigned long sum_load = 0;
fcgi_extension_host *host;
-
+
host = ex->hosts[n];
-
+
fcgi_restart_dead_procs(srv, p, host);
-
- for (proc = host->first; proc; proc = proc->next) {
- sum_load += proc->load;
- }
-
- if (host->num_procs &&
- host->num_procs < host->max_procs &&
- (sum_load / host->num_procs) > host->max_load_per_proc) {
- /* overload, spawn new child */
- fcgi_proc *fp = NULL;
-
- if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "overload detected, spawning a new child");
- }
-
- for (fp = host->unused_procs; fp && fp->pid != 0; fp = fp->next);
-
- if (fp) {
- if (fp == host->unused_procs) host->unused_procs = fp->next;
-
- if (fp->next) fp->next->prev = NULL;
-
- host->max_id++;
- } else {
- fp = fastcgi_process_init();
- fp->id = host->max_id++;
- }
-
- host->num_procs++;
-
- if (buffer_is_empty(host->unixsocket)) {
- fp->port = host->port + fp->id;
- } else {
- buffer_copy_string_buffer(fp->socket, host->unixsocket);
- buffer_append_string(fp->socket, "-");
- buffer_append_long(fp->socket, fp->id);
- }
-
- if (fcgi_spawn_connection(srv, p, host, fp)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "ERROR: spawning fcgi failed.");
- return HANDLER_ERROR;
- }
-
- fp->prev = NULL;
- fp->next = host->first;
- if (host->first) {
- host->first->prev = fp;
- }
- host->first = fp;
- }
-
- for (proc = host->first; proc; proc = proc->next) {
- if (proc->load != 0) break;
- if (host->num_procs <= host->min_procs) break;
- if (proc->pid == 0) continue;
-
- if (srv->cur_ts - proc->last_used > host->idle_timeout) {
- /* a proc is idling for a long time now,
- * terminated it */
-
- if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "ssbsd",
- "idle-timeout reached, terminating child:",
- "socket:", proc->socket,
- "pid", proc->pid);
- }
-
-
- if (proc->next) proc->next->prev = proc->prev;
- if (proc->prev) proc->prev->next = proc->next;
-
- if (proc->prev == NULL) host->first = proc->next;
-
- proc->prev = NULL;
- proc->next = host->unused_procs;
-
- if (host->unused_procs) host->unused_procs->prev = proc;
- host->unused_procs = proc;
-
- kill(proc->pid, SIGTERM);
-
- proc->state = PROC_STATE_KILLED;
-
- log_error_write(srv, __FILE__, __LINE__, "ssbsd",
- "killed:",
- "socket:", proc->socket,
- "pid", proc->pid);
-
- host->num_procs--;
-
- /* proc is now in unused, let the next second handle the next process */
- break;
- }
- }
-
+
for (proc = host->unused_procs; proc; proc = proc->next) {
int status;
-
+
if (proc->pid == 0) continue;
-
+
switch (waitpid(proc->pid, &status, WNOHANG)) {
case 0:
/* child still running after timeout, good */
@@ -3749,10 +3777,10 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
case -1:
if (errno != EINTR) {
/* no PID found ? should never happen */
- log_error_write(srv, __FILE__, __LINE__, "sddss",
+ log_error_write(srv, __FILE__, __LINE__, "sddss",
"pid ", proc->pid, proc->state,
"not found:", strerror(errno));
-
+
#if 0
if (errno == ECHILD) {
/* someone else has cleaned up for us */
@@ -3766,22 +3794,23 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
/* the child should not terminate at all */
if (WIFEXITED(status)) {
if (proc->state != PROC_STATE_KILLED) {
- log_error_write(srv, __FILE__, __LINE__, "sdb",
- "child exited:",
- WEXITSTATUS(status), proc->socket);
+ log_error_write(srv, __FILE__, __LINE__, "sdb",
+ "child exited:",
+ WEXITSTATUS(status), proc->connection_name);
}
} else if (WIFSIGNALED(status)) {
if (WTERMSIG(status) != SIGTERM) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "child signaled:",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child signaled:",
WTERMSIG(status));
}
} else {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "child died somehow:",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child died somehow:",
status);
}
proc->pid = 0;
+ if (proc->state == PROC_STATE_RUNNING) host->active_procs--;
proc->state = PROC_STATE_UNSET;
host->max_id--;
}
@@ -3794,6 +3823,7 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
}
+int mod_fastcgi_plugin_init(plugin *p);
int mod_fastcgi_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("fastcgi");
@@ -3808,8 +3838,8 @@ int mod_fastcgi_plugin_init(plugin *p) {
p->handle_subrequest = mod_fastcgi_handle_subrequest;
p->handle_joblist = mod_fastcgi_handle_joblist;
p->handle_trigger = mod_fastcgi_handle_trigger;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_flv_streaming.c b/src/mod_flv_streaming.c
new file mode 100644
index 0000000..7a100db
--- /dev/null
+++ b/src/mod_flv_streaming.c
@@ -0,0 +1,277 @@
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "response.h"
+#include "http_chunk.h"
+#include "stat_cache.h"
+
+#include "plugin.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* plugin config for all request/connections */
+
+typedef struct {
+ array *extensions;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ buffer *query_str;
+ array *get_params;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_flv_streaming_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->query_str = buffer_init();
+ p->get_params = array_init();
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_flv_streaming_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (!s) continue;
+
+ array_free(s->extensions);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ buffer_free(p->query_str);
+ array_free(p->get_params);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "flv-streaming.extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->extensions = array_init();
+
+ cv[0].destination = s->extensions;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_flv_streaming_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(extensions);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("flv-streaming.extensions"))) {
+ PATCH(extensions);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+static int split_get_params(array *get_params, buffer *qrystr) {
+ size_t is_key = 1;
+ size_t i;
+ char *key = NULL, *val = NULL;
+
+ key = qrystr->ptr;
+
+ /* we need the \0 */
+ for (i = 0; i < qrystr->used; i++) {
+ switch(qrystr->ptr[i]) {
+ case '=':
+ if (is_key) {
+ val = qrystr->ptr + i + 1;
+
+ qrystr->ptr[i] = '\0';
+
+ is_key = 0;
+ }
+
+ break;
+ case '&':
+ case '\0': /* fin symbol */
+ if (!is_key) {
+ data_string *ds;
+ /* we need at least a = since the last & */
+
+ /* terminate the value */
+ qrystr->ptr[i] = '\0';
+
+ if (NULL == (ds = (data_string *)array_get_unused_element(get_params, TYPE_STRING))) {
+ ds = data_string_init();
+ }
+ buffer_copy_string_len(ds->key, key, strlen(key));
+ buffer_copy_string_len(ds->value, val, strlen(val));
+
+ array_insert_unique(get_params, (data_unset *)ds);
+ }
+
+ key = qrystr->ptr + i + 1;
+ val = NULL;
+ is_key = 1;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+URIHANDLER_FUNC(mod_flv_streaming_path_handler) {
+ plugin_data *p = p_d;
+ int s_len;
+ size_t k;
+
+ UNUSED(srv);
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+ if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
+
+ mod_flv_streaming_patch_connection(srv, con, p);
+
+ s_len = con->physical.path->used - 1;
+
+ for (k = 0; k < p->conf.extensions->used; k++) {
+ data_string *ds = (data_string *)p->conf.extensions->data[k];
+ int ct_len = ds->value->used - 1;
+
+ if (ct_len > s_len) continue;
+ if (ds->value->used == 0) continue;
+
+ if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
+ data_string *get_param;
+ stat_cache_entry *sce = NULL;
+ buffer *b;
+ int start;
+ char *err = NULL;
+ /* if there is a start=[0-9]+ in the header use it as start,
+ * otherwise send the full file */
+
+ array_reset(p->get_params);
+ buffer_copy_string_buffer(p->query_str, con->uri.query);
+ split_get_params(p->get_params, p->query_str);
+
+ if (NULL == (get_param = (data_string *)array_get_element(p->get_params, "start"))) {
+ return HANDLER_GO_ON;
+ }
+
+ /* too short */
+ if (get_param->value->used < 2) return HANDLER_GO_ON;
+
+ /* check if it is a number */
+ start = strtol(get_param->value->ptr, &err, 10);
+ if (*err != '\0') {
+ return HANDLER_GO_ON;
+ }
+
+ if (start <= 0) return HANDLER_GO_ON;
+
+ /* check if start is > filesize */
+ if (HANDLER_GO_ON != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+ return HANDLER_GO_ON;
+ }
+
+ if (start > sce->st.st_size) {
+ return HANDLER_GO_ON;
+ }
+
+ /* we are safe now, let's build a flv header */
+ b = chunkqueue_get_append_buffer(con->write_queue);
+ buffer_copy_string_len(b, CONST_STR_LEN("FLV\x1\x1\0\0\0\x9\0\0\0\x9"));
+
+ http_chunk_append_file(srv, con, con->physical.path, start, sce->st.st_size - start);
+
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("video/x-flv"));
+
+ con->file_finished = 1;
+
+ return HANDLER_FINISHED;
+ }
+ }
+
+ /* not found */
+ return HANDLER_GO_ON;
+}
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_flv_streaming_plugin_init(plugin *p);
+int mod_flv_streaming_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("flv_streaming");
+
+ p->init = mod_flv_streaming_init;
+ p->handle_physical = mod_flv_streaming_path_handler;
+ p->set_defaults = mod_flv_streaming_set_defaults;
+ p->cleanup = mod_flv_streaming_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/src/mod_indexfile.c b/src/mod_indexfile.c
index 4a784c6..c01da2f 100644
--- a/src/mod_indexfile.c
+++ b/src/mod_indexfile.c
@@ -1,9 +1,3 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-
#include "base.h"
#include "log.h"
#include "buffer.h"
@@ -12,6 +6,11 @@
#include "stat_cache.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
/* plugin config for all request/connections */
typedef struct {
@@ -20,51 +19,51 @@ typedef struct {
typedef struct {
PLUGIN_DATA;
-
+
buffer *tmp_buf;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
/* init the plugin data */
INIT_FUNC(mod_indexfile_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
p->tmp_buf = buffer_init();
-
+
return p;
}
/* detroy the plugin data */
FREE_FUNC(mod_indexfile_free) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
if (!s) continue;
-
+
array_free(s->indexfiles);
-
+
free(s);
}
free(p->config_storage);
}
-
+
buffer_free(p->tmp_buf);
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
@@ -73,33 +72,33 @@ FREE_FUNC(mod_indexfile_free) {
SETDEFAULTS_FUNC(mod_indexfile_set_defaults) {
plugin_data *p = p_d;
size_t i = 0;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "index-file.names", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ "server.indexfiles", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
s->indexfiles = array_init();
-
+
cv[0].destination = s->indexfiles;
cv[1].destination = s->indexfiles; /* old name for [0] */
-
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
}
-
+
return HANDLER_GO_ON;
}
@@ -108,21 +107,21 @@ SETDEFAULTS_FUNC(mod_indexfile_set_defaults) {
static int mod_indexfile_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(indexfiles);
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.indexfiles"))) {
PATCH(indexfiles);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("index-file.names"))) {
@@ -130,7 +129,7 @@ static int mod_indexfile_patch_connection(server *srv, connection *con, plugin_d
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -139,81 +138,84 @@ URIHANDLER_FUNC(mod_indexfile_subrequest) {
plugin_data *p = p_d;
size_t k;
stat_cache_entry *sce = NULL;
-
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
if (con->uri.path->used == 0) return HANDLER_GO_ON;
if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
-
+
mod_indexfile_patch_connection(srv, con, p);
-
+
if (con->conf.log_request_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "-- handling the request as Indexfile");
log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path);
}
-
+
/* indexfile */
for (k = 0; k < p->conf.indexfiles->used; k++) {
data_string *ds = (data_string *)p->conf.indexfiles->data[k];
-
+
if (ds->value && ds->value->ptr[0] == '/') {
- /* if the index-file starts with a prefix as use this file as
+ /* if the index-file starts with a prefix as use this file as
* index-generator */
buffer_copy_string_buffer(p->tmp_buf, con->physical.doc_root);
} else {
buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
}
buffer_append_string_buffer(p->tmp_buf, ds->value);
-
+
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
if (errno == EACCES) {
con->http_status = 403;
buffer_reset(con->physical.path);
-
+
return HANDLER_FINISHED;
}
-
+
if (errno != ENOENT &&
errno != ENOTDIR) {
/* we have no idea what happend. let's tell the user so. */
-
+
con->http_status = 500;
-
+
log_error_write(srv, __FILE__, __LINE__, "ssbsb",
"file not found ... or so: ", strerror(errno),
con->uri.path,
"->", con->physical.path);
-
+
buffer_reset(con->physical.path);
-
+
return HANDLER_FINISHED;
}
continue;
}
-
+
/* rewrite uri.path to the real path (/ -> /index.php) */
buffer_append_string_buffer(con->uri.path, ds->value);
buffer_copy_string_buffer(con->physical.path, p->tmp_buf);
-
+
/* fce is already set up a few lines above */
-
+
return HANDLER_GO_ON;
}
-
+
/* not found */
return HANDLER_GO_ON;
}
/* this function is called at dlopen() time and inits the callbacks */
+int mod_indexfile_plugin_init(plugin *p);
int mod_indexfile_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("indexfile");
-
+
p->init = mod_indexfile_init;
p->handle_subrequest_start = mod_indexfile_subrequest;
p->set_defaults = mod_indexfile_set_defaults;
p->cleanup = mod_indexfile_free;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_magnet.c b/src/mod_magnet.c
new file mode 100644
index 0000000..d10e3ff
--- /dev/null
+++ b/src/mod_magnet.c
@@ -0,0 +1,1110 @@
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+
+#include "plugin.h"
+
+#include "mod_magnet_cache.h"
+#include "response.h"
+#include "stat_cache.h"
+#include "status_counter.h"
+#include "etag.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <setjmp.h>
+
+#ifdef HAVE_LUA_H
+#include <lua.h>
+#include <lauxlib.h>
+
+#define MAGNET_CONFIG_RAW_URL "magnet.attract-raw-url-to"
+#define MAGNET_CONFIG_PHYSICAL_PATH "magnet.attract-physical-path-to"
+#define MAGNET_RESTART_REQUEST 99
+
+/* plugin config for all request/connections */
+
+static jmp_buf exceptionjmp;
+
+typedef struct {
+ array *url_raw;
+ array *physical_path;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ script_cache *cache;
+
+ buffer *encode_buf;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_magnet_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->cache = script_cache_init();
+ p->encode_buf = buffer_init();
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_magnet_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ if (!s) continue;
+
+ array_free(s->url_raw);
+ array_free(s->physical_path);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ script_cache_free(p->cache);
+ buffer_free(p->encode_buf);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_magnet_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { MAGNET_CONFIG_RAW_URL, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { MAGNET_CONFIG_PHYSICAL_PATH, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->url_raw = array_init();
+ s->physical_path = array_init();
+
+ cv[0].destination = s->url_raw;
+ cv[1].destination = s->physical_path;
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_magnet_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(url_raw);
+ PATCH(physical_path);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN(MAGNET_CONFIG_RAW_URL))) {
+ PATCH(url_raw);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(MAGNET_CONFIG_PHYSICAL_PATH))) {
+ PATCH(physical_path);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+/* See http://lua-users.org/wiki/GeneralizedPairsAndIpairs for implementation details. */
+
+/* Override the default pairs() function to allow us to use a __pairs metakey */
+static int magnet_pairs(lua_State *L) {
+ luaL_checkany(L, 1);
+
+ if (luaL_getmetafield(L, 1, "__pairs")) {
+ lua_insert(L, 1);
+ lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
+ return lua_gettop(L);
+ } else {
+ lua_pushvalue(L, lua_upvalueindex(1));
+ lua_insert(L, 1);
+ lua_call(L, lua_gettop(L) - 1, LUA_MULTRET);
+ return lua_gettop(L);
+ }
+}
+
+/* Define a function that will iterate over an array* (in upval 1) using current position (upval 2) */
+static int magnet_array_next(lua_State *L) {
+ data_unset *du;
+ data_string *ds;
+ data_integer *di;
+
+ size_t pos = lua_tointeger(L, lua_upvalueindex(1));
+ array *a = lua_touserdata(L, lua_upvalueindex(2));
+
+ lua_settop(L, 0);
+
+ if (pos >= a->used) return 0;
+ if (NULL != (du = a->data[pos])) {
+ if (du->key->used) {
+ lua_pushlstring(L, du->key->ptr, du->key->used - 1);
+ }
+ else {
+ lua_pushlstring(L, "", 0);
+ }
+ switch (du->type) {
+ case TYPE_STRING:
+ ds = (data_string *)du;
+ if (ds->value && ds->value->used) {
+ lua_pushlstring(L, ds->value->ptr, ds->value->used - 1);
+ } else {
+ lua_pushnil(L);
+ }
+ break;
+ case TYPE_COUNT:
+ case TYPE_INTEGER:
+ di = (data_integer *)du;
+ lua_pushinteger(L, di->value);
+ break;
+ default:
+ lua_pushnil(L);
+ break;
+ }
+
+ /* Update our positional upval to reflect our new current position */
+ pos++;
+ lua_pushinteger(L, pos);
+ lua_replace(L, lua_upvalueindex(1));
+
+ /* Returning 2 items on the stack (key, value) */
+ return 2;
+ }
+ return 0;
+}
+
+/* Create the closure necessary to iterate over the array *a with the above function */
+static int magnet_array_pairs(lua_State *L, array *a) {
+ lua_pushinteger(L, 0); /* Push our current pos (the start) into upval 1 */
+ lua_pushlightuserdata(L, a); /* Push our array *a into upval 2 */
+ lua_pushcclosure(L, magnet_array_next, 2); /* Push our new closure with 2 upvals */
+ return 1;
+}
+
+static int magnet_print(lua_State *L) {
+ const char *s = luaL_checkstring(L, 1);
+ server *srv;
+
+ lua_pushstring(L, "lighty.srv");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ srv = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "(lua-print)", s);
+
+ return 0;
+}
+
+static int magnet_stat(lua_State *L) {
+ const char *s = luaL_checkstring(L, 1);
+ server *srv;
+ connection *con;
+ buffer sb;
+ stat_cache_entry *sce = NULL;
+
+ lua_pushstring(L, "lighty.srv");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ srv = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ lua_pushstring(L, "lighty.con");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ con = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ sb.ptr = (char *)s;
+ sb.used = sb.size = strlen(s) + 1;
+
+ if (HANDLER_GO_ON != stat_cache_get_entry(srv, con, &sb, &sce)) {
+ lua_pushnil(L);
+
+ return 1;
+ }
+
+ lua_newtable(L);
+
+ lua_pushboolean(L, S_ISREG(sce->st.st_mode));
+ lua_setfield(L, -2, "is_file");
+
+ lua_pushboolean(L, S_ISDIR(sce->st.st_mode));
+ lua_setfield(L, -2, "is_dir");
+
+ lua_pushboolean(L, S_ISCHR(sce->st.st_mode));
+ lua_setfield(L, -2, "is_char");
+
+ lua_pushboolean(L, S_ISBLK(sce->st.st_mode));
+ lua_setfield(L, -2, "is_block");
+
+ lua_pushboolean(L, S_ISSOCK(sce->st.st_mode));
+ lua_setfield(L, -2, "is_socket");
+
+ lua_pushboolean(L, S_ISLNK(sce->st.st_mode));
+ lua_setfield(L, -2, "is_link");
+
+ lua_pushboolean(L, S_ISFIFO(sce->st.st_mode));
+ lua_setfield(L, -2, "is_fifo");
+
+ lua_pushinteger(L, sce->st.st_mtime);
+ lua_setfield(L, -2, "st_mtime");
+
+ lua_pushinteger(L, sce->st.st_ctime);
+ lua_setfield(L, -2, "st_ctime");
+
+ lua_pushinteger(L, sce->st.st_atime);
+ lua_setfield(L, -2, "st_atime");
+
+ lua_pushinteger(L, sce->st.st_uid);
+ lua_setfield(L, -2, "st_uid");
+
+ lua_pushinteger(L, sce->st.st_gid);
+ lua_setfield(L, -2, "st_gid");
+
+ lua_pushinteger(L, sce->st.st_size);
+ lua_setfield(L, -2, "st_size");
+
+ lua_pushinteger(L, sce->st.st_ino);
+ lua_setfield(L, -2, "st_ino");
+
+
+ if (!buffer_is_empty(sce->etag)) {
+ /* we have to mutate the etag */
+ buffer *b = buffer_init();
+ etag_mutate(b, sce->etag);
+
+ lua_pushlstring(L, b->ptr, b->used - 1);
+ buffer_free(b);
+ } else {
+ lua_pushnil(L);
+ }
+ lua_setfield(L, -2, "etag");
+
+ if (!buffer_is_empty(sce->content_type)) {
+ lua_pushlstring(L, sce->content_type->ptr, sce->content_type->used - 1);
+ } else {
+ lua_pushnil(L);
+ }
+ lua_setfield(L, -2, "content-type");
+
+ return 1;
+}
+
+
+static int magnet_atpanic(lua_State *L) {
+ const char *s = luaL_checkstring(L, 1);
+ server *srv;
+
+ lua_pushstring(L, "lighty.srv");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ srv = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "(lua-atpanic)", s);
+
+ longjmp(exceptionjmp, 1);
+}
+
+static int magnet_reqhdr_get(lua_State *L) {
+ connection *con;
+ data_string *ds;
+
+ const char *key = luaL_checkstring(L, 2);
+
+ lua_pushstring(L, "lighty.con");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ con = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ if (NULL != (ds = (data_string *)array_get_element(con->request.headers, key))) {
+ if (ds->value->used) {
+ lua_pushlstring(L, ds->value->ptr, ds->value->used - 1);
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int magnet_reqhdr_pairs(lua_State *L) {
+ connection *con;
+
+ lua_pushstring(L, "lighty.con");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ con = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ return magnet_array_pairs(L, con->request.headers);
+}
+
+static int magnet_status_get(lua_State *L) {
+ data_integer *di;
+ server *srv;
+ size_t key_len = 0;
+
+ const char *key = luaL_checklstring(L, 2, &key_len);
+
+ lua_pushstring(L, "lighty.srv");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ srv = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ di = status_counter_get_counter(srv, key, key_len);
+
+ lua_pushnumber(L, (double)di->value);
+
+ return 1;
+}
+
+static int magnet_status_set(lua_State *L) {
+ size_t key_len = 0;
+ server *srv;
+
+ const char *key = luaL_checklstring(L, 2, &key_len);
+ int counter = luaL_checkint(L, 3);
+
+ lua_pushstring(L, "lighty.srv");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ srv = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ status_counter_set(srv, key, key_len, counter);
+
+ return 0;
+}
+
+static int magnet_status_pairs(lua_State *L) {
+ server *srv;
+
+ lua_pushstring(L, "lighty.srv");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ srv = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ return magnet_array_pairs(L, srv->status);
+}
+
+typedef struct {
+ const char *name;
+ enum {
+ MAGNET_ENV_UNSET,
+
+ MAGNET_ENV_PHYICAL_PATH,
+ MAGNET_ENV_PHYICAL_REL_PATH,
+ MAGNET_ENV_PHYICAL_DOC_ROOT,
+
+ MAGNET_ENV_URI_PATH,
+ MAGNET_ENV_URI_PATH_RAW,
+ MAGNET_ENV_URI_SCHEME,
+ MAGNET_ENV_URI_AUTHORITY,
+ MAGNET_ENV_URI_QUERY,
+
+ MAGNET_ENV_REQUEST_METHOD,
+ MAGNET_ENV_REQUEST_URI,
+ MAGNET_ENV_REQUEST_ORIG_URI,
+ MAGNET_ENV_REQUEST_PATH_INFO,
+ MAGNET_ENV_REQUEST_REMOTE_IP,
+ MAGNET_ENV_REQUEST_PROTOCOL
+ } type;
+} magnet_env_t;
+
+static const magnet_env_t magnet_env[] = {
+ { "physical.path", MAGNET_ENV_PHYICAL_PATH },
+ { "physical.rel-path", MAGNET_ENV_PHYICAL_REL_PATH },
+ { "physical.doc-root", MAGNET_ENV_PHYICAL_DOC_ROOT },
+
+ { "uri.path", MAGNET_ENV_URI_PATH },
+ { "uri.path-raw", MAGNET_ENV_URI_PATH_RAW },
+ { "uri.scheme", MAGNET_ENV_URI_SCHEME },
+ { "uri.authority", MAGNET_ENV_URI_AUTHORITY },
+ { "uri.query", MAGNET_ENV_URI_QUERY },
+
+ { "request.method", MAGNET_ENV_REQUEST_METHOD },
+ { "request.uri", MAGNET_ENV_REQUEST_URI },
+ { "request.orig-uri", MAGNET_ENV_REQUEST_ORIG_URI },
+ { "request.path-info", MAGNET_ENV_REQUEST_PATH_INFO },
+ { "request.remote-ip", MAGNET_ENV_REQUEST_REMOTE_IP },
+ { "request.protocol", MAGNET_ENV_REQUEST_PROTOCOL },
+
+ { NULL, MAGNET_ENV_UNSET }
+};
+
+static buffer *magnet_env_get_buffer_by_id(server *srv, connection *con, int id) {
+ buffer *dest = NULL;
+
+ UNUSED(srv);
+
+ /**
+ * map all internal variables to lua
+ *
+ */
+
+ switch (id) {
+ case MAGNET_ENV_PHYICAL_PATH: dest = con->physical.path; break;
+ case MAGNET_ENV_PHYICAL_REL_PATH: dest = con->physical.rel_path; break;
+ case MAGNET_ENV_PHYICAL_DOC_ROOT: dest = con->physical.doc_root; break;
+
+ case MAGNET_ENV_URI_PATH: dest = con->uri.path; break;
+ case MAGNET_ENV_URI_PATH_RAW: dest = con->uri.path_raw; break;
+ case MAGNET_ENV_URI_SCHEME: dest = con->uri.scheme; break;
+ case MAGNET_ENV_URI_AUTHORITY: dest = con->uri.authority; break;
+ case MAGNET_ENV_URI_QUERY: dest = con->uri.query; break;
+
+ case MAGNET_ENV_REQUEST_METHOD:
+ buffer_copy_string(srv->tmp_buf, get_http_method_name(con->request.http_method));
+ dest = srv->tmp_buf;
+ break;
+ case MAGNET_ENV_REQUEST_URI: dest = con->request.uri; break;
+ case MAGNET_ENV_REQUEST_ORIG_URI: dest = con->request.orig_uri; break;
+ case MAGNET_ENV_REQUEST_PATH_INFO: dest = con->request.pathinfo; break;
+ case MAGNET_ENV_REQUEST_REMOTE_IP: dest = con->dst_addr_buf; break;
+ case MAGNET_ENV_REQUEST_PROTOCOL:
+ buffer_copy_string(srv->tmp_buf, get_http_version_name(con->request.http_version));
+ dest = srv->tmp_buf;
+ break;
+
+ case MAGNET_ENV_UNSET: break;
+ }
+
+ return dest;
+}
+
+static buffer *magnet_env_get_buffer(server *srv, connection *con, const char *key) {
+ size_t i;
+
+ for (i = 0; magnet_env[i].name; i++) {
+ if (0 == strcmp(key, magnet_env[i].name)) break;
+ }
+
+ return magnet_env_get_buffer_by_id(srv, con, magnet_env[i].type);
+}
+
+static int magnet_env_get(lua_State *L) {
+ server *srv;
+ connection *con;
+
+ const char *key = luaL_checkstring(L, 2);
+ buffer *dest = NULL;
+
+ lua_pushstring(L, "lighty.srv");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ srv = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ lua_pushstring(L, "lighty.con");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ con = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ dest = magnet_env_get_buffer(srv, con, key);
+
+ if (dest && dest->used) {
+ lua_pushlstring(L, dest->ptr, dest->used - 1);
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+static int magnet_env_set(lua_State *L) {
+ server *srv;
+ connection *con;
+
+ const char *key = luaL_checkstring(L, 2);
+ const char *val = luaL_checkstring(L, 3);
+ buffer *dest = NULL;
+
+ lua_pushstring(L, "lighty.srv");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ srv = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ lua_pushstring(L, "lighty.con");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ con = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ if (NULL != (dest = magnet_env_get_buffer(srv, con, key))) {
+ buffer_copy_string(dest, val);
+ } else {
+ /* couldn't save */
+
+ return luaL_error(L, "couldn't store '%s' in lighty.env[]", key);
+ }
+
+ return 0;
+}
+
+static int magnet_env_next(lua_State *L) {
+ server *srv;
+ connection *con;
+ int pos = lua_tointeger(L, lua_upvalueindex(1));
+
+ buffer *dest;
+
+ lua_pushstring(L, "lighty.srv");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ srv = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ lua_pushstring(L, "lighty.con");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ con = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ lua_settop(L, 0);
+
+ if (NULL == magnet_env[pos].name) return 0; /* end of list */
+
+ lua_pushstring(L, magnet_env[pos].name);
+
+ dest = magnet_env_get_buffer_by_id(srv, con, magnet_env[pos].type);
+ if (dest && dest->used) {
+ lua_pushlstring(L, dest->ptr, dest->used - 1);
+ } else {
+ lua_pushnil(L);
+ }
+
+ /* Update our positional upval to reflect our new current position */
+ pos++;
+ lua_pushinteger(L, pos);
+ lua_replace(L, lua_upvalueindex(1));
+
+ /* Returning 2 items on the stack (key, value) */
+ return 2;
+}
+
+static int magnet_env_pairs(lua_State *L) {
+ lua_pushinteger(L, 0); /* Push our current pos (the start) into upval 1 */
+ lua_pushcclosure(L, magnet_env_next, 1); /* Push our new closure with 1 upvals */
+ return 1;
+}
+
+static int magnet_cgi_get(lua_State *L) {
+ connection *con;
+ data_string *ds;
+
+ const char *key = luaL_checkstring(L, 2);
+
+ lua_pushstring(L, "lighty.con");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ con = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ if (NULL != (ds = (data_string *)array_get_element(con->environment, key)) && ds->value->used)
+ lua_pushlstring(L, CONST_BUF_LEN(ds->value));
+ else
+ lua_pushnil(L);
+
+ return 1;
+}
+
+static int magnet_cgi_set(lua_State *L) {
+ connection *con;
+
+ const char *key = luaL_checkstring(L, 2);
+ const char *val = luaL_checkstring(L, 3);
+
+ lua_pushstring(L, "lighty.con");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ con = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ array_set_key_value(con->environment, key, strlen(key), val, strlen(val));
+
+ return 0;
+}
+
+static int magnet_cgi_pairs(lua_State *L) {
+ connection *con;
+
+ lua_pushstring(L, "lighty.con");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ con = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ return magnet_array_pairs(L, con->environment);
+}
+
+
+static int magnet_copy_response_header(server *srv, connection *con, plugin_data *p, lua_State *L) {
+ UNUSED(p);
+ /**
+ * get the environment of the function
+ */
+
+ lua_getfenv(L, -1); /* -1 is the function */
+
+ /* lighty.header */
+
+ lua_getfield(L, -1, "lighty"); /* lighty.* from the env */
+ assert(lua_istable(L, -1));
+
+ lua_getfield(L, -1, "header"); /* lighty.header */
+ if (lua_istable(L, -1)) {
+ /* header is found, and is a table */
+
+ lua_pushnil(L);
+ while (lua_next(L, -2) != 0) {
+ if (lua_isstring(L, -1) && lua_isstring(L, -2)) {
+ const char *key, *val;
+ size_t key_len, val_len;
+
+ key = lua_tolstring(L, -2, &key_len);
+ val = lua_tolstring(L, -1, &val_len);
+
+ response_header_overwrite(srv, con, key, key_len, val, val_len);
+ }
+
+ lua_pop(L, 1);
+ }
+ }
+
+ lua_pop(L, 1); /* pop the header-table */
+ lua_pop(L, 1); /* pop the lighty-env */
+ lua_pop(L, 1); /* pop the function env */
+
+ return 0;
+}
+
+/**
+ * walk through the content array
+ *
+ * content = { "<pre>", { file = "/content" } , "</pre>" }
+ *
+ * header["Content-Type"] = "text/html"
+ *
+ * return 200
+ */
+static int magnet_attach_content(server *srv, connection *con, plugin_data *p, lua_State *L) {
+ UNUSED(p);
+ /**
+ * get the environment of the function
+ */
+
+ assert(lua_isfunction(L, -1));
+ lua_getfenv(L, -1); /* -1 is the function */
+
+ lua_getfield(L, -1, "lighty"); /* lighty.* from the env */
+ assert(lua_istable(L, -1));
+
+ lua_getfield(L, -1, "content"); /* lighty.content */
+ if (lua_istable(L, -1)) {
+ int i;
+ /* header is found, and is a table */
+
+ for (i = 1; ; i++) {
+ lua_rawgeti(L, -1, i);
+
+ /* -1 is the value and should be the value ... aka a table */
+ if (lua_isstring(L, -1)) {
+ size_t s_len = 0;
+ const char *s = lua_tolstring(L, -1, &s_len);
+
+ chunkqueue_append_mem(con->write_queue, s, s_len + 1);
+ } else if (lua_istable(L, -1)) {
+ lua_getfield(L, -1, "filename");
+ lua_getfield(L, -2, "length");
+ lua_getfield(L, -3, "offset");
+
+ if (lua_isstring(L, -3)) { /* filename has to be a string */
+ buffer *fn = buffer_init();
+ stat_cache_entry *sce;
+
+ buffer_copy_string(fn, lua_tostring(L, -3));
+
+ if (HANDLER_GO_ON == stat_cache_get_entry(srv, con, fn, &sce)) {
+ off_t off = 0;
+ off_t len = 0;
+
+ if (lua_isnumber(L, -1)) {
+ off = lua_tonumber(L, -1);
+ }
+
+ if (lua_isnumber(L, -2)) {
+ len = lua_tonumber(L, -2);
+ } else {
+ len = sce->st.st_size;
+ }
+
+ if (off < 0) {
+ return luaL_error(L, "offset for '%s' is negative", fn->ptr);
+ }
+
+ if (len < off) {
+ return luaL_error(L, "offset > length for '%s'", fn->ptr);
+ }
+
+ chunkqueue_append_file(con->write_queue, fn, off, len - off);
+ }
+
+ buffer_free(fn);
+ } else {
+ lua_pop(L, 3 + 2); /* correct the stack */
+
+ return luaL_error(L, "content[%d] is a table and requires the field \"filename\"", i);
+ }
+
+ lua_pop(L, 3);
+ } else if (lua_isnil(L, -1)) {
+ /* oops, end of list */
+
+ lua_pop(L, 1);
+
+ break;
+ } else {
+ lua_pop(L, 4);
+
+ return luaL_error(L, "content[%d] is neither a string nor a table: ", i);
+ }
+
+ lua_pop(L, 1); /* pop the content[...] table */
+ }
+ } else {
+ return luaL_error(L, "lighty.content has to be a table");
+ }
+ lua_pop(L, 1); /* pop the header-table */
+ lua_pop(L, 1); /* pop the lighty-table */
+ lua_pop(L, 1); /* php the function env */
+
+ return 0;
+}
+
+static int traceback (lua_State *L) {
+ if (!lua_isstring(L, 1)) /* 'message' not a string? */
+ return 1; /* keep it intact */
+ lua_getfield(L, LUA_GLOBALSINDEX, "debug");
+ if (!lua_istable(L, -1)) {
+ lua_pop(L, 1);
+ return 1;
+ }
+ lua_getfield(L, -1, "traceback");
+ if (!lua_isfunction(L, -1)) {
+ lua_pop(L, 2);
+ return 1;
+ }
+ lua_pushvalue(L, 1); /* pass error message */
+ lua_pushinteger(L, 2); /* skip this function and traceback */
+ lua_call(L, 2, 1); /* call debug.traceback */
+ return 1;
+}
+
+static int push_traceback(lua_State *L, int narg) {
+ int base = lua_gettop(L) - narg; /* function index */
+ lua_pushcfunction(L, traceback);
+ lua_insert(L, base);
+ return base;
+}
+
+static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, buffer *name) {
+ lua_State *L;
+ int lua_return_value = -1;
+ int errfunc;
+ /* get the script-context */
+
+
+ L = script_cache_get_script(srv, con, p->cache, name);
+
+ if (lua_isstring(L, -1)) {
+ log_error_write(srv, __FILE__, __LINE__,
+ "sbss",
+ "loading script",
+ name,
+ "failed:",
+ lua_tostring(L, -1));
+
+ lua_pop(L, 1);
+
+ assert(lua_gettop(L) == 0); /* only the function should be on the stack */
+
+ con->http_status = 500;
+ con->mode = DIRECT;
+
+ return HANDLER_FINISHED;
+ }
+
+ lua_pushstring(L, "lighty.srv");
+ lua_pushlightuserdata(L, srv);
+ lua_settable(L, LUA_REGISTRYINDEX); /* registery[<id>] = srv */
+
+ lua_pushstring(L, "lighty.con");
+ lua_pushlightuserdata(L, con);
+ lua_settable(L, LUA_REGISTRYINDEX); /* registery[<id>] = con */
+
+ lua_atpanic(L, magnet_atpanic);
+
+ /**
+ * we want to create empty environment for our script
+ *
+ * setmetatable({}, {__index = _G})
+ *
+ * if a function, symbol is not defined in our env, __index will lookup
+ * in the global env.
+ *
+ * all variables created in the script-env will be thrown
+ * away at the end of the script run.
+ */
+ lua_newtable(L); /* my empty environment aka {} (sp += 1) */
+
+ /* we have to overwrite the print function */
+ lua_pushcfunction(L, magnet_print); /* (sp += 1) */
+ lua_setfield(L, -2, "print"); /* -1 is the env we want to set(sp -= 1) */
+
+ /**
+ * lighty.request[] has the HTTP-request headers
+ * lighty.content[] is a table of string/file
+ * lighty.header[] is a array to set response headers
+ */
+
+ lua_newtable(L); /* lighty.* (sp += 1) */
+
+ lua_newtable(L); /* {} (sp += 1) */
+ lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
+ lua_pushcfunction(L, magnet_reqhdr_get); /* (sp += 1) */
+ lua_setfield(L, -2, "__index"); /* (sp -= 1) */
+ lua_pushcfunction(L, magnet_reqhdr_pairs); /* (sp += 1) */
+ lua_setfield(L, -2, "__pairs"); /* (sp -= 1) */
+ lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */
+ lua_setfield(L, -2, "request"); /* content = {} (sp -= 1) */
+
+ lua_newtable(L); /* {} (sp += 1) */
+ lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
+ lua_pushcfunction(L, magnet_env_get); /* (sp += 1) */
+ lua_setfield(L, -2, "__index"); /* (sp -= 1) */
+ lua_pushcfunction(L, magnet_env_set); /* (sp += 1) */
+ lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */
+ lua_pushcfunction(L, magnet_env_pairs); /* (sp += 1) */
+ lua_setfield(L, -2, "__pairs"); /* (sp -= 1) */
+ lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */
+ lua_setfield(L, -2, "env"); /* content = {} (sp -= 1) */
+
+ lua_newtable(L); /* {} (sp += 1) */
+ lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
+ lua_pushcfunction(L, magnet_cgi_get); /* (sp += 1) */
+ lua_setfield(L, -2, "__index"); /* (sp -= 1) */
+ lua_pushcfunction(L, magnet_cgi_set); /* (sp += 1) */
+ lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */
+ lua_pushcfunction(L, magnet_cgi_pairs); /* (sp += 1) */
+ lua_setfield(L, -2, "__pairs"); /* (sp -= 1) */
+ lua_setmetatable(L, -2); /* tie the metatable to req_env (sp -= 1) */
+ lua_setfield(L, -2, "req_env"); /* content = {} (sp -= 1) */
+
+ lua_newtable(L); /* {} (sp += 1) */
+ lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
+ lua_pushcfunction(L, magnet_status_get); /* (sp += 1) */
+ lua_setfield(L, -2, "__index"); /* (sp -= 1) */
+ lua_pushcfunction(L, magnet_status_set); /* (sp += 1) */
+ lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */
+ lua_pushcfunction(L, magnet_status_pairs); /* (sp += 1) */
+ lua_setfield(L, -2, "__pairs"); /* (sp -= 1) */
+ lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */
+ lua_setfield(L, -2, "status"); /* content = {} (sp -= 1) */
+
+ /* add empty 'content' and 'header' tables */
+ lua_newtable(L); /* {} (sp += 1) */
+ lua_setfield(L, -2, "content"); /* content = {} (sp -= 1) */
+
+ lua_newtable(L); /* {} (sp += 1) */
+ lua_setfield(L, -2, "header"); /* header = {} (sp -= 1) */
+
+ lua_pushinteger(L, MAGNET_RESTART_REQUEST);
+ lua_setfield(L, -2, "RESTART_REQUEST");
+
+ lua_pushcfunction(L, magnet_stat); /* (sp += 1) */
+ lua_setfield(L, -2, "stat"); /* -1 is the env we want to set (sp -= 1) */
+
+ lua_setfield(L, -2, "lighty"); /* lighty.* (sp -= 1) */
+
+ /* override the default pairs() function to our __pairs capable version */
+ lua_getglobal(L, "pairs"); /* push original pairs() (sp += 1) */
+ lua_pushcclosure(L, magnet_pairs, 1);
+ lua_setfield(L, -2, "pairs"); /* (sp -= 1) */
+
+ lua_newtable(L); /* the meta-table for the new env (sp += 1) */
+ lua_pushvalue(L, LUA_GLOBALSINDEX); /* (sp += 1) */
+ lua_setfield(L, -2, "__index"); /* { __index = _G } (sp -= 1) */
+ lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) (sp -= 1) */
+
+
+ lua_setfenv(L, -2); /* on the stack should be a modified env (sp -= 1) */
+
+ errfunc = push_traceback(L, 0);
+ if (lua_pcall(L, 0, 1, errfunc)) {
+ lua_remove(L, errfunc);
+ log_error_write(srv, __FILE__, __LINE__,
+ "ss",
+ "lua_pcall():",
+ lua_tostring(L, -1));
+ lua_pop(L, 1); /* remove the error-msg and the function copy from the stack */
+
+ assert(lua_gettop(L) == 1); /* only the function should be on the stack */
+
+ con->http_status = 500;
+ con->mode = DIRECT;
+
+ return HANDLER_FINISHED;
+ }
+ lua_remove(L, errfunc);
+
+ /* we should have the function-copy and the return value on the stack */
+ assert(lua_gettop(L) == 2);
+
+ if (lua_isnumber(L, -1)) {
+ /* if the ret-value is a number, take it */
+ lua_return_value = (int)lua_tonumber(L, -1);
+ }
+ lua_pop(L, 1); /* pop the ret-value */
+
+ magnet_copy_response_header(srv, con, p, L);
+
+ if (lua_return_value > 99) {
+ con->http_status = lua_return_value;
+ con->file_finished = 1;
+
+ /* try { ...*/
+ if (0 == setjmp(exceptionjmp)) {
+ magnet_attach_content(srv, con, p, L);
+ if (!chunkqueue_is_empty(con->write_queue)) {
+ con->mode = p->id;
+ }
+ } else {
+ /* } catch () { */
+ con->http_status = 500;
+ con->mode = DIRECT;
+ }
+
+ assert(lua_gettop(L) == 1); /* only the function should be on the stack */
+
+ /* we are finished */
+ return HANDLER_FINISHED;
+ } else if (MAGNET_RESTART_REQUEST == lua_return_value) {
+ assert(lua_gettop(L) == 1); /* only the function should be on the stack */
+
+ return HANDLER_COMEBACK;
+ } else {
+ assert(lua_gettop(L) == 1); /* only the function should be on the stack */
+
+ return HANDLER_GO_ON;
+ }
+}
+
+static handler_t magnet_attract_array(server *srv, connection *con, plugin_data *p, array *files) {
+ size_t i;
+
+ /* no filename set */
+ if (files->used == 0) return HANDLER_GO_ON;
+
+ /**
+ * execute all files and jump out on the first !HANDLER_GO_ON
+ */
+ for (i = 0; i < files->used; i++) {
+ data_string *ds = (data_string *)files->data[i];
+ handler_t ret;
+
+ if (buffer_is_empty(ds->value)) continue;
+
+ ret = magnet_attract(srv, con, p, ds->value);
+
+ if (ret != HANDLER_GO_ON) return ret;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+URIHANDLER_FUNC(mod_magnet_uri_handler) {
+ plugin_data *p = p_d;
+
+ mod_magnet_patch_connection(srv, con, p);
+
+ return magnet_attract_array(srv, con, p, p->conf.url_raw);
+}
+
+URIHANDLER_FUNC(mod_magnet_physical) {
+ plugin_data *p = p_d;
+
+ mod_magnet_patch_connection(srv, con, p);
+
+ return magnet_attract_array(srv, con, p, p->conf.physical_path);
+}
+
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_magnet_plugin_init(plugin *p);
+int mod_magnet_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("magnet");
+
+ p->init = mod_magnet_init;
+ p->handle_uri_clean = mod_magnet_uri_handler;
+ p->handle_physical = mod_magnet_physical;
+ p->set_defaults = mod_magnet_set_defaults;
+ p->cleanup = mod_magnet_free;
+
+ p->data = NULL;
+
+ return 0;
+}
+
+#else
+int mod_magnet_plugin_init(plugin *p);
+int mod_magnet_plugin_init(plugin *p) {
+ UNUSED(p);
+ return -1;
+}
+#endif
diff --git a/src/mod_magnet_cache.c b/src/mod_magnet_cache.c
new file mode 100644
index 0000000..50326cf
--- /dev/null
+++ b/src/mod_magnet_cache.c
@@ -0,0 +1,137 @@
+#include "mod_magnet_cache.h"
+#include "stat_cache.h"
+
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+
+#ifdef HAVE_LUA_H
+#include <lualib.h>
+#include <lauxlib.h>
+
+static script *script_init() {
+ script *sc;
+
+ sc = calloc(1, sizeof(*sc));
+ sc->name = buffer_init();
+ sc->etag = buffer_init();
+
+ return sc;
+}
+
+static void script_free(script *sc) {
+ if (!sc) return;
+
+ lua_pop(sc->L, 1); /* the function copy */
+
+ buffer_free(sc->name);
+ buffer_free(sc->etag);
+
+ lua_close(sc->L);
+
+ free(sc);
+}
+
+script_cache *script_cache_init() {
+ script_cache *p;
+
+ p = calloc(1, sizeof(*p));
+
+ return p;
+}
+
+void script_cache_free(script_cache *p) {
+ size_t i;
+
+ if (!p) return;
+
+ for (i = 0; i < p->used; i++) {
+ script_free(p->ptr[i]);
+ }
+
+ free(p->ptr);
+
+ free(p);
+}
+
+lua_State *script_cache_get_script(server *srv, connection *con, script_cache *cache, buffer *name) {
+ size_t i;
+ script *sc = NULL;
+ stat_cache_entry *sce;
+
+ for (i = 0; i < cache->used; i++) {
+ sc = cache->ptr[i];
+
+ if (buffer_is_equal(name, sc->name)) {
+ sc->last_used = time(NULL);
+
+ /* oops, the script failed last time */
+
+ if (lua_gettop(sc->L) == 0) break;
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, sc->name, &sce)) {
+ lua_pop(sc->L, 1); /* pop the old function */
+ break;
+ }
+
+ if (!buffer_is_equal(sce->etag, sc->etag)) {
+ /* the etag is outdated, reload the function */
+ lua_pop(sc->L, 1);
+ break;
+ }
+
+ assert(lua_isfunction(sc->L, -1));
+ lua_pushvalue(sc->L, -1); /* copy the function-reference */
+
+ return sc->L;
+ }
+
+ sc = NULL;
+ }
+
+ /* if the script was script already loaded but either got changed or
+ * failed to load last time */
+ if (sc == NULL) {
+ sc = script_init();
+
+ if (cache->size == 0) {
+ cache->size = 16;
+ cache->ptr = malloc(cache->size * sizeof(*(cache->ptr)));
+ } else if (cache->used == cache->size) {
+ cache->size += 16;
+ cache->ptr = realloc(cache->ptr, cache->size * sizeof(*(cache->ptr)));
+ }
+
+ cache->ptr[cache->used++] = sc;
+
+ buffer_copy_string_buffer(sc->name, name);
+
+ sc->L = luaL_newstate();
+ luaL_openlibs(sc->L);
+ }
+
+ sc->last_used = time(NULL);
+
+ if (0 != luaL_loadfile(sc->L, name->ptr)) {
+ /* oops, an error, return it */
+
+ return sc->L;
+ }
+
+ if (HANDLER_GO_ON == stat_cache_get_entry(srv, con, sc->name, &sce)) {
+ buffer_copy_string_buffer(sc->etag, sce->etag);
+ }
+
+ /**
+ * pcall() needs the function on the stack
+ *
+ * as pcall() will pop the script from the stack when done, we have to
+ * duplicate it here
+ */
+ assert(lua_isfunction(sc->L, -1));
+ lua_pushvalue(sc->L, -1); /* copy the function-reference */
+
+ return sc->L;
+}
+
+#endif
diff --git a/src/mod_magnet_cache.h b/src/mod_magnet_cache.h
new file mode 100644
index 0000000..50c9e44
--- /dev/null
+++ b/src/mod_magnet_cache.h
@@ -0,0 +1,33 @@
+#ifndef _MOD_MAGNET_CACHE_H_
+#define _MOD_MAGNET_CACHE_H_
+
+#include "buffer.h"
+#include "base.h"
+
+#ifdef HAVE_LUA_H
+#include <lua.h>
+
+typedef struct {
+ buffer *name;
+ buffer *etag;
+
+ lua_State *L;
+
+ time_t last_used; /* LRU */
+} script;
+
+typedef struct {
+ script **ptr;
+
+ size_t used;
+ size_t size;
+} script_cache;
+
+script_cache *script_cache_init(void);
+void script_cache_free(script_cache *cache);
+
+lua_State *script_cache_get_script(server *srv, connection *con,
+ script_cache *cache, buffer *name);
+
+#endif
+#endif
diff --git a/src/mod_mysql_vhost.c b/src/mod_mysql_vhost.c
index bf13e09..df29186 100644
--- a/src/mod_mysql_vhost.c
+++ b/src/mod_mysql_vhost.c
@@ -21,12 +21,12 @@
#endif
/*
- * Plugin for lighttpd to use MySQL
+ * Plugin for lighttpd to use MySQL
* for domain to directory lookups,
* i.e virtual hosts (vhosts).
- *
- * Optionally sets fcgi_offset and fcgi_arg
- * in preparation for fcgi.c to handle
+ *
+ * Optionally sets fcgi_offset and fcgi_arg
+ * in preparation for fcgi.c to handle
* per-user fcgi chroot jails.
*
* /ada@riksnet.se 2004-12-06
@@ -35,15 +35,15 @@
#ifdef HAVE_MYSQL
typedef struct {
MYSQL *mysql;
-
+
buffer *mydb;
buffer *myuser;
buffer *mypass;
buffer *mysock;
-
+
buffer *hostname;
unsigned short port;
-
+
buffer *mysql_pre;
buffer *mysql_post;
} plugin_config;
@@ -51,12 +51,12 @@ typedef struct {
/* global plugin data */
typedef struct {
PLUGIN_DATA;
-
+
buffer *tmp_buf;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
/* per connection plugin data */
@@ -70,7 +70,7 @@ typedef struct {
/* init the plugin data */
INIT_FUNC(mod_mysql_vhost_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
p->tmp_buf = buffer_init();
@@ -83,35 +83,36 @@ SERVER_FUNC(mod_mysql_vhost_cleanup) {
plugin_data *p = p_d;
UNUSED(srv);
-
+
#ifdef DEBUG
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"mod_mysql_vhost_cleanup", p ? "yes" : "NO");
#endif
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
if (!s) continue;
-
+
mysql_close(s->mysql);
-
+
buffer_free(s->mydb);
buffer_free(s->myuser);
buffer_free(s->mypass);
buffer_free(s->mysock);
buffer_free(s->mysql_pre);
buffer_free(s->mysql_post);
-
+ buffer_free(s->hostname);
+
free(s);
}
free(p->config_storage);
}
buffer_free(p->tmp_buf);
-
+
free(p);
return HANDLER_GO_ON;
@@ -126,7 +127,7 @@ static void* mod_mysql_vhost_connection_data(server *srv, connection *con, void
UNUSED(srv);
#ifdef DEBUG
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"mod_mysql_connection_data", c ? "old" : "NEW");
#endif
@@ -149,10 +150,10 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_connection_close) {
UNUSED(srv);
#ifdef DEBUG
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"mod_mysql_vhost_handle_connection_close", c ? "yes" : "NO");
#endif
-
+
if (!c) return HANDLER_GO_ON;
buffer_free(c->server_name);
@@ -183,14 +184,14 @@ SERVER_FUNC(mod_mysql_vhost_set_defaults) {
{ "mysql-vhost.port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER },
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
buffer *sel;
-
-
+
+
s = calloc(1, sizeof(plugin_config));
s->mydb = buffer_init();
s->myuser = buffer_init();
@@ -200,10 +201,10 @@ SERVER_FUNC(mod_mysql_vhost_set_defaults) {
s->port = 0; /* default port for mysql */
sel = buffer_init();
s->mysql = NULL;
-
+
s->mysql_pre = buffer_init();
s->mysql_post = buffer_init();
-
+
cv[0].destination = s->mydb;
cv[1].destination = s->myuser;
cv[2].destination = s->mypass;
@@ -211,68 +212,87 @@ SERVER_FUNC(mod_mysql_vhost_set_defaults) {
cv[4].destination = sel;
cv[5].destination = s->hostname;
cv[6].destination = &(s->port);
-
+
p->config_storage[i] = s;
-
- if (config_insert_values_global(srv,
+
+ if (config_insert_values_global(srv,
((data_config *)srv->config_context->data[i])->value,
cv)) return HANDLER_ERROR;
-
+
s->mysql_pre = buffer_init();
s->mysql_post = buffer_init();
-
- if (sel->used && (qmark = index(sel->ptr, '?'))) {
+
+ if (sel->used && (qmark = strchr(sel->ptr, '?'))) {
*qmark = '\0';
buffer_copy_string(s->mysql_pre, sel->ptr);
buffer_copy_string(s->mysql_post, qmark+1);
} else {
buffer_copy_string_buffer(s->mysql_pre, sel);
}
-
+
/* required:
* - username
- * - database
- *
+ * - database
+ *
* optional:
* - password, default: empty
* - socket, default: mysql default
* - hostname, if set overrides socket
* - port, default: 3306
*/
-
+
/* all have to be set */
if (!(buffer_is_empty(s->myuser) ||
buffer_is_empty(s->mydb))) {
+ my_bool reconnect = 1;
- int fd;
-
if (NULL == (s->mysql = mysql_init(NULL))) {
log_error_write(srv, __FILE__, __LINE__, "s", "mysql_init() failed, exiting...");
-
+
return HANDLER_ERROR;
}
+
+#if MYSQL_VERSION_ID >= 50013
+ /* in mysql versions above 5.0.3 the reconnect flag is off by default */
+ mysql_options(s->mysql, MYSQL_OPT_RECONNECT, &reconnect);
+#endif
+
#define FOO(x) (s->x->used ? s->x->ptr : NULL)
-
- if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass),
+
+#if MYSQL_VERSION_ID >= 40100
+ /* CLIENT_MULTI_STATEMENTS first appeared in 4.1 */
+ if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass),
+ FOO(mydb), s->port, FOO(mysock), CLIENT_MULTI_STATEMENTS)) {
+#else
+ if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass),
FOO(mydb), s->port, FOO(mysock), 0)) {
+#endif
log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(s->mysql));
-
+
return HANDLER_ERROR;
}
#undef FOO
+
+#if 0
/* set close_on_exec for mysql the hard way */
/* Note: this only works as it is done during startup, */
/* otherwise we cannot be sure that mysql is fd i-1 */
- if (-1 == (fd = open("/dev/null", 0))) {
+ { int fd;
+ if (-1 != (fd = open("/dev/null", 0))) {
close(fd);
- fcntl(fd-1, F_SETFD, FD_CLOEXEC);
- }
+#ifdef FD_CLOEXEC
+ fcntl(fd-1, F_SETFD, FD_CLOEXEC);
+#endif
+ } }
+#else
+#ifdef FD_CLOEXEC
+ fcntl(s->mysql->net.fd, F_SETFD, FD_CLOEXEC);
+#endif
+#endif
}
}
-
-
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
#define PATCH(x) \
@@ -280,36 +300,36 @@ SERVER_FUNC(mod_mysql_vhost_set_defaults) {
static int mod_mysql_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(mysql_pre);
PATCH(mysql_post);
#ifdef HAVE_MYSQL
PATCH(mysql);
#endif
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("mysql-vhost.sql"))) {
PATCH(mysql_pre);
PATCH(mysql_post);
}
}
-
+
if (s->mysql) {
PATCH(mysql);
}
}
-
+
return 0;
}
#undef PATCH
@@ -355,6 +375,9 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
if (!row || cols < 1) {
/* no such virtual host */
mysql_free_result(result);
+#if MYSQL_VERSION_ID >= 40100
+ while (mysql_next_result(p->conf.mysql) == 0);
+#endif
return HANDLER_GO_ON;
}
@@ -378,7 +401,7 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
/* fcgi_offset and fcgi_arg are optional */
if (cols > 1 && row[1]) {
c->fcgi_offset = atoi(row[1]);
-
+
if (cols > 2 && row[2]) {
buffer_copy_string(c->fcgi_arg, row[2]);
} else {
@@ -388,43 +411,52 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
c->fcgi_offset = c->fcgi_arg->used = 0;
}
mysql_free_result(result);
+#if MYSQL_VERSION_ID >= 40100
+ while (mysql_next_result(p->conf.mysql) == 0);
+#endif
/* fix virtual server and docroot */
GO_ON: buffer_copy_string_buffer(con->server_name, c->server_name);
buffer_copy_string_buffer(con->physical.doc_root, c->document_root);
#ifdef DEBUG
- log_error_write(srv, __FILE__, __LINE__, "sbbdb",
- result ? "NOT CACHED" : "cached",
+ log_error_write(srv, __FILE__, __LINE__, "sbbdb",
+ result ? "NOT CACHED" : "cached",
con->server_name, con->physical.doc_root,
c->fcgi_offset, c->fcgi_arg);
#endif
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
ERR500: if (result) mysql_free_result(result);
+#if MYSQL_VERSION_ID >= 40100
+ while (mysql_next_result(p->conf.mysql) == 0);
+#endif
con->http_status = 500; /* Internal Error */
+ con->mode = DIRECT;
return HANDLER_FINISHED;
}
/* this function is called at dlopen() time and inits the callbacks */
+int mod_mysql_vhost_plugin_init(plugin *p);
int mod_mysql_vhost_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("mysql_vhost");
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("mysql_vhost");
+
+ p->init = mod_mysql_vhost_init;
+ p->cleanup = mod_mysql_vhost_cleanup;
+ p->connection_reset = mod_mysql_vhost_handle_connection_close;
- p->init = mod_mysql_vhost_init;
- p->cleanup = mod_mysql_vhost_cleanup;
- p->handle_request_done = mod_mysql_vhost_handle_connection_close;
+ p->set_defaults = mod_mysql_vhost_set_defaults;
+ p->handle_docroot = mod_mysql_vhost_handle_docroot;
- p->set_defaults = mod_mysql_vhost_set_defaults;
- p->handle_docroot = mod_mysql_vhost_handle_docroot;
-
return 0;
}
#else
/* we don't have mysql support, this plugin does nothing */
+int mod_mysql_vhost_plugin_init(plugin *p);
int mod_mysql_vhost_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
- p->name = buffer_init_string("mysql_vhost");
+ p->name = buffer_init_string("mysql_vhost");
return 0;
}
diff --git a/src/mod_proxy.c b/src/mod_proxy.c
index 6baf459..09d4fc1 100644
--- a/src/mod_proxy.c
+++ b/src/mod_proxy.c
@@ -1,13 +1,3 @@
-#include <sys/types.h>
-
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <assert.h>
-
#include "buffer.h"
#include "server.h"
#include "keyvalue.h"
@@ -24,6 +14,16 @@
#include "inet_ntop_cache.h"
#include "crc32.h"
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+
#include <stdio.h>
#ifdef HAVE_SYS_FILIO_H
@@ -38,16 +38,16 @@
#define PROXY_RETRY_TIMEOUT 60
/**
- *
- * the proxy module is based on the fastcgi module
- *
+ *
+ * the proxy module is based on the fastcgi module
+ *
* 28.06.2004 Jan Kneschke The first release
* 01.07.2004 Evgeny Rodichev Several bugfixes and cleanups
* - co-ordinate up- and downstream flows correctly (proxy_demux_response
* and proxy_handle_fdevent)
* - correctly transfer upstream http_response_status;
* - some unused structures removed.
- *
+ *
* TODO: - delay upstream read if write_queue is too large
* (to prevent memory eating, like in apache). Shoud be
* configurable).
@@ -63,29 +63,29 @@ typedef enum {
typedef struct {
array *extensions;
- int debug;
+ unsigned short debug;
proxy_balance_t balance;
} plugin_config;
typedef struct {
PLUGIN_DATA;
-
+
buffer *parse_response;
buffer *balance_buf;
-
+
plugin_config **config_storage;
-
+
plugin_config conf;
} plugin_data;
-typedef enum {
- PROXY_STATE_INIT,
- PROXY_STATE_CONNECT,
- PROXY_STATE_PREPARE_WRITE,
- PROXY_STATE_WRITE,
- PROXY_STATE_READ,
- PROXY_STATE_ERROR
+typedef enum {
+ PROXY_STATE_INIT,
+ PROXY_STATE_CONNECT,
+ PROXY_STATE_PREPARE_WRITE,
+ PROXY_STATE_WRITE,
+ PROXY_STATE_READ,
+ PROXY_STATE_ERROR
} proxy_connection_state_t;
enum { PROXY_STDOUT, PROXY_END_REQUEST };
@@ -93,36 +93,36 @@ enum { PROXY_STDOUT, PROXY_END_REQUEST };
typedef struct {
proxy_connection_state_t state;
time_t state_timestamp;
-
+
data_proxy *host;
-
+
buffer *response;
buffer *response_header;
chunkqueue *wb;
-
+
int fd; /* fd to the proxy process */
int fde_ndx; /* index into the fd-event buffer */
size_t path_info_offset; /* start of path_info in uri.path */
-
+
connection *remote_conn; /* dump pointer */
plugin_data *plugin_data; /* dump pointer */
} handler_ctx;
/* ok, we need a prototype */
-static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents);
+static handler_t proxy_handle_fdevent(server *srv, void *ctx, int revents);
-static handler_ctx * handler_ctx_init() {
+static handler_ctx * handler_ctx_init(void) {
handler_ctx * hctx;
-
+
hctx = calloc(1, sizeof(*hctx));
-
+
hctx->state = PROXY_STATE_INIT;
hctx->host = NULL;
-
+
hctx->response = buffer_init();
hctx->response_header = buffer_init();
@@ -130,7 +130,7 @@ static handler_ctx * handler_ctx_init() {
hctx->fd = -1;
hctx->fde_ndx = -1;
-
+
return hctx;
}
@@ -138,47 +138,47 @@ static void handler_ctx_free(handler_ctx *hctx) {
buffer_free(hctx->response);
buffer_free(hctx->response_header);
chunkqueue_free(hctx->wb);
-
+
free(hctx);
}
INIT_FUNC(mod_proxy_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
p->parse_response = buffer_init();
p->balance_buf = buffer_init();
-
+
return p;
}
FREE_FUNC(mod_proxy_free) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
buffer_free(p->parse_response);
buffer_free(p->balance_buf);
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
-
+
if (s) {
-
+
array_free(s->extensions);
-
+
free(s);
}
}
free(p->config_storage);
}
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
@@ -186,37 +186,37 @@ SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
plugin_data *p = p_d;
data_unset *du;
size_t i = 0;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "proxy.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ "proxy.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ "proxy.balance", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
array *ca;
-
+
s = malloc(sizeof(plugin_config));
s->extensions = array_init();
s->debug = 0;
-
+
cv[0].destination = s->extensions;
cv[1].destination = &(s->debug);
cv[2].destination = p->balance_buf;
buffer_reset(p->balance_buf);
-
+
p->config_storage[i] = s;
ca = ((data_config *)srv->config_context->data[i])->value;
-
+
if (0 != config_insert_values_global(srv, ca, cv)) {
return HANDLER_ERROR;
}
-
+
if (buffer_is_empty(p->balance_buf)) {
s->balance = PROXY_BALANCE_FAIR;
} else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("fair"))) {
@@ -226,7 +226,7 @@ SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
} else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("hash"))) {
s->balance = PROXY_BALANCE_HASH;
} else {
- log_error_write(srv, __FILE__, __LINE__, "sb",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
"proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf);
return HANDLER_ERROR;
}
@@ -234,92 +234,91 @@ SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
if (NULL != (du = array_get_element(ca, "proxy.server"))) {
size_t j;
data_array *da = (data_array *)du;
-
+
if (du->type != TYPE_ARRAY) {
- log_error_write(srv, __FILE__, __LINE__, "sss",
+ log_error_write(srv, __FILE__, __LINE__, "sss",
"unexpected type for key: ", "proxy.server", "array of strings");
-
+
return HANDLER_ERROR;
}
-
- /*
+
+ /*
* proxy.server = ( "<ext>" => ...,
* "<ext>" => ... )
*/
-
+
for (j = 0; j < da->value->used; j++) {
data_array *da_ext = (data_array *)da->value->data[j];
size_t n;
-
+
if (da_ext->type != TYPE_ARRAY) {
- log_error_write(srv, __FILE__, __LINE__, "sssbs",
- "unexpected type for key: ", "proxy.server",
+ log_error_write(srv, __FILE__, __LINE__, "sssbs",
+ "unexpected type for key: ", "proxy.server",
"[", da->value->data[j]->key, "](string)");
-
+
return HANDLER_ERROR;
}
-
- /*
- * proxy.server = ( "<ext>" =>
- * ( "<host>" => ( ... ),
+
+ /*
+ * proxy.server = ( "<ext>" =>
+ * ( "<host>" => ( ... ),
* "<host>" => ( ... )
- * ),
+ * ),
* "<ext>" => ... )
*/
-
+
for (n = 0; n < da_ext->value->used; n++) {
data_array *da_host = (data_array *)da_ext->value->data[n];
-
+
data_proxy *df;
data_array *dfa;
-
- config_values_t pcv[] = {
+
+ config_values_t pcv[] = {
{ "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { "balance", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (da_host->type != TYPE_ARRAY) {
- log_error_write(srv, __FILE__, __LINE__, "ssSBS",
- "unexpected type for key:",
- "proxy.server",
+ log_error_write(srv, __FILE__, __LINE__, "ssSBS",
+ "unexpected type for key:",
+ "proxy.server",
"[", da_ext->value->data[n]->key, "](string)");
-
+
return HANDLER_ERROR;
}
-
+
df = data_proxy_init();
-
+
df->port = 80;
-
+
buffer_copy_string_buffer(df->key, da_host->key);
-
+
pcv[0].destination = df->host;
pcv[1].destination = &(df->port);
-
+
if (0 != config_insert_values_internal(srv, da_host->value, pcv)) {
return HANDLER_ERROR;
}
-
+
if (buffer_is_empty(df->host)) {
- log_error_write(srv, __FILE__, __LINE__, "sbbbs",
- "missing key (string):",
+ log_error_write(srv, __FILE__, __LINE__, "sbbbs",
+ "missing key (string):",
da->key,
da_ext->key,
da_host->key,
"host");
-
+
return HANDLER_ERROR;
}
-
+
/* if extension already exists, take it */
-
+
if (NULL == (dfa = (data_array *)array_get_element(s->extensions, da_ext->key->ptr))) {
dfa = data_array_init();
-
+
buffer_copy_string_buffer(dfa->key, da_ext->key);
-
+
array_insert_unique(dfa->value, (data_unset *)df);
array_insert_unique(s->extensions, (data_unset *)dfa);
} else {
@@ -329,19 +328,19 @@ SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
}
}
}
-
+
return HANDLER_GO_ON;
}
-void proxy_connection_close(server *srv, handler_ctx *hctx) {
+static void proxy_connection_close(server *srv, handler_ctx *hctx) {
plugin_data *p;
connection *con;
-
+
if (NULL == hctx) return;
-
+
p = hctx->plugin_data;
con = hctx->remote_conn;
-
+
if (hctx->fd != -1) {
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
fdevent_unregister(srv->ev, hctx->fd);
@@ -349,54 +348,73 @@ void proxy_connection_close(server *srv, handler_ctx *hctx) {
close(hctx->fd);
srv->cur_fds--;
}
-
+
+ if (hctx->host) {
+ hctx->host->usage--;
+ }
+
handler_ctx_free(hctx);
- con->plugin_ctx[p->id] = NULL;
+ con->plugin_ctx[p->id] = NULL;
}
static int proxy_establish_connection(server *srv, handler_ctx *hctx) {
struct sockaddr *proxy_addr;
struct sockaddr_in proxy_addr_in;
+#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
+ struct sockaddr_in6 proxy_addr_in6;
+#endif
socklen_t servlen;
-
+
plugin_data *p = hctx->plugin_data;
data_proxy *host= hctx->host;
int proxy_fd = hctx->fd;
-
- memset(&proxy_addr, 0, sizeof(proxy_addr));
-
- proxy_addr_in.sin_family = AF_INET;
- proxy_addr_in.sin_addr.s_addr = inet_addr(host->host->ptr);
- proxy_addr_in.sin_port = htons(host->port);
- servlen = sizeof(proxy_addr_in);
-
- proxy_addr = (struct sockaddr *) &proxy_addr_in;
-
+
+
+#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
+ if (strstr(host->host->ptr, ":")) {
+ memset(&proxy_addr_in6, 0, sizeof(proxy_addr_in6));
+ proxy_addr_in6.sin6_family = AF_INET6;
+ inet_pton(AF_INET6, host->host->ptr, (char *) &proxy_addr_in6.sin6_addr);
+ proxy_addr_in6.sin6_port = htons(host->port);
+ servlen = sizeof(proxy_addr_in6);
+ proxy_addr = (struct sockaddr *) &proxy_addr_in6;
+ } else
+#endif
+ {
+ memset(&proxy_addr_in, 0, sizeof(proxy_addr_in));
+ proxy_addr_in.sin_family = AF_INET;
+ proxy_addr_in.sin_addr.s_addr = inet_addr(host->host->ptr);
+ proxy_addr_in.sin_port = htons(host->port);
+ servlen = sizeof(proxy_addr_in);
+ proxy_addr = (struct sockaddr *) &proxy_addr_in;
+ }
+
+
if (-1 == connect(proxy_fd, proxy_addr, servlen)) {
if (errno == EINPROGRESS || errno == EALREADY) {
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"connect delayed:", proxy_fd);
}
-
+
return 1;
} else {
-
- log_error_write(srv, __FILE__, __LINE__, "sdsd",
+
+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
"connect failed:", proxy_fd, strerror(errno), errno);
-
+
return -1;
}
}
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"connect succeeded: ", proxy_fd);
}
return 0;
}
-void proxy_set_header(connection *con, const char *key, const char *value) {
+static void proxy_set_header(connection *con, const char *key, const char *value) {
data_string *ds_dst;
if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
@@ -408,7 +426,7 @@ void proxy_set_header(connection *con, const char *key, const char *value) {
array_insert_unique(con->request.headers, (data_unset *)ds_dst);
}
-void proxy_append_header(connection *con, const char *key, const char *value) {
+static void proxy_append_header(connection *con, const char *key, const char *value) {
data_string *ds_dst;
if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
@@ -423,25 +441,25 @@ void proxy_append_header(connection *con, const char *key, const char *value) {
static int proxy_create_env(server *srv, handler_ctx *hctx) {
size_t i;
-
+
connection *con = hctx->remote_conn;
buffer *b;
-
+
/* build header */
b = chunkqueue_get_append_buffer(hctx->wb);
-
+
/* request line */
buffer_copy_string(b, get_http_method_name(con->request.http_method));
- BUFFER_APPEND_STRING_CONST(b, " ");
-
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
+
buffer_append_string_buffer(b, con->request.uri);
- BUFFER_APPEND_STRING_CONST(b, " HTTP/1.0\r\n");
+ buffer_append_string_len(b, CONST_STR_LEN(" HTTP/1.0\r\n"));
proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
- /* http_host is NOT is just a pointer to a buffer
+ /* http_host is NOT is just a pointer to a buffer
* which is NULL if it is not set */
- if (con->request.http_host &&
+ if (con->request.http_host &&
!buffer_is_empty(con->request.http_host)) {
proxy_set_header(con, "X-Host", con->request.http_host->ptr);
}
@@ -450,24 +468,25 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) {
/* request header */
for (i = 0; i < con->request.headers->used; i++) {
data_string *ds;
-
+
ds = (data_string *)con->request.headers->data[i];
-
+
if (ds->value->used && ds->key->used) {
if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
-
+ if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Proxy-Connection"))) continue;
+
buffer_append_string_buffer(b, ds->key);
- BUFFER_APPEND_STRING_CONST(b, ": ");
+ buffer_append_string_len(b, CONST_STR_LEN(": "));
buffer_append_string_buffer(b, ds->value);
- BUFFER_APPEND_STRING_CONST(b, "\r\n");
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
}
}
-
- BUFFER_APPEND_STRING_CONST(b, "\r\n");
-
+
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
+
hctx->wb->bytes_in += b->used - 1;
/* body */
-
+
if (con->request.content_length) {
chunkqueue *req_cq = con->request_content_queue;
chunk *req_c;
@@ -480,7 +499,7 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) {
/* we announce toWrite octects
* now take all the request_content chunk that we need to fill this request
- * */
+ * */
switch (req_c->type) {
case FILE_CHUNK:
@@ -508,26 +527,26 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) {
req_c->offset += weHave;
req_cq->bytes_out += weHave;
-
+
hctx->wb->bytes_in += weHave;
break;
default:
break;
}
-
+
offset += weHave;
}
}
-
+
return 0;
}
static int proxy_set_state(server *srv, handler_ctx *hctx, proxy_connection_state_t state) {
hctx->state = state;
hctx->state_timestamp = srv->cur_ts;
-
+
return 0;
}
@@ -535,19 +554,19 @@ static int proxy_set_state(server *srv, handler_ctx *hctx, proxy_connection_stat
static int proxy_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
char *s, *ns;
int http_response_status = -1;
-
+
UNUSED(srv);
/* \r\n -> \0\0 */
-
+
buffer_copy_string_buffer(p->parse_response, in);
-
+
for (s = p->parse_response->ptr; NULL != (ns = strstr(s, "\r\n")); s = ns + 2) {
char *key, *value;
int key_len;
data_string *ds;
int copy_header;
-
+
ns[0] = '\0';
ns[1] = '\0';
@@ -567,7 +586,7 @@ static int proxy_response_parse(server *srv, connection *con, plugin_data *p, bu
con->parsed_response |= HTTP_STATUS;
continue;
}
-
+
if (NULL == (value = strchr(s, ':'))) {
/* now we expect: "<key>: <value>\n" */
@@ -576,13 +595,13 @@ static int proxy_response_parse(server *srv, connection *con, plugin_data *p, bu
key = s;
key_len = value - key;
-
+
value++;
/* strip WS */
while (*value == ' ' || *value == '\t') value++;
-
+
copy_header = 1;
-
+
switch(key_len) {
case 4:
if (0 == strncasecmp(key, "Date", key_len)) {
@@ -615,11 +634,11 @@ static int proxy_response_parse(server *srv, connection *con, plugin_data *p, bu
}
buffer_copy_string_len(ds->key, key, key_len);
buffer_copy_string(ds->value, value);
-
+
array_insert_unique(con->response.headers, (data_unset *)ds);
}
}
-
+
return 0;
}
@@ -628,14 +647,14 @@ static int proxy_demux_response(server *srv, handler_ctx *hctx) {
int fin = 0;
int b;
ssize_t r;
-
+
plugin_data *p = hctx->plugin_data;
connection *con = hctx->remote_conn;
int proxy_fd = hctx->fd;
-
+
/* check how much we have to read */
if (ioctl(hctx->fd, FIONREAD, &b)) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"ioctl failed: ",
proxy_fd);
return -1;
@@ -653,24 +672,25 @@ static int proxy_demux_response(server *srv, handler_ctx *hctx) {
buffer_prepare_append(hctx->response, b + 1);
hctx->response->used = 1;
} else {
- buffer_prepare_append(hctx->response, hctx->response->used + b);
+ buffer_prepare_append(hctx->response, b);
}
-
+
if (-1 == (r = read(hctx->fd, hctx->response->ptr + hctx->response->used - 1, b))) {
- log_error_write(srv, __FILE__, __LINE__, "sds",
+ if (errno == EAGAIN) return 0;
+ log_error_write(srv, __FILE__, __LINE__, "sds",
"unexpected end-of-file (perhaps the proxy process died):",
proxy_fd, strerror(errno));
return -1;
}
-
+
/* this should be catched by the b > 0 above */
assert(r);
-
+
hctx->response->used += r;
hctx->response->ptr[hctx->response->used - 1] = '\0';
#if 0
- log_error_write(srv, __FILE__, __LINE__, "sdsbs",
+ log_error_write(srv, __FILE__, __LINE__, "sdsbs",
"demux: Response buffer len", hctx->response->used, ":", hctx->response, ":");
#endif
@@ -678,171 +698,158 @@ static int proxy_demux_response(server *srv, handler_ctx *hctx) {
con->got_response = 1;
buffer_prepare_copy(hctx->response_header, 128);
}
-
+
if (0 == con->file_started) {
char *c;
-
+
/* search for the \r\n\r\n in the string */
if (NULL != (c = buffer_search_string_len(hctx->response, "\r\n\r\n", 4))) {
size_t hlen = c - hctx->response->ptr + 4;
size_t blen = hctx->response->used - hlen - 1;
/* found */
-
+
buffer_append_string_len(hctx->response_header, hctx->response->ptr, c - hctx->response->ptr + 4);
#if 0
log_error_write(srv, __FILE__, __LINE__, "sb", "Header:", hctx->response_header);
#endif
/* parse the response header */
proxy_response_parse(srv, con, p, hctx->response_header);
-
+
/* enable chunked-transfer-encoding */
if (con->request.http_version == HTTP_VERSION_1_1 &&
!(con->parsed_response & HTTP_CONTENT_LENGTH)) {
con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
}
-
+
con->file_started = 1;
if (blen) {
http_chunk_append_mem(srv, con, c + 4, blen + 1);
- joblist_append(srv, con);
}
hctx->response->used = 0;
+ joblist_append(srv, con);
}
} else {
http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
joblist_append(srv, con);
hctx->response->used = 0;
}
-
+
} else {
/* reading from upstream done */
con->file_finished = 1;
-
+
http_chunk_append_mem(srv, con, NULL, 0);
joblist_append(srv, con);
-
+
fin = 1;
}
-
+
return fin;
}
static handler_t proxy_write_request(server *srv, handler_ctx *hctx) {
data_proxy *host= hctx->host;
- plugin_data *p = hctx->plugin_data;
connection *con = hctx->remote_conn;
-
+
int ret;
-
- if (!host ||
+
+ if (!host ||
(!host->host->used || !host->port)) return -1;
-
+
switch(hctx->state) {
+ case PROXY_STATE_CONNECT:
+ /* wait for the connect() to finish */
+
+ /* connect failed ? */
+ if (-1 == hctx->fde_ndx) return HANDLER_ERROR;
+
+ /* wait */
+ return HANDLER_WAIT_FOR_EVENT;
+
+ break;
+
case PROXY_STATE_INIT:
- if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
+#if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
+ if (strstr(host->host->ptr,":")) {
+ if (-1 == (hctx->fd = socket(AF_INET6, SOCK_STREAM, 0))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
return HANDLER_ERROR;
+ }
+ } else
+#endif
+ {
+ if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
+ return HANDLER_ERROR;
+ }
}
hctx->fde_ndx = -1;
-
+
srv->cur_fds++;
-
+
fdevent_register(srv->ev, hctx->fd, proxy_handle_fdevent, hctx);
-
+
if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
-
+
return HANDLER_ERROR;
}
-
- /* fall through */
-
- case PROXY_STATE_CONNECT:
- /* try to finish the connect() */
- if (hctx->state == PROXY_STATE_INIT) {
- /* first round */
- switch (proxy_establish_connection(srv, hctx)) {
- case 1:
- proxy_set_state(srv, hctx, PROXY_STATE_CONNECT);
-
- /* connection is in progress, wait for an event and call getsockopt() below */
-
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
-
- return HANDLER_WAIT_FOR_EVENT;
- case -1:
- /* if ECONNREFUSED choose another connection -> FIXME */
- hctx->fde_ndx = -1;
-
- return HANDLER_ERROR;
- default:
- /* everything is ok, go on */
- break;
- }
- } else {
- int socket_error;
- socklen_t socket_error_len = sizeof(socket_error);
-
- /* we don't need it anymore */
- fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
- /* try to finish the connect() */
- if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "getsockopt failed:", strerror(errno));
-
- return HANDLER_ERROR;
- }
- if (socket_error != 0) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "establishing connection failed:", strerror(socket_error),
- "port:", hctx->host->port);
-
- return HANDLER_ERROR;
- }
- if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "s", "proxy - connect - delayed success");
- }
+ switch (proxy_establish_connection(srv, hctx)) {
+ case 1:
+ proxy_set_state(srv, hctx, PROXY_STATE_CONNECT);
+
+ /* connection is in progress, wait for an event and call getsockopt() below */
+
+ fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
+
+ return HANDLER_WAIT_FOR_EVENT;
+ case -1:
+ /* if ECONNREFUSED choose another connection -> FIXME */
+ hctx->fde_ndx = -1;
+
+ return HANDLER_ERROR;
+ default:
+ /* everything is ok, go on */
+ proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE);
+ break;
}
-
- proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE);
+
/* fall through */
+
case PROXY_STATE_PREPARE_WRITE:
proxy_create_env(srv, hctx);
-
+
proxy_set_state(srv, hctx, PROXY_STATE_WRITE);
-
+
/* fall through */
case PROXY_STATE_WRITE:;
- ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
+ ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb, MAX_WRITE_LIMIT);
chunkqueue_remove_finished_chunks(hctx->wb);
- if (-1 == ret) {
- if (errno != EAGAIN &&
- errno != EINTR) {
- log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
-
- return HANDLER_ERROR;
- } else {
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
+ if (-1 == ret) { /* error on our side */
+ log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
- return HANDLER_WAIT_FOR_EVENT;
- }
+ return HANDLER_ERROR;
+ } else if (-2 == ret) { /* remote close */
+ log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed, remote connection close:", strerror(errno), errno);
+
+ return HANDLER_ERROR;
}
if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
proxy_set_state(srv, hctx, PROXY_STATE_READ);
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
+ fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
} else {
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
-
+ fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
+
return HANDLER_WAIT_FOR_EVENT;
}
-
+
return HANDLER_WAIT_FOR_EVENT;
case PROXY_STATE_READ:
/* waiting for a response */
@@ -851,7 +858,7 @@ static handler_t proxy_write_request(server *srv, handler_ctx *hctx) {
log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
return HANDLER_ERROR;
}
-
+
return HANDLER_GO_ON;
}
@@ -860,23 +867,23 @@ static handler_t proxy_write_request(server *srv, handler_ctx *hctx) {
static int mod_proxy_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(extensions);
PATCH(debug);
PATCH(balance);
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.server"))) {
PATCH(extensions);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.debug"))) {
@@ -886,60 +893,60 @@ static int mod_proxy_patch_connection(server *srv, connection *con, plugin_data
}
}
}
-
+
return 0;
}
#undef PATCH
SUBREQUEST_FUNC(mod_proxy_handle_subrequest) {
plugin_data *p = p_d;
-
+
handler_ctx *hctx = con->plugin_ctx[p->id];
data_proxy *host;
-
+
if (NULL == hctx) return HANDLER_GO_ON;
mod_proxy_patch_connection(srv, con, p);
-
+
host = hctx->host;
-
+
/* not my job */
if (con->mode != p->id) return HANDLER_GO_ON;
-
+
/* ok, create the request */
switch(proxy_write_request(srv, hctx)) {
case HANDLER_ERROR:
- log_error_write(srv, __FILE__, __LINE__, "sbdd", "proxy-server disabled:",
+ log_error_write(srv, __FILE__, __LINE__, "sbdd", "proxy-server disabled:",
host->host,
host->port,
hctx->fd);
-
+
/* disable this server */
host->is_disabled = 1;
host->disable_ts = srv->cur_ts;
-
+
proxy_connection_close(srv, hctx);
-
- /* reset the enviroment and restart the sub-request */
+
+ /* reset the enviroment and restart the sub-request */
buffer_reset(con->physical.path);
con->mode = DIRECT;
joblist_append(srv, con);
- /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
- * and hope that the childs will be restarted
- *
+ /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
+ * and hope that the childs will be restarted
+ *
*/
return HANDLER_WAIT_FOR_FD;
case HANDLER_WAIT_FOR_EVENT:
- return HANDLER_WAIT_FOR_EVENT;
+ break;
case HANDLER_WAIT_FOR_FD:
return HANDLER_WAIT_FOR_FD;
default:
break;
}
-
+
if (con->file_started == 1) {
return HANDLER_FINISHED;
} else {
@@ -947,18 +954,17 @@ SUBREQUEST_FUNC(mod_proxy_handle_subrequest) {
}
}
-static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) {
- server *srv = (server *)s;
+static handler_t proxy_handle_fdevent(server *srv, void *ctx, int revents) {
handler_ctx *hctx = ctx;
connection *con = hctx->remote_conn;
plugin_data *p = hctx->plugin_data;
-
-
+
+
if ((revents & FDEVENT_IN) &&
hctx->state == PROXY_STATE_READ) {
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"proxy: fdevent-in", hctx->state);
}
@@ -966,11 +972,9 @@ static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) {
case 0:
break;
case 1:
- hctx->host->usage--;
-
/* we are done */
proxy_connection_close(srv, hctx);
-
+
joblist_append(srv, con);
return HANDLER_FINISHED;
case -1:
@@ -983,69 +987,125 @@ static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) {
/* response might have been already started, kill the connection */
connection_set_state(srv, con, CON_STATE_ERROR);
}
-
+
joblist_append(srv, con);
return HANDLER_FINISHED;
}
}
-
+
if (revents & FDEVENT_OUT) {
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"proxy: fdevent-out", hctx->state);
}
- if (hctx->state == PROXY_STATE_CONNECT ||
+ if (hctx->state == PROXY_STATE_CONNECT) {
+ int socket_error;
+ socklen_t socket_error_len = sizeof(socket_error);
+
+ /* we don't need it anymore */
+ fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
+ hctx->fde_ndx = -1;
+
+ /* try to finish the connect() */
+ if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "getsockopt failed:", strerror(errno));
+
+ joblist_append(srv, con);
+ return HANDLER_FINISHED;
+ }
+ if (socket_error != 0) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "establishing connection failed:", strerror(socket_error),
+ "port:", hctx->host->port);
+
+ joblist_append(srv, con);
+ return HANDLER_FINISHED;
+ }
+ if (p->conf.debug) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "proxy - connect - delayed success");
+ }
+
+ proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE);
+ }
+
+ if (hctx->state == PROXY_STATE_PREPARE_WRITE ||
hctx->state == PROXY_STATE_WRITE) {
/* we are allowed to send something out
- *
- * 1. in a unfinished connect() call
+ *
+ * 1. after a just finished connect() call
* 2. in a unfinished write() call (long POST request)
*/
return mod_proxy_handle_subrequest(srv, con, p);
} else {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"proxy: out", hctx->state);
}
}
-
+
/* perhaps this issue is already handled */
if (revents & FDEVENT_HUP) {
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"proxy: fdevent-hup", hctx->state);
}
-
+
if (hctx->state == PROXY_STATE_CONNECT) {
/* connect() -> EINPROGRESS -> HUP */
-
+
/**
- * what is proxy is doing if it can't reach the next hop ?
- *
+ * what is proxy is doing if it can't reach the next hop ?
+ *
*/
-
- proxy_connection_close(srv, hctx);
- joblist_append(srv, con);
-
- con->http_status = 503;
- con->mode = DIRECT;
-
+
+ if (hctx->host) {
+ hctx->host->is_disabled = 1;
+ hctx->host->disable_ts = srv->cur_ts;
+ log_error_write(srv, __FILE__, __LINE__, "sbdd", "proxy-server disabled:",
+ hctx->host->host,
+ hctx->host->port,
+ hctx->fd);
+
+ /* disable this server */
+ hctx->host->is_disabled = 1;
+ hctx->host->disable_ts = srv->cur_ts;
+
+ proxy_connection_close(srv, hctx);
+
+ /* reset the enviroment and restart the sub-request */
+ buffer_reset(con->physical.path);
+ con->mode = DIRECT;
+
+ joblist_append(srv, con);
+ } else {
+ proxy_connection_close(srv, hctx);
+ joblist_append(srv, con);
+
+ con->mode = DIRECT;
+ con->http_status = 503;
+ }
+
return HANDLER_FINISHED;
}
- con->file_finished = 1;
+ if (!con->file_finished) {
+ http_chunk_append_mem(srv, con, NULL, 0);
+ }
+ con->file_finished = 1;
proxy_connection_close(srv, hctx);
joblist_append(srv, con);
} else if (revents & FDEVENT_ERR) {
/* kill all connections to the proxy process */
-
+
log_error_write(srv, __FILE__, __LINE__, "sd", "proxy-FDEVENT_ERR, but no HUP", revents);
+ con->file_finished = 1;
joblist_append(srv, con);
proxy_connection_close(srv, hctx);
}
-
+
return HANDLER_FINISHED;
}
@@ -1059,69 +1119,82 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p
buffer *fn;
data_array *extension = NULL;
size_t path_info_offset;
-
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
/* Possibly, we processed already this request */
if (con->file_started == 1) return HANDLER_GO_ON;
-
+
mod_proxy_patch_connection(srv, con, p);
-
+
fn = con->uri.path;
if (fn->used == 0) {
return HANDLER_ERROR;
}
-
+
s_len = fn->used - 1;
-
-
+
+
path_info_offset = 0;
- if (p->conf.debug) {
+ if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "s", "proxy - start");
}
/* check if extension matches */
for (k = 0; k < p->conf.extensions->used; k++) {
+ data_array *ext = NULL;
size_t ct_len;
-
- extension = (data_array *)p->conf.extensions->data[k];
-
- if (extension->key->used == 0) continue;
-
- ct_len = extension->key->used - 1;
-
+
+ ext = (data_array *)p->conf.extensions->data[k];
+
+ if (ext->key->used == 0) continue;
+
+ ct_len = ext->key->used - 1;
+
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 (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) {
- path_info_offset = pi_offset - fn->ptr;
+ if (*(ext->key->ptr) == '/') {
+ if (strncmp(fn->ptr, ext->key->ptr, ct_len) == 0) {
+ if (s_len > ct_len + 1) {
+ char *pi_offset;
+
+ if (NULL != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) {
+ path_info_offset = pi_offset - fn->ptr;
+ }
}
+ extension = ext;
+ break;
}
- break;
- } else if (0 == strncmp(fn->ptr + s_len - ct_len, extension->key->ptr, ct_len)) {
+ } else if (0 == strncmp(fn->ptr + s_len - ct_len, ext->key->ptr, ct_len)) {
/* check extension in the form ".fcg" */
+ extension = ext;
break;
}
}
-
- if (k == p->conf.extensions->used) {
+
+ if (NULL == extension) {
return HANDLER_GO_ON;
}
- if (p->conf.debug) {
+ if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "s", "proxy - ext found");
}
- switch(p->conf.balance) {
+ if (extension->value->used == 1) {
+ if ( ((data_proxy *)extension->value->data[0])->is_disabled ) {
+ ndx = -1;
+ } else {
+ ndx = 0;
+ }
+ } else if (extension->value->used != 0) switch(p->conf.balance) {
case PROXY_BALANCE_HASH:
/* hash balancing */
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"proxy - used hash balancing, hosts:", extension->value->used);
}
@@ -1130,13 +1203,13 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p
unsigned long cur_max;
if (host->is_disabled) continue;
-
+
cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
generate_crc32c(CONST_BUF_LEN(host->host)) + /* we can cache this */
generate_crc32c(CONST_BUF_LEN(con->uri.authority));
-
+
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sbbbd",
+ log_error_write(srv, __FILE__, __LINE__, "sbbbd",
"proxy - election:",
con->uri.path,
host->host,
@@ -1156,88 +1229,92 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p
case PROXY_BALANCE_FAIR:
/* fair balancing */
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"proxy - used fair balancing");
}
for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
data_proxy *host = (data_proxy *)extension->value->data[k];
-
+
if (host->is_disabled) continue;
if (host->usage < max_usage) {
max_usage = host->usage;
-
+
ndx = k;
}
}
break;
- case PROXY_BALANCE_RR:
+ case PROXY_BALANCE_RR: {
+ data_proxy *host;
+
/* round robin */
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"proxy - used round-robin balancing");
}
/* just to be sure */
assert(extension->value->used < INT_MAX);
-
- for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
- data_proxy *host = (data_proxy *)extension->value->data[k];
-
- if (host->is_disabled) continue;
- /* first usable ndx */
- if (max_usage == INT_MAX) {
- max_usage = k;
- }
+ host = (data_proxy *)extension->value->data[0];
- /* get next ndx */
- if ((int)k > host->last_used_ndx) {
- ndx = k;
- host->last_used_ndx = k;
+ /* Use last_used_ndx from first host in list */
+ k = host->last_used_ndx;
+ ndx = k + 1; /* use next host after the last one */
+ if (ndx < 0) ndx = 0;
- break;
+ /* Search first active host after last_used_ndx */
+ while ( ndx < (int) extension->value->used
+ && (host = (data_proxy *)extension->value->data[ndx])->is_disabled ) ndx++;
+
+ if (ndx >= (int) extension->value->used) {
+ /* didn't found a higher id, wrap to the start */
+ for (ndx = 0; ndx <= (int) k; ndx++) {
+ host = (data_proxy *)extension->value->data[ndx];
+ if (!host->is_disabled) break;
}
+
+ /* No active host found */
+ if (host->is_disabled) ndx = -1;
}
-
- /* didn't found a higher id, wrap to the start */
- if (ndx != -1 && max_usage != INT_MAX) {
- ndx = max_usage;
- }
+
+ /* Save new index for next round */
+ ((data_proxy *)extension->value->data[0])->last_used_ndx = ndx;
break;
+ }
default:
break;
}
-
+
/* found a server */
if (ndx != -1) {
data_proxy *host = (data_proxy *)extension->value->data[ndx];
-
- /*
- * if check-local is disabled, use the uri.path handler
- *
+
+ /*
+ * if check-local is disabled, use the uri.path handler
+ *
*/
-
+
/* init handler-context */
handler_ctx *hctx;
hctx = handler_ctx_init();
-
+
hctx->path_info_offset = path_info_offset;
hctx->remote_conn = con;
hctx->plugin_data = p;
hctx->host = host;
-
+
con->plugin_ctx[p->id] = hctx;
-
+
host->usage++;
-
+
con->mode = p->id;
-
+
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sbd",
+ log_error_write(srv, __FILE__, __LINE__, "sbd",
"proxy - found a host",
host->host, host->port);
}
@@ -1246,11 +1323,11 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p
} else {
/* no handler found */
con->http_status = 500;
-
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "no proxy-handler found for:",
+
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "no proxy-handler found for:",
fn);
-
+
return HANDLER_FINISHED;
}
return HANDLER_GO_ON;
@@ -1258,7 +1335,7 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p
static handler_t mod_proxy_connection_close_callback(server *srv, connection *con, void *p_d) {
plugin_data *p = p_d;
-
+
proxy_connection_close(srv, con->plugin_ctx[p->id]);
return HANDLER_GO_ON;
@@ -1277,11 +1354,11 @@ TRIGGER_FUNC(mod_proxy_trigger) {
size_t i, n, k;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
-
- if (!s) continue;
+
+ if (!s) continue;
/* get the extensions for all configs */
-
+
for (k = 0; k < s->extensions->used; k++) {
data_array *extension = (data_array *)s->extensions->data[k];
@@ -1291,8 +1368,8 @@ TRIGGER_FUNC(mod_proxy_trigger) {
if (!host->is_disabled ||
srv->cur_ts - host->disable_ts < 5) continue;
-
- log_error_write(srv, __FILE__, __LINE__, "sbd",
+
+ log_error_write(srv, __FILE__, __LINE__, "sbd",
"proxy - re-enabled:",
host->host, host->port);
@@ -1306,6 +1383,7 @@ TRIGGER_FUNC(mod_proxy_trigger) {
}
+int mod_proxy_plugin_init(plugin *p);
int mod_proxy_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("proxy");
@@ -1318,8 +1396,8 @@ int mod_proxy_plugin_init(plugin *p) {
p->handle_uri_clean = mod_proxy_check_extension;
p->handle_subrequest = mod_proxy_handle_subrequest;
p->handle_trigger = mod_proxy_trigger;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_redirect.c b/src/mod_redirect.c
index 6040631..5d51b86 100644
--- a/src/mod_redirect.c
+++ b/src/mod_redirect.c
@@ -1,7 +1,3 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
#include "base.h"
#include "log.h"
#include "buffer.h"
@@ -9,48 +5,50 @@
#include "plugin.h"
#include "response.h"
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
typedef struct {
pcre_keyvalue_buffer *redirect;
data_config *context; /* to which apply me */
+
+ unsigned short redirect_code;
} plugin_config;
typedef struct {
PLUGIN_DATA;
buffer *match_buf;
buffer *location;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
INIT_FUNC(mod_redirect_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
p->match_buf = buffer_init();
p->location = buffer_init();
-
+
return p;
}
FREE_FUNC(mod_redirect_free) {
plugin_data *p = p_d;
-
+
if (!p) return HANDLER_GO_ON;
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
-
+
pcre_keyvalue_buffer_free(s->redirect);
-
+
free(s);
}
free(p->config_storage);
@@ -59,9 +57,9 @@ FREE_FUNC(mod_redirect_free) {
buffer_free(p->match_buf);
buffer_free(p->location);
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
@@ -69,97 +67,104 @@ SETDEFAULTS_FUNC(mod_redirect_set_defaults) {
plugin_data *p = p_d;
data_unset *du;
size_t i = 0;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "url.redirect", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "url.redirect-code", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
/* 0 */
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
size_t j;
array *ca;
data_array *da = (data_array *)du;
-
+
s = calloc(1, sizeof(plugin_config));
s->redirect = pcre_keyvalue_buffer_init();
-
+ s->redirect_code = 301;
+
cv[0].destination = s->redirect;
-
+ cv[1].destination = &(s->redirect_code);
+
p->config_storage[i] = s;
ca = ((data_config *)srv->config_context->data[i])->value;
-
+
if (0 != config_insert_values_global(srv, ca, cv)) {
return HANDLER_ERROR;
}
-
+
if (NULL == (du = array_get_element(ca, "url.redirect"))) {
/* no url.redirect defined */
continue;
}
-
+
if (du->type != TYPE_ARRAY) {
- log_error_write(srv, __FILE__, __LINE__, "sss",
+ log_error_write(srv, __FILE__, __LINE__, "sss",
"unexpected type for key: ", "url.redirect", "array of strings");
-
+
return HANDLER_ERROR;
}
-
+
da = (data_array *)du;
-
+
for (j = 0; j < da->value->used; j++) {
if (da->value->data[j]->type != TYPE_STRING) {
- log_error_write(srv, __FILE__, __LINE__, "sssbs",
- "unexpected type for key: ",
- "url.redirect",
+ log_error_write(srv, __FILE__, __LINE__, "sssbs",
+ "unexpected type for key: ",
+ "url.redirect",
"[", da->value->data[j]->key, "](string)");
-
+
return HANDLER_ERROR;
}
-
- if (0 != pcre_keyvalue_buffer_append(s->redirect,
+
+ if (0 != pcre_keyvalue_buffer_append(srv, s->redirect,
((data_string *)(da->value->data[j]))->key->ptr,
((data_string *)(da->value->data[j]))->value->ptr)) {
-
- log_error_write(srv, __FILE__, __LINE__, "sb",
+
+ log_error_write(srv, __FILE__, __LINE__, "sb",
"pcre-compile failed for", da->value->data[j]->key);
}
}
}
-
+
return HANDLER_GO_ON;
}
#ifdef HAVE_PCRE_H
static int mod_redirect_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
p->conf.redirect = s->redirect;
-
+ p->conf.redirect_code = s->redirect_code;
+ p->conf.context = NULL;
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (0 == strcmp(du->key->ptr, "url.redirect")) {
p->conf.redirect = s->redirect;
p->conf.context = dc;
+ } else if (0 == strcmp(du->key->ptr, "url.redirect-code")) {
+ p->conf.redirect_code = s->redirect_code;
}
}
}
-
+
return 0;
}
#endif
@@ -168,17 +173,17 @@ static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_
plugin_data *p = p_data;
size_t i;
- /*
+ /*
* REWRITE URL
- *
+ *
* e.g. redirect /base/ to /index.php?section=base
- *
+ *
*/
-
+
mod_redirect_patch_connection(srv, con, p);
-
+
buffer_copy_string_buffer(p->match_buf, con->request.uri);
-
+
for (i = 0; i < p->conf.redirect->used; i++) {
pcre *match;
pcre_extra *extra;
@@ -188,12 +193,12 @@ static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_
pcre_keyvalue *kv = p->conf.redirect->kv[i];
# define N 10
int ovec[N * 3];
-
+
match = kv->key;
extra = kv->key_extra;
pattern = kv->value->ptr;
pattern_len = kv->value->used - 1;
-
+
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",
@@ -202,75 +207,83 @@ static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_
}
} else {
const char **list;
- size_t start, end;
+ size_t start;
size_t k;
-
+
/* it matched */
pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
-
+
/* search for $[0-9] */
-
+
buffer_reset(p->location);
-
- start = 0; end = pattern_len;
- for (k = 0; k < pattern_len; k++) {
- if ((pattern[k] == '$' || pattern[k] == '%') &&
- isdigit((unsigned char)pattern[k + 1])) {
+
+ start = 0;
+ for (k = 0; k + 1 < pattern_len; k++) {
+ if (pattern[k] == '$' || pattern[k] == '%') {
/* got one */
-
+
size_t num = pattern[k + 1] - '0';
-
- end = k;
-
- buffer_append_string_len(p->location, pattern + start, end - start);
-
- if (pattern[k] == '$') {
+
+ buffer_append_string_len(p->location, pattern + start, k - start);
+
+ if (!isdigit((unsigned char)pattern[k + 1])) {
+ /* enable escape: "%%" => "%", "%a" => "%a", "$$" => "$" */
+ buffer_append_string_len(p->location, pattern+k, pattern[k] == pattern[k+1] ? 1 : 2);
+ } else if (pattern[k] == '$') {
/* n is always > 0 */
if (num < (size_t)n) {
buffer_append_string(p->location, list[num]);
}
+ } else if (p->conf.context == NULL) {
+ /* we have no context, we are global */
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "used a rewrite containing a %[0-9]+ in the global scope, ignored:",
+ kv->value);
} else {
config_append_cond_match_buffer(con, p->conf.context, p->location, num);
}
-
+
k++;
start = k + 1;
- }
+ }
}
-
+
buffer_append_string_len(p->location, pattern + start, pattern_len - start);
-
+
pcre_free(list);
-
+
response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
-
- con->http_status = 301;
-
+
+ con->http_status = p->conf.redirect_code > 99 && p->conf.redirect_code < 1000 ? p->conf.redirect_code : 301;
+ con->mode = DIRECT;
+ con->file_finished = 1;
+
return HANDLER_FINISHED;
}
}
#undef N
-
+
#else
UNUSED(srv);
UNUSED(con);
UNUSED(p_data);
#endif
-
+
return HANDLER_GO_ON;
}
+int mod_redirect_plugin_init(plugin *p);
int mod_redirect_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("redirect");
-
+
p->init = mod_redirect_init;
p->handle_uri_clean = mod_redirect_uri_handler;
p->set_defaults = mod_redirect_set_defaults;
p->cleanup = mod_redirect_free;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_rewrite.c b/src/mod_rewrite.c
index ff152a9..9672c4e 100644
--- a/src/mod_rewrite.c
+++ b/src/mod_rewrite.c
@@ -1,37 +1,34 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
#include "base.h"
#include "log.h"
#include "buffer.h"
#include "plugin.h"
+#include "stat_cache.h"
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
-typedef struct {
#ifdef HAVE_PCRE_H
+typedef struct {
pcre *key;
-#endif
-
+
buffer *value;
-
+
int once;
} rewrite_rule;
typedef struct {
rewrite_rule **ptr;
-
+
size_t used;
size_t size;
} rewrite_rule_buffer;
typedef struct {
rewrite_rule_buffer *rewrite;
- data_config *context; /* to which apply me */
+ rewrite_rule_buffer *rewrite_NF;
+ data_config *context, *context_NF; /* to which apply me */
} plugin_config;
typedef struct {
@@ -42,20 +39,20 @@ typedef struct {
typedef struct {
PLUGIN_DATA;
buffer *match_buf;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
-static handler_ctx * handler_ctx_init() {
+static handler_ctx * handler_ctx_init(void) {
handler_ctx * hctx;
-
+
hctx = calloc(1, sizeof(*hctx));
-
+
hctx->state = REWRITE_STATE_UNSET;
hctx->loops = 0;
-
+
return hctx;
}
@@ -63,66 +60,56 @@ static void handler_ctx_free(handler_ctx *hctx) {
free(hctx);
}
-rewrite_rule_buffer *rewrite_rule_buffer_init(void) {
+static rewrite_rule_buffer *rewrite_rule_buffer_init(void) {
rewrite_rule_buffer *kvb;
-
+
kvb = calloc(1, sizeof(*kvb));
-
+
return kvb;
}
-int rewrite_rule_buffer_append(rewrite_rule_buffer *kvb, buffer *key, buffer *value, int once) {
-#ifdef HAVE_PCRE_H
+static int rewrite_rule_buffer_append(rewrite_rule_buffer *kvb, buffer *key, buffer *value, int once) {
size_t i;
const char *errptr;
int erroff;
-
+
if (!key) return -1;
if (kvb->size == 0) {
kvb->size = 4;
kvb->used = 0;
-
+
kvb->ptr = malloc(kvb->size * sizeof(*kvb->ptr));
-
+
for(i = 0; i < kvb->size; i++) {
kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
}
} else if (kvb->used == kvb->size) {
kvb->size += 4;
-
+
kvb->ptr = realloc(kvb->ptr, kvb->size * sizeof(*kvb->ptr));
-
+
for(i = kvb->used; i < kvb->size; i++) {
kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
}
}
-
+
if (NULL == (kvb->ptr[kvb->used]->key = pcre_compile(key->ptr,
0, &errptr, &erroff, NULL))) {
-
+
return -1;
}
-
+
kvb->ptr[kvb->used]->value = buffer_init();
buffer_copy_string_buffer(kvb->ptr[kvb->used]->value, value);
kvb->ptr[kvb->used]->once = once;
-
+
kvb->used++;
-
- return 0;
-#else
- UNUSED(kvb);
- UNUSED(value);
- UNUSED(once);
- UNUSED(key);
- return -1;
-#endif
+ return 0;
}
-void rewrite_rule_buffer_free(rewrite_rule_buffer *kvb) {
-#ifdef HAVE_PCRE_H
+static void rewrite_rule_buffer_free(rewrite_rule_buffer *kvb) {
size_t i;
for (i = 0; i < kvb->size; i++) {
@@ -130,239 +117,264 @@ void rewrite_rule_buffer_free(rewrite_rule_buffer *kvb) {
if (kvb->ptr[i]->value) buffer_free(kvb->ptr[i]->value);
free(kvb->ptr[i]);
}
-
+
if (kvb->ptr) free(kvb->ptr);
-#endif
-
+
free(kvb);
}
INIT_FUNC(mod_rewrite_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
p->match_buf = buffer_init();
-
+
return p;
}
FREE_FUNC(mod_rewrite_free) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
-
+
buffer_free(p->match_buf);
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
rewrite_rule_buffer_free(s->rewrite);
-
+ rewrite_rule_buffer_free(s->rewrite_NF);
+
free(s);
}
free(p->config_storage);
}
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
-static int parse_config_entry(server *srv, plugin_config *s, array *ca, const char *option, int once) {
+static int parse_config_entry(server *srv, array *ca, rewrite_rule_buffer *kvb, const char *option, int once) {
data_unset *du;
-
+
if (NULL != (du = array_get_element(ca, option))) {
- data_array *da = (data_array *)du;
+ data_array *da;
size_t j;
-
+
if (du->type != TYPE_ARRAY) {
- log_error_write(srv, __FILE__, __LINE__, "sss",
+ log_error_write(srv, __FILE__, __LINE__, "sss",
"unexpected type for key: ", option, "array of strings");
-
+
return HANDLER_ERROR;
}
-
+
da = (data_array *)du;
-
+
for (j = 0; j < da->value->used; j++) {
if (da->value->data[j]->type != TYPE_STRING) {
- log_error_write(srv, __FILE__, __LINE__, "sssbs",
- "unexpected type for key: ",
- option,
+ log_error_write(srv, __FILE__, __LINE__, "sssbs",
+ "unexpected type for key: ",
+ option,
"[", da->value->data[j]->key, "](string)");
-
+
return HANDLER_ERROR;
}
-
- if (0 != rewrite_rule_buffer_append(s->rewrite,
+
+ if (0 != rewrite_rule_buffer_append(kvb,
((data_string *)(da->value->data[j]))->key,
((data_string *)(da->value->data[j]))->value,
once)) {
-#ifdef HAVE_PCRE_H
- log_error_write(srv, __FILE__, __LINE__, "sb",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
"pcre-compile failed for", da->value->data[j]->key);
-#else
- log_error_write(srv, __FILE__, __LINE__, "s",
- "pcre support is missing, please install libpcre and the headers");
-#endif
}
}
}
-
+
+ return 0;
+}
+#else
+static int parse_config_entry(server *srv, array *ca, const char *option) {
+ static int logged_message = 0;
+ if (logged_message) return 0;
+ if (NULL != array_get_element(ca, option)) {
+ logged_message = 1;
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "pcre support is missing, please install libpcre and the headers");
+ }
return 0;
}
+#endif
SETDEFAULTS_FUNC(mod_rewrite_set_defaults) {
- plugin_data *p = p_d;
size_t i = 0;
-
- config_values_t cv[] = {
+ config_values_t cv[] = {
{ "url.rewrite-repeat", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ "url.rewrite-once", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
-
- /* old names, still supported
- *
+
+ /* these functions only rewrite if the target is not already in the filestore
+ *
+ * url.rewrite-repeat-if-not-file is the equivalent of url.rewrite-repeat
+ * url.rewrite-if-not-file is the equivalent of url.rewrite-once
+ *
+ */
+ { "url.rewrite-repeat-if-not-file", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "url.rewrite-if-not-file", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+
+ /* old names, still supported
+ *
* url.rewrite remapped to url.rewrite-once
* url.rewrite-final is url.rewrite-once
- *
+ *
*/
- { "url.rewrite", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { "url.rewrite-final", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "url.rewrite", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { "url.rewrite-final", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
+#ifdef HAVE_PCRE_H
+ plugin_data *p = p_d;
+
if (!p) return HANDLER_ERROR;
-
+
/* 0 */
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+#else
+ UNUSED(p_d);
+#endif
+
for (i = 0; i < srv->config_context->used; i++) {
- plugin_config *s;
array *ca;
-
+#ifdef HAVE_PCRE_H
+ plugin_config *s;
+
s = calloc(1, sizeof(plugin_config));
- s->rewrite = rewrite_rule_buffer_init();
-
- cv[0].destination = s->rewrite;
- cv[1].destination = s->rewrite;
- cv[2].destination = s->rewrite;
-
+ s->rewrite = rewrite_rule_buffer_init();
+ s->rewrite_NF = rewrite_rule_buffer_init();
p->config_storage[i] = s;
+#endif
+
ca = ((data_config *)srv->config_context->data[i])->value;
-
+
if (0 != config_insert_values_global(srv, ca, cv)) {
return HANDLER_ERROR;
}
-
- parse_config_entry(srv, s, ca, "url.rewrite-once", 1);
- parse_config_entry(srv, s, ca, "url.rewrite-final", 1);
- parse_config_entry(srv, s, ca, "url.rewrite", 1);
- parse_config_entry(srv, s, ca, "url.rewrite-repeat", 0);
+
+#ifndef HAVE_PCRE_H
+# define parse_config_entry(srv, ca, x, option, y) parse_config_entry(srv, ca, option)
+#endif
+ parse_config_entry(srv, ca, s->rewrite, "url.rewrite-once", 1);
+ parse_config_entry(srv, ca, s->rewrite, "url.rewrite-final", 1);
+ parse_config_entry(srv, ca, s->rewrite_NF, "url.rewrite-if-not-file", 1);
+ parse_config_entry(srv, ca, s->rewrite_NF, "url.rewrite-repeat-if-not-file", 0);
+ parse_config_entry(srv, ca, s->rewrite, "url.rewrite", 1);
+ parse_config_entry(srv, ca, s->rewrite, "url.rewrite-repeat", 0);
}
-
+
return HANDLER_GO_ON;
}
+
#ifdef HAVE_PCRE_H
+
+#define PATCH(x) \
+ p->conf.x = s->x;
static int mod_rewrite_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
- p->conf.rewrite = s->rewrite;
-
+
+ PATCH(rewrite);
+ PATCH(rewrite_NF);
+ p->conf.context = NULL;
+ p->conf.context_NF = NULL;
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
if (COMP_HTTP_URL == dc->comp) continue;
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite"))) {
- p->conf.rewrite = s->rewrite;
+ PATCH(rewrite);
p->conf.context = dc;
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-once"))) {
- p->conf.rewrite = s->rewrite;
+ PATCH(rewrite);
p->conf.context = dc;
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-repeat"))) {
- p->conf.rewrite = s->rewrite;
+ PATCH(rewrite);
p->conf.context = dc;
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-if-not-file"))) {
+ PATCH(rewrite_NF);
+ p->conf.context_NF = dc;
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-repeat-if-not-file"))) {
+ PATCH(rewrite_NF);
+ p->conf.context_NF = dc;
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-final"))) {
- p->conf.rewrite = s->rewrite;
+ PATCH(rewrite);
p->conf.context = dc;
}
}
}
-
+
return 0;
}
-#endif
+
URIHANDLER_FUNC(mod_rewrite_con_reset) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
-
+
if (con->plugin_ctx[p->id]) {
handler_ctx_free(con->plugin_ctx[p->id]);
con->plugin_ctx[p->id] = NULL;
}
-
+
return HANDLER_GO_ON;
}
-URIHANDLER_FUNC(mod_rewrite_uri_handler) {
-#ifdef HAVE_PCRE_H
- plugin_data *p = p_d;
+static int process_rewrite_rules(server *srv, connection *con, plugin_data *p, rewrite_rule_buffer *kvb) {
size_t i;
handler_ctx *hctx;
- /*
- * REWRITE URL
- *
- * e.g. rewrite /base/ to /index.php?section=base
- *
- */
-
if (con->plugin_ctx[p->id]) {
hctx = con->plugin_ctx[p->id];
-
+
if (hctx->loops++ > 100) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"ENDLESS LOOP IN rewrite-rule DETECTED ... aborting request, perhaps you want to use url.rewrite-once instead of url.rewrite-repeat");
-
+
return HANDLER_ERROR;
}
-
+
if (hctx->state == REWRITE_STATE_FINISHED) return HANDLER_GO_ON;
}
-
- mod_rewrite_patch_connection(srv, con, p);
- if (!p->conf.rewrite) return HANDLER_GO_ON;
-
buffer_copy_string_buffer(p->match_buf, con->request.uri);
-
- for (i = 0; i < p->conf.rewrite->used; i++) {
+
+ for (i = 0; i < kvb->used; i++) {
pcre *match;
const char *pattern;
size_t pattern_len;
int n;
- rewrite_rule *rule = p->conf.rewrite->ptr[i];
+ rewrite_rule *rule = kvb->ptr[i];
# define N 10
int ovec[N * 3];
-
+
match = rule->key;
pattern = rule->value->ptr;
pattern_len = rule->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_ERROR_NOMATCH) {
log_error_write(srv, __FILE__, __LINE__, "sd",
@@ -371,80 +383,128 @@ URIHANDLER_FUNC(mod_rewrite_uri_handler) {
}
} else {
const char **list;
- size_t start, end;
+ size_t start;
size_t k;
-
+
/* it matched */
pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
-
+
/* search for $[0-9] */
-
+
buffer_reset(con->request.uri);
-
- start = 0; end = pattern_len;
- for (k = 0; k < pattern_len; k++) {
- if ((pattern[k] == '$' || pattern[k] == '%') &&
- isdigit((unsigned char)pattern[k + 1])) {
+
+ start = 0;
+ for (k = 0; k+1 < pattern_len; k++) {
+ if (pattern[k] == '$' || pattern[k] == '%') {
/* got one */
-
+
size_t num = pattern[k + 1] - '0';
-
- end = k;
-
- buffer_append_string_len(con->request.uri, pattern + start, end - start);
-
- if (pattern[k] == '$') {
+
+ buffer_append_string_len(con->request.uri, pattern + start, k - start);
+
+ if (!isdigit((unsigned char)pattern[k + 1])) {
+ /* enable escape: "%%" => "%", "%a" => "%a", "$$" => "$" */
+ buffer_append_string_len(con->request.uri, pattern+k, pattern[k] == pattern[k+1] ? 1 : 2);
+ } else if (pattern[k] == '$') {
/* n is always > 0 */
if (num < (size_t)n) {
buffer_append_string(con->request.uri, list[num]);
}
+ } else if (p->conf.context == NULL) {
+ /* we have no context, we are global */
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "used a redirect containing a %[0-9]+ in the global scope, ignored:",
+ rule->value);
+
} else {
config_append_cond_match_buffer(con, p->conf.context, con->request.uri, num);
}
-
+
k++;
start = k + 1;
- }
+ }
}
-
+
buffer_append_string_len(con->request.uri, pattern + start, pattern_len - start);
-
+
pcre_free(list);
-
- hctx = handler_ctx_init();
-
- con->plugin_ctx[p->id] = hctx;
-
+
+ if (con->plugin_ctx[p->id] == NULL) {
+ hctx = handler_ctx_init();
+ con->plugin_ctx[p->id] = hctx;
+ } else {
+ hctx = con->plugin_ctx[p->id];
+ }
+
if (rule->once) hctx->state = REWRITE_STATE_FINISHED;
-
+
return HANDLER_COMEBACK;
}
- }
#undef N
-
-#else
- UNUSED(srv);
- UNUSED(con);
- UNUSED(p_d);
-#endif
+ }
+
+ return HANDLER_GO_ON;
+}
+
+URIHANDLER_FUNC(mod_rewrite_physical) {
+ plugin_data *p = p_d;
+ handler_t r;
+ stat_cache_entry *sce;
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
+ mod_rewrite_patch_connection(srv, con, p);
+ p->conf.context = p->conf.context_NF;
+
+ if (!p->conf.rewrite_NF) return HANDLER_GO_ON;
+
+ /* skip if physical.path is a regular file */
+ sce = NULL;
+ if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+ if (S_ISREG(sce->st.st_mode)) return HANDLER_GO_ON;
+ }
+
+ switch(r = process_rewrite_rules(srv, con, p, p->conf.rewrite_NF)) {
+ case HANDLER_COMEBACK:
+ buffer_reset(con->physical.path);
+ default:
+ return r;
+ }
return HANDLER_GO_ON;
}
+URIHANDLER_FUNC(mod_rewrite_uri_handler) {
+ plugin_data *p = p_d;
+
+ mod_rewrite_patch_connection(srv, con, p);
+
+ if (!p->conf.rewrite) return HANDLER_GO_ON;
+
+ return process_rewrite_rules(srv, con, p, p->conf.rewrite);
+
+ return HANDLER_GO_ON;
+}
+#endif
+
+int mod_rewrite_plugin_init(plugin *p);
int mod_rewrite_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("rewrite");
-
+
+#ifdef HAVE_PCRE_H
p->init = mod_rewrite_init;
/* it has to stay _raw as we are matching on uri + querystring
*/
-
+
p->handle_uri_raw = mod_rewrite_uri_handler;
- p->set_defaults = mod_rewrite_set_defaults;
+ p->handle_physical = mod_rewrite_physical;
p->cleanup = mod_rewrite_free;
p->connection_reset = mod_rewrite_con_reset;
-
+#endif
+ p->set_defaults = mod_rewrite_set_defaults;
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_rrdtool.c b/src/mod_rrdtool.c
index c7b897a..67a0215 100644
--- a/src/mod_rrdtool.c
+++ b/src/mod_rrdtool.c
@@ -1,4 +1,10 @@
-#define _GNU_SOURCE
+#include "server.h"
+#include "connections.h"
+#include "response.h"
+#include "connections.h"
+#include "log.h"
+
+#include "plugin.h"
#include <sys/types.h>
#include <fcntl.h>
@@ -9,13 +15,6 @@
#include <errno.h>
#include <time.h>
-#include "server.h"
-#include "connections.h"
-#include "response.h"
-#include "connections.h"
-#include "log.h"
-
-#include "plugin.h"
#ifdef HAVE_FORK
/* no need for waitpid if we don't have fork */
#include <sys/wait.h>
@@ -23,7 +22,7 @@
typedef struct {
buffer *path_rrdtool_bin;
buffer *path_rrd;
-
+
double requests, *requests_ptr;
double bytes_written, *bytes_written_ptr;
double bytes_read, *bytes_read_ptr;
@@ -31,84 +30,84 @@ typedef struct {
typedef struct {
PLUGIN_DATA;
-
+
buffer *cmd;
buffer *resp;
-
+
int read_fd, write_fd;
pid_t rrdtool_pid;
-
+
int rrdtool_running;
-
+
plugin_config **config_storage;
plugin_config conf;
} plugin_data;
INIT_FUNC(mod_rrd_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
p->resp = buffer_init();
p->cmd = buffer_init();
-
+
return p;
}
FREE_FUNC(mod_rrd_free) {
plugin_data *p = p_d;
size_t i;
-
+
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
-
+
buffer_free(s->path_rrdtool_bin);
buffer_free(s->path_rrd);
-
+
free(s);
}
}
buffer_free(p->cmd);
buffer_free(p->resp);
-
+
free(p->config_storage);
-
+
if (p->rrdtool_pid) {
int status;
close(p->read_fd);
close(p->write_fd);
-#ifdef HAVE_FORK
+#ifdef HAVE_FORK
/* collect status */
waitpid(p->rrdtool_pid, &status, 0);
#endif
}
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
-int mod_rrd_create_pipe(server *srv, plugin_data *p) {
+static int mod_rrd_create_pipe(server *srv, plugin_data *p) {
+#ifdef HAVE_FORK
pid_t pid;
-
+
int to_rrdtool_fds[2];
int from_rrdtool_fds[2];
-#ifdef HAVE_FORK
if (pipe(to_rrdtool_fds)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"pipe failed: ", strerror(errno));
return -1;
}
-
+
if (pipe(from_rrdtool_fds)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"pipe failed: ", strerror(errno));
return -1;
}
-
+
/* fork, execve */
switch (pid = fork()) {
case 0: {
@@ -117,47 +116,40 @@ int mod_rrd_create_pipe(server *srv, plugin_data *p) {
int argc;
int i = 0;
char *dash = "-";
-
+
/* move stdout to from_rrdtool_fd[1] */
close(STDOUT_FILENO);
dup2(from_rrdtool_fds[1], STDOUT_FILENO);
close(from_rrdtool_fds[1]);
/* not needed */
close(from_rrdtool_fds[0]);
-
+
/* move the stdin to to_rrdtool_fd[0] */
close(STDIN_FILENO);
dup2(to_rrdtool_fds[0], STDIN_FILENO);
close(to_rrdtool_fds[0]);
/* not needed */
close(to_rrdtool_fds[1]);
-
- close(STDERR_FILENO);
-
- if (srv->errorlog_mode == ERRORLOG_FILE) {
- dup2(srv->errorlog_fd, STDERR_FILENO);
- close(srv->errorlog_fd);
- }
-
+
/* set up args */
argc = 3;
args = malloc(sizeof(*args) * argc);
i = 0;
-
+
args[i++] = p->conf.path_rrdtool_bin->ptr;
args[i++] = dash;
- args[i++] = NULL;
+ args[i ] = NULL;
/* we don't need the client socket */
for (i = 3; i < 256; i++) {
close(i);
}
-
+
/* exec the cgi */
execv(args[0], args);
-
- log_error_write(srv, __FILE__, __LINE__, "sss", "spawing rrdtool failed: ", strerror(errno), args[0]);
-
+
+ /* log_error_write(srv, __FILE__, __LINE__, "sss", "spawing rrdtool failed: ", strerror(errno), args[0]); */
+
/* */
SEGFAULT();
break;
@@ -168,85 +160,136 @@ int mod_rrd_create_pipe(server *srv, plugin_data *p) {
break;
default: {
/* father */
-
+
close(from_rrdtool_fds[1]);
close(to_rrdtool_fds[0]);
-
+
/* register PID and wait for them asyncronously */
p->write_fd = to_rrdtool_fds[1];
p->read_fd = from_rrdtool_fds[0];
p->rrdtool_pid = pid;
-
+
+#ifdef FD_CLOEXEC
+ fcntl(p->write_fd, F_SETFD, FD_CLOEXEC);
+ fcntl(p->read_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
break;
}
}
-
+
return 0;
#else
return -1;
#endif
}
+/* read/write wrappers to catch EINTR */
+
+/* write to blocking socket; blocks until all data is sent, write returns 0 or an error (apart from EINTR) occurs. */
+static ssize_t safe_write(int fd, const void *buf, size_t count) {
+ ssize_t res, sum = 0;
+
+ for (;;) {
+ res = write(fd, buf, count);
+ if (res >= 0) {
+ sum += res;
+ /* do not try again if res == 0 */
+ if (res == 0 || (size_t) res == count) return sum;
+ count -= res;
+ buf = (const char*) buf + res;
+ continue;
+ }
+ switch (errno) {
+ case EINTR:
+ continue;
+ default:
+ return -1;
+ }
+ }
+}
+
+/* this assumes we get enough data on a successful read */
+static ssize_t safe_read(int fd, void *buf, size_t count) {
+ ssize_t res;
+
+ for (;;) {
+ res = read(fd, buf, count);
+ if (res >= 0) return res;
+ switch (errno) {
+ case EINTR:
+ continue;
+ default:
+ return -1;
+ }
+ }
+}
+
static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s) {
struct stat st;
-
+ int r;
+
/* check if DB already exists */
if (0 == stat(s->path_rrd->ptr, &st)) {
/* check if it is plain file */
if (!S_ISREG(st.st_mode)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
"not a regular file:", s->path_rrd);
return HANDLER_ERROR;
}
- } else {
- int r ;
- /* create a new one */
-
- BUFFER_COPY_STRING_CONST(p->cmd, "create ");
- buffer_append_string_buffer(p->cmd, s->path_rrd);
- buffer_append_string(p->cmd, " --step 60 ");
- buffer_append_string(p->cmd, "DS:InOctets:ABSOLUTE:600:U:U ");
- buffer_append_string(p->cmd, "DS:OutOctets:ABSOLUTE:600:U:U ");
- buffer_append_string(p->cmd, "DS:Requests:ABSOLUTE:600:U:U ");
- buffer_append_string(p->cmd, "RRA:AVERAGE:0.5:1:600 ");
- buffer_append_string(p->cmd, "RRA:AVERAGE:0.5:6:700 ");
- buffer_append_string(p->cmd, "RRA:AVERAGE:0.5:24:775 ");
- buffer_append_string(p->cmd, "RRA:AVERAGE:0.5:288:797 ");
- buffer_append_string(p->cmd, "RRA:MAX:0.5:1:600 ");
- buffer_append_string(p->cmd, "RRA:MAX:0.5:6:700 ");
- buffer_append_string(p->cmd, "RRA:MAX:0.5:24:775 ");
- buffer_append_string(p->cmd, "RRA:MAX:0.5:288:797 ");
- buffer_append_string(p->cmd, "RRA:MIN:0.5:1:600 ");
- buffer_append_string(p->cmd, "RRA:MIN:0.5:6:700 ");
- buffer_append_string(p->cmd, "RRA:MIN:0.5:24:775 ");
- buffer_append_string(p->cmd, "RRA:MIN:0.5:288:797\n");
-
- if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "rrdtool-write: failed", strerror(errno));
-
- return HANDLER_ERROR;
- }
-
- buffer_prepare_copy(p->resp, 4096);
- if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "rrdtool-read: failed", strerror(errno));
-
- return HANDLER_ERROR;
- }
-
- p->resp->used = r;
-
- if (p->resp->ptr[0] != 'O' ||
- p->resp->ptr[1] != 'K') {
- log_error_write(srv, __FILE__, __LINE__, "sbb",
- "rrdtool-response:", p->cmd, p->resp);
-
- return HANDLER_ERROR;
+
+ /* still create DB if it's empty file */
+ if (st.st_size > 0) {
+ return HANDLER_GO_ON;
}
}
-
+
+ /* create a new one */
+ buffer_copy_string_len(p->cmd, CONST_STR_LEN("create "));
+ buffer_append_string_buffer(p->cmd, s->path_rrd);
+ buffer_append_string_len(p->cmd, CONST_STR_LEN(
+ " --step 60 "
+ "DS:InOctets:ABSOLUTE:600:U:U "
+ "DS:OutOctets:ABSOLUTE:600:U:U "
+ "DS:Requests:ABSOLUTE:600:U:U "
+ "RRA:AVERAGE:0.5:1:600 "
+ "RRA:AVERAGE:0.5:6:700 "
+ "RRA:AVERAGE:0.5:24:775 "
+ "RRA:AVERAGE:0.5:288:797 "
+ "RRA:MAX:0.5:1:600 "
+ "RRA:MAX:0.5:6:700 "
+ "RRA:MAX:0.5:24:775 "
+ "RRA:MAX:0.5:288:797 "
+ "RRA:MIN:0.5:1:600 "
+ "RRA:MIN:0.5:6:700 "
+ "RRA:MIN:0.5:24:775 "
+ "RRA:MIN:0.5:288:797\n"));
+
+ if (-1 == (safe_write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "rrdtool-write: failed", strerror(errno));
+
+ return HANDLER_ERROR;
+ }
+
+ buffer_prepare_copy(p->resp, 4096);
+ if (-1 == (r = safe_read(p->read_fd, p->resp->ptr, p->resp->size))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "rrdtool-read: failed", strerror(errno));
+
+ return HANDLER_ERROR;
+ }
+
+ p->resp->used = r;
+
+ if (p->resp->ptr[0] != 'O' ||
+ p->resp->ptr[1] != 'K') {
+ log_error_write(srv, __FILE__, __LINE__, "sbb",
+ "rrdtool-response:", p->cmd, p->resp);
+
+ return HANDLER_ERROR;
+ }
+
return HANDLER_GO_ON;
}
@@ -255,37 +298,37 @@ static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s)
static int mod_rrd_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(path_rrdtool_bin);
PATCH(path_rrd);
-
+
p->conf.bytes_written_ptr = &(s->bytes_written);
p->conf.bytes_read_ptr = &(s->bytes_read);
p->conf.requests_ptr = &(s->requests);
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("rrdtool.db-name"))) {
PATCH(path_rrd);
/* get pointers to double values */
-
+
p->conf.bytes_written_ptr = &(s->bytes_written);
p->conf.bytes_read_ptr = &(s->bytes_read);
p->conf.requests_ptr = &(s->requests);
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -293,157 +336,161 @@ static int mod_rrd_patch_connection(server *srv, connection *con, plugin_data *p
SETDEFAULTS_FUNC(mod_rrd_set_defaults) {
plugin_data *p = p_d;
size_t i;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "rrdtool.binary", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
{ "rrdtool.db-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
s->path_rrdtool_bin = buffer_init();
s->path_rrd = buffer_init();
s->requests = 0;
s->bytes_written = 0;
s->bytes_read = 0;
-
+
cv[0].destination = s->path_rrdtool_bin;
cv[1].destination = s->path_rrd;
-
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
-
+
if (i > 0 && !buffer_is_empty(s->path_rrdtool_bin)) {
/* path_rrdtool_bin is a global option */
-
- log_error_write(srv, __FILE__, __LINE__, "s",
+
+ log_error_write(srv, __FILE__, __LINE__, "s",
"rrdtool.binary can only be set as a global option.");
-
+
return HANDLER_ERROR;
}
-
+
}
-
+
p->conf.path_rrdtool_bin = p->config_storage[0]->path_rrdtool_bin;
p->rrdtool_running = 0;
-
+
/* check for dir */
-
+
if (buffer_is_empty(p->conf.path_rrdtool_bin)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"rrdtool.binary has to be set");
return HANDLER_ERROR;
}
-
+
/* open the pipe to rrdtool */
if (mod_rrd_create_pipe(srv, p)) {
return HANDLER_ERROR;
}
-
+
p->rrdtool_running = 1;
-
+
return HANDLER_GO_ON;
}
TRIGGER_FUNC(mod_rrd_trigger) {
plugin_data *p = p_d;
size_t i;
-
+
if (!p->rrdtool_running) return HANDLER_GO_ON;
if ((srv->cur_ts % 60) != 0) return HANDLER_GO_ON;
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
int r;
-
+
if (buffer_is_empty(s->path_rrd)) continue;
-
+
/* write the data down every minute */
-
+
if (HANDLER_GO_ON != mod_rrdtool_create_rrd(srv, p, s)) return HANDLER_ERROR;
-
- BUFFER_COPY_STRING_CONST(p->cmd, "update ");
+
+ buffer_copy_string_len(p->cmd, CONST_STR_LEN("update "));
buffer_append_string_buffer(p->cmd, s->path_rrd);
- BUFFER_APPEND_STRING_CONST(p->cmd, " N:");
+ buffer_append_string_len(p->cmd, CONST_STR_LEN(" N:"));
buffer_append_off_t(p->cmd, s->bytes_read);
- BUFFER_APPEND_STRING_CONST(p->cmd, ":");
+ buffer_append_string_len(p->cmd, CONST_STR_LEN(":"));
buffer_append_off_t(p->cmd, s->bytes_written);
- BUFFER_APPEND_STRING_CONST(p->cmd, ":");
+ buffer_append_string_len(p->cmd, CONST_STR_LEN(":"));
buffer_append_long(p->cmd, s->requests);
- BUFFER_APPEND_STRING_CONST(p->cmd, "\n");
-
- if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
+ buffer_append_string_len(p->cmd, CONST_STR_LEN("\n"));
+
+ if (-1 == (r = safe_write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
p->rrdtool_running = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "ss",
+
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"rrdtool-write: failed", strerror(errno));
-
+
return HANDLER_ERROR;
}
-
+
buffer_prepare_copy(p->resp, 4096);
- if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
+ if (-1 == (r = safe_read(p->read_fd, p->resp->ptr, p->resp->size))) {
p->rrdtool_running = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "ss",
+
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"rrdtool-read: failed", strerror(errno));
-
+
return HANDLER_ERROR;
}
-
+
p->resp->used = r;
-
+
if (p->resp->ptr[0] != 'O' ||
p->resp->ptr[1] != 'K') {
- p->rrdtool_running = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "sbb",
+ /* don't fail on this error if we just started (graceful restart, the old one might have just updated too) */
+ if (!(strstr(p->resp->ptr, "(minimum one second step)") && (srv->cur_ts - srv->startup_ts < 3))) {
+ p->rrdtool_running = 0;
+
+ log_error_write(srv, __FILE__, __LINE__, "sbb",
"rrdtool-response:", p->cmd, p->resp);
-
- return HANDLER_ERROR;
+
+ return HANDLER_ERROR;
+ }
}
s->requests = 0;
s->bytes_written = 0;
s->bytes_read = 0;
}
-
+
return HANDLER_GO_ON;
}
REQUESTDONE_FUNC(mod_rrd_account) {
plugin_data *p = p_d;
-
+
mod_rrd_patch_connection(srv, con, p);
-
+
*(p->conf.requests_ptr) += 1;
*(p->conf.bytes_written_ptr) += con->bytes_written;
*(p->conf.bytes_read_ptr) += con->bytes_read;
-
+
return HANDLER_GO_ON;
}
+int mod_rrdtool_plugin_init(plugin *p);
int mod_rrdtool_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("rrd");
-
+
p->init = mod_rrd_init;
p->cleanup = mod_rrd_free;
p->set_defaults= mod_rrd_set_defaults;
-
+
p->handle_trigger = mod_rrd_trigger;
p->handle_request_done = mod_rrd_account;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_scgi.c b/src/mod_scgi.c
index a27b28a..6ae0782 100644
--- a/src/mod_scgi.c
+++ b/src/mod_scgi.c
@@ -1,13 +1,3 @@
-#include <sys/types.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <assert.h>
-#include <signal.h>
-
#include "buffer.h"
#include "server.h"
#include "keyvalue.h"
@@ -23,6 +13,16 @@
#include "inet_ntop_cache.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+#include <signal.h>
+
#include <stdio.h>
#ifdef HAVE_SYS_FILIO_H
@@ -31,34 +31,32 @@
#include "sys-socket.h"
-
-#ifndef UNIX_PATH_MAX
-# define UNIX_PATH_MAX 108
-#endif
-
#ifdef HAVE_SYS_UIO_H
-#include <sys/uio.h>
+# include <sys/uio.h>
#endif
+
#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
+# include <sys/wait.h>
#endif
+#include "version.h"
+
enum {EOL_UNSET, EOL_N, EOL_RN};
/*
- *
+ *
* TODO:
- *
+ *
* - add timeout for a connect to a non-scgi process
* (use state_timestamp + state)
- *
+ *
*/
typedef struct scgi_proc {
size_t id; /* id will be between 1 and max_procs */
buffer *socket; /* config.socket + "-" + id */
unsigned port; /* config.port + pno */
-
+
pid_t pid; /* PID of the spawned process (0 if not spawned locally) */
@@ -67,9 +65,9 @@ typedef struct scgi_proc {
time_t last_used; /* see idle_timeout */
size_t requests; /* see max_requests */
struct scgi_proc *prev, *next; /* see first */
-
+
time_t disable_ts; /* replace by host->something */
-
+
int is_local;
enum { PROC_STATE_UNSET, /* init-phase */
@@ -78,7 +76,7 @@ typedef struct scgi_proc {
PROC_STATE_KILLED, /* was killed as we don't have the load anymore */
PROC_STATE_DIED, /* marked as dead, should be restarted */
PROC_STATE_DISABLED /* proc disabled as it resulted in an error */
- } state;
+ } state;
} scgi_proc;
typedef struct {
@@ -86,20 +84,20 @@ typedef struct {
* sorted by lowest load
*
* whenever a job is done move it up in the list
- * until it is sorted, move it down as soon as the
+ * until it is sorted, move it down as soon as the
* job is started
*/
- scgi_proc *first;
- scgi_proc *unused_procs;
+ scgi_proc *first;
+ scgi_proc *unused_procs;
- /*
+ /*
* spawn at least min_procs, at max_procs.
*
- * as soon as the load of the first entry
+ * as soon as the load of the first entry
* is max_load_per_proc we spawn a new one
- * and add it to the first entry and give it
+ * and add it to the first entry and give it
* the load
- *
+ *
*/
unsigned short min_procs;
@@ -111,44 +109,44 @@ typedef struct {
/*
* kick the process from the list if it was not
- * used for idle_timeout until min_procs is
+ * used for idle_timeout until min_procs is
* reached. this helps to get the processlist
* small again we had a small peak load.
*
*/
-
+
unsigned short idle_timeout;
-
+
/*
* time after a disabled remote connection is tried to be re-enabled
- *
- *
+ *
+ *
*/
-
+
unsigned short disable_time;
/*
* same scgi processes get a little bit larger
- * than wanted. max_requests_per_proc kills a
+ * than wanted. max_requests_per_proc kills a
* process after a number of handled requests.
*
*/
size_t max_requests_per_proc;
-
+
/* config */
- /*
- * host:port
+ /*
+ * host:port
*
- * if host is one of the local IP adresses the
+ * 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
- *
- */
- buffer *host;
+ * to be specified
+ *
+ */
+ buffer *host;
unsigned short port;
/*
@@ -161,7 +159,7 @@ typedef struct {
*/
buffer *unixsocket;
- /* if socket is local we can start the scgi
+ /* if socket is local we can start the scgi
* process ourself
*
* bin-path is the path to the binary
@@ -169,19 +167,19 @@ typedef struct {
* check min_procs and max_procs for the number
* of process to start-up
*/
- buffer *bin_path;
-
- /* bin-path is set bin-environment is taken to
+ buffer *bin_path;
+
+ /* bin-path is set bin-environment is taken to
* create the environement before starting the
* FastCGI process
- *
+ *
*/
array *bin_env;
-
+
array *bin_env_copy;
-
+
/*
- * docroot-translation between URL->phys and the
+ * docroot-translation between URL->phys and the
* remote host
*
* reasons:
@@ -192,7 +190,7 @@ typedef struct {
buffer *docroot;
/*
- * check_local tell you if the phys file is stat()ed
+ * check_local tell you if the phys file is stat()ed
* or not. FastCGI doesn't care if the service is
* remote. If the web-server side doesn't contain
* the scgi-files we should not stat() for them
@@ -202,33 +200,42 @@ typedef struct {
/*
* append PATH_INFO to SCRIPT_FILENAME
- *
+ *
* php needs this if cgi.fix_pathinfo is provied
- *
+ *
*/
-
+
+ /*
+ * workaround for program when prefix="/"
+ *
+ * rule to build PATH_INFO is hardcoded for when check_local is disabled
+ * enable this option to use the workaround
+ *
+ */
+
+ unsigned short fix_root_path_name;
ssize_t load; /* replace by host->load */
size_t max_id; /* corresponds most of the time to
num_procs.
-
+
only if a process is killed max_id waits for the process itself
to die and decrements its afterwards */
} scgi_extension_host;
/*
* one extension can have multiple hosts assigned
- * one host can spawn additional processes on the same
+ * one host can spawn additional processes on the same
* socket (if we control it)
*
* ext -> host -> procs
* 1:n 1:n
*
- * if the scgi process is remote that whole goes down
+ * if the scgi process is remote that whole goes down
* to
*
* ext -> host -> procs
- * 1:n 1:1
+ * 1:n 1:1
*
* in case of PHP and FCGI_CHILDREN we have again a procs
* but we don't control it directly.
@@ -238,8 +245,9 @@ typedef struct {
typedef struct {
buffer *key; /* like .php */
+ int note_is_sent;
scgi_extension_host **hosts;
-
+
size_t used;
size_t size;
} scgi_extension;
@@ -253,14 +261,14 @@ typedef struct {
typedef struct {
- scgi_exts *exts;
-
+ scgi_exts *exts;
+
int debug;
} plugin_config;
typedef struct {
char **ptr;
-
+
size_t size;
size_t used;
} char_array;
@@ -268,88 +276,101 @@ typedef struct {
/* generic plugin data, shared between all connections */
typedef struct {
PLUGIN_DATA;
-
+
buffer *scgi_env;
-
+
buffer *path;
buffer *parse_response;
-
+
plugin_config **config_storage;
-
+
plugin_config conf; /* this is only used as long as no handler_ctx is setup */
} plugin_data;
/* connection specific data */
-typedef enum { FCGI_STATE_INIT, FCGI_STATE_CONNECT, FCGI_STATE_PREPARE_WRITE,
- FCGI_STATE_WRITE, FCGI_STATE_READ
+typedef enum { FCGI_STATE_INIT, FCGI_STATE_CONNECT, FCGI_STATE_PREPARE_WRITE,
+ FCGI_STATE_WRITE, FCGI_STATE_READ
} scgi_connection_state_t;
typedef struct {
- buffer *response;
+ buffer *response;
size_t response_len;
int response_type;
int response_padding;
-
+
scgi_proc *proc;
scgi_extension_host *host;
-
+
scgi_connection_state_t state;
time_t state_timestamp;
-
+
int reconnects; /* number of reconnect attempts */
-
+
read_buffer *rb;
chunkqueue *wb;
-
+
buffer *response_header;
-
+
int delayed; /* flag to mark that the connect() is delayed */
-
+
size_t request_id;
int fd; /* fd to the scgi process */
int fde_ndx; /* index into the fd-event buffer */
pid_t pid;
int got_proc;
-
+
plugin_config conf;
-
+
connection *remote_conn; /* dumb pointer */
plugin_data *plugin_data; /* dumb pointer */
} handler_ctx;
/* ok, we need a prototype */
-static handler_t scgi_handle_fdevent(void *s, void *ctx, int revents);
+static handler_t scgi_handle_fdevent(server *srv, void *ctx, int revents);
int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *proc);
+static void reset_signals(void) {
+#ifdef SIGTTOU
+ signal(SIGTTOU, SIG_DFL);
+#endif
+#ifdef SIGTTIN
+ signal(SIGTTIN, SIG_DFL);
+#endif
+#ifdef SIGTSTP
+ signal(SIGTSTP, SIG_DFL);
+#endif
+ signal(SIGHUP, SIG_DFL);
+ signal(SIGPIPE, SIG_DFL);
+ signal(SIGUSR1, SIG_DFL);
+}
-
-static handler_ctx * handler_ctx_init() {
+static handler_ctx * handler_ctx_init(void) {
handler_ctx * hctx;
-
+
hctx = calloc(1, sizeof(*hctx));
assert(hctx);
-
+
hctx->fde_ndx = -1;
-
+
hctx->response = buffer_init();
hctx->response_header = buffer_init();
-
+
hctx->request_id = 0;
hctx->state = FCGI_STATE_INIT;
hctx->proc = NULL;
-
+
hctx->response_len = 0;
hctx->response_type = 0;
hctx->response_padding = 0;
hctx->fd = -1;
-
+
hctx->reconnects = 0;
hctx->wb = chunkqueue_init();
-
+
return hctx;
}
@@ -358,38 +379,38 @@ static void handler_ctx_free(handler_ctx *hctx) {
buffer_free(hctx->response_header);
chunkqueue_free(hctx->wb);
-
+
if (hctx->rb) {
if (hctx->rb->ptr) free(hctx->rb->ptr);
free(hctx->rb);
}
-
+
free(hctx);
}
-scgi_proc *scgi_process_init() {
+static scgi_proc *scgi_process_init(void) {
scgi_proc *f;
f = calloc(1, sizeof(*f));
f->socket = buffer_init();
-
+
f->prev = NULL;
f->next = NULL;
-
+
return f;
}
-void scgi_process_free(scgi_proc *f) {
+static void scgi_process_free(scgi_proc *f) {
if (!f) return;
-
+
scgi_process_free(f->next);
-
+
buffer_free(f->socket);
-
+
free(f);
}
-scgi_extension_host *scgi_host_init() {
+static scgi_extension_host *scgi_host_init(void) {
scgi_extension_host *f;
f = calloc(1, sizeof(*f));
@@ -400,66 +421,66 @@ scgi_extension_host *scgi_host_init() {
f->bin_path = buffer_init();
f->bin_env = array_init();
f->bin_env_copy = array_init();
-
+
return f;
}
-void scgi_host_free(scgi_extension_host *h) {
+static void scgi_host_free(scgi_extension_host *h) {
if (!h) return;
-
+
buffer_free(h->host);
buffer_free(h->unixsocket);
buffer_free(h->docroot);
buffer_free(h->bin_path);
array_free(h->bin_env);
array_free(h->bin_env_copy);
-
+
scgi_process_free(h->first);
scgi_process_free(h->unused_procs);
-
+
free(h);
-
+
}
-scgi_exts *scgi_extensions_init() {
+static scgi_exts *scgi_extensions_init(void) {
scgi_exts *f;
f = calloc(1, sizeof(*f));
-
+
return f;
}
-void scgi_extensions_free(scgi_exts *f) {
+static void scgi_extensions_free(scgi_exts *f) {
size_t i;
-
+
if (!f) return;
-
+
for (i = 0; i < f->used; i++) {
scgi_extension *fe;
size_t j;
-
+
fe = f->exts[i];
-
+
for (j = 0; j < fe->used; j++) {
scgi_extension_host *h;
-
+
h = fe->hosts[j];
-
+
scgi_host_free(h);
}
-
+
buffer_free(fe->key);
free(fe->hosts);
-
+
free(fe);
}
-
+
free(f->exts);
-
+
free(f);
}
-int scgi_extension_insert(scgi_exts *ext, buffer *key, scgi_extension_host *fh) {
+static int scgi_extension_insert(scgi_exts *ext, buffer *key, scgi_extension_host *fh) {
scgi_extension *fe;
size_t i;
@@ -504,99 +525,109 @@ int scgi_extension_insert(scgi_exts *ext, buffer *key, scgi_extension_host *fh)
assert(fe->hosts);
}
- fe->hosts[fe->used++] = fh;
+ fe->hosts[fe->used++] = fh;
return 0;
-
+
}
INIT_FUNC(mod_scgi_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
p->scgi_env = buffer_init();
-
+
p->path = buffer_init();
p->parse_response = buffer_init();
-
+
return p;
}
FREE_FUNC(mod_scgi_free) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
buffer_free(p->scgi_env);
buffer_free(p->path);
buffer_free(p->parse_response);
-
+
if (p->config_storage) {
size_t i, j, n;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
scgi_exts *exts;
-
+
if (!s) continue;
-
+
exts = s->exts;
for (j = 0; j < exts->used; j++) {
scgi_extension *ex;
-
+
ex = exts->exts[j];
-
+
for (n = 0; n < ex->used; n++) {
scgi_proc *proc;
scgi_extension_host *host;
-
+
host = ex->hosts[n];
-
+
for (proc = host->first; proc; proc = proc->next) {
if (proc->pid != 0) kill(proc->pid, SIGTERM);
-
- if (proc->is_local &&
+
+ if (proc->is_local &&
!buffer_is_empty(proc->socket)) {
unlink(proc->socket->ptr);
}
}
-
+
for (proc = host->unused_procs; proc; proc = proc->next) {
if (proc->pid != 0) kill(proc->pid, SIGTERM);
-
- if (proc->is_local &&
+
+ if (proc->is_local &&
!buffer_is_empty(proc->socket)) {
unlink(proc->socket->ptr);
}
}
}
}
-
+
scgi_extensions_free(s->exts);
-
+
free(s);
}
free(p->config_storage);
}
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
char *dst;
-
+ size_t i;
+
if (!key || !val) return -1;
-
+
dst = malloc(key_len + val_len + 3);
memcpy(dst, key, key_len);
dst[key_len] = '=';
/* add the \0 from the value */
memcpy(dst + key_len + 1, val, val_len + 1);
-
+
+ for (i = 0; i < env->used; i++) {
+ if (0 == strncmp(dst, env->ptr[i], key_len + 1)) {
+ /* don't care about free as we are in a forked child which is going to exec(...) */
+ /* free(env->ptr[i]); */
+ env->ptr[i] = dst;
+ return 0;
+ }
+ }
+
if (env->size == 0) {
env->size = 16;
env->ptr = malloc(env->size * sizeof(*env->ptr));
@@ -604,13 +635,13 @@ static int env_add(char_array *env, const char *key, size_t key_len, const char
env->size += 16;
env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
}
-
+
env->ptr[env->used++] = dst;
-
+
return 0;
}
-static int scgi_spawn_connection(server *srv,
+static int scgi_spawn_connection(server *srv,
plugin_data *p,
scgi_extension_host *host,
scgi_proc *proc) {
@@ -622,30 +653,30 @@ static int scgi_spawn_connection(server *srv,
#endif
struct sockaddr_in scgi_addr_in;
struct sockaddr *scgi_addr;
-
+
socklen_t servlen;
-
+
#ifndef HAVE_FORK
return -1;
#endif
-
+
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "sdb",
"new proc, socket:", proc->port, proc->socket);
}
-
+
if (!buffer_is_empty(proc->socket)) {
memset(&scgi_addr, 0, sizeof(scgi_addr));
-
+
#ifdef HAVE_SYS_UN_H
scgi_addr_un.sun_family = AF_UNIX;
strcpy(scgi_addr_un.sun_path, proc->socket->ptr);
-
+
#ifdef SUN_LEN
servlen = SUN_LEN(&scgi_addr_un);
#else
/* stevens says: */
- servlen = proc->socket->used - 1 + sizeof(scgi_addr_un.sun_family);
+ servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
#endif
socket_type = AF_UNIX;
scgi_addr = (struct sockaddr *) &scgi_addr_un;
@@ -656,115 +687,120 @@ static int scgi_spawn_connection(server *srv,
#endif
} else {
scgi_addr_in.sin_family = AF_INET;
-
+
if (buffer_is_empty(host->host)) {
scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
} else {
struct hostent *he;
-
+
/* set a usefull default */
scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
-
-
+
+
if (NULL == (he = gethostbyname(host->host->ptr))) {
- log_error_write(srv, __FILE__, __LINE__,
- "sdb", "gethostbyname failed: ",
+ log_error_write(srv, __FILE__, __LINE__,
+ "sdb", "gethostbyname failed: ",
h_errno, host->host);
return -1;
}
-
+
if (he->h_addrtype != AF_INET) {
log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
return -1;
}
-
+
if (he->h_length != sizeof(struct in_addr)) {
log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
return -1;
}
-
+
memcpy(&(scgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
-
+
}
scgi_addr_in.sin_port = htons(proc->port);
servlen = sizeof(scgi_addr_in);
-
+
socket_type = AF_INET;
scgi_addr = (struct sockaddr *) &scgi_addr_in;
}
-
+
if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"failed:", strerror(errno));
return -1;
}
-
+
if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
/* server is not up, spawn in */
pid_t child;
int val;
-
+
if (!buffer_is_empty(proc->socket)) {
unlink(proc->socket->ptr);
}
-
+
close(scgi_fd);
-
+
/* reopen socket */
if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"socket failed:", strerror(errno));
return -1;
}
-
+
val = 1;
if (setsockopt(scgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"socketsockopt failed:", strerror(errno));
return -1;
}
-
+
/* create socket */
if (-1 == bind(scgi_fd, scgi_addr, servlen)) {
- log_error_write(srv, __FILE__, __LINE__, "sbds",
- "bind failed for:",
- proc->socket,
- proc->port,
+ log_error_write(srv, __FILE__, __LINE__, "sbds",
+ "bind failed for:",
+ proc->socket,
+ proc->port,
strerror(errno));
return -1;
}
-
+
if (-1 == listen(scgi_fd, 1024)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"listen failed:", strerror(errno));
return -1;
}
-
-#ifdef HAVE_FORK
+
+#ifdef HAVE_FORK
switch ((child = fork())) {
case 0: {
buffer *b;
size_t i = 0;
int fd = 0;
char_array env;
-
-
+
+
/* create environment */
env.ptr = NULL;
env.size = 0;
env.used = 0;
-
+
+ if (scgi_fd != 0) {
+ dup2(scgi_fd, 0);
+ close(scgi_fd);
+ }
+
/* we don't need the client socket */
for (fd = 3; fd < 256; fd++) {
- if (fd != 2 && fd != scgi_fd) close(fd);
+ close(fd);
}
-
+
/* build clean environment */
if (host->bin_env_copy->used) {
for (i = 0; i < host->bin_env_copy->used; i++) {
data_string *ds = (data_string *)host->bin_env_copy->data[i];
char *ge;
-
+
if (NULL != (ge = getenv(ds->value->ptr))) {
env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
}
@@ -772,44 +808,46 @@ static int scgi_spawn_connection(server *srv,
} else {
for (i = 0; environ[i]; i++) {
char *eq;
-
+
if (NULL != (eq = strchr(environ[i], '='))) {
env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
}
}
}
-
+
/* create environment */
for (i = 0; i < host->bin_env->used; i++) {
data_string *ds = (data_string *)host->bin_env->data[i];
-
+
env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
}
-
+
for (i = 0; i < env.used; i++) {
/* search for PHP_FCGI_CHILDREN */
if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
}
-
+
/* not found, add a default */
if (i == env.used) {
env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
}
-
+
env.ptr[env.used] = NULL;
-
+
b = buffer_init();
- buffer_copy_string(b, "exec ");
+ buffer_copy_string_len(b, CONST_STR_LEN("exec "));
buffer_append_string_buffer(b, host->bin_path);
-
+
+ reset_signals();
+
/* exec the cgi */
- execle("/bin/sh", "sh", "-c", b->ptr, NULL, env.ptr);
-
- log_error_write(srv, __FILE__, __LINE__, "sbs",
+ execle("/bin/sh", "sh", "-c", b->ptr, (char *)NULL, env.ptr);
+
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
"execl failed for:", host->bin_path, strerror(errno));
-
+
exit(errno);
-
+
break;
}
case -1:
@@ -817,32 +855,32 @@ static int scgi_spawn_connection(server *srv,
break;
default:
/* father */
-
+
/* wait */
select(0, NULL, NULL, NULL, &tv);
-
+
switch (waitpid(child, &status, WNOHANG)) {
case 0:
/* child still running after timeout, good */
break;
case -1:
/* no PID found ? should never happen */
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"pid not found:", strerror(errno));
return -1;
default:
/* the child should not terminate at all */
if (WIFEXITED(status)) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "child exited (is this a SCGI binary ?):",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child exited (is this a SCGI binary ?):",
WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "child signaled:",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child signaled:",
WTERMSIG(status));
} else {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "child died somehow:",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child died somehow:",
status);
}
return -1;
@@ -852,26 +890,26 @@ static int scgi_spawn_connection(server *srv,
proc->pid = child;
proc->last_used = srv->cur_ts;
proc->is_local = 1;
-
+
break;
}
#endif
} else {
proc->is_local = 0;
proc->pid = 0;
-
+
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "sb",
"(debug) socket is already used, won't spawn:",
proc->socket);
}
}
-
+
proc->state = PROC_STATE_RUNNING;
host->active_procs++;
-
+
close(scgi_fd);
-
+
return 0;
}
@@ -880,89 +918,89 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
plugin_data *p = p_d;
data_unset *du;
size_t i = 0;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "scgi.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ "scgi.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
array *ca;
-
+
s = malloc(sizeof(plugin_config));
s->exts = scgi_extensions_init();
s->debug = 0;
-
+
cv[0].destination = s->exts;
cv[1].destination = &(s->debug);
-
+
p->config_storage[i] = s;
ca = ((data_config *)srv->config_context->data[i])->value;
-
+
if (0 != config_insert_values_global(srv, ca, cv)) {
return HANDLER_ERROR;
}
-
- /*
+
+ /*
* <key> = ( ... )
*/
-
+
if (NULL != (du = array_get_element(ca, "scgi.server"))) {
size_t j;
data_array *da = (data_array *)du;
-
+
if (du->type != TYPE_ARRAY) {
- log_error_write(srv, __FILE__, __LINE__, "sss",
+ log_error_write(srv, __FILE__, __LINE__, "sss",
"unexpected type for key: ", "scgi.server", "array of strings");
-
+
return HANDLER_ERROR;
}
-
-
- /*
- * scgi.server = ( "<ext>" => ( ... ),
+
+
+ /*
+ * scgi.server = ( "<ext>" => ( ... ),
* "<ext>" => ( ... ) )
*/
-
+
for (j = 0; j < da->value->used; j++) {
size_t n;
data_array *da_ext = (data_array *)da->value->data[j];
-
+
if (da->value->data[j]->type != TYPE_ARRAY) {
- log_error_write(srv, __FILE__, __LINE__, "sssbs",
- "unexpected type for key: ", "scgi.server",
+ log_error_write(srv, __FILE__, __LINE__, "sssbs",
+ "unexpected type for key: ", "scgi.server",
"[", da->value->data[j]->key, "](string)");
-
+
return HANDLER_ERROR;
}
-
- /*
- * da_ext->key == name of the extension
+
+ /*
+ * da_ext->key == name of the extension
*/
-
- /*
- * scgi.server = ( "<ext>" =>
- * ( "<host>" => ( ... ),
+
+ /*
+ * scgi.server = ( "<ext>" =>
+ * ( "<host>" => ( ... ),
* "<host>" => ( ... )
- * ),
+ * ),
* "<ext>" => ... )
*/
-
+
for (n = 0; n < da_ext->value->used; n++) {
data_array *da_host = (data_array *)da_ext->value->data[n];
-
+
scgi_extension_host *df;
-
- config_values_t fcv[] = {
+
+ config_values_t fcv[] = {
{ "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ "docroot", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ "socket", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
{ "bin-path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
-
+
{ "check-local", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
{ "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
{ "min-procs-not-working", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 7 this is broken for now */
@@ -970,37 +1008,39 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
{ "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
{ "idle-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
{ "disable-time", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
-
+
{ "bin-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
{ "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
-
-
+ { "fix-root-scriptname", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
+
+
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (da_host->type != TYPE_ARRAY) {
- log_error_write(srv, __FILE__, __LINE__, "ssSBS",
- "unexpected type for key:",
- "scgi.server",
+ log_error_write(srv, __FILE__, __LINE__, "ssSBS",
+ "unexpected type for key:",
+ "scgi.server",
"[", da_host->key, "](string)");
-
+
return HANDLER_ERROR;
}
-
+
df = scgi_host_init();
-
+
df->check_local = 1;
df->min_procs = 4;
df->max_procs = 4;
df->max_load_per_proc = 1;
df->idle_timeout = 60;
df->disable_time = 60;
-
+ df->fix_root_path_name = 0;
+
fcv[0].destination = df->host;
fcv[1].destination = df->docroot;
fcv[2].destination = df->unixsocket;
fcv[3].destination = df->bin_path;
-
+
fcv[4].destination = &(df->check_local);
fcv[5].destination = &(df->port);
fcv[6].destination = &(df->min_procs);
@@ -1008,47 +1048,49 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
fcv[8].destination = &(df->max_load_per_proc);
fcv[9].destination = &(df->idle_timeout);
fcv[10].destination = &(df->disable_time);
-
+
fcv[11].destination = df->bin_env;
fcv[12].destination = df->bin_env_copy;
-
-
+ fcv[13].destination = &(df->fix_root_path_name);
+
+
if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
return HANDLER_ERROR;
}
-
- if ((!buffer_is_empty(df->host) || df->port) &&
+
+ if ((!buffer_is_empty(df->host) || df->port) &&
!buffer_is_empty(df->unixsocket)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"either host+port or socket");
-
+
return HANDLER_ERROR;
}
-
+
if (!buffer_is_empty(df->unixsocket)) {
/* unix domain socket */
-
- if (df->unixsocket->used > UNIX_PATH_MAX - 2) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ struct sockaddr_un un;
+
+ if (df->unixsocket->used > sizeof(un.sun_path) - 2) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
"path of the unixdomain socket is too large");
return HANDLER_ERROR;
}
} else {
/* tcp/ip */
-
- if (buffer_is_empty(df->host) &&
+
+ if (buffer_is_empty(df->host) &&
buffer_is_empty(df->bin_path)) {
- log_error_write(srv, __FILE__, __LINE__, "sbbbs",
- "missing key (string):",
+ log_error_write(srv, __FILE__, __LINE__, "sbbbs",
+ "missing key (string):",
da->key,
da_ext->key,
da_host->key,
"host");
-
+
return HANDLER_ERROR;
} else if (df->port == 0) {
- log_error_write(srv, __FILE__, __LINE__, "sbbbs",
- "missing key (short):",
+ log_error_write(srv, __FILE__, __LINE__, "sbbbs",
+ "missing key (short):",
da->key,
da_ext->key,
da_host->key,
@@ -1056,14 +1098,17 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
return HANDLER_ERROR;
}
}
-
- if (!buffer_is_empty(df->bin_path)) {
+
+ if (!buffer_is_empty(df->bin_path)) {
/* 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;
-
+
if (s->debug) {
log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
"--- scgi spawning local",
@@ -1073,7 +1118,7 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
"\n\tmin-procs:", df->min_procs,
"\n\tmax-procs:", df->max_procs);
}
-
+
for (pno = 0; pno < df->min_procs; pno++) {
scgi_proc *proc;
@@ -1085,10 +1130,10 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
proc->port = df->port + pno;
} else {
buffer_copy_string_buffer(proc->socket, df->unixsocket);
- buffer_append_string(proc->socket, "-");
+ buffer_append_string_len(proc->socket, CONST_STR_LEN("-"));
buffer_append_long(proc->socket, pno);
}
-
+
if (s->debug) {
log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
"--- scgi spawning",
@@ -1096,88 +1141,83 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
"\n\tsocket", df->unixsocket,
"\n\tcurrent:", pno, "/", df->min_procs);
}
-
+
if (scgi_spawn_connection(srv, p, df, proc)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"[ERROR]: spawning fcgi failed.");
return HANDLER_ERROR;
}
-
+
proc->next = df->first;
if (df->first) df->first->prev = proc;
-
+
df->first = proc;
}
} else {
scgi_proc *fp;
-
+
fp = scgi_process_init();
fp->id = df->num_procs++;
df->max_id++;
df->active_procs++;
fp->state = PROC_STATE_RUNNING;
-
+
if (buffer_is_empty(df->unixsocket)) {
fp->port = df->port;
} else {
buffer_copy_string_buffer(fp->socket, df->unixsocket);
}
-
+
df->first = fp;
-
+
df->min_procs = 1;
df->max_procs = 1;
}
-
+
/* if extension already exists, take it */
scgi_extension_insert(s->exts, da_ext->key, df);
}
}
}
}
-
+
return HANDLER_GO_ON;
}
static int scgi_set_state(server *srv, handler_ctx *hctx, scgi_connection_state_t state) {
hctx->state = state;
hctx->state_timestamp = srv->cur_ts;
-
+
return 0;
}
-void scgi_connection_cleanup(server *srv, handler_ctx *hctx) {
+static void scgi_connection_cleanup(server *srv, handler_ctx *hctx) {
plugin_data *p;
connection *con;
-
+
if (NULL == hctx) return;
-
+
p = hctx->plugin_data;
con = hctx->remote_conn;
-
- if (con->mode != p->id) {
- WP();
- return;
- }
-
+
if (hctx->fd != -1) {
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
fdevent_unregister(srv->ev, hctx->fd);
close(hctx->fd);
srv->cur_fds--;
}
-
+
if (hctx->host && hctx->proc) {
hctx->host->load--;
-
+
if (hctx->got_proc) {
/* after the connect the process gets a load */
hctx->proc->load--;
-
+
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "sddb",
- "release proc:",
+ "release proc:",
hctx->fd,
hctx->proc->pid, hctx->proc->socket);
}
@@ -1186,87 +1226,88 @@ void scgi_connection_cleanup(server *srv, handler_ctx *hctx) {
scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
}
-
+
handler_ctx_free(hctx);
- con->plugin_ctx[p->id] = NULL;
+ con->plugin_ctx[p->id] = NULL;
}
static int scgi_reconnect(server *srv, handler_ctx *hctx) {
plugin_data *p = hctx->plugin_data;
-
- /* child died
- *
- * 1.
- *
+
+ /* child died
+ *
+ * 1.
+ *
* connect was ok, connection was accepted
* but the php accept loop checks after the accept if it should die or not.
- *
- * if yes we can only detect it at a write()
- *
+ *
+ * if yes we can only detect it at a write()
+ *
* next step is resetting this attemp and setup a connection again
- *
+ *
* if we have more then 5 reconnects for the same request, die
- *
- * 2.
- *
+ *
+ * 2.
+ *
* we have a connection but the child died by some other reason
- *
+ *
*/
-
+
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
fdevent_unregister(srv->ev, hctx->fd);
close(hctx->fd);
srv->cur_fds--;
-
+
scgi_set_state(srv, hctx, FCGI_STATE_INIT);
-
+
hctx->request_id = 0;
hctx->reconnects++;
-
+
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "sddb",
- "release proc:",
+ "release proc:",
hctx->fd,
hctx->proc->pid, hctx->proc->socket);
}
-
+
hctx->proc->load--;
scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
-
+
return 0;
}
static handler_t scgi_connection_reset(server *srv, connection *con, void *p_d) {
plugin_data *p = p_d;
-
+
scgi_connection_cleanup(srv, con->plugin_ctx[p->id]);
-
+
return HANDLER_GO_ON;
}
static int scgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
size_t len;
-
+
if (!key || !val) return -1;
-
+
len = key_len + val_len + 2;
-
+
buffer_prepare_append(env, len);
- /* include the NUL */
- memcpy(env->ptr + env->used, key, key_len + 1);
+ memcpy(env->ptr + env->used, key, key_len);
+ env->ptr[env->used + key_len] = '\0';
env->used += key_len + 1;
- memcpy(env->ptr + env->used, val, val_len + 1);
+ memcpy(env->ptr + env->used, val, val_len);
+ env->ptr[env->used + val_len] = '\0';
env->used += val_len + 1;
-
+
return 0;
}
/**
- *
+ *
* returns
* -1 error
* 0 connected
@@ -1280,13 +1321,13 @@ static int scgi_establish_connection(server *srv, handler_ctx *hctx) {
struct sockaddr_un scgi_addr_un;
#endif
socklen_t servlen;
-
+
scgi_extension_host *host = hctx->host;
scgi_proc *proc = hctx->proc;
int scgi_fd = hctx->fd;
-
+
memset(&scgi_addr, 0, sizeof(scgi_addr));
-
+
if (!buffer_is_empty(proc->socket)) {
#ifdef HAVE_SYS_UN_H
/* use the unix domain socket */
@@ -1296,7 +1337,7 @@ static int scgi_establish_connection(server *srv, handler_ctx *hctx) {
servlen = SUN_LEN(&scgi_addr_un);
#else
/* stevens says: */
- servlen = proc->socket->used - 1 + sizeof(scgi_addr_un.sun_family);
+ servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
#endif
scgi_addr = (struct sockaddr *) &scgi_addr_un;
#else
@@ -1305,105 +1346,105 @@ static int scgi_establish_connection(server *srv, handler_ctx *hctx) {
} else {
scgi_addr_in.sin_family = AF_INET;
if (0 == inet_aton(host->host->ptr, &(scgi_addr_in.sin_addr))) {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
- "converting IP-adress failed for", host->host,
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "converting IP-adress failed for", host->host,
"\nBe sure to specify an IP address here");
-
+
return -1;
}
scgi_addr_in.sin_port = htons(proc->port);
servlen = sizeof(scgi_addr_in);
-
+
scgi_addr = (struct sockaddr *) &scgi_addr_in;
}
-
+
if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
- if (errno == EINPROGRESS ||
+ if (errno == EINPROGRESS ||
errno == EALREADY ||
errno == EINTR) {
if (hctx->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"connect delayed, will continue later:", scgi_fd);
}
-
+
return 1;
} else {
- log_error_write(srv, __FILE__, __LINE__, "sdsddb",
- "connect failed:", scgi_fd,
+ log_error_write(srv, __FILE__, __LINE__, "sdsddb",
+ "connect failed:", scgi_fd,
strerror(errno), errno,
proc->port, proc->socket);
if (errno == EAGAIN) {
/* this is Linux only */
-
- log_error_write(srv, __FILE__, __LINE__, "s",
+
+ log_error_write(srv, __FILE__, __LINE__, "s",
"If this happend on Linux: You have been run out of local ports. "
"Check the manual, section Performance how to handle this.");
- }
-
+ }
+
return -1;
}
}
if (hctx->conf.debug > 1) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"connect succeeded: ", scgi_fd);
}
-
+
return 0;
}
static int scgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
size_t i;
-
+
for (i = 0; i < con->request.headers->used; i++) {
data_string *ds;
-
+
ds = (data_string *)con->request.headers->data[i];
-
+
if (ds->value->used && ds->key->used) {
size_t j;
buffer_reset(srv->tmp_buf);
-
+
if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
- BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
+ buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("HTTP_"));
srv->tmp_buf->used--;
}
-
+
buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
for (j = 0; j < ds->key->used - 1; j++) {
- srv->tmp_buf->ptr[srv->tmp_buf->used++] =
- light_isalpha(ds->key->ptr[j]) ?
+ srv->tmp_buf->ptr[srv->tmp_buf->used++] =
+ light_isalpha(ds->key->ptr[j]) ?
ds->key->ptr[j] & ~32 : '_';
}
srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
-
+
scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
}
}
-
+
for (i = 0; i < con->environment->used; i++) {
data_string *ds;
-
+
ds = (data_string *)con->environment->data[i];
-
+
if (ds->value->used && ds->key->used) {
size_t j;
buffer_reset(srv->tmp_buf);
-
+
buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
for (j = 0; j < ds->key->used - 1; j++) {
- srv->tmp_buf->ptr[srv->tmp_buf->used++] =
- isalpha((unsigned char)ds->key->ptr[j]) ?
+ srv->tmp_buf->ptr[srv->tmp_buf->used++] =
+ light_isalnum((unsigned char)ds->key->ptr[j]) ?
toupper((unsigned char)ds->key->ptr[j]) : '_';
}
srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
-
+
scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
}
}
-
+
return 0;
}
@@ -1415,34 +1456,48 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
char b2[INET6_ADDRSTRLEN + 1];
#endif
buffer *b;
-
+
plugin_data *p = hctx->plugin_data;
scgi_extension_host *host= hctx->host;
connection *con = hctx->remote_conn;
server_socket *srv_sock = con->srv_socket;
-
+
sock_addr our_addr;
socklen_t our_addr_len;
-
+
buffer_prepare_copy(p->scgi_env, 1024);
/* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */
-
+
/* request.content_length < SSIZE_MAX, see request.c */
- ltostr(buf, con->request.content_length);
+ LI_ltostr(buf, con->request.content_length);
scgi_env_add(p->scgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
scgi_env_add(p->scgi_env, CONST_STR_LEN("SCGI"), CONST_STR_LEN("1"));
- scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
-
+ if (buffer_is_empty(con->conf.server_tag)) {
+ scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_DESC));
+ } else {
+ scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_BUF_LEN(con->conf.server_tag));
+ }
+
if (con->server_name->used) {
- scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
+ size_t len = con->server_name->used - 1;
+
+ if (con->server_name->ptr[0] == '[') {
+ const char *colon = strstr(con->server_name->ptr, "]:");
+ if (colon) len = (colon + 1) - con->server_name->ptr;
+ } else {
+ const char *colon = strchr(con->server_name->ptr, ':');
+ if (colon) len = colon - con->server_name->ptr;
+ }
+
+ scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), con->server_name->ptr, len);
} else {
#ifdef HAVE_IPV6
- s = inet_ntop(srv_sock->addr.plain.sa_family,
- srv_sock->addr.plain.sa_family == AF_INET6 ?
+ s = inet_ntop(srv_sock->addr.plain.sa_family,
+ srv_sock->addr.plain.sa_family == AF_INET6 ?
(const void *) &(srv_sock->addr.ipv6.sin6_addr) :
(const void *) &(srv_sock->addr.ipv4.sin_addr),
b2, sizeof(b2)-1);
@@ -1451,47 +1506,47 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
#endif
scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
}
-
+
scgi_env_add(p->scgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
-
- ltostr(buf,
+
+ LI_ltostr(buf,
#ifdef HAVE_IPV6
ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
#else
ntohs(srv_sock->addr.ipv4.sin_port)
#endif
);
-
+
scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
-
+
/* get the server-side of the connection to the client */
our_addr_len = sizeof(our_addr);
-
+
if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
} else {
s = inet_ntop_cache_get_ip(srv, &(our_addr));
}
scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
-
- ltostr(buf,
+
+ LI_ltostr(buf,
#ifdef HAVE_IPV6
ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
#else
ntohs(con->dst_addr.ipv4.sin_port)
#endif
);
-
+
scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
-
+
s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
-
+
if (!buffer_is_empty(con->authed_user)) {
scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_USER"),
CONST_BUF_LEN(con->authed_user));
}
-
+
/*
* SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
@@ -1500,16 +1555,16 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
*/
scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
-
+
if (!buffer_is_empty(con->request.pathinfo)) {
scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
-
+
/* PATH_TRANSLATED is only defined if PATH_INFO is set */
-
+
if (!buffer_is_empty(host->docroot)) {
buffer_copy_string_buffer(p->path, host->docroot);
} else {
- buffer_copy_string_buffer(p->path, con->physical.doc_root);
+ buffer_copy_string_buffer(p->path, con->physical.basedir);
}
buffer_append_string_buffer(p->path, con->request.pathinfo);
scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_TRANSLATED"), CONST_BUF_LEN(p->path));
@@ -1526,21 +1581,21 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
*/
if (!buffer_is_empty(host->docroot)) {
- /*
- * rewrite SCRIPT_FILENAME
- *
+ /*
+ * rewrite SCRIPT_FILENAME
+ *
*/
-
+
buffer_copy_string_buffer(p->path, host->docroot);
buffer_append_string_buffer(p->path, con->uri.path);
-
+
scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
} else {
buffer_copy_string_buffer(p->path, con->physical.path);
-
+
scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
- scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
+ scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir));
}
scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {
@@ -1551,30 +1606,30 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
} else {
scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
}
-
+
s = get_http_method_name(con->request.http_method);
scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
s = get_http_version_name(con->request.http_version);
scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
-
+
#ifdef USE_OPENSSL
if (srv_sock->is_ssl) {
scgi_env_add(p->scgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
}
#endif
-
+
scgi_env_add_request_headers(srv, con, p);
b = chunkqueue_get_append_buffer(hctx->wb);
-
+
buffer_append_long(b, p->scgi_env->used);
buffer_append_string_len(b, CONST_STR_LEN(":"));
buffer_append_string_len(b, (const char *)p->scgi_env->ptr, p->scgi_env->used);
buffer_append_string_len(b, CONST_STR_LEN(","));
hctx->wb->bytes_in += b->used - 1;
-
+
if (con->request.content_length) {
chunkqueue *req_cq = con->request_content_queue;
chunk *req_c;
@@ -1587,7 +1642,7 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
/* we announce toWrite octects
* now take all the request_content chunk that we need to fill this request
- * */
+ * */
switch (req_c->type) {
case FILE_CHUNK:
@@ -1615,32 +1670,18 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
req_c->offset += weHave;
req_cq->bytes_out += weHave;
-
+
hctx->wb->bytes_in += weHave;
break;
default:
break;
}
-
+
offset += weHave;
}
}
-
-#if 0
- for (i = 0; i < hctx->write_buffer->used; i++) {
- fprintf(stderr, "%02x ", hctx->write_buffer->ptr[i]);
- if ((i+1) % 16 == 0) {
- size_t j;
- for (j = i-15; j <= i; j++) {
- fprintf(stderr, "%c",
- isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
- }
- fprintf(stderr, "\n");
- }
- }
-#endif
-
+
return 0;
}
@@ -1648,61 +1689,60 @@ static int scgi_response_parse(server *srv, connection *con, plugin_data *p, buf
char *ns;
const char *s;
int line = 0;
-
+
UNUSED(srv);
-
+
buffer_copy_string_buffer(p->parse_response, in);
-
- for (s = p->parse_response->ptr;
- NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n')));
+
+ for (s = p->parse_response->ptr;
+ NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n')));
s = ns + (eol == EOL_RN ? 2 : 1), line++) {
const char *key, *value;
int key_len;
data_string *ds;
-
+
ns[0] = '\0';
-
- if (line == 0 &&
+
+ if (line == 0 &&
0 == strncmp(s, "HTTP/1.", 7)) {
/* non-parsed header ... we parse them anyway */
-
+
if ((s[7] == '1' ||
s[7] == '0') &&
s[8] == ' ') {
int status;
/* after the space should be a status code for us */
-
+
status = strtol(s+9, NULL, 10);
-
- if (con->http_status >= 100 &&
- con->http_status < 1000) {
- /* we expected 3 digits and didn't got them */
+
+ if (status >= 100 && status < 1000) {
+ /* we expected 3 digits got them */
con->parsed_response |= HTTP_STATUS;
con->http_status = status;
}
}
} else {
-
+
key = s;
if (NULL == (value = strchr(s, ':'))) {
/* we expect: "<key>: <value>\r\n" */
continue;
}
-
+
key_len = value - key;
value += 1;
-
+
/* skip LWS */
while (*value == ' ' || *value == '\t') value++;
-
+
if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
ds = data_response_init();
}
buffer_copy_string_len(ds->key, key, key_len);
buffer_copy_string(ds->value, value);
-
+
array_insert_unique(con->response.headers, (data_unset *)ds);
-
+
switch(key_len) {
case 4:
if (0 == strncasecmp(key, "Date", key_len)) {
@@ -1737,13 +1777,13 @@ static int scgi_response_parse(server *srv, connection *con, plugin_data *p, buf
}
}
}
-
+
/* CGI/1.1 rev 03 - 7.2.1.2 */
if ((con->parsed_response & HTTP_LOCATION) &&
!(con->parsed_response & HTTP_STATUS)) {
con->http_status = 302;
}
-
+
return 0;
}
@@ -1751,10 +1791,10 @@ static int scgi_response_parse(server *srv, connection *con, plugin_data *p, buf
static int scgi_demux_response(server *srv, handler_ctx *hctx) {
plugin_data *p = hctx->plugin_data;
connection *con = hctx->remote_conn;
-
+
while(1) {
int n;
-
+
buffer_prepare_copy(hctx->response, 1024);
if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
if (errno == EAGAIN || errno == EINTR) {
@@ -1765,143 +1805,145 @@ static int scgi_demux_response(server *srv, handler_ctx *hctx) {
log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
return -1;
}
-
+
if (n == 0) {
/* read finished */
-
+
con->file_finished = 1;
-
+
/* send final chunk */
http_chunk_append_mem(srv, con, NULL, 0);
joblist_append(srv, con);
-
+
return 1;
}
-
+
hctx->response->ptr[n] = '\0';
hctx->response->used = n+1;
-
+
/* split header from body */
-
+
if (con->file_started == 0) {
char *c;
int in_header = 0;
int header_end = 0;
int cp, eol = EOL_UNSET;
size_t used = 0;
-
+ size_t hlen = 0;
+
buffer_append_string_buffer(hctx->response_header, hctx->response);
-
+
/* nph (non-parsed headers) */
if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
-
+
/* search for the \r\n\r\n or \n\n in the string */
for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
if (*c == ':') in_header = 1;
else if (*c == '\n') {
if (in_header == 0) {
/* got a response without a response header */
-
+
c = NULL;
header_end = 1;
break;
}
-
+
if (eol == EOL_UNSET) eol = EOL_N;
-
+
if (*(c+1) == '\n') {
header_end = 1;
+ hlen = cp + 2;
break;
}
-
+
} else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
if (in_header == 0) {
/* got a response without a response header */
-
+
c = NULL;
header_end = 1;
break;
}
-
+
if (eol == EOL_UNSET) eol = EOL_RN;
-
+
if (used > 3 &&
- *(c+2) == '\r' &&
+ *(c+2) == '\r' &&
*(c+3) == '\n') {
header_end = 1;
+ hlen = cp + 4;
break;
}
-
+
/* skip the \n */
c++;
cp++;
used--;
}
}
-
+
if (header_end) {
if (c == NULL) {
/* no header, but a body */
-
+
if (con->request.http_version == HTTP_VERSION_1_1) {
con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
}
-
+
http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
joblist_append(srv, con);
} else {
- size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
size_t blen = hctx->response_header->used - hlen - 1;
-
+
/* a small hack: terminate after at the second \r */
- hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
- hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
-
+ hctx->response_header->used = hlen;
+ hctx->response_header->ptr[hlen - 1] = '\0';
+
/* parse the response header */
scgi_response_parse(srv, con, p, hctx->response_header, eol);
-
+
/* enable chunked-transfer-encoding */
if (con->request.http_version == HTTP_VERSION_1_1 &&
!(con->parsed_response & HTTP_CONTENT_LENGTH)) {
con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
}
-
+
if ((hctx->response->used != hlen) && blen > 0) {
- http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
+ http_chunk_append_mem(srv, con, hctx->response_header->ptr + hlen, blen + 1);
joblist_append(srv, con);
}
}
-
+
con->file_started = 1;
}
} else {
http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
joblist_append(srv, con);
}
-
-#if 0
+
+#if 0
log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
#endif
}
-
+
return 0;
}
-int scgi_proclist_sort_up(server *srv, scgi_extension_host *host, scgi_proc *proc) {
+static int scgi_proclist_sort_up(server *srv, scgi_extension_host *host, scgi_proc *proc) {
scgi_proc *p;
-
+
UNUSED(srv);
-
- /* we have been the smallest of the current list
- * and we want to insert the node sorted as soon
+
+ /* we have been the smallest of the current list
+ * and we want to insert the node sorted as soon
* possible
*
- * 1 0 0 0 1 1 1
- * | ^
+ * 1 0 0 0 1 1 1
+ * | ^
* | |
* +------+
- *
+ *
*/
/* nothing to sort, only one element */
@@ -1909,9 +1951,9 @@ int scgi_proclist_sort_up(server *srv, scgi_extension_host *host, scgi_proc *pro
for (p = proc; p->next && p->next->load < proc->load; p = p->next);
- /* no need to move something
+ /* no need to move something
*
- * 1 2 2 2 3 3 3
+ * 1 2 2 2 3 3 3
* ^
* |
* +
@@ -1930,16 +1972,16 @@ int scgi_proclist_sort_up(server *srv, scgi_extension_host *host, scgi_proc *pro
if (proc->prev) proc->prev->next = proc->next;
if (proc->next) proc->next->prev = proc->prev;
-
+
/* proc should be right of p */
-
+
proc->next = p->next;
proc->prev = p;
if (p->next) p->next->prev = proc;
p->next = proc;
#if 0
for(p = host->first; p; p = p->next) {
- log_error_write(srv, __FILE__, __LINE__, "dd",
+ log_error_write(srv, __FILE__, __LINE__, "dd",
p->pid, p->load);
}
#else
@@ -1951,21 +1993,21 @@ int scgi_proclist_sort_up(server *srv, scgi_extension_host *host, scgi_proc *pro
int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *proc) {
scgi_proc *p;
-
+
UNUSED(srv);
-
- /* we have been the smallest of the current list
- * and we want to insert the node sorted as soon
+
+ /* we have been the smallest of the current list
+ * and we want to insert the node sorted as soon
* possible
*
- * 0 0 0 0 1 0 1
+ * 0 0 0 0 1 0 1
* ^ |
* | |
* +----------+
*
*
* the basic is idea is:
- * - the last active scgi process should be still
+ * - the last active scgi process should be still
* in ram and is not swapped out yet
* - processes that are not reused will be killed
* after some time by the trigger-handler
@@ -1975,7 +2017,7 @@ int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *p
* ice-cold processes are propably unused since more
* than 'unused-timeout', are swaped out and won't be
* reused in the next seconds anyway.
- *
+ *
*/
/* nothing to sort, only one element */
@@ -1984,16 +2026,16 @@ int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *p
for (p = host->first; p != proc && p->load < proc->load; p = p->next);
- /* no need to move something
+ /* no need to move something
*
- * 1 2 2 2 3 3 3
+ * 1 2 2 2 3 3 3
* ^
* |
* +
*
*/
if (p == proc) return 0;
-
+
/* we have to move left. If we are already the first element
* we are done */
if (host->first == proc) return 0;
@@ -2009,9 +2051,9 @@ int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *p
p->prev = proc;
if (proc->prev == NULL) host->first = proc;
-#if 0
+#if 0
for(p = host->first; p; p = p->next) {
- log_error_write(srv, __FILE__, __LINE__, "dd",
+ log_error_write(srv, __FILE__, __LINE__, "dd",
p->pid, p->load);
}
#else
@@ -2023,40 +2065,40 @@ int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *p
static int scgi_restart_dead_procs(server *srv, plugin_data *p, scgi_extension_host *host) {
scgi_proc *proc;
-
+
for (proc = host->first; proc; proc = proc->next) {
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sbdbdddd",
- "proc:",
- host->host, proc->port,
+ log_error_write(srv, __FILE__, __LINE__, "sbdbdddd",
+ "proc:",
+ host->host, proc->port,
proc->socket,
proc->state,
proc->is_local,
proc->load,
proc->pid);
}
-
+
if (0 == proc->is_local) {
- /*
- * external servers might get disabled
- *
- * enable the server again, perhaps it is back again
+ /*
+ * external servers might get disabled
+ *
+ * enable the server again, perhaps it is back again
*/
-
+
if ((proc->state == PROC_STATE_DISABLED) &&
(srv->cur_ts - proc->disable_ts > host->disable_time)) {
proc->state = PROC_STATE_RUNNING;
host->active_procs++;
-
- log_error_write(srv, __FILE__, __LINE__, "sbdb",
- "fcgi-server re-enabled:",
- host->host, host->port,
+
+ log_error_write(srv, __FILE__, __LINE__, "sbdb",
+ "fcgi-server re-enabled:",
+ host->host, host->port,
host->unixsocket);
}
} else {
/* the child should not terminate at all */
int status;
-
+
if (proc->state == PROC_STATE_DIED_WAIT_FOR_PID) {
switch(waitpid(proc->pid, &status, WNOHANG)) {
case 0:
@@ -2067,33 +2109,33 @@ static int scgi_restart_dead_procs(server *srv, plugin_data *p, scgi_extension_h
default:
if (WIFEXITED(status)) {
#if 0
- log_error_write(srv, __FILE__, __LINE__, "sdsd",
+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
"child exited, pid:", proc->pid,
"status:", WEXITSTATUS(status));
#endif
} else if (WIFSIGNALED(status)) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "child signaled:",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child signaled:",
WTERMSIG(status));
} else {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "child died somehow:",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child died somehow:",
status);
}
-
+
proc->state = PROC_STATE_DIED;
break;
}
}
-
- /*
+
+ /*
* local servers might died, but we restart them
- *
+ *
*/
if (proc->state == PROC_STATE_DIED &&
proc->load == 0) {
/* restart the child */
-
+
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
"--- scgi spawning",
@@ -2101,18 +2143,18 @@ static int scgi_restart_dead_procs(server *srv, plugin_data *p, scgi_extension_h
"\n\tsocket", host->unixsocket,
"\n\tcurrent:", 1, "/", host->min_procs);
}
-
+
if (scgi_spawn_connection(srv, p, host, proc)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"ERROR: spawning fcgi failed.");
return HANDLER_ERROR;
}
-
+
scgi_proclist_sort_down(srv, host, proc);
}
}
}
-
+
return 0;
}
@@ -2121,13 +2163,16 @@ static handler_t scgi_write_request(server *srv, handler_ctx *hctx) {
plugin_data *p = hctx->plugin_data;
scgi_extension_host *host= hctx->host;
connection *con = hctx->remote_conn;
-
+
int ret;
- /* sanity check */
- if (!host ||
- ((!host->host->used || !host->port) && !host->unixsocket->used)) {
- log_error_write(srv, __FILE__, __LINE__, "sxddd",
+ /* sanity check */
+ if (!host) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "fatal error: host = NULL");
+ return HANDLER_ERROR;
+ }
+ if (((!host->host->used || !host->port) && !host->unixsocket->used)) {
+ log_error_write(srv, __FILE__, __LINE__, "sxddd",
"write-req: error",
host,
host->host->used,
@@ -2135,190 +2180,183 @@ static handler_t scgi_write_request(server *srv, handler_ctx *hctx) {
host->unixsocket->used);
return HANDLER_ERROR;
}
-
+
switch(hctx->state) {
case FCGI_STATE_INIT:
ret = host->unixsocket->used ? AF_UNIX : AF_INET;
-
+
if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
if (errno == EMFILE ||
errno == EINTR) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"wait for fd at connection:", con->fd);
-
+
return HANDLER_WAIT_FOR_FD;
}
-
- log_error_write(srv, __FILE__, __LINE__, "ssdd",
+
+ log_error_write(srv, __FILE__, __LINE__, "ssdd",
"socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
return HANDLER_ERROR;
}
hctx->fde_ndx = -1;
-
+
srv->cur_fds++;
-
+
fdevent_register(srv->ev, hctx->fd, scgi_handle_fdevent, hctx);
-
+
if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"fcntl failed: ", strerror(errno));
-
+
return HANDLER_ERROR;
}
-
+
/* fall through */
case FCGI_STATE_CONNECT:
if (hctx->state == FCGI_STATE_INIT) {
- for (hctx->proc = hctx->host->first;
- hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
+ for (hctx->proc = hctx->host->first;
+ hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
hctx->proc = hctx->proc->next);
-
+
/* all childs are dead */
if (hctx->proc == NULL) {
hctx->fde_ndx = -1;
-
+
return HANDLER_ERROR;
}
-
+
if (hctx->proc->is_local) {
hctx->pid = hctx->proc->pid;
}
-
+
switch (scgi_establish_connection(srv, hctx)) {
case 1:
scgi_set_state(srv, hctx, FCGI_STATE_CONNECT);
-
+
/* connection is in progress, wait for an event and call getsockopt() below */
-
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
-
+
+ fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
+
return HANDLER_WAIT_FOR_EVENT;
case -1:
/* if ECONNREFUSED choose another connection -> FIXME */
hctx->fde_ndx = -1;
-
+
return HANDLER_ERROR;
default:
/* everything is ok, go on */
break;
}
-
+
} else {
int socket_error;
socklen_t socket_error_len = sizeof(socket_error);
-
+
/* try to finish the connect() */
if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"getsockopt failed:", strerror(errno));
-
+
return HANDLER_ERROR;
}
if (socket_error != 0) {
if (!hctx->proc->is_local || p->conf.debug) {
/* local procs get restarted */
-
+
log_error_write(srv, __FILE__, __LINE__, "ss",
- "establishing connection failed:", strerror(socket_error),
+ "establishing connection failed:", strerror(socket_error),
"port:", hctx->proc->port);
}
-
+
return HANDLER_ERROR;
}
}
-
+
/* ok, we have the connection */
-
+
hctx->proc->load++;
hctx->proc->last_used = srv->cur_ts;
hctx->got_proc = 1;
-
+
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "sddbdd",
- "got proc:",
+ "got proc:",
hctx->fd,
- hctx->proc->pid,
- hctx->proc->socket,
+ hctx->proc->pid,
+ hctx->proc->socket,
hctx->proc->port,
hctx->proc->load);
}
/* move the proc-list entry down the list */
scgi_proclist_sort_up(srv, hctx->host, hctx->proc);
-
+
scgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
/* fall through */
case FCGI_STATE_PREPARE_WRITE:
scgi_create_env(srv, hctx);
-
+
scgi_set_state(srv, hctx, FCGI_STATE_WRITE);
-
+
/* fall through */
case FCGI_STATE_WRITE:
- ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
+ ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb, MAX_WRITE_LIMIT);
chunkqueue_remove_finished_chunks(hctx->wb);
-
- if (-1 == ret) {
- if (errno == ENOTCONN) {
- /* the connection got dropped after accept()
- *
- * this is most of the time a PHP which dies
+
+ if (ret < 0) {
+ if (errno == ENOTCONN || ret == -2) {
+ /* the connection got dropped after accept()
+ *
+ * this is most of the time a PHP which dies
* after PHP_FCGI_MAX_REQUESTS
- *
- */
+ *
+ */
if (hctx->wb->bytes_out == 0 &&
hctx->reconnects < 5) {
- usleep(10000); /* take away the load of the webserver
- * to let the php a chance to restart
+ usleep(10000); /* take away the load of the webserver
+ * to let the php a chance to restart
*/
-
+
scgi_reconnect(srv, hctx);
-
+
return HANDLER_WAIT_FOR_FD;
}
-
+
/* not reconnected ... why
- *
+ *
* far@#lighttpd report this for FreeBSD
- *
+ *
*/
-
- log_error_write(srv, __FILE__, __LINE__, "ssdsd",
- "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
+
+ log_error_write(srv, __FILE__, __LINE__, "ssosd",
+ "connection was dropped after accept(). reconnect() denied:",
"write-offset:", hctx->wb->bytes_out,
"reconnect attempts:", hctx->reconnects);
-
- return HANDLER_ERROR;
- }
-
- if ((errno != EAGAIN) &&
- (errno != EINTR)) {
-
- log_error_write(srv, __FILE__, __LINE__, "ssd",
- "write failed:", strerror(errno), errno);
-
+
return HANDLER_ERROR;
} else {
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
-
- return HANDLER_WAIT_FOR_EVENT;
+ /* -1 == ret => error on our side */
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "write failed:", strerror(errno), errno);
+
+ return HANDLER_ERROR;
}
}
-
+
if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
/* we don't need the out event anymore */
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
+ fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
scgi_set_state(srv, hctx, FCGI_STATE_READ);
} else {
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
-
+ fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
+
return HANDLER_WAIT_FOR_EVENT;
}
-
+
break;
case FCGI_STATE_READ:
/* waiting for a response */
@@ -2327,67 +2365,67 @@ static handler_t scgi_write_request(server *srv, handler_ctx *hctx) {
log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
return HANDLER_ERROR;
}
-
+
return HANDLER_WAIT_FOR_EVENT;
}
SUBREQUEST_FUNC(mod_scgi_handle_subrequest) {
plugin_data *p = p_d;
-
+
handler_ctx *hctx = con->plugin_ctx[p->id];
scgi_proc *proc;
scgi_extension_host *host;
-
+
if (NULL == hctx) return HANDLER_GO_ON;
-
+
/* not my job */
if (con->mode != p->id) return HANDLER_GO_ON;
-
+
/* ok, create the request */
switch(scgi_write_request(srv, hctx)) {
case HANDLER_ERROR:
proc = hctx->proc;
host = hctx->host;
-
- if (proc &&
+
+ if (proc &&
0 == proc->is_local &&
proc->state != PROC_STATE_DISABLED) {
/* only disable remote servers as we don't manage them*/
-
- log_error_write(srv, __FILE__, __LINE__, "sbdb", "fcgi-server disabled:",
+
+ log_error_write(srv, __FILE__, __LINE__, "sbdb", "fcgi-server disabled:",
host->host,
proc->port,
proc->socket);
-
+
/* disable this server */
proc->disable_ts = srv->cur_ts;
proc->state = PROC_STATE_DISABLED;
host->active_procs--;
}
-
+
if (hctx->state == FCGI_STATE_INIT ||
hctx->state == FCGI_STATE_CONNECT) {
- /* connect() or getsockopt() failed,
- * restart the request-handling
+ /* connect() or getsockopt() failed,
+ * restart the request-handling
*/
if (proc && proc->is_local) {
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sbdb", "connect() to scgi failed, restarting the request-handling:",
+ log_error_write(srv, __FILE__, __LINE__, "sbdb", "connect() to scgi failed, restarting the request-handling:",
host->host,
proc->port,
proc->socket);
}
- /*
+ /*
* several hctx might reference the same proc
- *
+ *
* Only one of them should mark the proc as dead all the other
* ones should just take a new one.
- *
+ *
* If a new proc was started with the old struct this might lead
* the mark a perfect proc as dead otherwise
- *
+ *
*/
if (proc->state == PROC_STATE_RUNNING &&
hctx->pid == proc->pid) {
@@ -2395,25 +2433,25 @@ SUBREQUEST_FUNC(mod_scgi_handle_subrequest) {
}
}
scgi_restart_dead_procs(srv, p, host);
-
+
scgi_connection_cleanup(srv, hctx);
-
+
buffer_reset(con->physical.path);
con->mode = DIRECT;
joblist_append(srv, con);
-
- /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
- * and hope that the childs will be restarted
- *
+
+ /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
+ * and hope that the childs will be restarted
+ *
*/
return HANDLER_WAIT_FOR_FD;
} else {
scgi_connection_cleanup(srv, hctx);
-
+
buffer_reset(con->physical.path);
con->mode = DIRECT;
con->http_status = 503;
-
+
return HANDLER_FINISHED;
}
case HANDLER_WAIT_FOR_EVENT:
@@ -2431,35 +2469,28 @@ SUBREQUEST_FUNC(mod_scgi_handle_subrequest) {
}
static handler_t scgi_connection_close(server *srv, handler_ctx *hctx) {
- plugin_data *p;
connection *con;
-
+
if (NULL == hctx) return HANDLER_GO_ON;
-
- p = hctx->plugin_data;
+
con = hctx->remote_conn;
-
- if (con->mode != p->id) return HANDLER_GO_ON;
-
- log_error_write(srv, __FILE__, __LINE__, "ssdsd",
- "emergency exit: scgi:",
+
+ log_error_write(srv, __FILE__, __LINE__, "ssdsd",
+ "emergency exit: scgi:",
"connection-fd:", con->fd,
"fcgi-fd:", hctx->fd);
-
-
-
+
scgi_connection_cleanup(srv, hctx);
-
+
return HANDLER_FINISHED;
}
-static handler_t scgi_handle_fdevent(void *s, void *ctx, int revents) {
- server *srv = (server *)s;
+static handler_t scgi_handle_fdevent(server *srv, void *ctx, int revents) {
handler_ctx *hctx = ctx;
connection *con = hctx->remote_conn;
plugin_data *p = hctx->plugin_data;
-
+
scgi_proc *proc = hctx->proc;
scgi_extension_host *host= hctx->host;
@@ -2471,15 +2502,15 @@ static handler_t scgi_handle_fdevent(void *s, void *ctx, int revents) {
case 1:
/* we are done */
scgi_connection_cleanup(srv, hctx);
-
+
joblist_append(srv, con);
return HANDLER_FINISHED;
case -1:
if (proc->pid && proc->state != PROC_STATE_DIED) {
int status;
-
+
/* only fetch the zombie if it is not already done */
-
+
switch(waitpid(proc->pid, &status, WNOHANG)) {
case 0:
/* child is still alive */
@@ -2489,19 +2520,19 @@ static handler_t scgi_handle_fdevent(void *s, void *ctx, int revents) {
default:
/* the child should not terminate at all */
if (WIFEXITED(status)) {
- log_error_write(srv, __FILE__, __LINE__, "sdsd",
+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
"child exited, pid:", proc->pid,
"status:", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "child signaled:",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child signaled:",
WTERMSIG(status));
} else {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "child died somehow:",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child died somehow:",
status);
}
-
+
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
"--- scgi spawning",
@@ -2509,117 +2540,117 @@ static handler_t scgi_handle_fdevent(void *s, void *ctx, int revents) {
"\n\tsocket", host->unixsocket,
"\n\tcurrent:", 1, "/", host->min_procs);
}
-
+
if (scgi_spawn_connection(srv, p, host, proc)) {
/* child died */
proc->state = PROC_STATE_DIED;
} else {
scgi_proclist_sort_down(srv, host, proc);
}
-
+
break;
}
}
if (con->file_started == 0) {
/* nothing has been send out yet, try to use another child */
-
+
if (hctx->wb->bytes_out == 0 &&
hctx->reconnects < 5) {
scgi_reconnect(srv, hctx);
-
- log_error_write(srv, __FILE__, __LINE__, "sdsdsd",
+
+ log_error_write(srv, __FILE__, __LINE__, "ssdsd",
"response not sent, request not sent, reconnection.",
"connection-fd:", con->fd,
"fcgi-fd:", hctx->fd);
-
+
return HANDLER_WAIT_FOR_FD;
}
-
- log_error_write(srv, __FILE__, __LINE__, "sdsdsd",
+
+ log_error_write(srv, __FILE__, __LINE__, "sosdsd",
"response not sent, request sent:", hctx->wb->bytes_out,
"connection-fd:", con->fd,
"fcgi-fd:", hctx->fd);
-
+
scgi_connection_cleanup(srv, hctx);
-
+
connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
buffer_reset(con->physical.path);
con->http_status = 500;
con->mode = DIRECT;
} else {
/* response might have been already started, kill the connection */
- scgi_connection_cleanup(srv, hctx);
-
- log_error_write(srv, __FILE__, __LINE__, "ssdsd",
+ log_error_write(srv, __FILE__, __LINE__, "ssdsd",
"response already sent out, termination connection",
"connection-fd:", con->fd,
"fcgi-fd:", hctx->fd);
-
+
+ scgi_connection_cleanup(srv, hctx);
+
connection_set_state(srv, con, CON_STATE_ERROR);
}
/* */
-
-
+
+
joblist_append(srv, con);
return HANDLER_FINISHED;
}
}
-
+
if (revents & FDEVENT_OUT) {
if (hctx->state == FCGI_STATE_CONNECT ||
hctx->state == FCGI_STATE_WRITE) {
/* we are allowed to send something out
- *
+ *
* 1. in a unfinished connect() call
* 2. in a unfinished write() call (long POST request)
*/
return mod_scgi_handle_subrequest(srv, con, p);
} else {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "got a FDEVENT_OUT and didn't know why:",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "got a FDEVENT_OUT and didn't know why:",
hctx->state);
}
}
-
+
/* perhaps this issue is already handled */
if (revents & FDEVENT_HUP) {
if (hctx->state == FCGI_STATE_CONNECT) {
/* getoptsock will catch this one (right ?)
- *
- * if we are in connect we might get a EINPROGRESS
- * in the first call and a FDEVENT_HUP in the
+ *
+ * if we are in connect we might get a EINPROGRESS
+ * in the first call and a FDEVENT_HUP in the
* second round
- *
+ *
* FIXME: as it is a bit ugly.
- *
+ *
*/
return mod_scgi_handle_subrequest(srv, con, p);
} else if (hctx->state == FCGI_STATE_READ &&
hctx->proc->port == 0) {
/* FIXME:
- *
+ *
* ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
* even if the FCGI_FIN packet is not received yet
*/
} else {
- log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
- "error: unexpected close of scgi connection for",
+ log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
+ "error: unexpected close of scgi connection for",
con->uri.path,
- "(no scgi process on host: ",
+ "(no scgi process on host: ",
host->host,
- ", port: ",
+ ", port: ",
host->port,
" ?)",
hctx->state);
-
+
connection_set_state(srv, con, CON_STATE_ERROR);
scgi_connection_close(srv, hctx);
joblist_append(srv, con);
}
} else if (revents & FDEVENT_ERR) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"fcgi: got a FDEVENT_ERR. Don't know why.");
/* kill all connections to the scgi process */
@@ -2628,7 +2659,7 @@ static handler_t scgi_handle_fdevent(void *s, void *ctx, int revents) {
scgi_connection_close(srv, hctx);
joblist_append(srv, con);
}
-
+
return HANDLER_FINISHED;
}
#define PATCH(x) \
@@ -2636,22 +2667,22 @@ static handler_t scgi_handle_fdevent(void *s, void *ctx, int revents) {
static int scgi_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(exts);
PATCH(debug);
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.server"))) {
PATCH(exts);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.debug"))) {
@@ -2659,7 +2690,7 @@ static int scgi_patch_connection(server *srv, connection *con, plugin_data *p) {
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -2669,167 +2700,181 @@ static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, i
plugin_data *p = p_d;
size_t s_len;
int used = -1;
- int ndx;
size_t k;
buffer *fn;
scgi_extension *extension = NULL;
-
+ scgi_extension_host *host = NULL;
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
/* Possibly, we processed already this request */
if (con->file_started == 1) return HANDLER_GO_ON;
-
+
fn = uri_path_handler ? con->uri.path : con->physical.path;
- if (fn->used == 0) {
- return HANDLER_ERROR;
- }
+ if (buffer_is_empty(fn)) return HANDLER_GO_ON;
s_len = fn->used - 1;
-
+
scgi_patch_connection(srv, con, p);
/* check if extension matches */
for (k = 0; k < p->conf.exts->used; k++) {
size_t ct_len;
-
- extension = p->conf.exts->exts[k];
-
- if (extension->key->used == 0) continue;
-
- ct_len = extension->key->used - 1;
-
+ scgi_extension *ext = p->conf.exts->exts[k];
+
+ if (ext->key->used == 0) continue;
+
+ ct_len = ext->key->used - 1;
+
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;
- } else if (0 == strncmp(fn->ptr + s_len - ct_len, extension->key->ptr, ct_len)) {
+ if (*(ext->key->ptr) == '/') {
+ if (strncmp(fn->ptr, ext->key->ptr, ct_len) == 0) {
+ extension = ext;
+ break;
+ }
+ } else if (0 == strncmp(fn->ptr + s_len - ct_len, ext->key->ptr, ct_len)) {
/* check extension in the form ".fcg" */
+ extension = ext;
break;
}
}
/* extension doesn't match */
- if (k == p->conf.exts->used) {
+ if (NULL == extension) {
return HANDLER_GO_ON;
}
-
+
/* get best server */
- for (k = 0, ndx = -1; k < extension->used; k++) {
- scgi_extension_host *host = extension->hosts[k];
-
- /* we should have at least one proc that can do somthing */
- if (host->active_procs == 0) continue;
-
- if (used == -1 || host->load < used) {
- used = host->load;
-
- ndx = k;
+ for (k = 0; k < extension->used; k++) {
+ scgi_extension_host *h = extension->hosts[k];
+
+ /* we should have at least one proc that can do something */
+ if (h->active_procs == 0) {
+ continue;
+ }
+
+ if (used == -1 || h->load < used) {
+ used = h->load;
+
+ host = h;
}
}
- /* found a server */
- if (ndx != -1) {
- scgi_extension_host *host = extension->hosts[ndx];
-
- /*
- * if check-local is disabled, use the uri.path handler
- *
- */
-
- /* init handler-context */
- if (uri_path_handler) {
- if (host->check_local == 0) {
- handler_ctx *hctx;
- char *pathinfo;
-
- hctx = handler_ctx_init();
-
- hctx->remote_conn = con;
- hctx->plugin_data = p;
- hctx->host = host;
- hctx->proc = NULL;
-
- hctx->conf.exts = p->conf.exts;
- hctx->conf.debug = p->conf.debug;
-
- con->plugin_ctx[p->id] = hctx;
-
- host->load++;
-
- con->mode = p->id;
-
- if (con->conf.log_request_handling) {
- log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_scgi");
- }
+ if (!host) {
+ /* sorry, we don't have a server alive for this ext */
+ buffer_reset(con->physical.path);
+ con->http_status = 500;
- /* the prefix is the SCRIPT_NAME,
- * everthing from start to the next slash
- * this is important for check-local = "disable"
- *
- * if prefix = /admin.fcgi
- *
- * /admin.fcgi/foo/bar
- *
- * SCRIPT_NAME = /admin.fcgi
- * PATH_INFO = /foo/bar
- *
- * if prefix = /fcgi-bin/
- *
- * /fcgi-bin/foo/bar
- *
- * SCRIPT_NAME = /fcgi-bin/foo
- * PATH_INFO = /bar
- *
- */
-
- /* the rewrite is only done for /prefix/? matches */
- if (extension->key->ptr[0] == '/' &&
- con->uri.path->used > extension->key->used &&
- NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
- /* rewrite uri.path and pathinfo */
-
- buffer_copy_string(con->request.pathinfo, pathinfo);
-
- con->uri.path->used -= con->request.pathinfo->used - 1;
- con->uri.path->ptr[con->uri.path->used - 1] = '\0';
- }
- }
- return HANDLER_GO_ON;
- } else {
+ /* only send the 'no handler' once */
+ if (!extension->note_is_sent) {
+ extension->note_is_sent = 1;
+
+ log_error_write(srv, __FILE__, __LINE__, "sbsbs",
+ "all handlers for ", con->uri.path,
+ "on", extension->key,
+ "are down.");
+ }
+
+ return HANDLER_FINISHED;
+ }
+
+ /* a note about no handler is not sent yet */
+ extension->note_is_sent = 0;
+
+ /*
+ * if check-local is disabled, use the uri.path handler
+ *
+ */
+
+ /* init handler-context */
+ if (uri_path_handler) {
+ if (host->check_local == 0) {
handler_ctx *hctx;
+ char *pathinfo;
+
hctx = handler_ctx_init();
-
+
hctx->remote_conn = con;
hctx->plugin_data = p;
hctx->host = host;
- hctx->proc = NULL;
-
+ hctx->proc = NULL;
+
hctx->conf.exts = p->conf.exts;
hctx->conf.debug = p->conf.debug;
-
+
con->plugin_ctx[p->id] = hctx;
-
+
host->load++;
-
+
con->mode = p->id;
-
+
if (con->conf.log_request_handling) {
- log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "handling it in mod_fastcgi");
}
- return HANDLER_GO_ON;
+ /* the prefix is the SCRIPT_NAME,
+ * everything from start to the next slash
+ * this is important for check-local = "disable"
+ *
+ * if prefix = /admin.fcgi
+ *
+ * /admin.fcgi/foo/bar
+ *
+ * SCRIPT_NAME = /admin.fcgi
+ * PATH_INFO = /foo/bar
+ *
+ * if prefix = /fcgi-bin/
+ *
+ * /fcgi-bin/foo/bar
+ *
+ * SCRIPT_NAME = /fcgi-bin/foo
+ * PATH_INFO = /bar
+ *
+ */
+
+ /* the rewrite is only done for /prefix/? matches */
+ if (host->fix_root_path_name && extension->key->ptr[0] == '/' && extension->key->ptr[1] == '\0') {
+ buffer_copy_string(con->request.pathinfo, con->uri.path->ptr);
+ con->uri.path->used = 1;
+ con->uri.path->ptr[con->uri.path->used - 1] = '\0';
+ } else if (extension->key->ptr[0] == '/' &&
+ con->uri.path->used > extension->key->used &&
+ NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
+ /* rewrite uri.path and pathinfo */
+
+ buffer_copy_string(con->request.pathinfo, pathinfo);
+
+ con->uri.path->used -= con->request.pathinfo->used - 1;
+ con->uri.path->ptr[con->uri.path->used - 1] = '\0';
+ }
}
} else {
- /* no handler found */
- buffer_reset(con->physical.path);
- con->http_status = 500;
-
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "no fcgi-handler found for:",
- fn);
-
- return HANDLER_FINISHED;
+ handler_ctx *hctx;
+ hctx = handler_ctx_init();
+
+ hctx->remote_conn = con;
+ hctx->plugin_data = p;
+ hctx->host = host;
+ hctx->proc = NULL;
+
+ hctx->conf.exts = p->conf.exts;
+ hctx->conf.debug = p->conf.debug;
+
+ con->plugin_ctx[p->id] = hctx;
+
+ host->load++;
+
+ con->mode = p->id;
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
+ }
}
+
return HANDLER_GO_ON;
}
@@ -2846,19 +2891,19 @@ static handler_t scgi_check_extension_2(server *srv, connection *con, void *p_d)
JOBLIST_FUNC(mod_scgi_handle_joblist) {
plugin_data *p = p_d;
handler_ctx *hctx = con->plugin_ctx[p->id];
-
+
if (hctx == NULL) return HANDLER_GO_ON;
if (hctx->fd != -1) {
switch (hctx->state) {
case FCGI_STATE_READ:
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
-
+ fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
+
break;
case FCGI_STATE_CONNECT:
case FCGI_STATE_WRITE:
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
-
+ fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
+
break;
case FCGI_STATE_INIT:
/* at reconnect */
@@ -2875,21 +2920,21 @@ JOBLIST_FUNC(mod_scgi_handle_joblist) {
static handler_t scgi_connection_close_callback(server *srv, connection *con, void *p_d) {
plugin_data *p = p_d;
-
+
return scgi_connection_close(srv, con->plugin_ctx[p->id]);
}
TRIGGER_FUNC(mod_scgi_handle_trigger) {
plugin_data *p = p_d;
size_t i, j, n;
-
-
+
+
/* perhaps we should kill a connect attempt after 10-15 seconds
- *
+ *
* currently we wait for the TCP timeout which is on Linux 180 seconds
- *
- *
- *
+ *
+ *
+ *
*/
/* check all childs if they are still up */
@@ -2906,61 +2951,61 @@ TRIGGER_FUNC(mod_scgi_handle_trigger) {
scgi_extension *ex;
ex = exts->exts[j];
-
+
for (n = 0; n < ex->used; n++) {
-
+
scgi_proc *proc;
unsigned long sum_load = 0;
scgi_extension_host *host;
-
+
host = ex->hosts[n];
-
+
scgi_restart_dead_procs(srv, p, host);
-
+
for (proc = host->first; proc; proc = proc->next) {
sum_load += proc->load;
}
-
+
if (host->num_procs &&
host->num_procs < host->max_procs &&
(sum_load / host->num_procs) > host->max_load_per_proc) {
/* overload, spawn new child */
scgi_proc *fp = NULL;
-
+
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"overload detected, spawning a new child");
}
-
+
for (fp = host->unused_procs; fp && fp->pid != 0; fp = fp->next);
-
+
if (fp) {
if (fp == host->unused_procs) host->unused_procs = fp->next;
-
+
if (fp->next) fp->next->prev = NULL;
-
+
host->max_id++;
} else {
fp = scgi_process_init();
fp->id = host->max_id++;
}
-
+
host->num_procs++;
-
+
if (buffer_is_empty(host->unixsocket)) {
fp->port = host->port + fp->id;
} else {
buffer_copy_string_buffer(fp->socket, host->unixsocket);
- buffer_append_string(fp->socket, "-");
+ buffer_append_string_len(fp->socket, CONST_STR_LEN("-"));
buffer_append_long(fp->socket, fp->id);
}
-
+
if (scgi_spawn_connection(srv, p, host, fp)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"ERROR: spawning fcgi failed.");
return HANDLER_ERROR;
}
-
+
fp->prev = NULL;
fp->next = host->first;
if (host->first) {
@@ -2968,56 +3013,56 @@ TRIGGER_FUNC(mod_scgi_handle_trigger) {
}
host->first = fp;
}
-
+
for (proc = host->first; proc; proc = proc->next) {
if (proc->load != 0) break;
if (host->num_procs <= host->min_procs) break;
if (proc->pid == 0) continue;
-
+
if (srv->cur_ts - proc->last_used > host->idle_timeout) {
/* a proc is idling for a long time now,
* terminated it */
-
+
if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "ssbsd",
- "idle-timeout reached, terminating child:",
- "socket:", proc->socket,
+ log_error_write(srv, __FILE__, __LINE__, "ssbsd",
+ "idle-timeout reached, terminating child:",
+ "socket:", proc->socket,
"pid", proc->pid);
}
-
-
+
+
if (proc->next) proc->next->prev = proc->prev;
if (proc->prev) proc->prev->next = proc->next;
-
+
if (proc->prev == NULL) host->first = proc->next;
-
+
proc->prev = NULL;
proc->next = host->unused_procs;
-
+
if (host->unused_procs) host->unused_procs->prev = proc;
host->unused_procs = proc;
-
+
kill(proc->pid, SIGTERM);
-
+
proc->state = PROC_STATE_KILLED;
-
- log_error_write(srv, __FILE__, __LINE__, "ssbsd",
- "killed:",
- "socket:", proc->socket,
+
+ log_error_write(srv, __FILE__, __LINE__, "ssbsd",
+ "killed:",
+ "socket:", proc->socket,
"pid", proc->pid);
-
+
host->num_procs--;
-
+
/* proc is now in unused, let the next second handle the next process */
break;
- }
+ }
}
-
+
for (proc = host->unused_procs; proc; proc = proc->next) {
int status;
-
+
if (proc->pid == 0) continue;
-
+
switch (waitpid(proc->pid, &status, WNOHANG)) {
case 0:
/* child still running after timeout, good */
@@ -3025,10 +3070,10 @@ TRIGGER_FUNC(mod_scgi_handle_trigger) {
case -1:
if (errno != EINTR) {
/* no PID found ? should never happen */
- log_error_write(srv, __FILE__, __LINE__, "sddss",
+ log_error_write(srv, __FILE__, __LINE__, "sddss",
"pid ", proc->pid, proc->state,
"not found:", strerror(errno));
-
+
#if 0
if (errno == ECHILD) {
/* someone else has cleaned up for us */
@@ -3042,19 +3087,19 @@ TRIGGER_FUNC(mod_scgi_handle_trigger) {
/* the child should not terminate at all */
if (WIFEXITED(status)) {
if (proc->state != PROC_STATE_KILLED) {
- log_error_write(srv, __FILE__, __LINE__, "sdb",
- "child exited:",
+ log_error_write(srv, __FILE__, __LINE__, "sdb",
+ "child exited:",
WEXITSTATUS(status), proc->socket);
}
} else if (WIFSIGNALED(status)) {
if (WTERMSIG(status) != SIGTERM) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "child signaled:",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child signaled:",
WTERMSIG(status));
}
} else {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "child died somehow:",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "child died somehow:",
status);
}
proc->pid = 0;
@@ -3070,6 +3115,7 @@ TRIGGER_FUNC(mod_scgi_handle_trigger) {
}
+int mod_scgi_plugin_init(plugin *p);
int mod_scgi_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("scgi");
@@ -3084,8 +3130,8 @@ int mod_scgi_plugin_init(plugin *p) {
p->handle_subrequest = mod_scgi_handle_subrequest;
p->handle_joblist = mod_scgi_handle_joblist;
p->handle_trigger = mod_scgi_handle_trigger;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_secure_download.c b/src/mod_secure_download.c
index 1ea5a50..a9c031f 100644
--- a/src/mod_secure_download.c
+++ b/src/mod_secure_download.c
@@ -1,22 +1,14 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
#include "base.h"
#include "log.h"
#include "buffer.h"
#include "plugin.h"
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
-#ifdef USE_OPENSSL
-# include <openssl/md5.h>
-#else
-# include "md5.h"
-#endif
+#include "md5.h"
#define HASHLEN 16
typedef unsigned char HASH[HASHLEN];
@@ -25,7 +17,7 @@ typedef char HASHHEX[HASHHEXLEN+1];
#ifdef USE_OPENSSL
#define IN const
#else
-#define IN
+#define IN
#endif
#define OUT
@@ -36,28 +28,28 @@ typedef struct {
buffer *doc_root;
buffer *secret;
buffer *uri_prefix;
-
- unsigned short timeout;
+
+ unsigned int timeout;
} plugin_config;
typedef struct {
PLUGIN_DATA;
-
+
buffer *md5;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
/* init the plugin data */
INIT_FUNC(mod_secdownload_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
p->md5 = buffer_init();
-
+
return p;
}
@@ -65,27 +57,27 @@ INIT_FUNC(mod_secdownload_init) {
FREE_FUNC(mod_secdownload_free) {
plugin_data *p = p_d;
UNUSED(srv);
-
+
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
-
+
buffer_free(s->secret);
buffer_free(s->doc_root);
buffer_free(s->uri_prefix);
-
+
free(s);
}
free(p->config_storage);
}
-
+
buffer_free(p->md5);
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
@@ -94,65 +86,65 @@ FREE_FUNC(mod_secdownload_free) {
SETDEFAULTS_FUNC(mod_secdownload_set_defaults) {
plugin_data *p = p_d;
size_t i = 0;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "secdownload.secret", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ "secdownload.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ "secdownload.uri-prefix", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { "secdownload.timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "secdownload.timeout", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
s->secret = buffer_init();
s->doc_root = buffer_init();
s->uri_prefix = buffer_init();
s->timeout = 60;
-
+
cv[0].destination = s->secret;
cv[1].destination = s->doc_root;
cv[2].destination = s->uri_prefix;
cv[3].destination = &(s->timeout);
-
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
}
-
+
return HANDLER_GO_ON;
}
/**
* checks if the supplied string is a MD5 string
- *
+ *
* @param str a possible MD5 string
* @return if the supplied string is a valid MD5 string 1 is returned otherwise 0
*/
-int is_hex_len(const char *str, size_t len) {
+static int is_hex_len(const char *str, size_t len) {
size_t i;
-
+
if (NULL == str) return 0;
-
+
for (i = 0; i < len && *str; i++, str++) {
/* illegal characters */
if (!((*str >= '0' && *str <= '9') ||
(*str >= 'a' && *str <= 'f') ||
- (*str >= 'A' && *str <= 'F'))
+ (*str >= 'A' && *str <= 'F'))
) {
return 0;
}
}
-
+
return i == len;
}
@@ -161,24 +153,24 @@ int is_hex_len(const char *str, size_t len) {
static int mod_secdownload_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(secret);
PATCH(doc_root);
PATCH(uri_prefix);
PATCH(timeout);
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.secret"))) {
PATCH(secret);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.document-root"))) {
@@ -190,7 +182,7 @@ static int mod_secdownload_patch_connection(server *srv, connection *con, plugin
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -198,108 +190,112 @@ static int mod_secdownload_patch_connection(server *srv, connection *con, plugin
URIHANDLER_FUNC(mod_secdownload_uri_handler) {
plugin_data *p = p_d;
- MD5_CTX Md5Ctx;
+ li_MD5_CTX Md5Ctx;
HASH HA1;
const char *rel_uri, *ts_str, *md5_str;
time_t ts = 0;
size_t i;
-
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
if (con->uri.path->used == 0) return HANDLER_GO_ON;
-
+
mod_secdownload_patch_connection(srv, con, p);
if (buffer_is_empty(p->conf.uri_prefix)) return HANDLER_GO_ON;
-
+
if (buffer_is_empty(p->conf.secret)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"secdownload.secret has to be set");
return HANDLER_ERROR;
}
-
+
if (buffer_is_empty(p->conf.doc_root)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"secdownload.document-root has to be set");
return HANDLER_ERROR;
}
-
- /*
+
+ /*
* /<uri-prefix>[a-f0-9]{32}/[a-f0-9]{8}/<rel-path>
*/
-
+
if (0 != strncmp(con->uri.path->ptr, p->conf.uri_prefix->ptr, p->conf.uri_prefix->used - 1)) return HANDLER_GO_ON;
-
+
md5_str = con->uri.path->ptr + p->conf.uri_prefix->used - 1;
-
+
if (!is_hex_len(md5_str, 32)) return HANDLER_GO_ON;
if (*(md5_str + 32) != '/') return HANDLER_GO_ON;
-
+
ts_str = md5_str + 32 + 1;
-
+
if (!is_hex_len(ts_str, 8)) return HANDLER_GO_ON;
if (*(ts_str + 8) != '/') return HANDLER_GO_ON;
-
+
for (i = 0; i < 8; i++) {
ts = (ts << 4) + hex2int(*(ts_str + i));
}
-
+
/* timed-out */
- if (srv->cur_ts - ts > p->conf.timeout ||
- srv->cur_ts - ts < -p->conf.timeout) {
- con->http_status = 408;
-
+ if ( (srv->cur_ts > ts && (unsigned int) (srv->cur_ts - ts) > p->conf.timeout) ||
+ (srv->cur_ts < ts && (unsigned int) (ts - srv->cur_ts) > p->conf.timeout) ) {
+ /* "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;
}
-
+
rel_uri = ts_str + 8;
-
- /* checking MD5
- *
+
+ /* checking MD5
+ *
* <secret><rel-path><timestamp-hex>
*/
-
+
buffer_copy_string_buffer(p->md5, p->conf.secret);
buffer_append_string(p->md5, rel_uri);
buffer_append_string_len(p->md5, ts_str, 8);
-
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)p->md5->ptr, p->md5->used - 1);
- MD5_Final(HA1, &Md5Ctx);
-
+
+ li_MD5_Init(&Md5Ctx);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)p->md5->ptr, p->md5->used - 1);
+ li_MD5_Final(HA1, &Md5Ctx);
+
buffer_copy_string_hex(p->md5, (char *)HA1, 16);
-
- if (0 != strncmp(md5_str, p->md5->ptr, 32)) {
+
+ if (0 != strncasecmp(md5_str, p->md5->ptr, 32)) {
con->http_status = 403;
-
- log_error_write(srv, __FILE__, __LINE__, "sss",
+
+ log_error_write(srv, __FILE__, __LINE__, "sss",
"md5 invalid:",
md5_str, p->md5->ptr);
-
+
return HANDLER_FINISHED;
}
-
+
/* starting with the last / we should have relative-path to the docroot
*/
-
+
buffer_copy_string_buffer(con->physical.doc_root, p->conf.doc_root);
buffer_copy_string(con->physical.rel_path, rel_uri);
buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
-
+
return HANDLER_GO_ON;
}
/* this function is called at dlopen() time and inits the callbacks */
+int mod_secdownload_plugin_init(plugin *p);
int mod_secdownload_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("secdownload");
-
+
p->init = mod_secdownload_init;
p->handle_physical = mod_secdownload_uri_handler;
p->set_defaults = mod_secdownload_set_defaults;
p->cleanup = mod_secdownload_free;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_setenv.c b/src/mod_setenv.c
index 9501554..d9cf94d 100644
--- a/src/mod_setenv.c
+++ b/src/mod_setenv.c
@@ -1,6 +1,3 @@
-#include <stdlib.h>
-#include <string.h>
-
#include "base.h"
#include "log.h"
#include "buffer.h"
@@ -9,6 +6,9 @@
#include "response.h"
+#include <stdlib.h>
+#include <string.h>
+
/* plugin config for all request/connections */
typedef struct {
@@ -18,25 +18,25 @@ typedef struct {
typedef struct {
array *request_header;
array *response_header;
-
+
array *environment;
} plugin_config;
typedef struct {
PLUGIN_DATA;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
-static handler_ctx * handler_ctx_init() {
+static handler_ctx * handler_ctx_init(void) {
handler_ctx * hctx;
-
+
hctx = calloc(1, sizeof(*hctx));
-
+
hctx->handled = 0;
-
+
return hctx;
}
@@ -48,36 +48,36 @@ static void handler_ctx_free(handler_ctx *hctx) {
/* init the plugin data */
INIT_FUNC(mod_setenv_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
return p;
}
/* detroy the plugin data */
FREE_FUNC(mod_setenv_free) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
-
+
array_free(s->request_header);
array_free(s->response_header);
array_free(s->environment);
-
+
free(s);
}
free(p->config_storage);
}
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
@@ -86,37 +86,37 @@ FREE_FUNC(mod_setenv_free) {
SETDEFAULTS_FUNC(mod_setenv_set_defaults) {
plugin_data *p = p_d;
size_t i = 0;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "setenv.add-request-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ "setenv.add-response-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ "setenv.add-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
s->request_header = array_init();
s->response_header = array_init();
s->environment = array_init();
-
+
cv[0].destination = s->request_header;
cv[1].destination = s->response_header;
cv[2].destination = s->environment;
-
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
}
-
+
return HANDLER_GO_ON;
}
@@ -125,23 +125,23 @@ SETDEFAULTS_FUNC(mod_setenv_set_defaults) {
static int mod_setenv_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(request_header);
PATCH(response_header);
PATCH(environment);
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-request-header"))) {
PATCH(request_header);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-response-header"))) {
@@ -151,7 +151,7 @@ static int mod_setenv_patch_connection(server *srv, connection *con, plugin_data
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -160,12 +160,12 @@ URIHANDLER_FUNC(mod_setenv_uri_handler) {
plugin_data *p = p_d;
size_t k;
handler_ctx *hctx;
-
+
if (con->plugin_ctx[p->id]) {
hctx = con->plugin_ctx[p->id];
} else {
hctx = handler_ctx_init();
-
+
con->plugin_ctx[p->id] = hctx;
}
@@ -180,68 +180,69 @@ URIHANDLER_FUNC(mod_setenv_uri_handler) {
for (k = 0; k < p->conf.request_header->used; k++) {
data_string *ds = (data_string *)p->conf.request_header->data[k];
data_string *ds_dst;
-
+
if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
ds_dst = data_string_init();
}
-
+
buffer_copy_string_buffer(ds_dst->key, ds->key);
buffer_copy_string_buffer(ds_dst->value, ds->value);
-
+
array_insert_unique(con->request.headers, (data_unset *)ds_dst);
}
-
+
for (k = 0; k < p->conf.environment->used; k++) {
data_string *ds = (data_string *)p->conf.environment->data[k];
data_string *ds_dst;
-
+
if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
ds_dst = data_string_init();
}
-
+
buffer_copy_string_buffer(ds_dst->key, ds->key);
buffer_copy_string_buffer(ds_dst->value, ds->value);
-
+
array_insert_unique(con->environment, (data_unset *)ds_dst);
}
-
+
for (k = 0; k < p->conf.response_header->used; k++) {
data_string *ds = (data_string *)p->conf.response_header->data[k];
-
+
response_header_insert(srv, con, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
}
-
+
/* not found */
return HANDLER_GO_ON;
}
-REQUESTDONE_FUNC(mod_setenv_reset) {
+CONNECTION_FUNC(mod_setenv_reset) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
-
+
if (con->plugin_ctx[p->id]) {
handler_ctx_free(con->plugin_ctx[p->id]);
con->plugin_ctx[p->id] = NULL;
}
- return HANDLER_GO_ON;
+ return HANDLER_GO_ON;
}
/* this function is called at dlopen() time and inits the callbacks */
+int mod_setenv_plugin_init(plugin *p);
int mod_setenv_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("setenv");
-
+
p->init = mod_setenv_init;
p->handle_uri_clean = mod_setenv_uri_handler;
p->set_defaults = mod_setenv_set_defaults;
p->cleanup = mod_setenv_free;
-
- p->handle_request_done = mod_setenv_reset;
+
+ p->connection_reset = mod_setenv_reset;
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_simple_vhost.c b/src/mod_simple_vhost.c
index 8f81384..bbb61d5 100644
--- a/src/mod_simple_vhost.c
+++ b/src/mod_simple_vhost.c
@@ -1,8 +1,3 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
#include "base.h"
#include "log.h"
#include "buffer.h"
@@ -10,15 +5,16 @@
#include "plugin.h"
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
typedef struct {
buffer *server_root;
buffer *default_host;
buffer *document_root;
-
+
buffer *docroot_cache_key;
buffer *docroot_cache_value;
buffer *docroot_cache_servername;
@@ -28,119 +24,119 @@ typedef struct {
typedef struct {
PLUGIN_DATA;
-
+
buffer *doc_root;
-
+
plugin_config **config_storage;
- plugin_config conf;
+ plugin_config conf;
} plugin_data;
INIT_FUNC(mod_simple_vhost_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
p->doc_root = buffer_init();
-
+
return p;
}
FREE_FUNC(mod_simple_vhost_free) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
-
+
buffer_free(s->document_root);
buffer_free(s->default_host);
buffer_free(s->server_root);
-
+
buffer_free(s->docroot_cache_key);
buffer_free(s->docroot_cache_value);
buffer_free(s->docroot_cache_servername);
-
+
free(s);
}
-
+
free(p->config_storage);
}
-
+
buffer_free(p->doc_root);
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults) {
plugin_data *p = p_d;
size_t i;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "simple-vhost.server-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "simple-vhost.default-host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "simple-vhost.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "simple-vhost.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
-
+
s->server_root = buffer_init();
s->default_host = buffer_init();
s->document_root = buffer_init();
-
+
s->docroot_cache_key = buffer_init();
s->docroot_cache_value = buffer_init();
s->docroot_cache_servername = buffer_init();
s->debug = 0;
-
+
cv[0].destination = s->server_root;
cv[1].destination = s->default_host;
cv[2].destination = s->document_root;
cv[3].destination = &(s->debug);
-
-
+
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
}
-
+
return HANDLER_GO_ON;
}
static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) {
stat_cache_entry *sce = NULL;
-
+
buffer_prepare_copy(out, 128);
if (p->conf.server_root->used) {
buffer_copy_string_buffer(out, p->conf.server_root);
-
+
if (host->used) {
/* a hostname has to start with a alpha-numerical character
* and must not contain a slash "/"
*/
char *dp;
-
+
BUFFER_APPEND_SLASH(out);
-
+
if (NULL == (dp = strchr(host->ptr, ':'))) {
buffer_append_string_buffer(out, host);
} else {
@@ -148,7 +144,7 @@ static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *
}
}
BUFFER_APPEND_SLASH(out);
-
+
if (p->conf.document_root->used > 2 && p->conf.document_root->ptr[0] == '/') {
buffer_append_string_len(out, p->conf.document_root->ptr + 1, p->conf.document_root->used - 2);
} else {
@@ -159,7 +155,7 @@ static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *
buffer_copy_string_buffer(out, con->conf.document_root);
BUFFER_APPEND_SLASH(out);
}
-
+
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, out, &sce)) {
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "sb",
@@ -169,7 +165,7 @@ static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *
} else if (!S_ISDIR(sce->st.st_mode)) {
return -1;
}
-
+
return 0;
}
@@ -179,29 +175,29 @@ static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *
static int mod_simple_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(server_root);
PATCH(default_host);
PATCH(document_root);
-
+
PATCH(docroot_cache_key);
PATCH(docroot_cache_value);
PATCH(docroot_cache_servername);
PATCH(debug);
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.server-root"))) {
PATCH(server_root);
PATCH(docroot_cache_key);
@@ -216,7 +212,7 @@ static int mod_simple_vhost_patch_connection(server *srv, connection *con, plugi
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -227,12 +223,12 @@ static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_
/*
* cache the last successfull translation from hostname (authority) to docroot
* - this saves us a stat() call
- *
+ *
*/
-
+
mod_simple_vhost_patch_connection(srv, con, p);
-
- if (p->conf.docroot_cache_key->used &&
+
+ if (p->conf.docroot_cache_key->used &&
con->uri.authority->used &&
buffer_is_equal(p->conf.docroot_cache_key, con->uri.authority)) {
/* cache hit */
@@ -243,39 +239,44 @@ static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_
if ((con->uri.authority->used == 0) ||
build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) {
/* not found, fallback the default-host */
- if (build_doc_root(srv, con, p,
- p->doc_root,
+ if (build_doc_root(srv, con, p,
+ p->doc_root,
p->conf.default_host)) {
return HANDLER_GO_ON;
} else {
buffer_copy_string_buffer(con->server_name, p->conf.default_host);
+ buffer_copy_string_buffer(con->physical.doc_root, p->doc_root);
+
+ /* do not cache default host */
+ return HANDLER_GO_ON;
}
} else {
buffer_copy_string_buffer(con->server_name, con->uri.authority);
}
-
+
/* copy to cache */
buffer_copy_string_buffer(p->conf.docroot_cache_key, con->uri.authority);
buffer_copy_string_buffer(p->conf.docroot_cache_value, p->doc_root);
buffer_copy_string_buffer(p->conf.docroot_cache_servername, con->server_name);
-
+
buffer_copy_string_buffer(con->physical.doc_root, p->doc_root);
}
-
+
return HANDLER_GO_ON;
}
+int mod_simple_vhost_plugin_init(plugin *p);
int mod_simple_vhost_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("simple_vhost");
-
+
p->init = mod_simple_vhost_init;
p->set_defaults = mod_simple_vhost_set_defaults;
p->handle_docroot = mod_simple_vhost_docroot;
p->cleanup = mod_simple_vhost_free;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_skeleton.c b/src/mod_skeleton.c
index a3fa186..66de2b1 100644
--- a/src/mod_skeleton.c
+++ b/src/mod_skeleton.c
@@ -1,26 +1,22 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
#include "base.h"
#include "log.h"
#include "buffer.h"
#include "plugin.h"
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
/**
* this is a skeleton for a lighttpd plugin
- *
+ *
* just replaces every occurance of 'skeleton' by your plugin name
- *
+ *
* e.g. in vim:
- *
+ *
* :%s/skeleton/myhandler/
- *
+ *
*/
@@ -33,12 +29,12 @@ typedef struct {
typedef struct {
PLUGIN_DATA;
-
+
buffer *match_buf;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
typedef struct {
@@ -47,36 +43,36 @@ typedef struct {
static handler_ctx * handler_ctx_init() {
handler_ctx * hctx;
-
+
hctx = calloc(1, sizeof(*hctx));
-
+
return hctx;
}
static void handler_ctx_free(handler_ctx *hctx) {
-
+
free(hctx);
}
/* init the plugin data */
INIT_FUNC(mod_skeleton_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
p->match_buf = buffer_init();
-
+
return p;
}
/* detroy the plugin data */
FREE_FUNC(mod_skeleton_free) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
size_t i;
@@ -84,18 +80,18 @@ FREE_FUNC(mod_skeleton_free) {
plugin_config *s = p->config_storage[i];
if (!s) continue;
-
+
array_free(s->match);
-
+
free(s);
}
free(p->config_storage);
}
-
+
buffer_free(p->match_buf);
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
@@ -104,31 +100,31 @@ FREE_FUNC(mod_skeleton_free) {
SETDEFAULTS_FUNC(mod_skeleton_set_defaults) {
plugin_data *p = p_d;
size_t i = 0;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "skeleton.array", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
s->match = array_init();
-
+
cv[0].destination = s->match;
-
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
}
-
+
return HANDLER_GO_ON;
}
@@ -137,27 +133,27 @@ SETDEFAULTS_FUNC(mod_skeleton_set_defaults) {
static int mod_skeleton_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(match);
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("skeleton.array"))) {
PATCH(match);
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -166,29 +162,31 @@ URIHANDLER_FUNC(mod_skeleton_uri_handler) {
plugin_data *p = p_d;
int s_len;
size_t k, i;
-
+
UNUSED(srv);
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
if (con->uri.path->used == 0) return HANDLER_GO_ON;
-
+
mod_skeleton_patch_connection(srv, con, p);
s_len = con->uri.path->used - 1;
-
+
for (k = 0; k < p->conf.match->used; k++) {
data_string *ds = (data_string *)p->conf.match->data[k];
int ct_len = ds->value->used - 1;
-
+
if (ct_len > s_len) continue;
if (ds->value->used == 0) continue;
-
+
if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
con->http_status = 403;
-
+
return HANDLER_FINISHED;
}
}
-
+
/* not found */
return HANDLER_GO_ON;
}
@@ -198,13 +196,13 @@ URIHANDLER_FUNC(mod_skeleton_uri_handler) {
int mod_skeleton_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("skeleton");
-
+
p->init = mod_skeleton_init;
p->handle_uri_clean = mod_skeleton_uri_handler;
p->set_defaults = mod_skeleton_set_defaults;
p->cleanup = mod_skeleton_free;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_ssi.c b/src/mod_ssi.c
index b6a19d7..897f49e 100644
--- a/src/mod_ssi.c
+++ b/src/mod_ssi.c
@@ -1,13 +1,3 @@
-#include <sys/types.h>
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-#include <unistd.h>
-
#include "base.h"
#include "log.h"
#include "buffer.h"
@@ -24,30 +14,46 @@
#include "sys-socket.h"
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <unistd.h>
+
#ifdef HAVE_PWD_H
-#include <pwd.h>
+# include <pwd.h>
#endif
#ifdef HAVE_FORK
-#include <sys/wait.h>
+# include <sys/wait.h>
#endif
#ifdef HAVE_SYS_FILIO_H
-#include <sys/filio.h>
+# include <sys/filio.h>
#endif
+#include "etag.h"
+#include "version.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;
-
+
p = calloc(1, sizeof(*p));
-
+
p->timefmt = buffer_init();
p->stat_fn = buffer_init();
-
+
p->ssi_vars = array_init();
p->ssi_cgi_env = array_init();
-
+
return p;
}
@@ -55,21 +61,22 @@ INIT_FUNC(mod_ssi_init) {
FREE_FUNC(mod_ssi_free) {
plugin_data *p = p_d;
UNUSED(srv);
-
+
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
-
+
array_free(s->ssi_extension);
-
+ buffer_free(s->content_type);
+
free(s);
}
free(p->config_storage);
}
-
+
array_free(p->ssi_vars);
array_free(p->ssi_cgi_env);
#ifdef HAVE_PCRE_H
@@ -77,9 +84,9 @@ FREE_FUNC(mod_ssi_free) {
#endif
buffer_free(p->timefmt);
buffer_free(p->stat_fn);
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
@@ -92,36 +99,39 @@ SETDEFAULTS_FUNC(mod_ssi_set_defaults) {
const char *errptr;
int erroff;
#endif
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "ssi.extension", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "ssi.content-type", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
s->ssi_extension = array_init();
-
+ s->content_type = buffer_init();
+
cv[0].destination = s->ssi_extension;
-
+ cv[1].destination = s->content_type;
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
}
-
+
#ifdef HAVE_PCRE_H
/* allow 2 params */
if (NULL == (p->ssi_regex = pcre_compile("<!--#([a-z]+)\\s+(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?-->", 0, &errptr, &erroff, NULL))) {
log_error_write(srv, __FILE__, __LINE__, "sds",
- "ssi: pcre ",
+ "ssi: pcre ",
erroff, errptr);
return HANDLER_ERROR;
}
@@ -130,52 +140,52 @@ SETDEFAULTS_FUNC(mod_ssi_set_defaults) {
"mod_ssi: pcre support is missing, please recompile with pcre support or remove mod_ssi from the list of modules");
return HANDLER_ERROR;
#endif
-
+
return HANDLER_GO_ON;
}
-int ssi_env_add(array *env, const char *key, const char *val) {
+static int ssi_env_add(array *env, const char *key, const char *val) {
data_string *ds;
-
+
if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
ds = data_string_init();
}
buffer_copy_string(ds->key, key);
buffer_copy_string(ds->value, val);
-
+
array_insert_unique(env, (data_unset *)ds);
-
+
return 0;
}
/**
*
* the next two functions are take from fcgi.c
- *
+ *
*/
static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
size_t i;
-
+
for (i = 0; i < con->request.headers->used; i++) {
data_string *ds;
-
+
ds = (data_string *)con->request.headers->data[i];
-
+
if (ds->value->used && ds->key->used) {
size_t j;
buffer_reset(srv->tmp_buf);
-
+
/* don't forward the Authorization: Header */
if (0 == strcasecmp(ds->key->ptr, "AUTHORIZATION")) {
continue;
}
-
+
if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
- buffer_copy_string(srv->tmp_buf, "HTTP_");
+ buffer_copy_string_len(srv->tmp_buf, CONST_STR_LEN("HTTP_"));
srv->tmp_buf->used--;
}
-
+
buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
for (j = 0; j < ds->key->used - 1; j++) {
char c = '_';
@@ -189,33 +199,61 @@ static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data
srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
}
srv->tmp_buf->ptr[srv->tmp_buf->used] = '\0';
-
+
ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
}
}
-
+
+ for (i = 0; i < con->environment->used; i++) {
+ data_string *ds;
+
+ ds = (data_string *)con->environment->data[i];
+
+ if (ds->value->used && ds->key->used) {
+ size_t j;
+
+ buffer_reset(srv->tmp_buf);
+ buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
+
+ for (j = 0; j < ds->key->used - 1; j++) {
+ char c = '_';
+ if (light_isalpha(ds->key->ptr[j])) {
+ /* upper-case */
+ c = ds->key->ptr[j] & ~32;
+ } else if (light_isdigit(ds->key->ptr[j])) {
+ /* copy */
+ c = ds->key->ptr[j];
+ }
+ srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
+ }
+ srv->tmp_buf->ptr[srv->tmp_buf->used] = '\0';
+
+ ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
+ }
+ }
+
return 0;
}
static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
char buf[32];
-
+
server_socket *srv_sock = con->srv_socket;
-
+
#ifdef HAVE_IPV6
char b2[INET6_ADDRSTRLEN + 1];
#endif
#define CONST_STRING(x) \
x
-
+
array_reset(p->ssi_cgi_env);
-
- ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_SOFTWARE"), PACKAGE_NAME"/"PACKAGE_VERSION);
+
+ ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_SOFTWARE"), PACKAGE_DESC);
ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_NAME"),
#ifdef HAVE_IPV6
- inet_ntop(srv_sock->addr.plain.sa_family,
- srv_sock->addr.plain.sa_family == AF_INET6 ?
+ inet_ntop(srv_sock->addr.plain.sa_family,
+ srv_sock->addr.plain.sa_family == AF_INET6 ?
(const void *) &(srv_sock->addr.ipv6.sin6_addr) :
(const void *) &(srv_sock->addr.ipv4.sin_addr),
b2, sizeof(b2)-1)
@@ -224,30 +262,30 @@ static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
#endif
);
ssi_env_add(p->ssi_cgi_env, CONST_STRING("GATEWAY_INTERFACE"), "CGI/1.1");
-
- ltostr(buf,
+
+ LI_ltostr(buf,
#ifdef HAVE_IPV6
ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
#else
ntohs(srv_sock->addr.ipv4.sin_port)
#endif
);
-
+
ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PORT"), buf);
-
+
ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_ADDR"),
inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
-
+
if (con->authed_user->used) {
ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_USER"),
con->authed_user->ptr);
}
-
+
if (con->request.content_length > 0) {
/* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
-
+
/* request.content_length < SSIZE_MAX, see request.c */
- ltostr(buf, con->request.content_length);
+ LI_ltostr(buf, con->request.content_length);
ssi_env_add(p->ssi_cgi_env, CONST_STRING("CONTENT_LENGTH"), buf);
}
@@ -271,30 +309,30 @@ static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
if (con->request.pathinfo->used) {
ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), con->request.pathinfo->ptr);
}
-
+
ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_FILENAME"), con->physical.path->ptr);
ssi_env_add(p->ssi_cgi_env, CONST_STRING("DOCUMENT_ROOT"), con->physical.doc_root->ptr);
-
+
ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_URI"), con->request.uri->ptr);
ssi_env_add(p->ssi_cgi_env, CONST_STRING("QUERY_STRING"), con->uri.query->used ? con->uri.query->ptr : "");
ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_METHOD"), get_http_method_name(con->request.http_method));
ssi_env_add(p->ssi_cgi_env, CONST_STRING("REDIRECT_STATUS"), "200");
ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PROTOCOL"), get_http_version_name(con->request.http_version));
-
+
ssi_env_add_request_headers(srv, con, p);
-
+
return 0;
}
-static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
+static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
const char **l, size_t n) {
size_t i, ssicmd = 0;
char buf[255];
buffer *b = NULL;
-
- struct {
+
+ struct {
const char *var;
- enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
+ enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
SSI_CONFIG, SSI_PRINTENV, SSI_SET, SSI_IF, SSI_ELIF,
SSI_ELSE, SSI_ENDIF, SSI_EXEC } type;
} ssicmds[] = {
@@ -310,27 +348,28 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
{ "endif", SSI_ENDIF },
{ "else", SSI_ELSE },
{ "exec", SSI_EXEC },
-
+
{ NULL, SSI_UNSET }
};
-
+
for (i = 0; ssicmds[i].var; i++) {
if (0 == strcmp(l[1], ssicmds[i].var)) {
ssicmd = ssicmds[i].type;
break;
}
}
-
+
switch(ssicmd) {
case SSI_ECHO: {
/* echo */
- int var = 0, enc = 0;
+ int var = 0;
+ /* int enc = 0; */
const char *var_val = NULL;
stat_cache_entry *sce = NULL;
-
- struct {
+
+ struct {
const char *var;
- enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI,
+ enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI,
SSI_ECHO_LAST_MODIFIED, SSI_ECHO_USER_NAME } type;
} echovars[] = {
{ "DATE_GMT", SSI_ECHO_DATE_GMT },
@@ -339,27 +378,29 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
{ "DOCUMENT_URI", SSI_ECHO_DOCUMENT_URI },
{ "LAST_MODIFIED", SSI_ECHO_LAST_MODIFIED },
{ "USER_NAME", SSI_ECHO_USER_NAME },
-
+
{ NULL, SSI_ECHO_UNSET }
};
-
- struct {
+
+/*
+ struct {
const char *var;
enum { SSI_ENC_UNSET, SSI_ENC_URL, SSI_ENC_NONE, SSI_ENC_ENTITY } type;
} encvars[] = {
{ "url", SSI_ENC_URL },
{ "none", SSI_ENC_NONE },
{ "entity", SSI_ENC_ENTITY },
-
+
{ NULL, SSI_ENC_UNSET }
};
-
+*/
+
for (i = 2; i < n; i += 2) {
if (0 == strcmp(l[i], "var")) {
int j;
-
+
var_val = l[i+1];
-
+
for (j = 0; echovars[j].var; j++) {
if (0 == strcmp(l[i+1], echovars[j].var)) {
var = echovars[j].type;
@@ -367,36 +408,38 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
}
}
} else if (0 == strcmp(l[i], "encoding")) {
+/*
int j;
-
+
for (j = 0; encvars[j].var; j++) {
if (0 == strcmp(l[i+1], encvars[j].var)) {
enc = encvars[j].type;
break;
}
}
+*/
} else {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: unknow attribute for ",
+ "ssi: unknow attribute for ",
l[1], l[i]);
}
}
-
+
if (p->if_is_false) break;
-
+
if (!var_val) {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: ",
+ "ssi: ",
l[1], "var is missing");
break;
}
stat_cache_get_entry(srv, con, con->physical.path, &sce);
-
+
switch(var) {
case SSI_ECHO_USER_NAME: {
struct passwd *pw;
-
+
b = chunkqueue_get_append_buffer(con->write_queue);
#ifdef HAVE_PWD_H
if (NULL == (pw = getpwuid(sce->st.st_uid))) {
@@ -411,10 +454,10 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
}
case SSI_ECHO_LAST_MODIFIED: {
time_t t = sce->st.st_mtime;
-
+
b = chunkqueue_get_append_buffer(con->write_queue);
if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
- buffer_copy_string(b, "(none)");
+ buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
} else {
buffer_copy_string(b, buf);
}
@@ -422,10 +465,10 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
}
case SSI_ECHO_DATE_LOCAL: {
time_t t = time(NULL);
-
+
b = chunkqueue_get_append_buffer(con->write_queue);
if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
- buffer_copy_string(b, "(none)");
+ buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
} else {
buffer_copy_string(b, buf);
}
@@ -433,10 +476,10 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
}
case SSI_ECHO_DATE_GMT: {
time_t t = time(NULL);
-
+
b = chunkqueue_get_append_buffer(con->write_queue);
if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) {
- buffer_copy_string(b, "(none)");
+ buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
} else {
buffer_copy_string(b, buf);
}
@@ -444,7 +487,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
}
case SSI_ECHO_DOCUMENT_NAME: {
char *sl;
-
+
b = chunkqueue_get_append_buffer(con->write_queue);
if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
buffer_copy_string_buffer(b, con->physical.path);
@@ -461,15 +504,15 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
default: {
data_string *ds;
/* check if it is a cgi-var */
-
+
b = chunkqueue_get_append_buffer(con->write_queue);
-
+
if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val))) {
buffer_copy_string_buffer(b, ds->value);
} else {
- buffer_copy_string(b, "(none)");
+ buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
}
-
+
break;
}
}
@@ -481,7 +524,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
const char * file_path = NULL, *virt_path = NULL;
struct stat st;
char *sl;
-
+
for (i = 2; i < n; i += 2) {
if (0 == strcmp(l[i], "file")) {
file_path = l[i+1];
@@ -489,78 +532,76 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
virt_path = l[i+1];
} else {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: unknow attribute for ",
+ "ssi: unknow attribute for ",
l[1], l[i]);
}
}
-
+
if (!file_path && !virt_path) {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: ",
+ "ssi: ",
l[1], "file or virtual are missing");
break;
}
-
+
if (file_path && virt_path) {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: ",
+ "ssi: ",
l[1], "only one of file and virtual is allowed here");
break;
}
-
-
+
+
if (p->if_is_false) break;
-
+
if (file_path) {
/* current doc-root */
if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
- buffer_copy_string(p->stat_fn, "/");
+ buffer_copy_string_len(p->stat_fn, CONST_STR_LEN("/"));
} else {
buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, sl - con->physical.path->ptr + 1);
}
-
- /* fn */
- if (NULL == (sl = strrchr(file_path, '/'))) {
- buffer_append_string(p->stat_fn, file_path);
- } else {
- buffer_append_string(p->stat_fn, sl + 1);
- }
+
+ buffer_copy_string(srv->tmp_buf, file_path);
+ buffer_urldecode_path(srv->tmp_buf);
+ buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
+ buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
} else {
/* virtual */
-
+
if (virt_path[0] == '/') {
buffer_copy_string(p->stat_fn, virt_path);
} else {
/* there is always a / */
sl = strrchr(con->uri.path->ptr, '/');
-
+
buffer_copy_string_len(p->stat_fn, con->uri.path->ptr, sl - con->uri.path->ptr + 1);
buffer_append_string(p->stat_fn, virt_path);
}
-
+
buffer_urldecode_path(p->stat_fn);
buffer_path_simplify(srv->tmp_buf, p->stat_fn);
-
+
/* we have an uri */
-
+
buffer_copy_string_buffer(p->stat_fn, con->physical.doc_root);
buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
}
-
+
if (0 == stat(p->stat_fn->ptr, &st)) {
time_t t = st.st_mtime;
-
+
switch (ssicmd) {
case SSI_FSIZE:
b = chunkqueue_get_append_buffer(con->write_queue);
if (p->sizefmt) {
int j = 0;
const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL };
-
+
off_t s = st.st_size;
-
+
for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++);
-
+
buffer_copy_off_t(b, s);
buffer_append_string(b, abr[j]);
} else {
@@ -570,18 +611,23 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
case SSI_FLASTMOD:
b = chunkqueue_get_append_buffer(con->write_queue);
if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
- buffer_copy_string(b, "(none)");
+ buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
} else {
buffer_copy_string(b, buf);
}
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 {
log_error_write(srv, __FILE__, __LINE__, "sbs",
- "ssi: stating failed ",
+ "ssi: stating failed ",
p->stat_fn, strerror(errno));
}
break;
@@ -595,33 +641,33 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
val = l[i+1];
} else {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: unknow attribute for ",
+ "ssi: unknow attribute for ",
l[1], l[i]);
}
}
-
+
if (p->if_is_false) break;
-
+
if (key && val) {
data_string *ds;
-
+
if (NULL == (ds = (data_string *)array_get_unused_element(p->ssi_vars, TYPE_STRING))) {
ds = data_string_init();
}
buffer_copy_string(ds->key, key);
buffer_copy_string(ds->value, val);
-
+
array_insert_unique(p->ssi_vars, (data_unset *)ds);
} else {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: var and value have to be set in",
+ "ssi: var and value have to be set in",
l[0], l[1]);
}
break;
}
- case SSI_CONFIG:
+ case SSI_CONFIG:
if (p->if_is_false) break;
-
+
for (i = 2; i < n; i += 2) {
if (0 == strcmp(l[i], "timefmt")) {
buffer_copy_string(p->timefmt, l[i+1]);
@@ -634,63 +680,68 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
log_error_write(srv, __FILE__, __LINE__, "sssss",
"ssi: unknow value for attribute '",
l[i],
- "' for ",
+ "' for ",
l[1], l[i+1]);
}
} else {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: unknow attribute for ",
+ "ssi: unknow attribute for ",
l[1], l[i]);
}
}
break;
case SSI_PRINTENV:
if (p->if_is_false) break;
-
+
b = chunkqueue_get_append_buffer(con->write_queue);
- buffer_copy_string(b, "<pre>");
for (i = 0; i < p->ssi_vars->used; i++) {
data_string *ds = (data_string *)p->ssi_vars->data[p->ssi_vars->sorted[i]];
-
+
buffer_append_string_buffer(b, ds->key);
- buffer_append_string(b, ": ");
- buffer_append_string_buffer(b, ds->value);
- buffer_append_string(b, "<br />");
-
+ buffer_append_string_len(b, CONST_STR_LEN("="));
+ buffer_append_string_encoded(b, CONST_BUF_LEN(ds->value), ENCODING_MINIMAL_XML);
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
}
- buffer_append_string(b, "</pre>");
-
+ for (i = 0; i < p->ssi_cgi_env->used; i++) {
+ data_string *ds = (data_string *)p->ssi_cgi_env->data[p->ssi_cgi_env->sorted[i]];
+
+ buffer_append_string_buffer(b, ds->key);
+ buffer_append_string_len(b, CONST_STR_LEN("="));
+ buffer_append_string_encoded(b, CONST_BUF_LEN(ds->value), ENCODING_MINIMAL_XML);
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+ }
+
break;
case SSI_EXEC: {
const char *cmd = NULL;
pid_t pid;
int from_exec_fds[2];
-
+
for (i = 2; i < n; i += 2) {
if (0 == strcmp(l[i], "cmd")) {
cmd = l[i+1];
} else {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: unknow attribute for ",
+ "ssi: unknow attribute for ",
l[1], l[i]);
}
}
-
+
if (p->if_is_false) break;
-
+
/* create a return pipe and send output to the html-page
- *
- * as exec is assumed evil it is implemented synchronously
+ *
+ * as exec is assumed evil it is implemented synchronously
*/
-
+
if (!cmd) break;
-#ifdef HAVE_FORK
+#ifdef HAVE_FORK
if (pipe(from_exec_fds)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
"pipe failed: ", strerror(errno));
return -1;
}
-
+
/* fork, execve */
switch (pid = fork()) {
case 0: {
@@ -700,14 +751,14 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
close(from_exec_fds[1]);
/* not needed */
close(from_exec_fds[0]);
-
+
/* close stdin */
close(STDIN_FILENO);
-
- execl("/bin/sh", "sh", "-c", cmd, NULL);
-
+
+ execl("/bin/sh", "sh", "-c", cmd, (char *)NULL);
+
log_error_write(srv, __FILE__, __LINE__, "sss", "spawing exec failed:", strerror(errno), cmd);
-
+
/* */
SEGFAULT();
break;
@@ -720,44 +771,59 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
/* father */
int status;
ssize_t r;
-
- close(from_exec_fds[1]);
-
- /* wait for the client to end */
- 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;
- }
+ int was_interrupted = 0;
- if (toread > 0) {
- b = chunkqueue_get_append_buffer(con->write_queue);
+ close(from_exec_fds[1]);
- buffer_prepare_copy(b, toread + 1);
+ /* wait for the client to end */
- if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) {
- /* read failed */
- break;
+ /*
+ * OpenBSD and Solaris send a EINTR on SIGCHILD even if we ignore it
+ */
+ 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));
+ }
+ } 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;
}
}
@@ -765,51 +831,51 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
return -1;
#endif
-
+
break;
}
case SSI_IF: {
const char *expr = NULL;
-
+
for (i = 2; i < n; i += 2) {
if (0 == strcmp(l[i], "expr")) {
expr = l[i+1];
} else {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: unknow attribute for ",
+ "ssi: unknow attribute for ",
l[1], l[i]);
}
}
-
+
if (!expr) {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: ",
+ "ssi: ",
l[1], "expr missing");
break;
}
-
+
if ((!p->if_is_false) &&
- ((p->if_is_false_level == 0) ||
+ ((p->if_is_false_level == 0) ||
(p->if_level < p->if_is_false_level))) {
switch (ssi_eval_expr(srv, con, p, expr)) {
case -1:
- case 0:
- p->if_is_false = 1;
+ case 0:
+ p->if_is_false = 1;
p->if_is_false_level = p->if_level;
break;
- case 1:
- p->if_is_false = 0;
+ case 1:
+ p->if_is_false = 0;
break;
}
}
-
+
p->if_level++;
-
+
break;
}
case SSI_ELSE:
p->if_level--;
-
+
if (p->if_is_false) {
if ((p->if_level == p->if_is_false_level) &&
(p->if_is_false_endif == 0)) {
@@ -817,11 +883,11 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
}
} else {
p->if_is_false = 1;
-
+
p->if_is_false_level = p->if_level;
}
p->if_level++;
-
+
break;
case SSI_ELIF: {
const char *expr = NULL;
@@ -830,52 +896,52 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
expr = l[i+1];
} else {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: unknow attribute for ",
+ "ssi: unknow attribute for ",
l[1], l[i]);
}
}
-
+
if (!expr) {
log_error_write(srv, __FILE__, __LINE__, "sss",
- "ssi: ",
+ "ssi: ",
l[1], "expr missing");
break;
}
-
+
p->if_level--;
-
+
if (p->if_level == p->if_is_false_level) {
if ((p->if_is_false) &&
(p->if_is_false_endif == 0)) {
switch (ssi_eval_expr(srv, con, p, expr)) {
case -1:
- case 0:
- p->if_is_false = 1;
+ case 0:
+ p->if_is_false = 1;
p->if_is_false_level = p->if_level;
break;
- case 1:
- p->if_is_false = 0;
+ case 1:
+ p->if_is_false = 0;
break;
}
} else {
- p->if_is_false = 1;
+ p->if_is_false = 1;
p->if_is_false_level = p->if_level;
p->if_is_false_endif = 1;
}
}
-
+
p->if_level++;
-
+
break;
}
case SSI_ENDIF:
p->if_level--;
-
+
if (p->if_level == p->if_is_false_level) {
p->if_is_false = 0;
p->if_is_false_endif = 0;
}
-
+
break;
default:
log_error_write(srv, __FILE__, __LINE__, "ss",
@@ -883,41 +949,44 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
l[1]);
break;
}
-
+
return 0;
-
+
}
static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) {
stream s;
#ifdef HAVE_PCRE_H
int i, n;
-
+
#define N 10
int ovec[N * 3];
#endif
-
+
/* get a stream to the file */
-
+
array_reset(p->ssi_vars);
array_reset(p->ssi_cgi_env);
- buffer_copy_string(p->timefmt, "%a, %d %b %Y %H:%M:%S %Z");
+ buffer_copy_string_len(p->timefmt, CONST_STR_LEN("%a, %d %b %Y %H:%M:%S %Z"));
p->sizefmt = 0;
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);
return -1;
}
-
-
+
+
/**
- * <!--#element attribute=value attribute=value ... -->
- *
+ * <!--#element attribute=value attribute=value ... -->
+ *
* config DONE
- * errmsg -- missing
+ * errmsg -- missing
* sizefmt DONE
* timefmt DONE
* echo DONE
@@ -939,13 +1008,13 @@ static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p)
* set DONE
* var DONE
* value DONE
- *
+ *
* if DONE
* elif DONE
* else DONE
* endif DONE
- *
- *
+ *
+ *
* expressions
* AND, OR DONE
* comp DONE
@@ -953,60 +1022,89 @@ static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p)
* $... DONE
* '...' DONE
* ( ... ) DONE
- *
- *
- *
+ *
+ *
+ *
* ** all DONE **
- * DATE_GMT
- * The current date in Greenwich Mean Time.
- * DATE_LOCAL
- * The current date in the local time zone.
- * DOCUMENT_NAME
- * The filename (excluding directories) of the document requested by the user.
- * DOCUMENT_URI
- * The (%-decoded) URL path of the document requested by the user. Note that in the case of nested include files, this is not then URL for the current document.
- * LAST_MODIFIED
- * The last modification date of the document requested by the user.
- * USER_NAME
+ * DATE_GMT
+ * The current date in Greenwich Mean Time.
+ * DATE_LOCAL
+ * The current date in the local time zone.
+ * DOCUMENT_NAME
+ * The filename (excluding directories) of the document requested by the user.
+ * DOCUMENT_URI
+ * The (%-decoded) URL path of the document requested by the user. Note that in the case of nested include files, this is not then URL for the current document.
+ * LAST_MODIFIED
+ * The last modification date of the document requested by the user.
+ * USER_NAME
* Contains the owner of the file which included it.
- *
+ *
*/
-#ifdef HAVE_PCRE_H
+#ifdef HAVE_PCRE_H
for (i = 0; (n = pcre_exec(p->ssi_regex, NULL, s.start, s.size, i, 0, ovec, N * 3)) > 0; i = ovec[1]) {
const char **l;
- /* take every think from last offset to current match pos */
-
+ /* take everything from last offset to current match pos */
+
if (!p->if_is_false) chunkqueue_append_file(con->write_queue, con->physical.path, i, ovec[0] - i);
-
+
pcre_get_substring_list(s.start, ovec, n, &l);
process_ssi_stmt(srv, con, p, l, n);
pcre_free_substring_list(l);
}
-
+
switch(n) {
case PCRE_ERROR_NOMATCH:
/* copy everything/the rest */
chunkqueue_append_file(con->write_queue, con->physical.path, i, s.size - i);
-
+
break;
default:
log_error_write(srv, __FILE__, __LINE__, "sd",
"execution error while matching: ", n);
break;
}
-#endif
-
-
+#endif
+
+
stream_close(&s);
-
+
con->file_started = 1;
con->file_finished = 1;
-
- response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
-
+ con->mode = p->id;
+
+ if (p->conf.content_type->used <= 1) {
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
+ } else {
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->conf.content_type));
+ }
+
+ {
+ /* 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);
-
+
return 0;
}
@@ -1015,27 +1113,30 @@ static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p)
static int mod_ssi_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(ssi_extension);
-
+ PATCH(content_type);
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.extension"))) {
PATCH(ssi_extension);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.content-type"))) {
+ PATCH(content_type);
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -1043,44 +1144,48 @@ static int mod_ssi_patch_connection(server *srv, connection *con, plugin_data *p
URIHANDLER_FUNC(mod_ssi_physical_path) {
plugin_data *p = p_d;
size_t k;
-
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
if (con->physical.path->used == 0) return HANDLER_GO_ON;
-
+
mod_ssi_patch_connection(srv, con, p);
-
+
for (k = 0; k < p->conf.ssi_extension->used; k++) {
data_string *ds = (data_string *)p->conf.ssi_extension->data[k];
-
+
if (ds->value->used == 0) continue;
-
+
if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
/* handle ssi-request */
-
+
if (mod_ssi_handle_request(srv, con, p)) {
/* on error */
con->http_status = 500;
+ con->mode = DIRECT;
}
-
+
return HANDLER_FINISHED;
}
}
-
+
/* not found */
return HANDLER_GO_ON;
}
/* this function is called at dlopen() time and inits the callbacks */
+int mod_ssi_plugin_init(plugin *p);
int mod_ssi_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("ssi");
-
+
p->init = mod_ssi_init;
p->handle_subrequest_start = mod_ssi_physical_path;
p->set_defaults = mod_ssi_set_defaults;
p->cleanup = mod_ssi_free;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_ssi.h b/src/mod_ssi.h
index 80f03ed..241e832 100644
--- a/src/mod_ssi.h
+++ b/src/mod_ssi.h
@@ -15,27 +15,28 @@
typedef struct {
array *ssi_extension;
+ buffer *content_type;
} plugin_config;
typedef struct {
PLUGIN_DATA;
-
-#ifdef HAVE_PCRE_H
+
+#ifdef HAVE_PCRE_H
pcre *ssi_regex;
-#endif
+#endif
buffer *timefmt;
int sizefmt;
-
+
buffer *stat_fn;
-
+
array *ssi_vars;
array *ssi_cgi_env;
-
+
int if_level, if_is_false_level, if_is_false, if_is_false_endif;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
int ssi_eval_expr(server *srv, connection *con, plugin_data *p, const char *expr);
diff --git a/src/mod_ssi_expr.c b/src/mod_ssi_expr.c
index 98959ab..f839987 100644
--- a/src/mod_ssi_expr.c
+++ b/src/mod_ssi_expr.c
@@ -1,35 +1,35 @@
-#include <ctype.h>
-#include <string.h>
-
#include "buffer.h"
#include "log.h"
#include "mod_ssi.h"
#include "mod_ssi_expr.h"
#include "mod_ssi_exprparser.h"
+#include <ctype.h>
+#include <string.h>
+
typedef struct {
const char *input;
size_t offset;
size_t size;
-
+
int line_pos;
-
+
int in_key;
int in_brace;
int in_cond;
} ssi_tokenizer_t;
-ssi_val_t *ssi_val_init() {
+ssi_val_t *ssi_val_init(void) {
ssi_val_t *s;
-
+
s = calloc(1, sizeof(*s));
-
+
return s;
}
void ssi_val_free(ssi_val_t *s) {
if (s->str) buffer_free(s->str);
-
+
free(s);
}
@@ -45,192 +45,192 @@ static int ssi_expr_tokenizer(server *srv, connection *con, plugin_data *p,
ssi_tokenizer_t *t, int *token_id, buffer *token) {
int tid = 0;
size_t i;
-
+
UNUSED(con);
for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
char c = t->input[t->offset];
data_string *ds;
-
+
switch (c) {
- case '=':
+ case '=':
tid = TK_EQ;
-
+
t->offset++;
t->line_pos++;
-
- buffer_copy_string(token, "(=)");
-
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(=)"));
+
break;
case '>':
if (t->input[t->offset + 1] == '=') {
t->offset += 2;
t->line_pos += 2;
-
+
tid = TK_GE;
-
- buffer_copy_string(token, "(>=)");
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(>=)"));
} else {
t->offset += 1;
t->line_pos += 1;
-
+
tid = TK_GT;
-
- buffer_copy_string(token, "(>)");
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(>)"));
}
-
+
break;
case '<':
if (t->input[t->offset + 1] == '=') {
t->offset += 2;
t->line_pos += 2;
-
+
tid = TK_LE;
-
- buffer_copy_string(token, "(<=)");
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(<=)"));
} else {
t->offset += 1;
t->line_pos += 1;
-
+
tid = TK_LT;
-
- buffer_copy_string(token, "(<)");
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(<)"));
}
-
+
break;
-
+
case '!':
if (t->input[t->offset + 1] == '=') {
t->offset += 2;
t->line_pos += 2;
-
+
tid = TK_NE;
-
- buffer_copy_string(token, "(!=)");
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(!=)"));
} else {
t->offset += 1;
t->line_pos += 1;
-
+
tid = TK_NOT;
-
- buffer_copy_string(token, "(!)");
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(!)"));
}
-
+
break;
case '&':
if (t->input[t->offset + 1] == '&') {
t->offset += 2;
t->line_pos += 2;
-
+
tid = TK_AND;
-
- buffer_copy_string(token, "(&&)");
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(&&)"));
} else {
- log_error_write(srv, __FILE__, __LINE__, "sds",
- "pos:", t->line_pos,
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "pos:", t->line_pos,
"missing second &");
return -1;
}
-
+
break;
case '|':
if (t->input[t->offset + 1] == '|') {
t->offset += 2;
t->line_pos += 2;
-
+
tid = TK_OR;
-
- buffer_copy_string(token, "(||)");
+
+ buffer_copy_string_len(token, CONST_STR_LEN("(||)"));
} else {
- log_error_write(srv, __FILE__, __LINE__, "sds",
- "pos:", t->line_pos,
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "pos:", t->line_pos,
"missing second |");
return -1;
}
-
+
break;
case '\t':
case ' ':
t->offset++;
t->line_pos++;
break;
-
+
case '\'':
/* search for the terminating " */
for (i = 1; t->input[t->offset + i] && t->input[t->offset + i] != '\''; i++);
-
+
if (t->input[t->offset + i]) {
tid = TK_VALUE;
-
+
buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
-
+
t->offset += i + 1;
t->line_pos += i + 1;
} else {
/* ERROR */
-
- log_error_write(srv, __FILE__, __LINE__, "sds",
- "pos:", t->line_pos,
+
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "pos:", t->line_pos,
"missing closing quote");
-
+
return -1;
}
-
+
break;
case '(':
t->offset++;
t->in_brace++;
-
+
tid = TK_LPARAN;
-
- buffer_copy_string(token, "(");
+
+ buffer_copy_string_len(token, CONST_STR_LEN("("));
break;
case ')':
t->offset++;
t->in_brace--;
-
+
tid = TK_RPARAN;
-
- buffer_copy_string(token, ")");
+
+ buffer_copy_string_len(token, CONST_STR_LEN(")"));
break;
case '$':
if (t->input[t->offset + 1] == '{') {
for (i = 2; t->input[t->offset + i] && t->input[t->offset + i] != '}'; i++);
-
+
if (t->input[t->offset + i] != '}') {
- log_error_write(srv, __FILE__, __LINE__, "sds",
- "pos:", t->line_pos,
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "pos:", t->line_pos,
"missing closing quote");
-
+
return -1;
}
-
+
buffer_copy_string_len(token, t->input + t->offset + 2, i-3);
} else {
for (i = 1; isalpha(t->input[t->offset + i]) || t->input[t->offset + i] == '_'; i++);
-
+
buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
}
-
+
tid = TK_VALUE;
-
+
if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, token->ptr))) {
buffer_copy_string_buffer(token, ds->value);
} else if (NULL != (ds = (data_string *)array_get_element(p->ssi_vars, token->ptr))) {
buffer_copy_string_buffer(token, ds->value);
} else {
- buffer_copy_string(token, "");
+ buffer_copy_string_len(token, CONST_STR_LEN(""));
}
-
+
t->offset += i;
t->line_pos += i;
-
+
break;
default:
for (i = 0; isgraph(t->input[t->offset + i]); i++) {
char d = t->input[t->offset + i];
switch(d) {
- case ' ':
+ case ' ':
case '\t':
case ')':
case '(':
@@ -244,25 +244,25 @@ static int ssi_expr_tokenizer(server *srv, connection *con, plugin_data *p,
break;
}
}
-
+
tid = TK_VALUE;
-
+
buffer_copy_string_len(token, t->input + t->offset, i);
-
+
t->offset += i;
t->line_pos += i;
-
+
break;
}
}
-
+
if (tid) {
*token_id = tid;
-
+
return 1;
} else if (t->offset < t->size) {
- log_error_write(srv, __FILE__, __LINE__, "sds",
- "pos:", t->line_pos,
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "pos:", t->line_pos,
"foobar");
}
return 0;
@@ -275,50 +275,50 @@ int ssi_eval_expr(server *srv, connection *con, plugin_data *p, const char *expr
buffer *token;
ssi_ctx_t context;
int ret;
-
+
t.input = expr;
t.offset = 0;
t.size = strlen(expr);
t.line_pos = 1;
-
+
t.in_key = 1;
t.in_brace = 0;
t.in_cond = 0;
-
+
context.ok = 1;
context.srv = srv;
-
+
/* default context */
-
+
pParser = ssiexprparserAlloc( malloc );
token = buffer_init();
while((1 == (ret = ssi_expr_tokenizer(srv, con, p, &t, &token_id, token))) && context.ok) {
ssiexprparser(pParser, token_id, token, &context);
-
+
token = buffer_init();
}
ssiexprparser(pParser, 0, token, &context);
ssiexprparserFree(pParser, free );
-
+
buffer_free(token);
-
+
if (ret == -1) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"expr parser failed");
return -1;
}
-
+
if (context.ok == 0) {
- log_error_write(srv, __FILE__, __LINE__, "sds",
- "pos:", t.line_pos,
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "pos:", t.line_pos,
"parser failed somehow near here");
return -1;
}
#if 0
- log_error_write(srv, __FILE__, __LINE__, "ssd",
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
"expr: ",
expr,
context.val.bo);
-#endif
+#endif
return context.val.bo;
}
diff --git a/src/mod_ssi_expr.h b/src/mod_ssi_expr.h
index b484f78..2d3ae8b 100644
--- a/src/mod_ssi_expr.h
+++ b/src/mod_ssi_expr.h
@@ -5,16 +5,16 @@
typedef struct {
enum { SSI_TYPE_UNSET, SSI_TYPE_BOOL, SSI_TYPE_STRING } type;
-
+
buffer *str;
int bo;
} ssi_val_t;
typedef struct {
int ok;
-
+
ssi_val_t val;
-
+
void *srv;
} ssi_ctx_t;
diff --git a/src/mod_ssi_exprparser.c b/src/mod_ssi_exprparser.c
index 65ec4dc..cd88eda 100644
--- a/src/mod_ssi_exprparser.c
+++ b/src/mod_ssi_exprparser.c
@@ -4,24 +4,22 @@
/* First off, code is include which follows the "include" declaration
** in the input file. */
#include <stdio.h>
-#line 6 "./mod_ssi_exprparser.y"
+#line 6 "../../src/mod_ssi_exprparser.y"
-#include <assert.h>
-#include <string.h>
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
#include "mod_ssi_expr.h"
#include "buffer.h"
-#line 18 "mod_ssi_exprparser.c"
+#include <assert.h>
+#include <string.h>
+
+#line 16 "mod_ssi_exprparser.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.
*/
-/*
+/*
** These constants (all generated automatically by the parser generator)
** specify the various kinds of tokens (terminals) that the parser
-** understands.
+** understands.
**
** Each symbol here is a terminal symbol in the grammar.
*/
@@ -38,7 +36,7 @@
** and nonterminals. "int" is used otherwise.
** YYNOCODE is a number of type YYCODETYPE which corresponds
** to no legal terminal or nonterminal number. This
-** number is used to fill in empty slots of the hash
+** number is used to fill in empty slots of the hash
** table.
** YYFALLBACK If defined, this indicates that one or more tokens
** have fall-back values which should be used if the
@@ -47,7 +45,7 @@
** and nonterminal numbers. "unsigned char" is
** used if there are fewer than 250 rules and
** states combined. "int" is used otherwise.
-** ssiexprparserTOKENTYPE is the data type used for minor tokens given
+** ssiexprparserTOKENTYPE is the data type used for minor tokens given
** directly to the parser from the tokenizer.
** YYMINORTYPE is the data type used for all minor tokens.
** This is typically a union of many types, one of
@@ -91,7 +89,7 @@ typedef union {
/* Next are that tables used to determine what action to take based on the
** current state and lookahead token. These tables are used to implement
** functions that take a state number and lookahead value and return an
-** action integer.
+** action integer.
**
** Suppose the action integer is N. Then the action is determined as
** follows
@@ -116,7 +114,7 @@ typedef union {
** If the index value yy_shift_ofst[S]+X is out of range or if the value
** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
-** and that yy_default[S] should be used instead.
+** and that yy_default[S] should be used instead.
**
** The formula above is for computing the action when the lookahead is
** a terminal symbol. If the lookahead is a non-terminal (as occurs after
@@ -168,7 +166,7 @@ static YYACTIONTYPE yy_default[] = {
/* The next table maps tokens into fallback tokens. If a construct
** like the following:
-**
+**
** %fallback ID X Y Z.
**
** appears in the grammer, then ID becomes a fallback token for X, Y,
@@ -214,15 +212,15 @@ typedef struct yyParser yyParser;
#ifndef NDEBUG
#include <stdio.h>
-static FILE *yyTraceFILE = 0;
-static char *yyTracePrompt = 0;
+static FILE *yyTraceFILE = NULL;
+static char *yyTracePrompt = NULL;
#endif /* NDEBUG */
#ifndef NDEBUG
-/*
+/*
** Turn parser tracing on by giving a stream to which to write the trace
** and a prompt to preface each trace message. Tracing is turned off
-** by making either argument NULL
+** by making either argument NULL
**
** Inputs:
** <ul>
@@ -236,18 +234,20 @@ static char *yyTracePrompt = 0;
** Outputs:
** None.
*/
+#if 0
void ssiexprparserTrace(FILE *TraceFILE, char *zTracePrompt){
yyTraceFILE = TraceFILE;
yyTracePrompt = zTracePrompt;
if( yyTraceFILE==0 ) yyTracePrompt = 0;
else if( yyTracePrompt==0 ) yyTraceFILE = 0;
}
+#endif
#endif /* NDEBUG */
#ifndef NDEBUG
/* For tracing shifts, the names of all terminals and nonterminals
** are required. The following table supplies these names */
-static const char *yyTokenName[] = {
+static const char *yyTokenName[] = {
"$", "AND", "OR", "EQ",
"NE", "GT", "GE", "LT",
"LE", "NOT", "LPARAN", "RPARAN",
@@ -283,9 +283,10 @@ static const char *yyRuleName[] = {
** This function returns the symbolic name associated with a token
** value.
*/
+#if 0
const char *ssiexprparserTokenName(int tokenType){
#ifndef NDEBUG
- if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
+ if( tokenType>0 && (size_t)tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
return yyTokenName[tokenType];
}else{
return "Unknown";
@@ -294,8 +295,9 @@ const char *ssiexprparserTokenName(int tokenType){
return "";
#endif
}
+#endif
-/*
+/*
** This function allocates a new parser.
** The only argument is a pointer to a function which works like
** malloc.
@@ -326,7 +328,7 @@ static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
/* Here is inserted the actions which take place when a
** terminal or non-terminal is destroyed. This can happen
** when the symbol is popped from the stack during a
- ** reduce or during error processing or when a parser is
+ ** reduce or during error processing or when a parser is
** being destroyed before it is finished parsing.
**
** Note: during a reduce, the only symbols destroyed are those
@@ -345,9 +347,9 @@ static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
case 10:
case 11:
case 12:
-#line 24 "./mod_ssi_exprparser.y"
+#line 22 "../../src/mod_ssi_exprparser.y"
{ buffer_free((yypminor->yy0)); }
-#line 350 "mod_ssi_exprparser.c"
+#line 352 "mod_ssi_exprparser.c"
break;
default: break; /* If no destructor action specified: do nothing */
}
@@ -379,7 +381,7 @@ static int yy_pop_parser_stack(yyParser *pParser){
return yymajor;
}
-/*
+/*
** Deallocate and destroy a parser. Destructors are all called for
** all stack elements before shutting the parser down.
**
@@ -396,7 +398,7 @@ void ssiexprparserFree(
void (*freeProc)(void*) /* Function used to reclaim memory */
){
yyParser *pParser = (yyParser*)p;
- if( pParser==0 ) return;
+ if( pParser==NULL ) return;
while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
(*freeProc)((void*)pParser);
}
@@ -415,7 +417,7 @@ static int yy_find_shift_action(
){
int i;
int stateno = pParser->yystack[pParser->yyidx].stateno;
-
+
/* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
i = yy_shift_ofst[stateno];
if( i==YY_SHIFT_USE_DFLT ){
@@ -425,7 +427,7 @@ static int yy_find_shift_action(
return YY_NO_ACTION;
}
i += iLookAhead;
- if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
+ if( i<0 || (size_t)i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
#ifdef YYFALLBACK
int iFallback; /* Fallback token */
if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
@@ -459,7 +461,7 @@ static int yy_find_reduce_action(
){
int i;
int stateno = pParser->yystack[pParser->yyidx].stateno;
-
+
i = yy_reduce_ofst[stateno];
if( i==YY_REDUCE_USE_DFLT ){
return yy_default[stateno];
@@ -468,7 +470,7 @@ static int yy_find_reduce_action(
return YY_NO_ACTION;
}
i += iLookAhead;
- if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
+ if( i<0 || (size_t)i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
return yy_default[stateno];
}else{
return yy_action[i];
@@ -559,8 +561,8 @@ static void yy_reduce(
ssiexprparserARG_FETCH;
yymsp = &yypParser->yystack[yypParser->yyidx];
#ifndef NDEBUG
- if( yyTraceFILE && yyruleno>=0
- && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
+ if( yyTraceFILE && yyruleno>=0
+ && (size_t)yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
yyRuleName[yyruleno]);
}
@@ -576,29 +578,29 @@ static void yy_reduce(
** break;
*/
case 0:
-#line 31 "./mod_ssi_exprparser.y"
+#line 29 "../../src/mod_ssi_exprparser.y"
{
ctx->val.bo = ssi_val_tobool(yymsp[0].minor.yy29);
ctx->val.type = SSI_TYPE_BOOL;
-
+
ssi_val_free(yymsp[0].minor.yy29);
}
-#line 586 "mod_ssi_exprparser.c"
+#line 588 "mod_ssi_exprparser.c"
break;
case 1:
-#line 38 "./mod_ssi_exprparser.y"
+#line 36 "../../src/mod_ssi_exprparser.y"
{
int cmp;
-
- if (yymsp[-2].minor.yy29->type == SSI_TYPE_STRING &&
+
+ if (yymsp[-2].minor.yy29->type == SSI_TYPE_STRING &&
yymsp[0].minor.yy29->type == SSI_TYPE_STRING) {
cmp = strcmp(yymsp[-2].minor.yy29->str->ptr, yymsp[0].minor.yy29->str->ptr);
} else {
cmp = ssi_val_tobool(yymsp[-2].minor.yy29) - ssi_val_tobool(yymsp[0].minor.yy29);
}
-
+
yygotominor.yy29 = yymsp[-2].minor.yy29;
-
+
switch(yymsp[-1].minor.yy8) {
case SSI_COND_EQ: yygotominor.yy29->bo = (cmp == 0) ? 1 : 0; break;
case SSI_COND_NE: yygotominor.yy29->bo = (cmp != 0) ? 1 : 0; break;
@@ -607,131 +609,132 @@ static void yy_reduce(
case SSI_COND_LE: yygotominor.yy29->bo = (cmp <= 0) ? 1 : 0; break;
case SSI_COND_LT: yygotominor.yy29->bo = (cmp < 0) ? 1 : 0; break;
}
-
+
yygotominor.yy29->type = SSI_TYPE_BOOL;
-
+
ssi_val_free(yymsp[0].minor.yy29);
}
-#line 615 "mod_ssi_exprparser.c"
+#line 617 "mod_ssi_exprparser.c"
break;
case 2:
-#line 63 "./mod_ssi_exprparser.y"
+#line 61 "../../src/mod_ssi_exprparser.y"
{
yygotominor.yy29 = yymsp[0].minor.yy29;
}
-#line 622 "mod_ssi_exprparser.c"
+#line 624 "mod_ssi_exprparser.c"
break;
case 3:
-#line 66 "./mod_ssi_exprparser.y"
+#line 64 "../../src/mod_ssi_exprparser.y"
{
int e;
-
+
e = ssi_val_tobool(yymsp[-2].minor.yy29) && ssi_val_tobool(yymsp[0].minor.yy29);
-
+
yygotominor.yy29 = yymsp[-2].minor.yy29;
yygotominor.yy29->bo = e;
yygotominor.yy29->type = SSI_TYPE_BOOL;
ssi_val_free(yymsp[0].minor.yy29);
}
-#line 636 "mod_ssi_exprparser.c"
+#line 638 "mod_ssi_exprparser.c"
yy_destructor(1,&yymsp[-1].minor);
break;
case 4:
-#line 77 "./mod_ssi_exprparser.y"
+#line 75 "../../src/mod_ssi_exprparser.y"
{
int e;
-
+
e = ssi_val_tobool(yymsp[-2].minor.yy29) || ssi_val_tobool(yymsp[0].minor.yy29);
-
+
yygotominor.yy29 = yymsp[-2].minor.yy29;
yygotominor.yy29->bo = e;
yygotominor.yy29->type = SSI_TYPE_BOOL;
ssi_val_free(yymsp[0].minor.yy29);
}
-#line 651 "mod_ssi_exprparser.c"
+#line 653 "mod_ssi_exprparser.c"
yy_destructor(2,&yymsp[-1].minor);
break;
case 5:
-#line 88 "./mod_ssi_exprparser.y"
+#line 86 "../../src/mod_ssi_exprparser.y"
{
int e;
-
+
e = !ssi_val_tobool(yymsp[0].minor.yy29);
-
+
yygotominor.yy29 = yymsp[0].minor.yy29;
yygotominor.yy29->bo = e;
yygotominor.yy29->type = SSI_TYPE_BOOL;
}
-#line 665 "mod_ssi_exprparser.c"
+#line 667 "mod_ssi_exprparser.c"
yy_destructor(9,&yymsp[-1].minor);
break;
case 6:
-#line 97 "./mod_ssi_exprparser.y"
+#line 95 "../../src/mod_ssi_exprparser.y"
{
yygotominor.yy29 = yymsp[-1].minor.yy29;
}
-#line 673 "mod_ssi_exprparser.c"
+#line 675 "mod_ssi_exprparser.c"
yy_destructor(10,&yymsp[-2].minor);
yy_destructor(11,&yymsp[0].minor);
break;
case 7:
-#line 101 "./mod_ssi_exprparser.y"
+#line 99 "../../src/mod_ssi_exprparser.y"
{
yygotominor.yy29 = ssi_val_init();
yygotominor.yy29->str = yymsp[0].minor.yy19;
yygotominor.yy29->type = SSI_TYPE_STRING;
}
-#line 684 "mod_ssi_exprparser.c"
+#line 686 "mod_ssi_exprparser.c"
break;
case 8:
-#line 107 "./mod_ssi_exprparser.y"
+#line 105 "../../src/mod_ssi_exprparser.y"
{
- yygotominor.yy19 = buffer_init_string(yymsp[0].minor.yy0->ptr);
+ yygotominor.yy19 = yymsp[0].minor.yy0;
}
-#line 691 "mod_ssi_exprparser.c"
+#line 693 "mod_ssi_exprparser.c"
break;
case 9:
-#line 111 "./mod_ssi_exprparser.y"
+#line 109 "../../src/mod_ssi_exprparser.y"
{
yygotominor.yy19 = yymsp[-1].minor.yy19;
buffer_append_string_buffer(yygotominor.yy19, yymsp[0].minor.yy0);
+ buffer_free(yymsp[0].minor.yy0);
}
-#line 699 "mod_ssi_exprparser.c"
+#line 702 "mod_ssi_exprparser.c"
break;
case 10:
-#line 116 "./mod_ssi_exprparser.y"
+#line 115 "../../src/mod_ssi_exprparser.y"
{ yygotominor.yy8 = SSI_COND_EQ; }
-#line 704 "mod_ssi_exprparser.c"
+#line 707 "mod_ssi_exprparser.c"
yy_destructor(3,&yymsp[0].minor);
break;
case 11:
-#line 117 "./mod_ssi_exprparser.y"
+#line 116 "../../src/mod_ssi_exprparser.y"
{ yygotominor.yy8 = SSI_COND_NE; }
-#line 710 "mod_ssi_exprparser.c"
+#line 713 "mod_ssi_exprparser.c"
yy_destructor(4,&yymsp[0].minor);
break;
case 12:
-#line 118 "./mod_ssi_exprparser.y"
+#line 117 "../../src/mod_ssi_exprparser.y"
{ yygotominor.yy8 = SSI_COND_LE; }
-#line 716 "mod_ssi_exprparser.c"
+#line 719 "mod_ssi_exprparser.c"
yy_destructor(8,&yymsp[0].minor);
break;
case 13:
-#line 119 "./mod_ssi_exprparser.y"
+#line 118 "../../src/mod_ssi_exprparser.y"
{ yygotominor.yy8 = SSI_COND_GE; }
-#line 722 "mod_ssi_exprparser.c"
+#line 725 "mod_ssi_exprparser.c"
yy_destructor(6,&yymsp[0].minor);
break;
case 14:
-#line 120 "./mod_ssi_exprparser.y"
+#line 119 "../../src/mod_ssi_exprparser.y"
{ yygotominor.yy8 = SSI_COND_LT; }
-#line 728 "mod_ssi_exprparser.c"
+#line 731 "mod_ssi_exprparser.c"
yy_destructor(7,&yymsp[0].minor);
break;
case 15:
-#line 121 "./mod_ssi_exprparser.y"
+#line 120 "../../src/mod_ssi_exprparser.y"
{ yygotominor.yy8 = SSI_COND_GT; }
-#line 734 "mod_ssi_exprparser.c"
+#line 737 "mod_ssi_exprparser.c"
yy_destructor(5,&yymsp[0].minor);
break;
};
@@ -761,11 +764,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 16 "./mod_ssi_exprparser.y"
+#line 14 "../../src/mod_ssi_exprparser.y"
ctx->ok = 0;
-#line 768 "mod_ssi_exprparser.c"
+#line 771 "mod_ssi_exprparser.c"
ssiexprparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
@@ -778,6 +781,8 @@ static void yy_syntax_error(
YYMINORTYPE yyminor /* The minor type of the error token */
){
ssiexprparserARG_FETCH;
+ UNUSED(yymajor);
+ UNUSED(yyminor);
#define TOKEN (yyminor.yy0)
ssiexprparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
@@ -872,7 +877,7 @@ void ssiexprparser(
#ifdef YYERRORSYMBOL
/* A syntax error has occurred.
** The response to an error depends upon whether or not the
- ** grammar defines an error token "ERROR".
+ ** grammar defines an error token "ERROR".
**
** This is what we do if the grammar does define ERROR:
**
diff --git a/src/mod_ssi_exprparser.y b/src/mod_ssi_exprparser.y
index c123941..f4aaa96 100644
--- a/src/mod_ssi_exprparser.y
+++ b/src/mod_ssi_exprparser.y
@@ -4,13 +4,11 @@
%name ssiexprparser
%include {
-#include <assert.h>
-#include <string.h>
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
#include "mod_ssi_expr.h"
#include "buffer.h"
+
+#include <assert.h>
+#include <string.h>
}
%parse_failure {
@@ -31,22 +29,22 @@
input ::= exprline(B). {
ctx->val.bo = ssi_val_tobool(B);
ctx->val.type = SSI_TYPE_BOOL;
-
+
ssi_val_free(B);
}
exprline(A) ::= expr(B) cond(C) expr(D). {
int cmp;
-
- if (B->type == SSI_TYPE_STRING &&
+
+ if (B->type == SSI_TYPE_STRING &&
D->type == SSI_TYPE_STRING) {
cmp = strcmp(B->str->ptr, D->str->ptr);
} else {
cmp = ssi_val_tobool(B) - ssi_val_tobool(D);
}
-
+
A = B;
-
+
switch(C) {
case SSI_COND_EQ: A->bo = (cmp == 0) ? 1 : 0; break;
case SSI_COND_NE: A->bo = (cmp != 0) ? 1 : 0; break;
@@ -55,9 +53,9 @@ exprline(A) ::= expr(B) cond(C) expr(D). {
case SSI_COND_LE: A->bo = (cmp <= 0) ? 1 : 0; break;
case SSI_COND_LT: A->bo = (cmp < 0) ? 1 : 0; break;
}
-
+
A->type = SSI_TYPE_BOOL;
-
+
ssi_val_free(D);
}
exprline(A) ::= expr(B). {
@@ -65,9 +63,9 @@ exprline(A) ::= expr(B). {
}
expr(A) ::= expr(B) AND expr(C). {
int e;
-
+
e = ssi_val_tobool(B) && ssi_val_tobool(C);
-
+
A = B;
A->bo = e;
A->type = SSI_TYPE_BOOL;
@@ -76,9 +74,9 @@ expr(A) ::= expr(B) AND expr(C). {
expr(A) ::= expr(B) OR expr(C). {
int e;
-
+
e = ssi_val_tobool(B) || ssi_val_tobool(C);
-
+
A = B;
A->bo = e;
A->type = SSI_TYPE_BOOL;
@@ -87,9 +85,9 @@ expr(A) ::= expr(B) OR expr(C). {
expr(A) ::= NOT expr(B). {
int e;
-
+
e = !ssi_val_tobool(B);
-
+
A = B;
A->bo = e;
A->type = SSI_TYPE_BOOL;
@@ -105,12 +103,13 @@ expr(A) ::= value(B). {
}
value(A) ::= VALUE(B). {
- A = buffer_init_string(B->ptr);
+ A = B;
}
value(A) ::= value(B) VALUE(C). {
A = B;
buffer_append_string_buffer(A, C);
+ buffer_free(C);
}
cond(A) ::= EQ. { A = SSI_COND_EQ; }
diff --git a/src/mod_staticfile.c b/src/mod_staticfile.c
index cbc443d..f5114dd 100644
--- a/src/mod_staticfile.c
+++ b/src/mod_staticfile.c
@@ -1,8 +1,3 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
#include "base.h"
#include "log.h"
#include "buffer.h"
@@ -14,9 +9,14 @@
#include "http_chunk.h"
#include "response.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
/**
* this is a staticfile for a lighttpd plugin
- *
+ *
*/
@@ -25,52 +25,54 @@
typedef struct {
array *exclude_ext;
+ unsigned short etags_used;
+ unsigned short disable_pathinfo;
} plugin_config;
typedef struct {
PLUGIN_DATA;
-
+
buffer *range_buf;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
/* init the plugin data */
INIT_FUNC(mod_staticfile_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
p->range_buf = buffer_init();
-
+
return p;
}
/* detroy the plugin data */
FREE_FUNC(mod_staticfile_free) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
-
+
array_free(s->exclude_ext);
-
+
free(s);
}
free(p->config_storage);
}
buffer_free(p->range_buf);
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
@@ -79,31 +81,37 @@ FREE_FUNC(mod_staticfile_free) {
SETDEFAULTS_FUNC(mod_staticfile_set_defaults) {
plugin_data *p = p_d;
size_t i = 0;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "static-file.exclude-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "static-file.etags", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "static-file.disable-pathinfo", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
s->exclude_ext = array_init();
-
+ s->etags_used = 1;
+ s->disable_pathinfo = 0;
+
cv[0].destination = s->exclude_ext;
-
+ cv[1].destination = &(s->etags_used);
+ cv[2].destination = &(s->disable_pathinfo);
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
}
-
+
return HANDLER_GO_ON;
}
@@ -112,27 +120,33 @@ SETDEFAULTS_FUNC(mod_staticfile_set_defaults) {
static int mod_staticfile_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(exclude_ext);
-
+ PATCH(etags_used);
+ PATCH(disable_pathinfo);
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("static-file.exclude-extensions"))) {
PATCH(exclude_ext);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("static-file.etags"))) {
+ PATCH(etags_used);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("static-file.disable-pathinfo"))) {
+ PATCH(disable_pathinfo);
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -146,69 +160,69 @@ static int http_response_parse_range(server *srv, connection *con, plugin_data *
data_string *ds;
stat_cache_entry *sce = NULL;
buffer *content_type = NULL;
-
+
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
SEGFAULT();
}
-
+
start = 0;
end = sce->st.st_size - 1;
-
+
con->response.content_length = 0;
-
+
if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) {
content_type = ds->value;
}
-
+
for (s = con->request.http_range, error = 0;
!error && *s && NULL != (minus = strchr(s, '-')); ) {
char *err;
off_t la, le;
-
+
if (s == minus) {
/* -<stop> */
-
+
le = strtoll(s, &err, 10);
-
+
if (le == 0) {
/* RFC 2616 - 14.35.1 */
-
+
con->http_status = 416;
error = 1;
} else if (*err == '\0') {
/* end */
s = err;
-
+
end = sce->st.st_size - 1;
start = sce->st.st_size + le;
} else if (*err == ',') {
multipart = 1;
s = err + 1;
-
+
end = sce->st.st_size - 1;
start = sce->st.st_size + le;
} else {
error = 1;
}
-
+
} else if (*(minus+1) == '\0' || *(minus+1) == ',') {
/* <start>- */
-
+
la = strtoll(s, &err, 10);
-
+
if (err == minus) {
/* ok */
-
+
if (*(err + 1) == '\0') {
s = err + 1;
-
+
end = sce->st.st_size - 1;
start = la;
-
+
} else if (*(err + 1) == ',') {
multipart = 1;
s = err + 2;
-
+
end = sce->st.st_size - 1;
start = la;
} else {
@@ -220,119 +234,119 @@ static int http_response_parse_range(server *srv, connection *con, plugin_data *
}
} else {
/* <start>-<stop> */
-
+
la = strtoll(s, &err, 10);
-
+
if (err == minus) {
le = strtoll(minus+1, &err, 10);
-
+
/* RFC 2616 - 14.35.1 */
if (la > le) {
error = 1;
}
-
+
if (*err == '\0') {
/* ok, end*/
s = err;
-
+
end = le;
start = la;
} else if (*err == ',') {
multipart = 1;
s = err + 1;
-
+
end = le;
start = la;
} else {
/* error */
-
+
error = 1;
}
} else {
/* error */
-
+
error = 1;
}
}
-
+
if (!error) {
if (start < 0) start = 0;
-
+
/* RFC 2616 - 14.35.1 */
if (end > sce->st.st_size - 1) end = sce->st.st_size - 1;
-
+
if (start > sce->st.st_size - 1) {
error = 1;
-
+
con->http_status = 416;
}
}
-
+
if (!error) {
if (multipart) {
/* write boundary-header */
buffer *b;
-
+
b = chunkqueue_get_append_buffer(con->write_queue);
-
- buffer_copy_string(b, "\r\n--");
+
+ buffer_copy_string_len(b, CONST_STR_LEN("\r\n--"));
buffer_append_string(b, boundary);
-
+
/* write Content-Range */
- buffer_append_string(b, "\r\nContent-Range: bytes ");
+ buffer_append_string_len(b, CONST_STR_LEN("\r\nContent-Range: bytes "));
buffer_append_off_t(b, start);
- buffer_append_string(b, "-");
+ buffer_append_string_len(b, CONST_STR_LEN("-"));
buffer_append_off_t(b, end);
- buffer_append_string(b, "/");
+ buffer_append_string_len(b, CONST_STR_LEN("/"));
buffer_append_off_t(b, sce->st.st_size);
-
- buffer_append_string(b, "\r\nContent-Type: ");
+
+ buffer_append_string_len(b, CONST_STR_LEN("\r\nContent-Type: "));
buffer_append_string_buffer(b, content_type);
-
+
/* write END-OF-HEADER */
- buffer_append_string(b, "\r\n\r\n");
-
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n"));
+
con->response.content_length += b->used - 1;
-
+
}
-
+
chunkqueue_append_file(con->write_queue, con->physical.path, start, end - start + 1);
con->response.content_length += end - start + 1;
}
}
-
+
/* something went wrong */
if (error) return -1;
-
+
if (multipart) {
/* add boundary end */
buffer *b;
-
+
b = chunkqueue_get_append_buffer(con->write_queue);
-
+
buffer_copy_string_len(b, "\r\n--", 4);
buffer_append_string(b, boundary);
buffer_append_string_len(b, "--\r\n", 4);
-
+
con->response.content_length += b->used - 1;
-
+
/* set header-fields */
-
- buffer_copy_string(p->range_buf, "multipart/byteranges; boundary=");
+
+ buffer_copy_string_len(p->range_buf, CONST_STR_LEN("multipart/byteranges; boundary="));
buffer_append_string(p->range_buf, boundary);
-
+
/* overwrite content-type */
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->range_buf));
} else {
/* add Content-Range-header */
-
- buffer_copy_string(p->range_buf, "bytes ");
+
+ buffer_copy_string_len(p->range_buf, CONST_STR_LEN("bytes "));
buffer_append_off_t(p->range_buf, start);
- buffer_append_string(p->range_buf, "-");
+ buffer_append_string_len(p->range_buf, CONST_STR_LEN("-"));
buffer_append_off_t(p->range_buf, end);
- buffer_append_string(p->range_buf, "/");
+ buffer_append_string_len(p->range_buf, CONST_STR_LEN("/"));
buffer_append_off_t(p->range_buf, sce->st.st_size);
-
+
response_header_insert(srv, con, CONST_STR_LEN("Content-Range"), CONST_BUF_LEN(p->range_buf));
}
@@ -343,16 +357,16 @@ static int http_response_parse_range(server *srv, connection *con, plugin_data *
URIHANDLER_FUNC(mod_staticfile_subrequest) {
plugin_data *p = p_d;
size_t k;
- int s_len;
stat_cache_entry *sce = NULL;
- buffer *mtime;
+ buffer *mtime = NULL;
data_string *ds;
-
+ int allow_caching = 1;
+
/* someone else has done a decision for us */
if (con->http_status != 0) return HANDLER_GO_ON;
if (con->uri.path->used == 0) return HANDLER_GO_ON;
if (con->physical.path->used == 0) return HANDLER_GO_ON;
-
+
/* someone else has handled this request */
if (con->mode != DIRECT) return HANDLER_GO_ON;
@@ -365,128 +379,184 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) {
default:
return HANDLER_GO_ON;
}
-
+
mod_staticfile_patch_connection(srv, con, p);
-
- s_len = con->uri.path->used - 1;
-
+
+ if (p->conf.disable_pathinfo && 0 != con->request.pathinfo->used) {
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- NOT handling file as static file, pathinfo forbidden");
+ }
+ return HANDLER_GO_ON;
+ }
+
/* ignore certain extensions */
for (k = 0; k < p->conf.exclude_ext->used; k++) {
- ds = (data_string *)p->conf.exclude_ext->data[k];
-
+ ds = (data_string *)p->conf.exclude_ext->data[k];
+
if (ds->value->used == 0) continue;
if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "-- NOT handling file as static file, extension forbidden");
+ }
return HANDLER_GO_ON;
}
}
-
+
if (con->conf.log_request_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "-- handling file as static file");
}
-
+
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
con->http_status = 403;
-
+
log_error_write(srv, __FILE__, __LINE__, "sbsb",
"not a regular file:", con->uri.path,
"->", con->physical.path);
-
+
return HANDLER_FINISHED;
}
-
+
/* we only handline regular files */
+#ifdef HAVE_LSTAT
+ if ((sce->is_symlink == 1) && !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
if (!S_ISREG(sce->st.st_mode)) {
con->http_status = 404;
-
+
if (con->conf.log_file_not_found) {
log_error_write(srv, __FILE__, __LINE__, "sbsb",
"not a regular file:", con->uri.path,
"->", sce->name);
}
-
+
return HANDLER_FINISHED;
}
/* mod_compress might set several data directly, don't overwrite them */
-
+
/* set response content-type, if not set already */
if (NULL == array_get_element(con->response.headers, "Content-Type")) {
if (buffer_is_empty(sce->content_type)) {
+ /* we are setting application/octet-stream, but also announce that
+ * this header field might change in the seconds few requests
+ *
+ * This should fix the aggressive caching of FF and the script download
+ * seen by the first installations
+ */
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("application/octet-stream"));
+
+ allow_caching = 0;
} else {
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
}
}
-
- if (NULL == array_get_element(con->response.headers, "ETag")) {
- /* generate e-tag */
- etag_mutate(con->physical.etag, sce->etag);
-
- response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
+
+ if (con->conf.range_requests) {
+ response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes"));
}
- response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes"));
-
- /* prepare header */
- if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
- mtime = strftime_cache_get(srv, sce->st.st_mtime);
- response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
- } else {
- mtime = ds->value;
+
+ if (allow_caching) {
+ if (p->conf.etags_used && con->etag_flags != 0 && !buffer_is_empty(sce->etag)) {
+ if (NULL == array_get_element(con->response.headers, "ETag")) {
+ /* generate e-tag */
+ etag_mutate(con->physical.etag, sce->etag);
+
+ response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
+ }
+ }
+
+ /* prepare header */
+ if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
+ mtime = strftime_cache_get(srv, sce->st.st_mtime);
+ response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
+ } else {
+ mtime = ds->value;
+ }
+
+ if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
+ return HANDLER_FINISHED;
+ }
}
- if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
- return HANDLER_FINISHED;
- } else if (con->request.http_range && con->conf.range_requests) {
+ if (con->request.http_range && con->conf.range_requests) {
int do_range_request = 1;
/* check if we have a conditional GET */
- if (NULL != (ds = array_get_element(con->request.headers, "If-Range"))) {
- /* if the value is the same as our ETag, we do a Range-request,
+ if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If-Range"))) {
+ /* 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;
}
}
-
+
if (do_range_request) {
/* content prepared, I'm done */
con->file_finished = 1;
-
+
if (0 == http_response_parse_range(srv, con, p)) {
con->http_status = 206;
}
return HANDLER_FINISHED;
}
}
-
+
/* if we are still here, prepare body */
-
- /* we add it here for all requests
- * the HEAD request will drop it afterwards again
+
+ /* we add it here for all requests
+ * the HEAD request will drop it afterwards again
*/
http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
-
+
+ con->http_status = 200;
con->file_finished = 1;
-
+
return HANDLER_FINISHED;
}
/* this function is called at dlopen() time and inits the callbacks */
+int mod_staticfile_plugin_init(plugin *p);
int mod_staticfile_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("staticfile");
-
+
p->init = mod_staticfile_init;
p->handle_subrequest_start = mod_staticfile_subrequest;
p->set_defaults = mod_staticfile_set_defaults;
p->cleanup = mod_staticfile_free;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_status.c b/src/mod_status.c
index f5a35e9..76061f9 100644
--- a/src/mod_status.c
+++ b/src/mod_status.c
@@ -1,4 +1,13 @@
-#define _GNU_SOURCE
+#include "server.h"
+#include "connections.h"
+#include "response.h"
+#include "connections.h"
+#include "log.h"
+
+#include "plugin.h"
+
+#include "inet_ntop_cache.h"
+
#include <sys/types.h>
#include <fcntl.h>
@@ -9,15 +18,7 @@
#include <time.h>
#include <stdio.h>
-#include "server.h"
-#include "connections.h"
-#include "response.h"
-#include "connections.h"
-#include "log.h"
-
-#include "plugin.h"
-
-#include "inet_ntop_cache.h"
+#include "version.h"
typedef struct {
buffer *config_url;
@@ -29,161 +30,161 @@ typedef struct {
typedef struct {
PLUGIN_DATA;
-
+
double traffic_out;
double requests;
-
+
double mod_5s_traffic_out[5];
double mod_5s_requests[5];
size_t mod_5s_ndx;
-
+
double rel_traffic_out;
double rel_requests;
-
+
double abs_traffic_out;
double abs_requests;
-
+
double bytes_written;
-
+
buffer *module_list;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
INIT_FUNC(mod_status_init) {
plugin_data *p;
size_t i;
-
+
p = calloc(1, sizeof(*p));
-
+
p->traffic_out = p->requests = 0;
p->rel_traffic_out = p->rel_requests = 0;
p->abs_traffic_out = p->abs_requests = 0;
p->bytes_written = 0;
p->module_list = buffer_init();
-
+
for (i = 0; i < 5; i++) {
p->mod_5s_traffic_out[i] = p->mod_5s_requests[i] = 0;
}
-
+
return p;
}
FREE_FUNC(mod_status_free) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
-
+
buffer_free(p->module_list);
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
-
+
buffer_free(s->status_url);
buffer_free(s->statistics_url);
buffer_free(s->config_url);
-
+
free(s);
}
free(p->config_storage);
}
-
-
+
+
free(p);
-
+
return HANDLER_GO_ON;
}
SETDEFAULTS_FUNC(mod_status_set_defaults) {
plugin_data *p = p_d;
size_t i;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "status.status-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "status.config-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "status.enable-sort", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
{ "status.statistics-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
s->config_url = buffer_init();
s->status_url = buffer_init();
s->sort = 1;
s->statistics_url = buffer_init();
-
+
cv[0].destination = s->status_url;
cv[1].destination = s->config_url;
cv[2].destination = &(s->sort);
cv[3].destination = s->statistics_url;
-
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
}
-
+
return HANDLER_GO_ON;
}
static int mod_status_row_append(buffer *b, const char *key, const char *value) {
- BUFFER_APPEND_STRING_CONST(b, " <tr>\n");
- BUFFER_APPEND_STRING_CONST(b, " <td><b>");
+ buffer_append_string_len(b, CONST_STR_LEN(" <tr>\n"));
+ buffer_append_string_len(b, CONST_STR_LEN(" <td><b>"));
buffer_append_string(b, key);
- BUFFER_APPEND_STRING_CONST(b, "</b></td>\n");
- BUFFER_APPEND_STRING_CONST(b, " <td>");
+ buffer_append_string_len(b, CONST_STR_LEN("</b></td>\n"));
+ buffer_append_string_len(b, CONST_STR_LEN(" <td>"));
buffer_append_string(b, value);
- BUFFER_APPEND_STRING_CONST(b, "</td>\n");
- BUFFER_APPEND_STRING_CONST(b, " </tr>\n");
-
+ buffer_append_string_len(b, CONST_STR_LEN("</td>\n"));
+ buffer_append_string_len(b, CONST_STR_LEN(" </tr>\n"));
+
return 0;
}
static int mod_status_header_append(buffer *b, const char *key) {
- BUFFER_APPEND_STRING_CONST(b, " <tr>\n");
- BUFFER_APPEND_STRING_CONST(b, " <th colspan=\"2\">");
+ buffer_append_string_len(b, CONST_STR_LEN(" <tr>\n"));
+ buffer_append_string_len(b, CONST_STR_LEN(" <th colspan=\"2\">"));
buffer_append_string(b, key);
- BUFFER_APPEND_STRING_CONST(b, "</th>\n");
- BUFFER_APPEND_STRING_CONST(b, " </tr>\n");
-
+ buffer_append_string_len(b, CONST_STR_LEN("</th>\n"));
+ buffer_append_string_len(b, CONST_STR_LEN(" </tr>\n"));
+
return 0;
}
static int mod_status_header_append_sort(buffer *b, void *p_d, const char* key) {
plugin_data *p = p_d;
-
+
if (p->conf.sort) {
- BUFFER_APPEND_STRING_CONST(b, "<th class=\"status\"><a href=\"#\" class=\"sortheader\" onclick=\"resort(this);return false;\">");
+ buffer_append_string_len(b, CONST_STR_LEN("<th class=\"status\"><a href=\"#\" class=\"sortheader\" onclick=\"resort(this);return false;\">"));
buffer_append_string(b, key);
- BUFFER_APPEND_STRING_CONST(b, "<span class=\"sortarrow\"></span></a></th>\n");
+ buffer_append_string_len(b, CONST_STR_LEN("<span class=\"sortarrow\">:</span></a></th>\n"));
} else {
- BUFFER_APPEND_STRING_CONST(b, "<th class=\"status\">");
+ buffer_append_string_len(b, CONST_STR_LEN("<th class=\"status\">"));
buffer_append_string(b, key);
- BUFFER_APPEND_STRING_CONST(b, "</th>\n");
+ buffer_append_string_len(b, CONST_STR_LEN("</th>\n"));
}
-
+
return 0;
}
static int mod_status_get_multiplier(double *avg, char *multiplier, int size) {
*multiplier = ' ';
-
+
if (*avg > size) { *avg /= size; *multiplier = 'k'; }
if (*avg > size) { *avg /= size; *multiplier = 'M'; }
if (*avg > size) { *avg /= size; *multiplier = 'G'; }
@@ -204,37 +205,36 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
char multiplier = '\0';
char buf[32];
time_t ts;
-
+
int days, hours, mins, seconds;
-
+
b = chunkqueue_get_append_buffer(con->write_queue);
- BUFFER_COPY_STRING_CONST(b,
+ buffer_copy_string_len(b, CONST_STR_LEN(
"<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
"<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
" <head>\n"
- " <title>Status</title>\n");
-
- BUFFER_APPEND_STRING_CONST(b,
+ " <title>Status</title>\n"
+
" <style type=\"text/css\">\n"
" table.status { border: black solid thin; }\n"
+ " td { white-space: nowrap; }\n"
" td.int { background-color: #f0f0f0; text-align: right }\n"
" td.string { background-color: #f0f0f0; text-align: left }\n"
" th.status { background-color: black; color: white; font-weight: bold; }\n"
" a.sortheader { background-color: black; color: white; font-weight: bold; text-decoration: none; display: block; }\n"
" span.sortarrow { color: white; text-decoration: none; }\n"
- " </style>\n");
-
+ " </style>\n"));
+
if (p->conf.sort) {
- BUFFER_APPEND_STRING_CONST(b,
+ buffer_append_string_len(b, CONST_STR_LEN(
"<script type=\"text/javascript\">\n"
"// <!--\n"
"var sort_column;\n"
- "var prev_span = null;\n");
-
- BUFFER_APPEND_STRING_CONST(b,
+ "var prev_span = null;\n"
+
"function get_inner_text(el) {\n"
" if((typeof el == 'string')||(typeof el == 'undefined'))\n"
" return el;\n"
@@ -250,9 +250,8 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
" }\n"
" }\n"
" return str;\n"
- "}\n");
-
- BUFFER_APPEND_STRING_CONST(b,
+ "}\n"
+
"function sortfn(a,b) {\n"
" var at = get_inner_text(a.cells[sort_column]);\n"
" var bt = get_inner_text(b.cells[sort_column]);\n"
@@ -265,9 +264,8 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
" else if (aa<bb) return -1;\n"
" else return 1;\n"
" }\n"
- "}\n");
-
- BUFFER_APPEND_STRING_CONST(b,
+ "}\n"
+
"function resort(lnk) {\n"
" var span = lnk.childNodes[1];\n"
" var table = lnk.parentNode.parentNode.parentNode.parentNode;\n"
@@ -275,9 +273,8 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
" for (j=1;j<table.rows.length;j++)\n"
" rows[j-1] = table.rows[j];\n"
" sort_column = lnk.parentNode.cellIndex;\n"
- " rows.sort(sortfn);\n");
-
- BUFFER_APPEND_STRING_CONST(b,
+ " rows.sort(sortfn);\n"
+
" if (prev_span != null) prev_span.innerHTML = '';\n"
" if (span.getAttribute('sortdir')=='down') {\n"
" span.innerHTML = '&uarr;';\n"
@@ -292,178 +289,185 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
" prev_span = span;\n"
"}\n"
"// -->\n"
- "</script>\n");
+ "</script>\n"));
}
-
- BUFFER_APPEND_STRING_CONST(b,
+
+ buffer_append_string_len(b, CONST_STR_LEN(
" </head>\n"
- " <body>\n");
-
-
-
+ " <body>\n"));
+
+
+
/* connection listing */
- BUFFER_APPEND_STRING_CONST(b, "<h1>Server-Status</h1>");
-
- BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">");
- BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\">");
+ buffer_append_string_len(b, CONST_STR_LEN("<h1>Server-Status (" PACKAGE_NAME " " PACKAGE_VERSION ")</h1>"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<table summary=\"status\" class=\"status\">"));
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Hostname</td><td class=\"string\">"));
buffer_append_string_buffer(b, con->uri.authority);
- BUFFER_APPEND_STRING_CONST(b, " (");
+ buffer_append_string_len(b, CONST_STR_LEN(" ("));
buffer_append_string_buffer(b, con->server_name);
- BUFFER_APPEND_STRING_CONST(b, ")</td></tr>\n");
- BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\">");
-
+ buffer_append_string_len(b, CONST_STR_LEN(")</td></tr>\n"));
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Uptime</td><td class=\"string\">"));
+
ts = srv->cur_ts - srv->startup_ts;
-
+
days = ts / (60 * 60 * 24);
ts %= (60 * 60 * 24);
-
+
hours = ts / (60 * 60);
ts %= (60 * 60);
-
+
mins = ts / (60);
ts %= (60);
-
+
seconds = ts;
-
+
if (days) {
buffer_append_long(b, days);
- BUFFER_APPEND_STRING_CONST(b, " days ");
+ buffer_append_string_len(b, CONST_STR_LEN(" days "));
}
-
+
if (hours) {
buffer_append_long(b, hours);
- BUFFER_APPEND_STRING_CONST(b, " hours ");
+ buffer_append_string_len(b, CONST_STR_LEN(" hours "));
}
-
+
if (mins) {
buffer_append_long(b, mins);
- BUFFER_APPEND_STRING_CONST(b, " min ");
+ buffer_append_string_len(b, CONST_STR_LEN(" min "));
}
-
+
buffer_append_long(b, seconds);
- BUFFER_APPEND_STRING_CONST(b, " s");
-
- BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
- BUFFER_APPEND_STRING_CONST(b, "<tr><td>Started at</td><td class=\"string\">");
-
+ buffer_append_string_len(b, CONST_STR_LEN(" s"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td></tr>\n"));
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Started at</td><td class=\"string\">"));
+
ts = srv->startup_ts;
-
+
strftime(buf, sizeof(buf) - 1, "%Y-%m-%d %H:%M:%S", localtime(&ts));
buffer_append_string(b, buf);
- BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
-
-
- BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">absolute (since start)</th></tr>\n");
-
- BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
+ buffer_append_string_len(b, CONST_STR_LEN("</td></tr>\n"));
+
+
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><th colspan=\"2\">absolute (since start)</th></tr>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Requests</td><td class=\"string\">"));
avg = p->abs_requests;
mod_status_get_multiplier(&avg, &multiplier, 1000);
-
+
buffer_append_long(b, avg);
- BUFFER_APPEND_STRING_CONST(b, " ");
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
if (multiplier) buffer_append_string_len(b, &multiplier, 1);
- BUFFER_APPEND_STRING_CONST(b, "req</td></tr>\n");
-
- BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
+ buffer_append_string_len(b, CONST_STR_LEN("req</td></tr>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Traffic</td><td class=\"string\">"));
avg = p->abs_traffic_out;
mod_status_get_multiplier(&avg, &multiplier, 1024);
sprintf(buf, "%.2f", avg);
buffer_append_string(b, buf);
- BUFFER_APPEND_STRING_CONST(b, " ");
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
if (multiplier) buffer_append_string_len(b, &multiplier, 1);
- BUFFER_APPEND_STRING_CONST(b, "byte</td></tr>\n");
+ buffer_append_string_len(b, CONST_STR_LEN("byte</td></tr>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><th colspan=\"2\">average (since start)</th></tr>\n"));
- BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (since start)</th></tr>\n");
-
- BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Requests</td><td class=\"string\">"));
avg = p->abs_requests / (srv->cur_ts - srv->startup_ts);
mod_status_get_multiplier(&avg, &multiplier, 1000);
buffer_append_long(b, avg);
- BUFFER_APPEND_STRING_CONST(b, " ");
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
if (multiplier) buffer_append_string_len(b, &multiplier, 1);
- BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
-
- BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
+ buffer_append_string_len(b, CONST_STR_LEN("req/s</td></tr>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Traffic</td><td class=\"string\">"));
avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts);
mod_status_get_multiplier(&avg, &multiplier, 1024);
sprintf(buf, "%.2f", avg);
buffer_append_string(b, buf);
- BUFFER_APPEND_STRING_CONST(b, " ");
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
if (multiplier) buffer_append_string_len(b, &multiplier, 1);
- BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
+ buffer_append_string_len(b, CONST_STR_LEN("byte/s</td></tr>\n"));
-
-
- BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (5s sliding average)</th></tr>\n");
+
+
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><th colspan=\"2\">average (5s sliding average)</th></tr>\n"));
for (j = 0, avg = 0; j < 5; j++) {
avg += p->mod_5s_requests[j];
}
-
+
avg /= 5;
-
- BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
+
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Requests</td><td class=\"string\">"));
mod_status_get_multiplier(&avg, &multiplier, 1000);
buffer_append_long(b, avg);
- BUFFER_APPEND_STRING_CONST(b, " ");
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
if (multiplier) buffer_append_string_len(b, &multiplier, 1);
-
- BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
-
+
+ buffer_append_string_len(b, CONST_STR_LEN("req/s</td></tr>\n"));
+
for (j = 0, avg = 0; j < 5; j++) {
avg += p->mod_5s_traffic_out[j];
}
-
+
avg /= 5;
-
- BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
+
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Traffic</td><td class=\"string\">"));
mod_status_get_multiplier(&avg, &multiplier, 1024);
sprintf(buf, "%.2f", avg);
buffer_append_string(b, buf);
- BUFFER_APPEND_STRING_CONST(b, " ");
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
if (multiplier) buffer_append_string_len(b, &multiplier, 1);
- BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
-
- BUFFER_APPEND_STRING_CONST(b, "</table>\n");
-
-
- BUFFER_APPEND_STRING_CONST(b, "<hr />\n<pre><b>legend</b>\n");
- BUFFER_APPEND_STRING_CONST(b, ". = connect, C = close, E = hard error\n");
- BUFFER_APPEND_STRING_CONST(b, "r = read, R = read-POST, W = write, h = handle-request\n");
- BUFFER_APPEND_STRING_CONST(b, "q = request-start, Q = request-end\n");
- BUFFER_APPEND_STRING_CONST(b, "s = response-start, S = response-end\n");
-
- BUFFER_APPEND_STRING_CONST(b, "<b>");
+ buffer_append_string_len(b, CONST_STR_LEN("byte/s</td></tr>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("</table>\n"));
+
+
+ buffer_append_string_len(b, CONST_STR_LEN(
+ "<hr />\n<pre><b>legend</b>\n"
+ ". = connect, C = close, E = hard error, k = keep-alive\n"
+ "r = read, R = read-POST, W = write, h = handle-request\n"
+ "q = request-start, Q = request-end\n"
+ "s = response-start, S = response-end\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<b>"));
buffer_append_long(b, srv->conns->used);
- BUFFER_APPEND_STRING_CONST(b, " connections</b>\n");
-
+ buffer_append_string_len(b, CONST_STR_LEN(" connections</b>\n"));
+
for (j = 0; j < srv->conns->used; j++) {
connection *c = srv->conns->ptr[j];
- const char *state = connection_get_short_state(c->state);
-
+ const char *state;
+
+ if (CON_STATE_READ == c->state && c->request.orig_uri->used > 0) {
+ state = "k";
+ } else {
+ state = connection_get_short_state(c->state);
+ }
+
buffer_append_string_len(b, state, 1);
-
+
if (((j + 1) % 50) == 0) {
- BUFFER_APPEND_STRING_CONST(b, "\n");
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
}
}
-
- BUFFER_APPEND_STRING_CONST(b, "\n</pre><hr />\n<h2>Connections</h2>\n");
-
- BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">\n");
- BUFFER_APPEND_STRING_CONST(b, "<tr>");
+
+ buffer_append_string_len(b, CONST_STR_LEN("\n</pre><hr />\n<h2>Connections</h2>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("<table summary=\"status\" class=\"status\">\n"));
+ buffer_append_string_len(b, CONST_STR_LEN("<tr>"));
mod_status_header_append_sort(b, p_d, "Client IP");
mod_status_header_append_sort(b, p_d, "Read");
mod_status_header_append_sort(b, p_d, "Written");
@@ -472,73 +476,87 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c
mod_status_header_append_sort(b, p_d, "Host");
mod_status_header_append_sort(b, p_d, "URI");
mod_status_header_append_sort(b, p_d, "File");
- BUFFER_APPEND_STRING_CONST(b, "</tr>\n");
-
+ buffer_append_string_len(b, CONST_STR_LEN("</tr>\n"));
+
for (j = 0; j < srv->conns->used; j++) {
connection *c = srv->conns->ptr[j];
-
- BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string\">");
-
+
+ buffer_append_string_len(b, CONST_STR_LEN("<tr><td class=\"string\">"));
+
buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(c->dst_addr)));
-
- BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
-
- if (con->request.content_length) {
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"int\">"));
+
+ if (c->request.content_length) {
buffer_append_long(b, c->request_content_queue->bytes_in);
- BUFFER_APPEND_STRING_CONST(b, "/");
+ buffer_append_string_len(b, CONST_STR_LEN("/"));
buffer_append_long(b, c->request.content_length);
} else {
- BUFFER_APPEND_STRING_CONST(b, "0/0");
+ buffer_append_string_len(b, CONST_STR_LEN("0/0"));
}
-
- BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
-
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"int\">"));
+
buffer_append_off_t(b, chunkqueue_written(c->write_queue));
- BUFFER_APPEND_STRING_CONST(b, "/");
+ buffer_append_string_len(b, CONST_STR_LEN("/"));
buffer_append_off_t(b, chunkqueue_length(c->write_queue));
-
- BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
-
- buffer_append_string(b, connection_get_state(c->state));
-
- BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
-
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));
+
+ if (CON_STATE_READ == c->state && c->request.orig_uri->used > 0) {
+ buffer_append_string_len(b, CONST_STR_LEN("keep-alive"));
+ } else {
+ buffer_append_string(b, connection_get_state(c->state));
+ }
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"int\">"));
+
buffer_append_long(b, srv->cur_ts - c->request_start);
-
- BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
-
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));
+
if (buffer_is_empty(c->server_name)) {
buffer_append_string_buffer(b, c->uri.authority);
}
else {
buffer_append_string_buffer(b, c->server_name);
}
-
- BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
-
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));
+
if (!buffer_is_empty(c->uri.path)) {
buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML);
}
-
- BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
-
+
+ if (!buffer_is_empty(c->uri.query)) {
+ buffer_append_string_len(b, CONST_STR_LEN("?"));
+ buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.query), ENCODING_HTML);
+ }
+
+ if (!buffer_is_empty(c->request.orig_uri)) {
+ buffer_append_string_len(b, CONST_STR_LEN(" ("));
+ buffer_append_string_encoded(b, CONST_BUF_LEN(c->request.orig_uri), ENCODING_HTML);
+ buffer_append_string_len(b, CONST_STR_LEN(")"));
+ }
+ buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));
+
buffer_append_string_buffer(b, c->physical.path);
-
- BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
+
+ buffer_append_string_len(b, CONST_STR_LEN("</td></tr>\n"));
}
-
-
- BUFFER_APPEND_STRING_CONST(b,
- "</table>\n");
-
-
- BUFFER_APPEND_STRING_CONST(b,
+
+
+ buffer_append_string_len(b, CONST_STR_LEN(
+ "</table>\n"));
+
+
+ buffer_append_string_len(b, CONST_STR_LEN(
" </body>\n"
"</html>\n"
- );
-
+ ));
+
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
-
+
return 0;
}
@@ -548,84 +566,105 @@ static handler_t mod_status_handle_server_status_text(server *srv, connection *c
buffer *b;
double avg;
time_t ts;
-
+ char buf[32];
+ unsigned int k;
+ unsigned int l;
+
b = chunkqueue_get_append_buffer(con->write_queue);
/* output total number of requests */
- BUFFER_APPEND_STRING_CONST(b, "Total Accesses: ");
+ buffer_append_string_len(b, CONST_STR_LEN("Total Accesses: "));
avg = p->abs_requests;
- buffer_append_long(b, avg);
- BUFFER_APPEND_STRING_CONST(b, "\n");
-
+ snprintf(buf, sizeof(buf) - 1, "%.0f", avg);
+ buffer_append_string(b, buf);
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+
/* output total traffic out in kbytes */
- BUFFER_APPEND_STRING_CONST(b, "Total kBytes: ");
+ buffer_append_string_len(b, CONST_STR_LEN("Total kBytes: "));
avg = p->abs_traffic_out / 1024;
- buffer_append_long(b, avg);
- BUFFER_APPEND_STRING_CONST(b, "\n");
-
+ snprintf(buf, sizeof(buf) - 1, "%.0f", avg);
+ buffer_append_string(b, buf);
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+
/* output uptime */
- BUFFER_APPEND_STRING_CONST(b, "Uptime: ");
+ buffer_append_string_len(b, CONST_STR_LEN("Uptime: "));
ts = srv->cur_ts - srv->startup_ts;
buffer_append_long(b, ts);
- BUFFER_APPEND_STRING_CONST(b, "\n");
-
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+
/* output busy servers */
- BUFFER_APPEND_STRING_CONST(b, "BusyServers: ");
+ buffer_append_string_len(b, CONST_STR_LEN("BusyServers: "));
buffer_append_long(b, srv->conns->used);
- BUFFER_APPEND_STRING_CONST(b, "\n");
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN("IdleServers: "));
+ buffer_append_long(b, srv->conns->size - srv->conns->used);
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
+
+ /* output scoreboard */
+ buffer_append_string_len(b, CONST_STR_LEN("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_len(b, CONST_STR_LEN("_"));
+ }
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
/* set text/plain output */
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
-
+
return 0;
}
static handler_t mod_status_handle_server_statistics(server *srv, connection *con, void *p_d) {
- plugin_data *p = p_d;
- buffer *b, *m = p->module_list;
+ buffer *b;
size_t i;
array *st = srv->status;
+ UNUSED(p_d);
if (0 == st->used) {
/* we have nothing to send */
con->http_status = 204;
con->file_finished = 1;
-
+
return HANDLER_FINISHED;
}
-
+
b = chunkqueue_get_append_buffer(con->write_queue);
for (i = 0; i < st->used; i++) {
size_t ndx = st->sorted[i];
buffer_append_string_buffer(b, st->data[ndx]->key);
- buffer_append_string(b, ": ");
+ buffer_append_string_len(b, CONST_STR_LEN(": "));
buffer_append_long(b, ((data_integer *)(st->data[ndx]))->value);
- buffer_append_string(b, "\n");
+ buffer_append_string_len(b, CONST_STR_LEN("\n"));
}
-
+
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
-
+
con->http_status = 200;
con->file_finished = 1;
-
+
return HANDLER_FINISHED;
}
static handler_t mod_status_handle_server_status(server *srv, connection *con, void *p_d) {
-
+
if (buffer_is_equal_string(con->uri.query, CONST_STR_LEN("auto"))) {
mod_status_handle_server_status_text(srv, con, p_d);
} else {
mod_status_handle_server_status_html(srv, con, p_d);
}
-
+
con->http_status = 200;
con->file_finished = 1;
-
+
return HANDLER_FINISHED;
}
@@ -634,37 +673,39 @@ static handler_t mod_status_handle_server_config(server *srv, connection *con, v
plugin_data *p = p_d;
buffer *b, *m = p->module_list;
size_t i;
-
- struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
- {
- /* - poll is most reliable
+
+ struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
+ {
+ /* - epoll is most reliable
* - select works everywhere
- * - linux-* are experimental
*/
+#ifdef USE_LINUX_EPOLL
+ { FDEVENT_HANDLER_LINUX_SYSEPOLL, "linux-sysepoll" },
+#endif
#ifdef USE_POLL
{ FDEVENT_HANDLER_POLL, "poll" },
#endif
#ifdef USE_SELECT
{ FDEVENT_HANDLER_SELECT, "select" },
#endif
-#ifdef USE_LINUX_EPOLL
- { FDEVENT_HANDLER_LINUX_SYSEPOLL, "linux-sysepoll" },
-#endif
-#ifdef USE_LINUX_SIGIO
- { FDEVENT_HANDLER_LINUX_RTSIG, "linux-rtsig" },
+#ifdef USE_LIBEV
+ { FDEVENT_HANDLER_LIBEV, "libev" },
#endif
#ifdef USE_SOLARIS_DEVPOLL
{ FDEVENT_HANDLER_SOLARIS_DEVPOLL,"solaris-devpoll" },
#endif
+#ifdef USE_SOLARIS_PORT
+ { FDEVENT_HANDLER_SOLARIS_PORT, "solaris-eventports" },
+#endif
#ifdef USE_FREEBSD_KQUEUE
{ FDEVENT_HANDLER_FREEBSD_KQUEUE, "freebsd-kqueue" },
#endif
{ FDEVENT_HANDLER_UNSET, NULL }
};
-
+
b = chunkqueue_get_append_buffer(con->write_queue);
-
- BUFFER_COPY_STRING_CONST(b,
+
+ buffer_copy_string_len(b, CONST_STR_LEN(
"<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
@@ -673,9 +714,9 @@ static handler_t mod_status_handle_server_config(server *srv, connection *con, v
" <title>Status</title>\n"
" </head>\n"
" <body>\n"
- " <h1>" PACKAGE_NAME " " PACKAGE_VERSION "</h1>\n"
- " <table border=\"1\">\n");
-
+ " <h1>" PACKAGE_DESC "</h1>\n"
+ " <table summary=\"status\" border=\"1\">\n"));
+
mod_status_header_append(b, "Server-Features");
#ifdef HAVE_PCRE_H
mod_status_row_append(b, "RegEx Conditionals", "enabled");
@@ -683,43 +724,43 @@ static handler_t mod_status_handle_server_config(server *srv, connection *con, v
mod_status_row_append(b, "RegEx Conditionals", "disabled - pcre missing");
#endif
mod_status_header_append(b, "Network Engine");
-
+
for (i = 0; event_handlers[i].name; i++) {
if (event_handlers[i].et == srv->event_handler) {
mod_status_row_append(b, "fd-Event-Handler", event_handlers[i].name);
break;
}
}
-
+
mod_status_header_append(b, "Config-File-Settings");
-
+
for (i = 0; i < srv->plugins.used; i++) {
plugin **ps = srv->plugins.ptr;
-
+
plugin *pl = ps[i];
-
+
if (i == 0) {
buffer_copy_string_buffer(m, pl->name);
} else {
- BUFFER_APPEND_STRING_CONST(m, "<br />");
+ buffer_append_string_len(m, CONST_STR_LEN("<br />"));
buffer_append_string_buffer(m, pl->name);
}
}
-
+
mod_status_row_append(b, "Loaded Modules", m->ptr);
-
- BUFFER_APPEND_STRING_CONST(b, " </table>\n");
-
- BUFFER_APPEND_STRING_CONST(b,
+
+ buffer_append_string_len(b, CONST_STR_LEN(" </table>\n"));
+
+ buffer_append_string_len(b, CONST_STR_LEN(
" </body>\n"
"</html>\n"
- );
-
+ ));
+
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
-
+
con->http_status = 200;
con->file_finished = 1;
-
+
return HANDLER_FINISHED;
}
@@ -728,24 +769,24 @@ static handler_t mod_status_handle_server_config(server *srv, connection *con, v
static int mod_status_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(status_url);
PATCH(config_url);
PATCH(sort);
PATCH(statistics_url);
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.status-url"))) {
PATCH(status_url);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.config-url"))) {
@@ -754,88 +795,91 @@ static int mod_status_patch_connection(server *srv, connection *con, plugin_data
PATCH(sort);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.statistics-url"))) {
PATCH(statistics_url);
- }
+ }
}
}
-
+
return 0;
}
static handler_t mod_status_handler(server *srv, connection *con, void *p_d) {
plugin_data *p = p_d;
-
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
mod_status_patch_connection(srv, con, p);
-
- if (!buffer_is_empty(p->conf.status_url) &&
+
+ if (!buffer_is_empty(p->conf.status_url) &&
buffer_is_equal(p->conf.status_url, con->uri.path)) {
return mod_status_handle_server_status(srv, con, p_d);
- } else if (!buffer_is_empty(p->conf.config_url) &&
+ } else if (!buffer_is_empty(p->conf.config_url) &&
buffer_is_equal(p->conf.config_url, con->uri.path)) {
return mod_status_handle_server_config(srv, con, p_d);
- } else if (!buffer_is_empty(p->conf.statistics_url) &&
+ } else if (!buffer_is_empty(p->conf.statistics_url) &&
buffer_is_equal(p->conf.statistics_url, con->uri.path)) {
return mod_status_handle_server_statistics(srv, con, p_d);
}
-
+
return HANDLER_GO_ON;
}
TRIGGER_FUNC(mod_status_trigger) {
plugin_data *p = p_d;
size_t i;
-
+
/* check all connections */
for (i = 0; i < srv->conns->used; i++) {
connection *c = srv->conns->ptr[i];
-
+
p->bytes_written += c->bytes_written_cur_second;
}
-
+
/* a sliding average */
p->mod_5s_traffic_out[p->mod_5s_ndx] = p->bytes_written;
p->mod_5s_requests [p->mod_5s_ndx] = p->requests;
-
+
p->mod_5s_ndx = (p->mod_5s_ndx+1) % 5;
-
+
p->abs_traffic_out += p->bytes_written;
p->rel_traffic_out += p->bytes_written;
-
+
p->bytes_written = 0;
-
+
/* reset storage - second */
p->traffic_out = 0;
p->requests = 0;
-
+
return HANDLER_GO_ON;
}
REQUESTDONE_FUNC(mod_status_account) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
p->requests++;
p->rel_requests++;
p->abs_requests++;
-
+
p->bytes_written += con->bytes_written_cur_second;
-
+
return HANDLER_GO_ON;
}
+int mod_status_plugin_init(plugin *p);
int mod_status_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("status");
-
+
p->init = mod_status_init;
p->cleanup = mod_status_free;
p->set_defaults= mod_status_set_defaults;
-
+
p->handle_uri_clean = mod_status_handler;
p->handle_trigger = mod_status_trigger;
p->handle_request_done = mod_status_account;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_trigger_b4_dl.c b/src/mod_trigger_b4_dl.c
index 8281ec0..f813413 100644
--- a/src/mod_trigger_b4_dl.c
+++ b/src/mod_trigger_b4_dl.c
@@ -1,7 +1,3 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
#include "base.h"
#include "log.h"
#include "buffer.h"
@@ -10,32 +6,37 @@
#include "response.h"
#include "inet_ntop_cache.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+
#if defined(HAVE_GDBM_H)
-#include <gdbm.h>
+# include <gdbm.h>
#endif
#if defined(HAVE_PCRE_H)
-#include <pcre.h>
+# include <pcre.h>
#endif
#if defined(HAVE_MEMCACHE_H)
-#include <memcache.h>
+# include <memcache.h>
#endif
/**
* this is a trigger_b4_dl for a lighttpd plugin
- *
+ *
*/
/* plugin config for all request/connections */
typedef struct {
buffer *db_filename;
-
+
buffer *trigger_url;
buffer *download_url;
buffer *deny_url;
-
+
array *mc_hosts;
buffer *mc_namespace;
#if defined(HAVE_PCRE_H)
@@ -46,58 +47,58 @@ typedef struct {
GDBM_FILE db;
#endif
-#if defined(HAVE_MEMCACHE_H)
+#if defined(HAVE_MEMCACHE_H)
struct memcache *mc;
#endif
-
+
unsigned short trigger_timeout;
unsigned short debug;
} plugin_config;
typedef struct {
PLUGIN_DATA;
-
+
buffer *tmp_buf;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
/* init the plugin data */
INIT_FUNC(mod_trigger_b4_dl_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
p->tmp_buf = buffer_init();
-
+
return p;
}
/* detroy the plugin data */
FREE_FUNC(mod_trigger_b4_dl_free) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
if (!s) continue;
-
+
buffer_free(s->db_filename);
buffer_free(s->download_url);
buffer_free(s->trigger_url);
buffer_free(s->deny_url);
-
+
buffer_free(s->mc_namespace);
array_free(s->mc_hosts);
-
+
#if defined(HAVE_PCRE_H)
if (s->trigger_regex) pcre_free(s->trigger_regex);
if (s->download_regex) pcre_free(s->download_regex);
@@ -108,16 +109,16 @@ FREE_FUNC(mod_trigger_b4_dl_free) {
#if defined(HAVE_MEMCACHE_H)
if (s->mc) mc_free(s->mc);
#endif
-
+
free(s);
}
free(p->config_storage);
}
-
+
buffer_free(p->tmp_buf);
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
@@ -126,9 +127,9 @@ FREE_FUNC(mod_trigger_b4_dl_free) {
SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
plugin_data *p = p_d;
size_t i = 0;
-
-
- config_values_t cv[] = {
+
+
+ config_values_t cv[] = {
{ "trigger-before-download.gdbm-filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ "trigger-before-download.trigger-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ "trigger-before-download.download-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
@@ -139,18 +140,18 @@ SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
{ "trigger-before-download.debug", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
#if defined(HAVE_PCRE_H)
const char *errptr;
int erroff;
#endif
-
+
s = calloc(1, sizeof(plugin_config));
s->db_filename = buffer_init();
s->download_url = buffer_init();
@@ -158,7 +159,7 @@ SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
s->deny_url = buffer_init();
s->mc_hosts = array_init();
s->mc_namespace = buffer_init();
-
+
cv[0].destination = s->db_filename;
cv[1].destination = s->trigger_url;
cv[2].destination = s->download_url;
@@ -167,41 +168,44 @@ SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
cv[5].destination = s->mc_hosts;
cv[6].destination = s->mc_namespace;
cv[7].destination = &(s->debug);
-
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
#if defined(HAVE_GDBM_H)
if (!buffer_is_empty(s->db_filename)) {
if (NULL == (s->db = gdbm_open(s->db_filename->ptr, 4096, GDBM_WRCREAT | GDBM_NOLOCK, S_IRUSR | S_IWUSR, 0))) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"gdbm-open failed");
return HANDLER_ERROR;
}
+#ifdef FD_CLOEXEC
+ fcntl(gdbm_fdesc(s->db), F_SETFD, FD_CLOEXEC);
+#endif
}
#endif
-#if defined(HAVE_PCRE_H)
+#if defined(HAVE_PCRE_H)
if (!buffer_is_empty(s->download_url)) {
if (NULL == (s->download_regex = pcre_compile(s->download_url->ptr,
0, &errptr, &erroff, NULL))) {
-
- log_error_write(srv, __FILE__, __LINE__, "sbss",
- "compiling regex for download-url failed:",
+
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
+ "compiling regex for download-url failed:",
s->download_url, "pos:", erroff);
return HANDLER_ERROR;
}
}
-
+
if (!buffer_is_empty(s->trigger_url)) {
if (NULL == (s->trigger_regex = pcre_compile(s->trigger_url->ptr,
0, &errptr, &erroff, NULL))) {
-
- log_error_write(srv, __FILE__, __LINE__, "sbss",
- "compiling regex for trigger-url failed:",
+
+ log_error_write(srv, __FILE__, __LINE__, "sbss",
+ "compiling regex for trigger-url failed:",
s->trigger_url, "pos:", erroff);
-
+
return HANDLER_ERROR;
}
}
@@ -211,33 +215,33 @@ SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
#if defined(HAVE_MEMCACHE_H)
size_t k;
s->mc = mc_new();
-
+
for (k = 0; k < s->mc_hosts->used; k++) {
data_string *ds = (data_string *)s->mc_hosts->data[k];
-
+
if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "connection to host failed:",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "connection to host failed:",
ds->value);
-
+
return HANDLER_ERROR;
}
}
#else
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"memcache support is not compiled in but trigger-before-download.memcache-hosts is set, aborting");
return HANDLER_ERROR;
#endif
}
-
+
#if (!defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)) || !defined(HAVE_PCRE_H)
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"(either gdbm or libmemcache) and pcre are require, but were not found, aborting");
return HANDLER_ERROR;
#endif
}
-
+
return HANDLER_GO_ON;
}
@@ -246,14 +250,14 @@ SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
static int mod_trigger_b4_dl_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
#if defined(HAVE_GDBM)
PATCH(db);
-#endif
+#endif
#if defined(HAVE_PCRE_H)
PATCH(download_regex);
PATCH(trigger_regex);
-#endif
+#endif
PATCH(trigger_timeout);
PATCH(deny_url);
PATCH(mc_namespace);
@@ -261,15 +265,15 @@ static int mod_trigger_b4_dl_patch_connection(server *srv, connection *con, plug
#if defined(HAVE_MEMCACHE_H)
PATCH(mc);
#endif
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
@@ -301,7 +305,7 @@ static int mod_trigger_b4_dl_patch_connection(server *srv, connection *con, plug
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -315,20 +319,22 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
int n;
# define N 10
int ovec[N * 3];
-
+
+ if (con->mode != DIRECT) return HANDLER_GO_ON;
+
if (con->uri.path->used == 0) return HANDLER_GO_ON;
-
+
mod_trigger_b4_dl_patch_connection(srv, con, p);
-
+
if (!p->conf.trigger_regex || !p->conf.download_regex) return HANDLER_GO_ON;
-
+
# if !defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)
return HANDLER_GO_ON;
# elif defined(HAVE_GDBM_H) && defined(HAVE_MEMCACHE_H)
if (!p->conf.db && !p->conf.mc) return HANDLER_GO_ON;
if (p->conf.db && p->conf.mc) {
/* can't decide which one */
-
+
return HANDLER_GO_ON;
}
# elif defined(HAVE_GDBM_H)
@@ -336,12 +342,12 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
# else
if (!p->conf.mc) return HANDLER_GO_ON;
# endif
-
+
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "X-Forwarded-For"))) {
/* X-Forwarded-For contains the ip behind the proxy */
-
+
remote_ip = ds->value->ptr;
-
+
/* memcache can't handle spaces */
} else {
remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
@@ -350,13 +356,13 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "ss", "(debug) remote-ip:", remote_ip);
}
-
+
/* check if URL is a trigger -> insert IP into DB */
if ((n = pcre_exec(p->conf.trigger_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
if (n != PCRE_ERROR_NOMATCH) {
log_error_write(srv, __FILE__, __LINE__, "sd",
"execution error while matching:", n);
-
+
return HANDLER_ERROR;
}
} else {
@@ -364,34 +370,34 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
if (p->conf.db) {
/* the trigger matched */
datum key, val;
-
+
key.dptr = (char *)remote_ip;
key.dsize = strlen(remote_ip);
-
+
val.dptr = (char *)&(srv->cur_ts);
val.dsize = sizeof(srv->cur_ts);
-
+
if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"insert failed");
}
}
# endif
-# if defined(HAVE_MEMCACHE_H)
+# if defined(HAVE_MEMCACHE_H)
if (p->conf.mc) {
size_t i;
buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
buffer_append_string(p->tmp_buf, remote_ip);
-
+
for (i = 0; i < p->tmp_buf->used - 1; i++) {
if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
}
-
+
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) triggered IP:", p->tmp_buf);
}
- if (0 != mc_set(p->conf.mc,
+ if (0 != mc_set(p->conf.mc,
CONST_BUF_LEN(p->tmp_buf),
(char *)&(srv->cur_ts), sizeof(srv->cur_ts),
p->conf.trigger_timeout, 0)) {
@@ -401,7 +407,7 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
}
# endif
}
-
+
/* check if URL is a download -> check IP in DB, update timestamp */
if ((n = pcre_exec(p->conf.download_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
if (n != PCRE_ERROR_NOMATCH) {
@@ -411,93 +417,95 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
}
} else {
/* the download uri matched */
-# if defined(HAVE_GDBM_H)
+# if defined(HAVE_GDBM_H)
if (p->conf.db) {
datum key, val;
time_t last_hit;
-
+
key.dptr = (char *)remote_ip;
key.dsize = strlen(remote_ip);
-
+
val = gdbm_fetch(p->conf.db, key);
-
+
if (val.dptr == NULL) {
/* not found, redirect */
-
+
response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
-
con->http_status = 307;
-
+ con->file_finished = 1;
+
return HANDLER_FINISHED;
}
-
+
last_hit = *(time_t *)(val.dptr);
-
+
free(val.dptr);
-
+
if (srv->cur_ts - last_hit > p->conf.trigger_timeout) {
/* found, but timeout, redirect */
-
+
response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
con->http_status = 307;
-
+ con->file_finished = 1;
+
if (p->conf.db) {
if (0 != gdbm_delete(p->conf.db, key)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"delete failed");
}
}
-
+
return HANDLER_FINISHED;
}
-
+
val.dptr = (char *)&(srv->cur_ts);
val.dsize = sizeof(srv->cur_ts);
-
+
if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"insert failed");
}
}
# endif
-
-# if defined(HAVE_MEMCACHE_H)
+
+# if defined(HAVE_MEMCACHE_H)
if (p->conf.mc) {
void *r;
size_t i;
-
+
buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
buffer_append_string(p->tmp_buf, remote_ip);
-
+
for (i = 0; i < p->tmp_buf->used - 1; i++) {
if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
}
-
+
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) checking IP:", p->tmp_buf);
}
/**
- *
+ *
* memcached is do expiration for us, as long as we can fetch it every thing is ok
- * and the timestamp is updated
- *
+ * and the timestamp is updated
+ *
*/
- if (NULL == (r = mc_aget(p->conf.mc,
+ if (NULL == (r = mc_aget(p->conf.mc,
CONST_BUF_LEN(p->tmp_buf)
))) {
-
+
response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
-
+
con->http_status = 307;
-
+ con->file_finished = 1;
+
return HANDLER_FINISHED;
}
-
+
free(r);
-
+
/* set a new timeout */
- if (0 != mc_set(p->conf.mc,
+ if (0 != mc_set(p->conf.mc,
CONST_BUF_LEN(p->tmp_buf),
(char *)&(srv->cur_ts), sizeof(srv->cur_ts),
p->conf.trigger_timeout, 0)) {
@@ -507,13 +515,13 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
}
# endif
}
-
+
#else
UNUSED(srv);
UNUSED(con);
UNUSED(p_d);
#endif
-
+
return HANDLER_GO_ON;
}
@@ -521,21 +529,21 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
plugin_data *p = p_d;
size_t i;
-
+
/* check DB each minute */
if (srv->cur_ts % 60 != 0) return HANDLER_GO_ON;
-
+
/* cleanup */
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
datum key, val, okey;
-
+
if (!s->db) continue;
-
+
okey.dptr = NULL;
-
- /* according to the manual this loop + delete does delete all entries on its way
- *
+
+ /* according to the manual this loop + delete does delete all entries on its way
+ *
* we don't care as the next round will remove them. We don't have to perfect here.
*/
for (key = gdbm_firstkey(s->db); key.dptr; key = gdbm_nextkey(s->db, okey)) {
@@ -544,21 +552,21 @@ TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
free(okey.dptr);
okey.dptr = NULL;
}
-
+
val = gdbm_fetch(s->db, key);
-
+
last_hit = *(time_t *)(val.dptr);
-
+
free(val.dptr);
-
+
if (srv->cur_ts - last_hit > s->trigger_timeout) {
gdbm_delete(s->db, key);
}
-
+
okey = key;
}
if (okey.dptr) free(okey.dptr);
-
+
/* reorg once a day */
if ((srv->cur_ts % (60 * 60 * 24) != 0)) gdbm_reorganize(s->db);
}
@@ -568,10 +576,11 @@ TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
/* this function is called at dlopen() time and inits the callbacks */
+int mod_trigger_b4_dl_plugin_init(plugin *p);
int mod_trigger_b4_dl_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("trigger_b4_dl");
-
+
p->init = mod_trigger_b4_dl_init;
p->handle_uri_clean = mod_trigger_b4_dl_uri_handler;
p->set_defaults = mod_trigger_b4_dl_set_defaults;
@@ -579,8 +588,8 @@ int mod_trigger_b4_dl_plugin_init(plugin *p) {
p->handle_trigger = mod_trigger_b4_dl_handle_trigger;
#endif
p->cleanup = mod_trigger_b4_dl_free;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_userdir.c b/src/mod_userdir.c
index 9612fa8..4a1967f 100644
--- a/src/mod_userdir.c
+++ b/src/mod_userdir.c
@@ -1,8 +1,3 @@
-#include <sys/types.h>
-
-#include <stdlib.h>
-#include <string.h>
-
#include "base.h"
#include "log.h"
#include "buffer.h"
@@ -11,8 +6,13 @@
#include "plugin.h"
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <string.h>
+
#ifdef HAVE_PWD_H
-#include <pwd.h>
+# include <pwd.h>
#endif
/* plugin config for all request/connections */
@@ -21,58 +21,59 @@ typedef struct {
array *include_user;
buffer *path;
buffer *basepath;
+ unsigned short letterhomes;
} plugin_config;
typedef struct {
PLUGIN_DATA;
-
+
buffer *username;
buffer *temp_path;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
/* init the plugin data */
INIT_FUNC(mod_userdir_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
p->username = buffer_init();
p->temp_path = buffer_init();
-
+
return p;
}
/* detroy the plugin data */
FREE_FUNC(mod_userdir_free) {
plugin_data *p = p_d;
-
+
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
size_t i;
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
-
+
array_free(s->include_user);
array_free(s->exclude_user);
buffer_free(s->path);
buffer_free(s->basepath);
-
+
free(s);
}
free(p->config_storage);
}
-
+
buffer_free(p->username);
buffer_free(p->temp_path);
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
@@ -81,40 +82,43 @@ FREE_FUNC(mod_userdir_free) {
SETDEFAULTS_FUNC(mod_userdir_set_defaults) {
plugin_data *p = p_d;
size_t i;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "userdir.path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ "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 }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
s->exclude_user = array_init();
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;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
}
-
+
return HANDLER_GO_ON;
}
@@ -123,24 +127,25 @@ SETDEFAULTS_FUNC(mod_userdir_set_defaults) {
static int mod_userdir_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(path);
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++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.path"))) {
PATCH(path);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.exclude-user"))) {
@@ -149,17 +154,18 @@ 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);
}
}
}
-
+
return 0;
}
#undef PATCH
URIHANDLER_FUNC(mod_userdir_docroot_handler) {
plugin_data *p = p_d;
- int uri_len;
size_t k;
char *rel_url;
#ifdef HAVE_PWD_H
@@ -169,18 +175,21 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) {
if (con->uri.path->used == 0) return HANDLER_GO_ON;
mod_userdir_patch_connection(srv, con, p);
-
- uri_len = con->uri.path->used - 1;
-
+
+ /* 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;
+
/* /~user/foo.html -> /home/user/public_html/foo.html */
-
+
if (con->uri.path->ptr[0] != '/' ||
con->uri.path->ptr[1] != '~') return HANDLER_GO_ON;
-
+
if (NULL == (rel_url = strchr(con->uri.path->ptr + 2, '/'))) {
/* / is missing -> redirect to .../ as we are a user - DIRECTORY ! :) */
http_response_redirect_to_directory(srv, con);
-
+
return HANDLER_FINISHED;
}
@@ -188,10 +197,10 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) {
if (0 == rel_url - (con->uri.path->ptr + 2)) {
return HANDLER_GO_ON;
}
-
+
buffer_copy_string_len(p->username, con->uri.path->ptr + 2, rel_url - (con->uri.path->ptr + 2));
-
- if (buffer_is_empty(p->conf.basepath)
+
+ if (buffer_is_empty(p->conf.basepath)
#ifdef HAVE_PWD_H
&& NULL == (pwd = getpwnam(p->username->ptr))
#endif
@@ -200,31 +209,31 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) {
return HANDLER_GO_ON;
}
-
+
for (k = 0; k < p->conf.exclude_user->used; k++) {
data_string *ds = (data_string *)p->conf.exclude_user->data[k];
-
+
if (buffer_is_equal(ds->value, p->username)) {
/* user in exclude list */
return HANDLER_GO_ON;
}
}
-
+
if (p->conf.include_user->used) {
int found_user = 0;
for (k = 0; k < p->conf.include_user->used; k++) {
data_string *ds = (data_string *)p->conf.include_user->data[k];
-
+
if (buffer_is_equal(ds->value, p->username)) {
/* user in include list */
found_user = 1;
break;
}
}
-
+
if (!found_user) return HANDLER_GO_ON;
}
-
+
/* we build the physical path */
if (buffer_is_empty(p->conf.basepath)) {
@@ -250,26 +259,49 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) {
return HANDLER_GO_ON;
}
}
+ if (con->conf.force_lowercase_filenames) {
+ buffer_to_lower(p->username);
+ }
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);
- buffer_append_string_buffer(p->temp_path, p->conf.path);
+ buffer_append_string_buffer(p->temp_path, p->conf.path);
if (buffer_is_empty(p->conf.basepath)) {
struct stat st;
int ret;
-
+
ret = stat(p->temp_path->ptr, &st);
if (ret < 0 || S_ISDIR(st.st_mode) != 1) {
return HANDLER_GO_ON;
- }
+ }
}
+ /* the physical rel_path is basically the same as uri.path;
+ * but it is converted to lowercase in case of force_lowercase_filenames and some special handling
+ * for trailing '.', ' ' and '/' on windows
+ * we assume that no docroot/physical handler changed this
+ * (docroot should only set the docroot/server name, phyiscal should only change the phyiscal.path;
+ * the exception mod_secure_download doesn't work with userdir anyway)
+ */
BUFFER_APPEND_SLASH(p->temp_path);
- buffer_append_string(p->temp_path, rel_url + 1); /* skip the / */
+ /* if no second '/' is found, we assume that it was stripped from the uri.path for the special handling
+ * on windows.
+ * we do not care about the trailing slash here on windows, as we already ensured it is a directory
+ *
+ * TODO: what to do with trailing dots in usernames on windows? they may result in the same directory
+ * as a username without them.
+ */
+ if (NULL != (rel_url = strchr(con->physical.rel_path->ptr + 2, '/'))) {
+ buffer_append_string(p->temp_path, rel_url + 1); /* skip the / */
+ }
buffer_copy_string_buffer(con->physical.path, p->temp_path);
buffer_reset(p->temp_path);
@@ -279,16 +311,17 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) {
/* this function is called at dlopen() time and inits the callbacks */
+int mod_userdir_plugin_init(plugin *p);
int mod_userdir_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("userdir");
-
+
p->init = mod_userdir_init;
p->handle_physical = mod_userdir_docroot_handler;
p->set_defaults = mod_userdir_set_defaults;
p->cleanup = mod_userdir_free;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_usertrack.c b/src/mod_usertrack.c
index 25fb8ec..9ecabdc 100644
--- a/src/mod_usertrack.c
+++ b/src/mod_usertrack.c
@@ -1,67 +1,63 @@
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
#include "base.h"
#include "log.h"
#include "buffer.h"
#include "plugin.h"
-#ifdef USE_OPENSSL
-# include <openssl/md5.h>
-#else
-# include "md5.h"
-#endif
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "md5.h"
/* plugin config for all request/connections */
typedef struct {
buffer *cookie_name;
buffer *cookie_domain;
- unsigned short cookie_max_age;
+ unsigned int cookie_max_age;
} plugin_config;
typedef struct {
PLUGIN_DATA;
-
+
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
/* init the plugin data */
INIT_FUNC(mod_usertrack_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
return p;
}
/* detroy the plugin data */
FREE_FUNC(mod_usertrack_free) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
-
+
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
-
+
buffer_free(s->cookie_name);
buffer_free(s->cookie_domain);
-
+
free(s);
}
free(p->config_storage);
}
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
@@ -70,69 +66,69 @@ FREE_FUNC(mod_usertrack_free) {
SETDEFAULTS_FUNC(mod_usertrack_set_defaults) {
plugin_data *p = p_d;
size_t i = 0;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "usertrack.cookie-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "usertrack.cookie-max-age", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "usertrack.cookie-max-age", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ "usertrack.cookie-domain", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
-
- { "usertrack.cookiename", NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },
+
+ { "usertrack.cookiename", NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
s->cookie_name = buffer_init();
s->cookie_domain = buffer_init();
s->cookie_max_age = 0;
-
+
cv[0].destination = s->cookie_name;
cv[1].destination = &(s->cookie_max_age);
cv[2].destination = s->cookie_domain;
-
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
-
+
if (buffer_is_empty(s->cookie_name)) {
- buffer_copy_string(s->cookie_name, "TRACKID");
+ buffer_copy_string_len(s->cookie_name, CONST_STR_LEN("TRACKID"));
} else {
size_t j;
for (j = 0; j < s->cookie_name->used - 1; j++) {
char c = s->cookie_name->ptr[j] | 32;
if (c < 'a' || c > 'z') {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "invalid character in usertrack.cookie-name:",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "invalid character in usertrack.cookie-name:",
s->cookie_name);
-
+
return HANDLER_ERROR;
}
}
}
-
+
if (!buffer_is_empty(s->cookie_domain)) {
size_t j;
for (j = 0; j < s->cookie_domain->used - 1; j++) {
char c = s->cookie_domain->ptr[j];
if (c <= 32 || c >= 127 || c == '"' || c == '\\') {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "invalid character in usertrack.cookie-domain:",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "invalid character in usertrack.cookie-domain:",
s->cookie_domain);
-
+
return HANDLER_ERROR;
}
}
}
}
-
+
return HANDLER_GO_ON;
}
@@ -141,23 +137,23 @@ SETDEFAULTS_FUNC(mod_usertrack_set_defaults) {
static int mod_usertrack_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(cookie_name);
PATCH(cookie_domain);
PATCH(cookie_max_age);
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-name"))) {
PATCH(cookie_name);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-max-age"))) {
@@ -167,7 +163,7 @@ static int mod_usertrack_patch_connection(server *srv, connection *con, plugin_d
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -176,96 +172,97 @@ URIHANDLER_FUNC(mod_usertrack_uri_handler) {
plugin_data *p = p_d;
data_string *ds;
unsigned char h[16];
- MD5_CTX Md5Ctx;
+ li_MD5_CTX Md5Ctx;
char hh[32];
-
+
if (con->uri.path->used == 0) return HANDLER_GO_ON;
-
+
mod_usertrack_patch_connection(srv, con, p);
-
+
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
char *g;
/* we have a cookie, does it contain a valid name ? */
-
- /* parse the cookie
- *
+
+ /* parse the cookie
+ *
* check for cookiename + (WS | '=')
- *
+ *
*/
-
+
if (NULL != (g = strstr(ds->value->ptr, p->conf.cookie_name->ptr))) {
char *nc;
-
+
/* skip WS */
for (nc = g + p->conf.cookie_name->used-1; *nc == ' ' || *nc == '\t'; nc++);
-
+
if (*nc == '=') {
/* ok, found the key of our own cookie */
-
+
if (strlen(nc) > 32) {
/* i'm lazy */
return HANDLER_GO_ON;
}
}
}
- }
-
+ }
+
/* set a cookie */
if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
ds = data_response_init();
}
- buffer_copy_string(ds->key, "Set-Cookie");
+ buffer_copy_string_len(ds->key, CONST_STR_LEN("Set-Cookie"));
buffer_copy_string_buffer(ds->value, p->conf.cookie_name);
- buffer_append_string(ds->value, "=\"");
-
+ buffer_append_string_len(ds->value, CONST_STR_LEN("="));
+
/* taken from mod_auth.c */
-
+
/* generate shared-secret */
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)con->uri.path->ptr, con->uri.path->used - 1);
- MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
-
+ li_MD5_Init(&Md5Ctx);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)con->uri.path->ptr, con->uri.path->used - 1);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
+
/* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
- ltostr(hh, srv->cur_ts);
- MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
- ltostr(hh, rand());
- MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
-
- MD5_Final(h, &Md5Ctx);
-
+ LI_ltostr(hh, srv->cur_ts);
+ li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
+ li_MD5_Update(&Md5Ctx, (unsigned char *)srv->entropy, sizeof(srv->entropy));
+ LI_ltostr(hh, rand());
+ li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
+
+ li_MD5_Final(h, &Md5Ctx);
+
buffer_append_string_encoded(ds->value, (char *)h, 16, ENCODING_HEX);
- buffer_append_string(ds->value, "\"; Path=\"/\"");
- buffer_append_string(ds->value, "; Version=\"1\"");
-
+ buffer_append_string_len(ds->value, CONST_STR_LEN("; Path=/"));
+ buffer_append_string_len(ds->value, CONST_STR_LEN("; Version=1"));
+
if (!buffer_is_empty(p->conf.cookie_domain)) {
- buffer_append_string(ds->value, "; Domain=\"");
- buffer_append_string_buffer(ds->value, p->conf.cookie_domain);
- buffer_append_string(ds->value, "\"");
+ buffer_append_string_len(ds->value, CONST_STR_LEN("; Domain="));
+ buffer_append_string_encoded(ds->value, CONST_BUF_LEN(p->conf.cookie_domain), ENCODING_REL_URI);
}
-
+
if (p->conf.cookie_max_age) {
- buffer_append_string(ds->value, "; max-age=");
+ buffer_append_string_len(ds->value, CONST_STR_LEN("; max-age="));
buffer_append_long(ds->value, p->conf.cookie_max_age);
}
-
+
array_insert_unique(con->response.headers, (data_unset *)ds);
-
+
return HANDLER_GO_ON;
}
/* this function is called at dlopen() time and inits the callbacks */
+int mod_usertrack_plugin_init(plugin *p);
int mod_usertrack_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("usertrack");
-
+
p->init = mod_usertrack_init;
p->handle_uri_clean = mod_usertrack_uri_handler;
p->set_defaults = mod_usertrack_set_defaults;
p->cleanup = mod_usertrack_free;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/mod_webdav.c b/src/mod_webdav.c
index 3306c73..2231ab8 100644
--- a/src/mod_webdav.c
+++ b/src/mod_webdav.c
@@ -1,19 +1,27 @@
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+#include "response.h"
+
+#include "plugin.h"
+
+#include "stream.h"
+#include "stat_cache.h"
+
+#include "sys-mmap.h"
+
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
-#include <dirent.h>
#include <errno.h>
-#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <assert.h>
-#include <sys/mman.h>
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include <unistd.h>
+#include <dirent.h>
#if defined(HAVE_LIBXML_H) && defined(HAVE_SQLITE3_H)
#define USE_PROPPATCH
@@ -23,26 +31,21 @@
#include <sqlite3.h>
#endif
-#include "base.h"
-#include "log.h"
-#include "buffer.h"
-#include "response.h"
-
-#include "plugin.h"
-
-#include "stream.h"
-#include "stat_cache.h"
-
+#if defined(HAVE_LIBXML_H) && defined(HAVE_SQLITE3_H) && defined(HAVE_UUID_UUID_H)
+#define USE_LOCKS
+#include <uuid/uuid.h>
+#endif
/**
* this is a webdav for a lighttpd plugin
*
- * at least a very basic one.
+ * at least a very basic one.
* - for now it is read-only and we only support PROPFIND
- *
+ *
*/
-
+#define WEBDAV_FILE_MODE S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH
+#define WEBDAV_DIR_MODE S_IRWXU | S_IRWXG | S_IRWXO
/* plugin config for all request/connections */
@@ -58,64 +61,70 @@ typedef struct {
sqlite3_stmt *stmt_delete_prop;
sqlite3_stmt *stmt_select_prop;
sqlite3_stmt *stmt_select_propnames;
-
+
sqlite3_stmt *stmt_delete_uri;
sqlite3_stmt *stmt_move_uri;
sqlite3_stmt *stmt_copy_uri;
+
+ sqlite3_stmt *stmt_remove_lock;
+ sqlite3_stmt *stmt_create_lock;
+ sqlite3_stmt *stmt_read_lock;
+ sqlite3_stmt *stmt_read_lock_by_uri;
+ sqlite3_stmt *stmt_refresh_lock;
#endif
} plugin_config;
typedef struct {
PLUGIN_DATA;
-
+
buffer *tmp_buf;
request_uri uri;
physical physical;
plugin_config **config_storage;
-
- plugin_config conf;
+
+ plugin_config conf;
} plugin_data;
/* init the plugin data */
INIT_FUNC(mod_webdav_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
p->tmp_buf = buffer_init();
p->uri.scheme = buffer_init();
p->uri.path_raw = buffer_init();
p->uri.path = buffer_init();
p->uri.authority = buffer_init();
-
+
p->physical.path = buffer_init();
p->physical.rel_path = buffer_init();
p->physical.doc_root = buffer_init();
p->physical.basedir = buffer_init();
-
+
return p;
}
/* detroy the plugin data */
FREE_FUNC(mod_webdav_free) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
if (!s) continue;
-
+
buffer_free(s->sqlite_db_name);
#ifdef USE_PROPPATCH
- if (s->sql) {
+ if (s->sql) {
sqlite3_finalize(s->stmt_delete_prop);
sqlite3_finalize(s->stmt_delete_uri);
sqlite3_finalize(s->stmt_copy_uri);
@@ -123,9 +132,15 @@ FREE_FUNC(mod_webdav_free) {
sqlite3_finalize(s->stmt_update_prop);
sqlite3_finalize(s->stmt_select_prop);
sqlite3_finalize(s->stmt_select_propnames);
+
+ sqlite3_finalize(s->stmt_read_lock);
+ sqlite3_finalize(s->stmt_read_lock_by_uri);
+ sqlite3_finalize(s->stmt_create_lock);
+ sqlite3_finalize(s->stmt_remove_lock);
+ sqlite3_finalize(s->stmt_refresh_lock);
sqlite3_close(s->sql);
}
-#endif
+#endif
free(s);
}
free(p->config_storage);
@@ -135,16 +150,16 @@ FREE_FUNC(mod_webdav_free) {
buffer_free(p->uri.path_raw);
buffer_free(p->uri.path);
buffer_free(p->uri.authority);
-
+
buffer_free(p->physical.path);
buffer_free(p->physical.rel_path);
buffer_free(p->physical.doc_root);
buffer_free(p->physical.basedir);
-
+
buffer_free(p->tmp_buf);
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
@@ -153,32 +168,32 @@ FREE_FUNC(mod_webdav_free) {
SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
plugin_data *p = p_d;
size_t i = 0;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "webdav.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ "webdav.is-readonly", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ "webdav.sqlite-db-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
{ "webdav.log-xml", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
s->sqlite_db_name = buffer_init();
-
+
cv[0].destination = &(s->enabled);
cv[1].destination = &(s->is_readonly);
cv[2].destination = s->sqlite_db_name;
cv[3].destination = &(s->log_xml);
-
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
@@ -189,12 +204,32 @@ SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
char *err;
if (SQLITE_OK != sqlite3_open(s->sqlite_db_name->ptr, &(s->sql))) {
- log_error_write(srv, __FILE__, __LINE__, "s", "sqlite3_open failed");
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "sqlite3_open failed for",
+ s->sqlite_db_name,
+ sqlite3_errmsg(s->sql));
return HANDLER_ERROR;
}
- if (SQLITE_OK != sqlite3_prepare(s->sql,
- CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
+ if (SQLITE_OK != sqlite3_exec(s->sql,
+ "CREATE TABLE properties ("
+ " resource TEXT NOT NULL,"
+ " prop TEXT NOT NULL,"
+ " ns TEXT NOT NULL,"
+ " value TEXT NOT NULL,"
+ " PRIMARY KEY(resource, prop, ns))",
+ NULL, NULL, &err)) {
+
+ if (0 != strcmp(err, "table properties already exists")) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
+ sqlite3_free(err);
+
+ return HANDLER_ERROR;
+ }
+ sqlite3_free(err);
+ }
+
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
&(s->stmt_select_prop), &next_stmt)) {
/* prepare failed */
@@ -202,8 +237,8 @@ SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
return HANDLER_ERROR;
}
- if (SQLITE_OK != sqlite3_prepare(s->sql,
- CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"),
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"),
&(s->stmt_select_propnames), &next_stmt)) {
/* prepare failed */
@@ -211,16 +246,67 @@ SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
return HANDLER_ERROR;
}
- if (SQLITE_OK != sqlite3_exec(s->sql,
- "CREATE TABLE properties ("
+
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"),
+ &(s->stmt_update_prop), &next_stmt)) {
+ /* prepare failed */
+
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
+ return HANDLER_ERROR;
+ }
+
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
+ &(s->stmt_delete_prop), &next_stmt)) {
+ /* prepare failed */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
+
+ return HANDLER_ERROR;
+ }
+
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"),
+ &(s->stmt_delete_uri), &next_stmt)) {
+ /* prepare failed */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
+
+ return HANDLER_ERROR;
+ }
+
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"),
+ &(s->stmt_copy_uri), &next_stmt)) {
+ /* prepare failed */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
+
+ return HANDLER_ERROR;
+ }
+
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"),
+ &(s->stmt_move_uri), &next_stmt)) {
+ /* prepare failed */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
+
+ return HANDLER_ERROR;
+ }
+
+ /* LOCKS */
+
+ if (SQLITE_OK != sqlite3_exec(s->sql,
+ "CREATE TABLE locks ("
+ " locktoken TEXT NOT NULL,"
" resource TEXT NOT NULL,"
- " prop TEXT NOT NULL,"
- " ns TEXT NOT NULL,"
- " value TEXT NOT NULL,"
- " PRIMARY KEY(resource, prop, ns))",
+ " lockscope TEXT NOT NULL,"
+ " locktype TEXT NOT NULL,"
+ " owner TEXT NOT NULL,"
+ " depth INT NOT NULL,"
+ " timeout TIMESTAMP NOT NULL,"
+ " PRIMARY KEY(locktoken))",
NULL, NULL, &err)) {
- if (0 != strcmp(err, "table properties already exists")) {
+ if (0 != strcmp(err, "table locks already exists")) {
log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
sqlite3_free(err);
@@ -228,127 +314,140 @@ SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
}
sqlite3_free(err);
}
-
- if (SQLITE_OK != sqlite3_prepare(s->sql,
- CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"),
- &(s->stmt_update_prop), &next_stmt)) {
+
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("INSERT INTO locks (locktoken, resource, lockscope, locktype, owner, depth, timeout) VALUES (?,?,?,?,?,?, CURRENT_TIME + 600)"),
+ &(s->stmt_create_lock), &next_stmt)) {
/* prepare failed */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
- log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
return HANDLER_ERROR;
}
- if (SQLITE_OK != sqlite3_prepare(s->sql,
- CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
- &(s->stmt_delete_prop), &next_stmt)) {
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("DELETE FROM locks WHERE locktoken = ?"),
+ &(s->stmt_remove_lock), &next_stmt)) {
/* prepare failed */
log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
return HANDLER_ERROR;
}
- if (SQLITE_OK != sqlite3_prepare(s->sql,
- CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"),
- &(s->stmt_delete_uri), &next_stmt)) {
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE locktoken = ?"),
+ &(s->stmt_read_lock), &next_stmt)) {
/* prepare failed */
log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
return HANDLER_ERROR;
}
- if (SQLITE_OK != sqlite3_prepare(s->sql,
- CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"),
- &(s->stmt_copy_uri), &next_stmt)) {
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE resource = ?"),
+ &(s->stmt_read_lock_by_uri), &next_stmt)) {
/* prepare failed */
log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
return HANDLER_ERROR;
}
- if (SQLITE_OK != sqlite3_prepare(s->sql,
- CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"),
- &(s->stmt_move_uri), &next_stmt)) {
+ if (SQLITE_OK != sqlite3_prepare(s->sql,
+ CONST_STR_LEN("UPDATE locks SET timeout = CURRENT_TIME + 600 WHERE locktoken = ?"),
+ &(s->stmt_refresh_lock), &next_stmt)) {
/* prepare failed */
log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
return HANDLER_ERROR;
}
+
+
#else
log_error_write(srv, __FILE__, __LINE__, "s", "Sorry, no sqlite3 and libxml2 support include, compile with --with-webdav-props");
return HANDLER_ERROR;
#endif
}
}
-
+
return HANDLER_GO_ON;
}
-#define PATCH(x) \
+#define PATCH_OPTION(x) \
p->conf.x = s->x;
static int mod_webdav_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
- PATCH(enabled);
- PATCH(is_readonly);
- PATCH(log_xml);
-
+
+ PATCH_OPTION(enabled);
+ PATCH_OPTION(is_readonly);
+ PATCH_OPTION(log_xml);
+
#ifdef USE_PROPPATCH
- PATCH(sql);
- PATCH(stmt_update_prop);
- PATCH(stmt_delete_prop);
- PATCH(stmt_select_prop);
- PATCH(stmt_select_propnames);
-
- PATCH(stmt_delete_uri);
- PATCH(stmt_move_uri);
- PATCH(stmt_copy_uri);
+ PATCH_OPTION(sql);
+ PATCH_OPTION(stmt_update_prop);
+ PATCH_OPTION(stmt_delete_prop);
+ PATCH_OPTION(stmt_select_prop);
+ PATCH_OPTION(stmt_select_propnames);
+
+ PATCH_OPTION(stmt_delete_uri);
+ PATCH_OPTION(stmt_move_uri);
+ PATCH_OPTION(stmt_copy_uri);
+
+ PATCH_OPTION(stmt_remove_lock);
+ PATCH_OPTION(stmt_refresh_lock);
+ PATCH_OPTION(stmt_create_lock);
+ PATCH_OPTION(stmt_read_lock);
+ PATCH_OPTION(stmt_read_lock_by_uri);
#endif
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.activate"))) {
- PATCH(enabled);
+ PATCH_OPTION(enabled);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.is-readonly"))) {
- PATCH(is_readonly);
+ PATCH_OPTION(is_readonly);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.log-xml"))) {
- PATCH(log_xml);
+ PATCH_OPTION(log_xml);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.sqlite-db-name"))) {
#ifdef USE_PROPPATCH
- PATCH(sql);
- PATCH(stmt_update_prop);
- PATCH(stmt_delete_prop);
- PATCH(stmt_select_prop);
- PATCH(stmt_select_propnames);
-
- PATCH(stmt_delete_uri);
- PATCH(stmt_move_uri);
- PATCH(stmt_copy_uri);
+ PATCH_OPTION(sql);
+ PATCH_OPTION(stmt_update_prop);
+ PATCH_OPTION(stmt_delete_prop);
+ PATCH_OPTION(stmt_select_prop);
+ PATCH_OPTION(stmt_select_propnames);
+
+ PATCH_OPTION(stmt_delete_uri);
+ PATCH_OPTION(stmt_move_uri);
+ PATCH_OPTION(stmt_copy_uri);
+
+ PATCH_OPTION(stmt_remove_lock);
+ PATCH_OPTION(stmt_refresh_lock);
+ PATCH_OPTION(stmt_create_lock);
+ PATCH_OPTION(stmt_read_lock);
+ PATCH_OPTION(stmt_read_lock_by_uri);
#endif
}
}
}
-
+
return 0;
}
-#undef PATCH
URIHANDLER_FUNC(mod_webdav_uri_handler) {
plugin_data *p = p_d;
-
+
UNUSED(srv);
if (con->uri.path->used == 0) return HANDLER_GO_ON;
-
+
mod_webdav_patch_connection(srv, con, p);
if (!p->conf.enabled) return HANDLER_GO_ON;
@@ -362,43 +461,43 @@ URIHANDLER_FUNC(mod_webdav_uri_handler) {
if (p->conf.is_readonly) {
response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND"));
} else {
- response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH"));
+ response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH, LOCK, UNLOCK"));
}
break;
default:
break;
}
-
+
/* not found */
return HANDLER_GO_ON;
}
-static int webdav_gen_prop_tag(server *srv, connection *con,
- char *prop_name,
- char *prop_ns,
- char *value,
+static int webdav_gen_prop_tag(server *srv, connection *con,
+ char *prop_name,
+ char *prop_ns,
+ char *value,
buffer *b) {
UNUSED(srv);
UNUSED(con);
if (value) {
- buffer_append_string(b,"<");
+ buffer_append_string_len(b,CONST_STR_LEN("<"));
buffer_append_string(b, prop_name);
- buffer_append_string(b, " xmlns=\"");
+ buffer_append_string_len(b, CONST_STR_LEN(" xmlns=\""));
buffer_append_string(b, prop_ns);
- buffer_append_string(b, "\">");
+ buffer_append_string_len(b, CONST_STR_LEN("\">"));
buffer_append_string(b, value);
- buffer_append_string(b,"</");
+ buffer_append_string_len(b,CONST_STR_LEN("</"));
buffer_append_string(b, prop_name);
- buffer_append_string(b, ">");
+ buffer_append_string_len(b, CONST_STR_LEN(">"));
} else {
- buffer_append_string(b,"<");
+ buffer_append_string_len(b,CONST_STR_LEN("<"));
buffer_append_string(b, prop_name);
- buffer_append_string(b, " xmlns=\"");
+ buffer_append_string_len(b, CONST_STR_LEN(" xmlns=\""));
buffer_append_string(b, prop_ns);
- buffer_append_string(b, "\"/>");
+ buffer_append_string_len(b, CONST_STR_LEN("\"/>"));
}
return 0;
@@ -408,24 +507,24 @@ static int webdav_gen_prop_tag(server *srv, connection *con,
static int webdav_gen_response_status_tag(server *srv, connection *con, physical *dst, int status, buffer *b) {
UNUSED(srv);
- buffer_append_string(b,"<D:response xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
+ buffer_append_string_len(b,CONST_STR_LEN("<D:response xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n"));
- buffer_append_string(b,"<D:href>\n");
+ buffer_append_string_len(b,CONST_STR_LEN("<D:href>\n"));
buffer_append_string_buffer(b, dst->rel_path);
- buffer_append_string(b,"</D:href>\n");
- buffer_append_string(b,"<D:status>\n");
-
+ buffer_append_string_len(b,CONST_STR_LEN("</D:href>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:status>\n"));
+
if (con->request.http_version == HTTP_VERSION_1_1) {
- BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
+ buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.1 "));
} else {
- BUFFER_COPY_STRING_CONST(b, "HTTP/1.0 ");
+ buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.0 "));
}
buffer_append_long(b, status);
- BUFFER_APPEND_STRING_CONST(b, " ");
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
buffer_append_string(b, get_http_status_name(status));
- buffer_append_string(b,"</D:status>\n");
- buffer_append_string(b,"</D:response>\n");
+ buffer_append_string_len(b,CONST_STR_LEN("</D:status>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("</D:response>\n"));
return 0;
}
@@ -458,16 +557,17 @@ static int webdav_delete_file(server *srv, connection *con, plugin_data *p, phys
/* bind the values to the insert */
- sqlite3_bind_text(stmt, 1,
- dst->rel_path->ptr,
+ sqlite3_bind_text(stmt, 1,
+ dst->rel_path->ptr,
dst->rel_path->used - 1,
SQLITE_TRANSIENT);
-
+
if (SQLITE_DONE != sqlite3_step(stmt)) {
/* */
- WP();
}
}
+#else
+ UNUSED(p);
#endif
}
@@ -493,12 +593,12 @@ static int webdav_delete_dir(server *srv, connection *con, plugin_data *p, physi
(de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
continue;
/* ignore the parent dir */
- }
+ }
buffer_copy_string_buffer(d.path, dst->path);
BUFFER_APPEND_SLASH(d.path);
buffer_append_string(d.path, de->d_name);
-
+
buffer_copy_string_buffer(d.rel_path, dst->rel_path);
BUFFER_APPEND_SLASH(d.rel_path);
buffer_append_string(d.rel_path, de->d_name);
@@ -508,7 +608,7 @@ static int webdav_delete_dir(server *srv, connection *con, plugin_data *p, physi
/* don't about it yet, rmdir will fail too */
} else if (S_ISDIR(st.st_mode)) {
have_multi_status = webdav_delete_dir(srv, con, p, &d, b);
-
+
/* try to unlink it */
if (-1 == rmdir(d.path->ptr)) {
switch(errno) {
@@ -535,14 +635,13 @@ static int webdav_delete_dir(server *srv, connection *con, plugin_data *p, physi
/* bind the values to the insert */
- sqlite3_bind_text(stmt, 1,
- d.rel_path->ptr,
+ sqlite3_bind_text(stmt, 1,
+ d.rel_path->ptr,
d.rel_path->used - 1,
SQLITE_TRANSIENT);
-
+
if (SQLITE_DONE != sqlite3_step(stmt)) {
/* */
- WP();
}
}
#endif
@@ -563,14 +662,14 @@ static int webdav_delete_dir(server *srv, connection *con, plugin_data *p, physi
static int webdav_copy_file(server *srv, connection *con, plugin_data *p, physical *src, physical *dst, int overwrite) {
stream s;
int status = 0, ofd;
-
+ UNUSED(srv);
UNUSED(con);
if (stream_open(&s, src->path)) {
return 403;
}
-
- if (-1 == (ofd = open(dst->path->ptr, O_WRONLY|O_TRUNC|O_CREAT|(overwrite ? 0 : O_EXCL), 0600))) {
+
+ if (-1 == (ofd = open(dst->path->ptr, O_WRONLY|O_TRUNC|O_CREAT|(overwrite ? 0 : O_EXCL), WEBDAV_FILE_MODE))) {
/* opening the destination failed for some reason */
switch(errno) {
case EEXIST:
@@ -601,7 +700,7 @@ static int webdav_copy_file(server *srv, connection *con, plugin_data *p, physic
break;
}
}
-
+
stream_close(&s);
close(ofd);
@@ -614,22 +713,23 @@ static int webdav_copy_file(server *srv, connection *con, plugin_data *p, physic
sqlite3_reset(stmt);
/* bind the values to the insert */
- sqlite3_bind_text(stmt, 1,
- dst->rel_path->ptr,
+ sqlite3_bind_text(stmt, 1,
+ dst->rel_path->ptr,
dst->rel_path->used - 1,
SQLITE_TRANSIENT);
- sqlite3_bind_text(stmt, 2,
- src->rel_path->ptr,
+ sqlite3_bind_text(stmt, 2,
+ src->rel_path->ptr,
src->rel_path->used - 1,
SQLITE_TRANSIENT);
-
+
if (SQLITE_DONE != sqlite3_step(stmt)) {
/* */
- WP();
}
}
}
+#else
+ UNUSED(p);
#endif
return status;
}
@@ -655,7 +755,7 @@ static int webdav_copy_dir(server *srv, connection *con, plugin_data *p, physica
(de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
continue;
}
-
+
buffer_copy_string_buffer(s.path, src->path);
BUFFER_APPEND_SLASH(s.path);
buffer_append_string(s.path, de->d_name);
@@ -676,7 +776,7 @@ static int webdav_copy_dir(server *srv, connection *con, plugin_data *p, physica
/* why ? */
} else if (S_ISDIR(st.st_mode)) {
/* a directory */
- if (-1 == mkdir(d.path->ptr, 0700) &&
+ if (-1 == mkdir(d.path->ptr, WEBDAV_DIR_MODE) &&
errno != EEXIST) {
/* WTH ? */
} else {
@@ -692,19 +792,18 @@ static int webdav_copy_dir(server *srv, connection *con, plugin_data *p, physica
sqlite3_reset(stmt);
/* bind the values to the insert */
- sqlite3_bind_text(stmt, 1,
- dst->rel_path->ptr,
+ sqlite3_bind_text(stmt, 1,
+ dst->rel_path->ptr,
dst->rel_path->used - 1,
SQLITE_TRANSIENT);
- sqlite3_bind_text(stmt, 2,
- src->rel_path->ptr,
+ sqlite3_bind_text(stmt, 2,
+ src->rel_path->ptr,
src->rel_path->used - 1,
SQLITE_TRANSIENT);
-
+
if (SQLITE_DONE != sqlite3_step(stmt)) {
/* */
- WP();
}
}
#endif
@@ -721,7 +820,7 @@ static int webdav_copy_dir(server *srv, connection *con, plugin_data *p, physica
buffer_free(s.rel_path);
buffer_free(d.path);
buffer_free(d.rel_path);
-
+
closedir(srcdir);
}
@@ -741,23 +840,23 @@ static int webdav_get_live_property(server *srv, connection *con, plugin_data *p
if (0 == strcmp(prop_name, "resourcetype")) {
if (S_ISDIR(sce->st.st_mode)) {
- buffer_append_string(b, "<D:resourcetype><D:collection/></D:resourcetype>");
+ buffer_append_string_len(b, CONST_STR_LEN("<D:resourcetype><D:collection/></D:resourcetype>"));
found = 1;
}
} else if (0 == strcmp(prop_name, "getcontenttype")) {
if (S_ISDIR(sce->st.st_mode)) {
- buffer_append_string(b, "<D:getcontenttype>httpd/unix-directory</D:getcontenttype>");
+ buffer_append_string_len(b, CONST_STR_LEN("<D:getcontenttype>httpd/unix-directory</D:getcontenttype>"));
found = 1;
- } else if(S_ISREG(sce->st.st_mode)) {
+ } else if(S_ISREG(sce->st.st_mode)) {
for (k = 0; k < con->conf.mimetypes->used; k++) {
data_string *ds = (data_string *)con->conf.mimetypes->data[k];
-
+
if (ds->key->used == 0) continue;
-
+
if (buffer_is_equal_right_len(dst->path, ds->key, ds->key->used - 1)) {
- buffer_append_string(b,"<D:getcontenttype>");
+ buffer_append_string_len(b,CONST_STR_LEN("<D:getcontenttype>"));
buffer_append_string_buffer(b, ds->value);
- buffer_append_string(b, "</D:getcontenttype>");
+ buffer_append_string_len(b, CONST_STR_LEN("</D:getcontenttype>"));
found = 1;
break;
@@ -765,26 +864,26 @@ static int webdav_get_live_property(server *srv, connection *con, plugin_data *p
}
}
} else if (0 == strcmp(prop_name, "creationdate")) {
- buffer_append_string(b, "<D:creationdate ns0:dt=\"dateTime.tz\">");
+ buffer_append_string_len(b, CONST_STR_LEN("<D:creationdate ns0:dt=\"dateTime.tz\">"));
strftime(ctime_buf, sizeof(ctime_buf), "%Y-%m-%dT%H:%M:%SZ", gmtime(&(sce->st.st_ctime)));
buffer_append_string(b, ctime_buf);
- buffer_append_string(b, "</D:creationdate>");
+ buffer_append_string_len(b, CONST_STR_LEN("</D:creationdate>"));
found = 1;
} else if (0 == strcmp(prop_name, "getlastmodified")) {
- buffer_append_string(b,"<D:getlastmodified ns0:dt=\"dateTime.rfc1123\">");
+ buffer_append_string_len(b,CONST_STR_LEN("<D:getlastmodified ns0:dt=\"dateTime.rfc1123\">"));
strftime(mtime_buf, sizeof(mtime_buf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(sce->st.st_mtime)));
buffer_append_string(b, mtime_buf);
- buffer_append_string(b, "</D:getlastmodified>");
+ buffer_append_string_len(b, CONST_STR_LEN("</D:getlastmodified>"));
found = 1;
} else if (0 == strcmp(prop_name, "getcontentlength")) {
- buffer_append_string(b,"<D:getcontentlength>");
+ buffer_append_string_len(b,CONST_STR_LEN("<D:getcontentlength>"));
buffer_append_off_t(b, sce->st.st_size);
- buffer_append_string(b, "</D:getcontentlength>");
+ buffer_append_string_len(b, CONST_STR_LEN("</D:getcontentlength>"));
found = 1;
} else if (0 == strcmp(prop_name, "getcontentlanguage")) {
- buffer_append_string(b,"<D:getcontentlanguage>");
- buffer_append_string(b, "en");
- buffer_append_string(b, "</D:getcontentlanguage>");
+ buffer_append_string_len(b,CONST_STR_LEN("<D:getcontentlanguage>"));
+ buffer_append_string_len(b, CONST_STR_LEN("en"));
+ buffer_append_string_len(b, CONST_STR_LEN("</D:getcontentlanguage>"));
found = 1;
}
}
@@ -807,23 +906,23 @@ static int webdav_get_property(server *srv, connection *con, plugin_data *p, phy
/* bind the values to the insert */
- sqlite3_bind_text(stmt, 1,
- dst->rel_path->ptr,
+ sqlite3_bind_text(stmt, 1,
+ dst->rel_path->ptr,
dst->rel_path->used - 1,
SQLITE_TRANSIENT);
- sqlite3_bind_text(stmt, 2,
+ sqlite3_bind_text(stmt, 2,
prop_name,
strlen(prop_name),
SQLITE_TRANSIENT);
- sqlite3_bind_text(stmt, 3,
+ sqlite3_bind_text(stmt, 3,
prop_ns,
strlen(prop_ns),
SQLITE_TRANSIENT);
/* it is the PK */
- while (SQLITE_ROW == sqlite3_step(p->conf.stmt_select_prop)) {
+ while (SQLITE_ROW == sqlite3_step(stmt)) {
/* there is a row for us, we only expect a single col 'value' */
- webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(p->conf.stmt_select_prop, 0), b);
+ webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(stmt, 0), b);
found = 1;
}
}
@@ -840,7 +939,7 @@ typedef struct {
char *prop;
} webdav_property;
-webdav_property live_properties[] = {
+static webdav_property live_properties[] = {
{ "DAV:", "creationdate" },
{ "DAV:", "displayname" },
{ "DAV:", "getcontentlanguage" },
@@ -871,8 +970,8 @@ static int webdav_get_props(server *srv, connection *con, plugin_data *p, physic
webdav_property *prop;
prop = props->ptr[i];
-
- if (0 != webdav_get_property(srv, con, p,
+
+ if (0 != webdav_get_property(srv, con, p,
dst, prop->prop, prop->ns, b_200)) {
webdav_gen_prop_tag(srv, con, prop->prop, prop->ns, NULL, b_404);
}
@@ -916,13 +1015,15 @@ static int webdav_parse_chunkqueue(server *srv, connection *con, plugin_data *p,
if (-1 == c->file.fd && /* open the file if not already open */
-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
-
+
return -1;
}
-
+
if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
- log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
+ log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
strerror(errno), c->file.name, c->file.fd);
+ close(c->file.fd);
+ c->file.fd = -1;
return -1;
}
@@ -936,9 +1037,9 @@ static int webdav_parse_chunkqueue(server *srv, connection *con, plugin_data *p,
}
if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->file.mmap.start + c->offset, weHave, 0))) {
- log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
+ log_error_write(srv, __FILE__, __LINE__, "sodd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
}
-
+
c->offset += weHave;
cq->bytes_out += weHave;
@@ -954,9 +1055,9 @@ static int webdav_parse_chunkqueue(server *srv, connection *con, plugin_data *p,
}
if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->mem->ptr + c->offset, weHave, 0))) {
- log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
+ log_error_write(srv, __FILE__, __LINE__, "sodd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
}
-
+
c->offset += weHave;
cq->bytes_out += weHave;
@@ -991,6 +1092,122 @@ static int webdav_parse_chunkqueue(server *srv, connection *con, plugin_data *p,
}
#endif
+#ifdef USE_LOCKS
+static int webdav_lockdiscovery(server *srv, connection *con,
+ buffer *locktoken, const char *lockscope, const char *locktype, int depth) {
+
+ buffer *b;
+
+ response_header_overwrite(srv, con, CONST_STR_LEN("Lock-Token"), CONST_BUF_LEN(locktoken));
+
+ response_header_overwrite(srv, con,
+ CONST_STR_LEN("Content-Type"),
+ CONST_STR_LEN("text/xml; charset=\"utf-8\""));
+
+ b = chunkqueue_get_append_buffer(con->write_queue);
+
+ buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:prop xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:lockdiscovery>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:activelock>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:lockscope>"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:"));
+ buffer_append_string(b, lockscope);
+ buffer_append_string_len(b, CONST_STR_LEN("/>"));
+ buffer_append_string_len(b,CONST_STR_LEN("</D:lockscope>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:locktype>"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:"));
+ buffer_append_string(b, locktype);
+ buffer_append_string_len(b, CONST_STR_LEN("/>"));
+ buffer_append_string_len(b,CONST_STR_LEN("</D:locktype>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:depth>"));
+ buffer_append_string(b, depth == 0 ? "0" : "infinity");
+ buffer_append_string_len(b,CONST_STR_LEN("</D:depth>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:timeout>"));
+ buffer_append_string_len(b, CONST_STR_LEN("Second-600"));
+ buffer_append_string_len(b,CONST_STR_LEN("</D:timeout>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:owner>"));
+ buffer_append_string_len(b,CONST_STR_LEN("</D:owner>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:locktoken>"));
+ buffer_append_string_len(b, CONST_STR_LEN("<D:href>"));
+ buffer_append_string_buffer(b, locktoken);
+ buffer_append_string_len(b, CONST_STR_LEN("</D:href>"));
+ buffer_append_string_len(b,CONST_STR_LEN("</D:locktoken>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:activelock>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("</D:lockdiscovery>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
+
+ return 0;
+}
+#endif
+
+/**
+ * check if resource is having the right locks to access to resource
+ *
+ *
+ *
+ */
+static int webdav_has_lock(server *srv, connection *con, plugin_data *p, buffer *uri) {
+ int has_lock = 1;
+
+#ifdef USE_LOCKS
+ data_string *ds;
+ UNUSED(srv);
+
+ /**
+ * This implementation is more fake than real
+ * we need a parser for the If: header to really handle the full scope
+ *
+ * X-Litmus: locks: 11 (owner_modify)
+ * If: <http://127.0.0.1:1025/dav/litmus/lockme> (<opaquelocktoken:2165478d-0611-49c4-be92-e790d68a38f1>)
+ * - a tagged check:
+ * if http://127.0.0.1:1025/dav/litmus/lockme is locked with
+ * opaquelocktoken:2165478d-0611-49c4-be92-e790d68a38f1, go on
+ *
+ * X-Litmus: locks: 16 (fail_cond_put)
+ * If: (<DAV:no-lock> ["-1622396671"])
+ * - untagged:
+ * go on if the resource has the etag [...] and the lock
+ */
+ if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
+ /* Ooh, ooh. A if tag, now the fun begins.
+ *
+ * this can only work with a real parser
+ **/
+ } else {
+ /* we didn't provided a lock-token -> */
+ /* if the resource is locked -> 423 */
+
+ sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
+
+ sqlite3_reset(stmt);
+
+ sqlite3_bind_text(stmt, 1,
+ CONST_BUF_LEN(uri),
+ SQLITE_TRANSIENT);
+
+ while (SQLITE_ROW == sqlite3_step(stmt)) {
+ has_lock = 0;
+ }
+ }
+#else
+ UNUSED(srv);
+ UNUSED(con);
+ UNUSED(p);
+ UNUSED(uri);
+#endif
+
+ return has_lock;
+}
+
URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
plugin_data *p = p_d;
buffer *b;
@@ -1001,7 +1218,8 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
buffer *prop_200;
buffer *prop_404;
webdav_properties *req_props;
-
+ stat_cache_entry *sce = NULL;
+
UNUSED(srv);
if (!p->conf.enabled) return HANDLER_GO_ON;
@@ -1019,7 +1237,19 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
req_props = NULL;
/* is there a content-body ? */
-
+
+ switch (stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
+ case HANDLER_ERROR:
+ if (errno == ENOENT) {
+ con->http_status = 404;
+ return HANDLER_FINISHED;
+ }
+ break;
+ default:
+ break;
+ }
+
+
#ifdef USE_PROPPATCH
/* any special requests or just allprop ? */
if (con->request.content_length) {
@@ -1087,14 +1317,13 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
/* get all property names (EMPTY) */
sqlite3_reset(stmt);
/* bind the values to the insert */
-
- sqlite3_bind_text(stmt, 1,
- con->uri.path->ptr,
+
+ sqlite3_bind_text(stmt, 1,
+ con->uri.path->ptr,
con->uri.path->used - 1,
SQLITE_TRANSIENT);
-
+
if (SQLITE_DONE != sqlite3_step(stmt)) {
- WP();
}
}
} else if (0 == xmlStrcmp(cmd->name, BAD_CAST "allprop")) {
@@ -1115,13 +1344,13 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
b = chunkqueue_get_append_buffer(con->write_queue);
-
- buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
- buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
+ buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:multistatus xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n"));
/* allprop */
-
+
prop_200 = buffer_init();
prop_404 = buffer_init();
@@ -1129,44 +1358,44 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
case 0:
/* Depth: 0 */
webdav_get_props(srv, con, p, &(con->physical), req_props, prop_200, prop_404);
-
- buffer_append_string(b,"<D:response>\n");
- buffer_append_string(b,"<D:href>");
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:response>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:href>"));
buffer_append_string_buffer(b, con->uri.scheme);
- buffer_append_string(b,"://");
+ buffer_append_string_len(b,CONST_STR_LEN("://"));
buffer_append_string_buffer(b, con->uri.authority);
buffer_append_string_encoded(b, CONST_BUF_LEN(con->uri.path), ENCODING_REL_URI);
- buffer_append_string(b,"</D:href>\n");
+ buffer_append_string_len(b,CONST_STR_LEN("</D:href>\n"));
if (!buffer_is_empty(prop_200)) {
- buffer_append_string(b,"<D:propstat>\n");
- buffer_append_string(b,"<D:prop>\n");
+ buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
buffer_append_string_buffer(b, prop_200);
- buffer_append_string(b,"</D:prop>\n");
-
- buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
-
- buffer_append_string(b,"</D:propstat>\n");
+ buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:status>HTTP/1.1 200 OK</D:status>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));
}
if (!buffer_is_empty(prop_404)) {
- buffer_append_string(b,"<D:propstat>\n");
- buffer_append_string(b,"<D:prop>\n");
+ buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
buffer_append_string_buffer(b, prop_404);
- buffer_append_string(b,"</D:prop>\n");
-
- buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
-
- buffer_append_string(b,"</D:propstat>\n");
+ buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:status>HTTP/1.1 404 Not Found</D:status>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));
}
- buffer_append_string(b,"</D:response>\n");
+ buffer_append_string_len(b,CONST_STR_LEN("</D:response>\n"));
break;
- case 1:
+ case 1:
if (NULL != (dir = opendir(con->physical.path->ptr))) {
struct dirent *de;
physical d;
@@ -1179,7 +1408,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
if (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0') {
continue;
/* ignore the parent dir */
- }
+ }
buffer_copy_string_buffer(d.path, dst->path);
BUFFER_APPEND_SLASH(d.path);
@@ -1188,7 +1417,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
BUFFER_APPEND_SLASH(d.rel_path);
if (de->d_name[0] == '.' && de->d_name[1] == '\0') {
- /* don't append the . */
+ /* don't append the . */
} else {
buffer_append_string(d.path, de->d_name);
buffer_append_string(d.rel_path, de->d_name);
@@ -1198,41 +1427,41 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
buffer_reset(prop_404);
webdav_get_props(srv, con, p, &d, req_props, prop_200, prop_404);
-
- buffer_append_string(b,"<D:response>\n");
- buffer_append_string(b,"<D:href>");
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:response>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:href>"));
buffer_append_string_buffer(b, con->uri.scheme);
- buffer_append_string(b,"://");
+ buffer_append_string_len(b,CONST_STR_LEN("://"));
buffer_append_string_buffer(b, con->uri.authority);
buffer_append_string_encoded(b, CONST_BUF_LEN(d.rel_path), ENCODING_REL_URI);
- buffer_append_string(b,"</D:href>\n");
+ buffer_append_string_len(b,CONST_STR_LEN("</D:href>\n"));
if (!buffer_is_empty(prop_200)) {
- buffer_append_string(b,"<D:propstat>\n");
- buffer_append_string(b,"<D:prop>\n");
+ buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
buffer_append_string_buffer(b, prop_200);
- buffer_append_string(b,"</D:prop>\n");
-
- buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
-
- buffer_append_string(b,"</D:propstat>\n");
+ buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:status>HTTP/1.1 200 OK</D:status>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));
}
if (!buffer_is_empty(prop_404)) {
- buffer_append_string(b,"<D:propstat>\n");
- buffer_append_string(b,"<D:prop>\n");
+ buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
+ buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
buffer_append_string_buffer(b, prop_404);
- buffer_append_string(b,"</D:prop>\n");
-
- buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
-
- buffer_append_string(b,"</D:propstat>\n");
+ buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:status>HTTP/1.1 404 Not Found</D:status>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));
}
- buffer_append_string(b,"</D:response>\n");
+ buffer_append_string_len(b,CONST_STR_LEN("</D:response>\n"));
}
closedir(dir);
buffer_free(d.path);
@@ -1255,7 +1484,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
buffer_free(prop_200);
buffer_free(prop_404);
- buffer_append_string(b,"</D:multistatus>\n");
+ buffer_append_string_len(b,CONST_STR_LEN("</D:multistatus>\n"));
if (p->conf.log_xml) {
log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
@@ -1275,10 +1504,10 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
return HANDLER_FINISHED;
}
-
+
/* let's create the directory */
- if (-1 == mkdir(con->physical.path->ptr, 0700)) {
+ if (-1 == mkdir(con->physical.path->ptr, WEBDAV_DIR_MODE)) {
switch(errno) {
case EPERM:
con->http_status = 403;
@@ -1294,6 +1523,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
}
} else {
con->http_status = 201;
+ con->file_finished = 1;
}
return HANDLER_FINISHED;
@@ -1302,7 +1532,13 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
con->http_status = 403;
return HANDLER_FINISHED;
}
-
+
+ /* does the client have a lock for this connection ? */
+ if (!webdav_has_lock(srv, con, p, con->uri.path)) {
+ con->http_status = 423;
+ return HANDLER_FINISHED;
+ }
+
/* stat and unlink afterwards */
if (-1 == stat(con->physical.path->ptr, &st)) {
/* don't about it yet, unlink will fail too */
@@ -1322,15 +1558,15 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
b = chunkqueue_get_append_buffer(con->write_queue);
-
- buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
- buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\">\n");
+ buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
+
+ buffer_append_string_len(b,CONST_STR_LEN("<D:multistatus xmlns:D=\"DAV:\">\n"));
buffer_append_string_buffer(b, multi_status_resp);
- buffer_append_string(b,"</D:multistatus>\n");
-
+ buffer_append_string_len(b,CONST_STR_LEN("</D:multistatus>\n"));
+
if (p->conf.log_xml) {
log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
}
@@ -1339,7 +1575,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
con->file_finished = 1;
} else {
/* everything went fine, remove the directory */
-
+
if (-1 == rmdir(con->physical.path->ptr)) {
switch(errno) {
case ENOENT:
@@ -1374,106 +1610,194 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
case HTTP_METHOD_PUT: {
int fd;
chunkqueue *cq = con->request_content_queue;
+ chunk *c;
+ data_string *ds_range;
if (p->conf.is_readonly) {
con->http_status = 403;
return HANDLER_FINISHED;
}
+ /* is a exclusive lock set on the source */
+ if (!webdav_has_lock(srv, con, p, con->uri.path)) {
+ con->http_status = 423;
+ return HANDLER_FINISHED;
+ }
+
+
assert(chunkqueue_length(cq) == (off_t)con->request.content_length);
- /* taken what we have in the request-body and write it to a file */
- if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC, 0600))) {
- /* we can't open the file */
- con->http_status = 403;
+ /* RFC2616 Section 9.6 PUT requires us to send 501 on all Content-* we don't support
+ * - most important Content-Range
+ *
+ *
+ * Example: Content-Range: bytes 100-1037/1038 */
+
+ if (NULL != (ds_range = (data_string *)array_get_element(con->request.headers, "Content-Range"))) {
+ const char *num = ds_range->value->ptr;
+ off_t offset;
+ char *err = NULL;
+
+ if (0 != strncmp(num, "bytes ", 6)) {
+ con->http_status = 501; /* not implemented */
+
+ return HANDLER_FINISHED;
+ }
+
+ /* we only support <num>- ... */
+
+ num += 6;
+
+ /* skip WS */
+ while (*num == ' ' || *num == '\t') num++;
+
+ if (*num == '\0') {
+ con->http_status = 501; /* not implemented */
+
+ return HANDLER_FINISHED;
+ }
+
+ offset = strtoll(num, &err, 10);
+
+ if (*err != '-' || offset < 0) {
+ con->http_status = 501; /* not implemented */
+
+ return HANDLER_FINISHED;
+ }
+
+ if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY, WEBDAV_FILE_MODE))) {
+ switch (errno) {
+ case ENOENT:
+ con->http_status = 404; /* not found */
+ break;
+ default:
+ con->http_status = 403; /* not found */
+ break;
+ }
+ return HANDLER_FINISHED;
+ }
+
+ if (-1 == lseek(fd, offset, SEEK_SET)) {
+ con->http_status = 501; /* not implemented */
+
+ close(fd);
+
+ return HANDLER_FINISHED;
+ }
+ con->http_status = 200; /* modified */
} else {
- chunk *c;
+ /* take what we have in the request-body and write it to a file */
- con->http_status = 201; /* created */
+ /* if the file doesn't exist, create it */
+ if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_TRUNC, WEBDAV_FILE_MODE))) {
+ if (errno == ENOENT &&
+ -1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, WEBDAV_FILE_MODE))) {
+ /* we can't open the file */
+ con->http_status = 403;
- for (c = cq->first; c; c = cq->first) {
- int r = 0;
+ return HANDLER_FINISHED;
+ } else {
+ con->http_status = 201; /* created */
+ }
+ } else {
+ con->http_status = 200; /* modified */
+ }
+ }
- /* copy all chunks */
- switch(c->type) {
- case FILE_CHUNK:
+ con->file_finished = 1;
- if (c->file.mmap.start == MAP_FAILED) {
- if (-1 == c->file.fd && /* open the file if not already open */
- -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
-
- return -1;
- }
-
- if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
- log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
- strerror(errno), c->file.name, c->file.fd);
+ for (c = cq->first; c; c = cq->first) {
+ int r = 0;
- return -1;
- }
+ /* copy all chunks */
+ switch(c->type) {
+ case FILE_CHUNK:
- c->file.mmap.length = c->file.length;
+ if (c->file.mmap.start == MAP_FAILED) {
+ if (-1 == c->file.fd && /* open the file if not already open */
+ -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
+ return HANDLER_ERROR;
+ }
+
+ if (MAP_FAILED == (c->file.mmap.start = mmap(NULL, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
+ log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
+ strerror(errno), c->file.name, c->file.fd);
close(c->file.fd);
c->file.fd = -1;
-
- /* chunk_reset() or chunk_free() will cleanup for us */
- }
- if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
- switch(errno) {
- case ENOSPC:
- con->http_status = 507;
-
- break;
- default:
- con->http_status = 403;
- break;
- }
+ return HANDLER_ERROR;
}
- break;
- case MEM_CHUNK:
- if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
- switch(errno) {
- case ENOSPC:
- con->http_status = 507;
-
- break;
- default:
- con->http_status = 403;
- break;
- }
+
+ c->file.mmap.length = c->file.length;
+
+ close(c->file.fd);
+ c->file.fd = -1;
+
+ /* chunk_reset() or chunk_free() will cleanup for us */
+ }
+
+ if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
+ switch(errno) {
+ case ENOSPC:
+ con->http_status = 507;
+
+ break;
+ default:
+ con->http_status = 403;
+ break;
}
- break;
- case UNUSED_CHUNK:
- break;
}
+ break;
+ case MEM_CHUNK:
+ if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
+ switch(errno) {
+ case ENOSPC:
+ con->http_status = 507;
- if (r > 0) {
- c->offset += r;
- cq->bytes_out += r;
- } else {
- break;
+ break;
+ default:
+ con->http_status = 403;
+ break;
+ }
}
- chunkqueue_remove_finished_chunks(cq);
+ break;
+ case UNUSED_CHUNK:
+ break;
}
- close(fd);
+ if (r > 0) {
+ c->offset += r;
+ cq->bytes_out += r;
+ } else {
+ break;
+ }
+ chunkqueue_remove_finished_chunks(cq);
}
+ close(fd);
+
return HANDLER_FINISHED;
}
- case HTTP_METHOD_MOVE:
+ case HTTP_METHOD_MOVE:
case HTTP_METHOD_COPY: {
buffer *destination = NULL;
- char *sep, *start;
+ char *sep, *sep2, *start;
int overwrite = 1;
if (p->conf.is_readonly) {
con->http_status = 403;
return HANDLER_FINISHED;
}
-
+
+ /* is a exclusive lock set on the source */
+ if (con->request.http_method == HTTP_METHOD_MOVE) {
+ if (!webdav_has_lock(srv, con, p, con->uri.path)) {
+ con->http_status = 423;
+ return HANDLER_FINISHED;
+ }
+ }
+
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Destination"))) {
destination = ds->value;
} else {
@@ -1517,6 +1841,10 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
con->http_status = 400;
return HANDLER_FINISHED;
}
+ if (NULL != (sep2 = memchr(start, '@', sep - start))) {
+ /* skip login information */
+ start = sep2 + 1;
+ }
buffer_copy_string_len(p->uri.authority, start, sep - start);
start = sep + 1;
@@ -1550,7 +1878,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
BUFFER_APPEND_SLASH(p->physical.path);
buffer_copy_string_buffer(p->physical.basedir, p->physical.path);
- /* don't add a second / */
+ /* don't add a second / */
if (p->physical.rel_path->ptr[0] == '/') {
buffer_append_string_len(p->physical.path, p->physical.rel_path->ptr + 1, p->physical.rel_path->used - 2);
} else {
@@ -1575,7 +1903,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
/* src is a directory */
if (-1 == stat(p->physical.path->ptr, &st)) {
- if (-1 == mkdir(p->physical.path->ptr, 0700)) {
+ if (-1 == mkdir(p->physical.path->ptr, WEBDAV_DIR_MODE)) {
con->http_status = 403;
return HANDLER_FINISHED;
}
@@ -1586,7 +1914,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
return HANDLER_FINISHED;
} else {
unlink(p->physical.path->ptr);
- if (-1 == mkdir(p->physical.path->ptr, 0700)) {
+ if (-1 == mkdir(p->physical.path->ptr, WEBDAV_DIR_MODE)) {
con->http_status = 403;
return HANDLER_FINISHED;
}
@@ -1606,10 +1934,17 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
rmdir(con->physical.path->ptr);
}
con->http_status = 201;
+ con->file_finished = 1;
} else {
/* it is just a file, good */
int r;
+ /* does the client have a lock for this connection ? */
+ if (!webdav_has_lock(srv, con, p, p->uri.path)) {
+ con->http_status = 423;
+ return HANDLER_FINISHED;
+ }
+
/* destination exists */
if (0 == (r = stat(p->physical.path->ptr, &st))) {
if (S_ISDIR(st.st_mode)) {
@@ -1625,6 +1960,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
if (-1 == r) {
con->http_status = 201; /* we will create a new one */
+ con->file_finished = 1;
switch(errno) {
case ENOTDIR:
@@ -1632,7 +1968,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
return HANDLER_FINISHED;
}
} else if (overwrite == 0) {
- /* destination exists, but overwrite is not set */
+ /* destination exists, but overwrite is not set */
con->http_status = 412;
return HANDLER_FINISHED;
} else {
@@ -1644,23 +1980,40 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
if (0 == rename(con->physical.path->ptr, p->physical.path->ptr)) {
#ifdef USE_PROPPATCH
- sqlite3_stmt *stmt = p->conf.stmt_move_uri;
+ sqlite3_stmt *stmt;
+ stmt = p->conf.stmt_delete_uri;
if (stmt) {
sqlite3_reset(stmt);
/* bind the values to the insert */
- sqlite3_bind_text(stmt, 1,
- p->uri.path->ptr,
+ sqlite3_bind_text(stmt, 1,
+ con->uri.path->ptr,
+ con->uri.path->used - 1,
+ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move(delete old) failed:", sqlite3_errmsg(p->conf.sql));
+ }
+ }
+
+ stmt = p->conf.stmt_move_uri;
+ if (stmt) {
+
+ sqlite3_reset(stmt);
+
+ /* bind the values to the insert */
+ sqlite3_bind_text(stmt, 1,
+ p->uri.path->ptr,
p->uri.path->used - 1,
SQLITE_TRANSIENT);
- sqlite3_bind_text(stmt, 2,
- con->uri.path->ptr,
+ sqlite3_bind_text(stmt, 2,
+ con->uri.path->ptr,
con->uri.path->used - 1,
SQLITE_TRANSIENT);
-
+
if (SQLITE_DONE != sqlite3_step(stmt)) {
log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move failed:", sqlite3_errmsg(p->conf.sql));
}
@@ -1687,12 +2040,17 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
return HANDLER_FINISHED;
}
- case HTTP_METHOD_PROPPATCH: {
+ case HTTP_METHOD_PROPPATCH:
if (p->conf.is_readonly) {
con->http_status = 403;
return HANDLER_FINISHED;
}
+ if (!webdav_has_lock(srv, con, p, con->uri.path)) {
+ con->http_status = 423;
+ return HANDLER_FINISHED;
+ }
+
/* check if destination exists */
if (-1 == stat(con->physical.path->ptr, &st)) {
switch(errno) {
@@ -1733,7 +2091,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
sqlite3_stmt *stmt;
- stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ?
+ stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ?
p->conf.stmt_delete_prop : p->conf.stmt_update_prop;
for (props = cmd->children; props; props = props->next) {
@@ -1758,34 +2116,35 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
/* bind the values to the insert */
- sqlite3_bind_text(stmt, 1,
- con->uri.path->ptr,
+ sqlite3_bind_text(stmt, 1,
+ con->uri.path->ptr,
con->uri.path->used - 1,
SQLITE_TRANSIENT);
- sqlite3_bind_text(stmt, 2,
+ sqlite3_bind_text(stmt, 2,
(char *)prop->name,
strlen((char *)prop->name),
SQLITE_TRANSIENT);
if (prop->ns) {
- sqlite3_bind_text(stmt, 3,
+ sqlite3_bind_text(stmt, 3,
(char *)prop->ns->href,
strlen((char *)prop->ns->href),
SQLITE_TRANSIENT);
} else {
- sqlite3_bind_text(stmt, 3,
+ sqlite3_bind_text(stmt, 3,
"",
0,
SQLITE_TRANSIENT);
}
if (stmt == p->conf.stmt_update_prop) {
- sqlite3_bind_text(stmt, 4,
+ sqlite3_bind_text(stmt, 4,
(char *)xmlNodeGetContent(prop),
strlen((char *)xmlNodeGetContent(prop)),
SQLITE_TRANSIENT);
}
-
+
if (SQLITE_DONE != (r = sqlite3_step(stmt))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "sql-set failed:", sqlite3_errmsg(p->conf.sql));
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "sql-set failed:", sqlite3_errmsg(p->conf.sql));
}
}
}
@@ -1800,7 +2159,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
goto propmatch_cleanup;
}
-
+
con->http_status = 400;
} else {
if (SQLITE_OK != sqlite3_exec(p->conf.sql, "COMMIT", NULL, NULL, &err)) {
@@ -1817,6 +2176,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
}
propmatch_cleanup:
+
xmlFreeDoc(xml);
} else {
con->http_status = 400;
@@ -1826,11 +2186,307 @@ propmatch_cleanup:
#endif
con->http_status = 501;
return HANDLER_FINISHED;
- }
+ case HTTP_METHOD_LOCK:
+ /**
+ * a mac wants to write
+ *
+ * LOCK /dav/expire.txt HTTP/1.1\r\n
+ * User-Agent: WebDAVFS/1.3 (01308000) Darwin/8.1.0 (Power Macintosh)\r\n
+ * Accept: * / *\r\n
+ * Depth: 0\r\n
+ * Timeout: Second-600\r\n
+ * Content-Type: text/xml; charset=\"utf-8\"\r\n
+ * Content-Length: 229\r\n
+ * Connection: keep-alive\r\n
+ * Host: 192.168.178.23:1025\r\n
+ * \r\n
+ * <?xml version=\"1.0\" encoding=\"utf-8\"?>\n
+ * <D:lockinfo xmlns:D=\"DAV:\">\n
+ * <D:lockscope><D:exclusive/></D:lockscope>\n
+ * <D:locktype><D:write/></D:locktype>\n
+ * <D:owner>\n
+ * <D:href>http://www.apple.com/webdav_fs/</D:href>\n
+ * </D:owner>\n
+ * </D:lockinfo>\n
+ */
+
+ if (depth != 0 && depth != -1) {
+ con->http_status = 400;
+
+ return HANDLER_FINISHED;
+ }
+
+#ifdef USE_LOCKS
+ if (con->request.content_length) {
+ xmlDocPtr xml;
+ buffer *hdr_if = NULL;
+
+ if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
+ hdr_if = ds->value;
+ }
+
+ /* we don't support Depth: Infinity on locks */
+ if (hdr_if == NULL && depth == -1) {
+ con->http_status = 409; /* Conflict */
+
+ return HANDLER_FINISHED;
+ }
+
+ if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {
+ xmlNode *rootnode = xmlDocGetRootElement(xml);
+
+ assert(rootnode);
+
+ if (0 == xmlStrcmp(rootnode->name, BAD_CAST "lockinfo")) {
+ xmlNode *lockinfo;
+ const xmlChar *lockscope = NULL, *locktype = NULL; /* TODO: compiler says unused: *owner = NULL; */
+
+ for (lockinfo = rootnode->children; lockinfo; lockinfo = lockinfo->next) {
+ if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "lockscope")) {
+ xmlNode *value;
+ for (value = lockinfo->children; value; value = value->next) {
+ if ((0 == xmlStrcmp(value->name, BAD_CAST "exclusive")) ||
+ (0 == xmlStrcmp(value->name, BAD_CAST "shared"))) {
+ lockscope = value->name;
+ } else {
+ con->http_status = 400;
+
+ xmlFreeDoc(xml);
+ return HANDLER_FINISHED;
+ }
+ }
+ } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "locktype")) {
+ xmlNode *value;
+ for (value = lockinfo->children; value; value = value->next) {
+ if ((0 == xmlStrcmp(value->name, BAD_CAST "write"))) {
+ locktype = value->name;
+ } else {
+ con->http_status = 400;
+
+ xmlFreeDoc(xml);
+ return HANDLER_FINISHED;
+ }
+ }
+
+ } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "owner")) {
+ }
+ }
+
+ if (lockscope && locktype) {
+ sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
+
+ /* is this resourse already locked ? */
+
+ /* SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout
+ * FROM locks
+ * WHERE resource = ? */
+
+ if (stmt) {
+
+ sqlite3_reset(stmt);
+
+ sqlite3_bind_text(stmt, 1,
+ p->uri.path->ptr,
+ p->uri.path->used - 1,
+ SQLITE_TRANSIENT);
+
+ /* it is the PK */
+ while (SQLITE_ROW == sqlite3_step(stmt)) {
+ /* we found a lock
+ * 1. is it compatible ?
+ * 2. is it ours */
+ char *sql_lockscope = (char *)sqlite3_column_text(stmt, 2);
+
+ if (strcmp(sql_lockscope, "exclusive")) {
+ con->http_status = 423;
+ } else if (0 == xmlStrcmp(lockscope, BAD_CAST "exclusive")) {
+ /* resourse is locked with a shared lock
+ * client wants exclusive */
+ con->http_status = 423;
+ }
+ }
+ if (con->http_status == 423) {
+ xmlFreeDoc(xml);
+ return HANDLER_FINISHED;
+ }
+ }
+
+ stmt = p->conf.stmt_create_lock;
+ if (stmt) {
+ /* create a lock-token */
+ uuid_t id;
+ char uuid[37] /* 36 + \0 */;
+
+ uuid_generate(id);
+ uuid_unparse(id, uuid);
+
+ buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("opaquelocktoken:"));
+ buffer_append_string(p->tmp_buf, uuid);
+
+ /* "CREATE TABLE locks ("
+ * " locktoken TEXT NOT NULL,"
+ * " resource TEXT NOT NULL,"
+ * " lockscope TEXT NOT NULL,"
+ * " locktype TEXT NOT NULL,"
+ * " owner TEXT NOT NULL,"
+ * " depth INT NOT NULL,"
+ */
+
+ sqlite3_reset(stmt);
+
+ sqlite3_bind_text(stmt, 1,
+ CONST_BUF_LEN(p->tmp_buf),
+ SQLITE_TRANSIENT);
+
+ sqlite3_bind_text(stmt, 2,
+ CONST_BUF_LEN(con->uri.path),
+ SQLITE_TRANSIENT);
+
+ sqlite3_bind_text(stmt, 3,
+ (const char *)lockscope,
+ xmlStrlen(lockscope),
+ SQLITE_TRANSIENT);
+
+ sqlite3_bind_text(stmt, 4,
+ (const char *)locktype,
+ xmlStrlen(locktype),
+ SQLITE_TRANSIENT);
+
+ /* owner */
+ sqlite3_bind_text(stmt, 5,
+ "",
+ 0,
+ SQLITE_TRANSIENT);
+
+ /* depth */
+ sqlite3_bind_int(stmt, 6,
+ depth);
+
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "create lock:", sqlite3_errmsg(p->conf.sql));
+ }
+
+ /* looks like we survived */
+ webdav_lockdiscovery(srv, con, p->tmp_buf, (const char *)lockscope, (const char *)locktype, depth);
+
+ con->http_status = 201;
+ con->file_finished = 1;
+ }
+ }
+ }
+
+ xmlFreeDoc(xml);
+ return HANDLER_FINISHED;
+ } else {
+ con->http_status = 400;
+ return HANDLER_FINISHED;
+ }
+ } else {
+
+ if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
+ buffer *locktoken = ds->value;
+ sqlite3_stmt *stmt = p->conf.stmt_refresh_lock;
+
+ /* remove the < > around the token */
+ if (locktoken->used < 6) {
+ con->http_status = 400;
+
+ return HANDLER_FINISHED;
+ }
+
+ buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 2, locktoken->used - 5);
+
+ sqlite3_reset(stmt);
+
+ sqlite3_bind_text(stmt, 1,
+ CONST_BUF_LEN(p->tmp_buf),
+ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "refresh lock:", sqlite3_errmsg(p->conf.sql));
+ }
+
+ webdav_lockdiscovery(srv, con, p->tmp_buf, "exclusive", "write", 0);
+
+ con->http_status = 200;
+ con->file_finished = 1;
+ return HANDLER_FINISHED;
+ } else {
+ /* we need a lock-token to refresh */
+ con->http_status = 400;
+
+ return HANDLER_FINISHED;
+ }
+ }
+ break;
+#else
+ con->http_status = 501;
+ return HANDLER_FINISHED;
+#endif
+ case HTTP_METHOD_UNLOCK:
+#ifdef USE_LOCKS
+ if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Lock-Token"))) {
+ buffer *locktoken = ds->value;
+ sqlite3_stmt *stmt = p->conf.stmt_remove_lock;
+
+ /* remove the < > around the token */
+ if (locktoken->used < 4) {
+ con->http_status = 400;
+
+ return HANDLER_FINISHED;
+ }
+
+ /**
+ * FIXME:
+ *
+ * if the resourse is locked:
+ * - by us: unlock
+ * - by someone else: 401
+ * if the resource is not locked:
+ * - 412
+ * */
+
+ buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 1, locktoken->used - 3);
+
+ sqlite3_reset(stmt);
+
+ sqlite3_bind_text(stmt, 1,
+ CONST_BUF_LEN(p->tmp_buf),
+ SQLITE_TRANSIENT);
+
+ sqlite3_bind_text(stmt, 2,
+ CONST_BUF_LEN(con->uri.path),
+ SQLITE_TRANSIENT);
+
+ if (SQLITE_DONE != sqlite3_step(stmt)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "remove lock:", sqlite3_errmsg(p->conf.sql));
+ }
+
+ if (0 == sqlite3_changes(p->conf.sql)) {
+ con->http_status = 401;
+ } else {
+ con->http_status = 204;
+ }
+ return HANDLER_FINISHED;
+ } else {
+ /* we need a lock-token to unlock */
+ con->http_status = 400;
+
+ return HANDLER_FINISHED;
+ }
+ break;
+#else
+ con->http_status = 501;
+ return HANDLER_FINISHED;
+#endif
default:
break;
}
-
+
/* not found */
return HANDLER_GO_ON;
}
@@ -1838,17 +2494,18 @@ propmatch_cleanup:
/* this function is called at dlopen() time and inits the callbacks */
+int mod_webdav_plugin_init(plugin *p);
int mod_webdav_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("webdav");
-
+
p->init = mod_webdav_init;
p->handle_uri_clean = mod_webdav_uri_handler;
p->handle_physical = mod_webdav_subrequest_handler;
p->set_defaults = mod_webdav_set_defaults;
p->cleanup = mod_webdav_free;
-
+
p->data = NULL;
-
+
return 0;
}
diff --git a/src/network.c b/src/network.c
index 922009f..f59f60d 100644
--- a/src/network.c
+++ b/src/network.c
@@ -1,3 +1,15 @@
+#include "network.h"
+#include "fdevent.h"
+#include "log.h"
+#include "connections.h"
+#include "plugin.h"
+#include "joblist.h"
+#include "configfile.h"
+
+#include "network_backends.h"
+#include "sys-mmap.h"
+#include "sys-socket.h"
+
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
@@ -9,33 +21,42 @@
#include <stdlib.h>
#include <assert.h>
-#include "network.h"
-#include "fdevent.h"
-#include "log.h"
-#include "connections.h"
-#include "plugin.h"
-#include "joblist.h"
-
-#include "network_backends.h"
-#include "sys-mmap.h"
-#include "sys-socket.h"
+#ifdef USE_OPENSSL
+# include <openssl/ssl.h>
+# include <openssl/err.h>
+# include <openssl/rand.h>
+# include <openssl/dh.h>
+# include <openssl/bn.h>
+
+# if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+# ifndef OPENSSL_NO_ECDH
+# include <openssl/ecdh.h>
+# endif
+# endif
+#endif
#ifdef USE_OPENSSL
-# include <openssl/ssl.h>
-# include <openssl/err.h>
-# include <openssl/rand.h>
+static void ssl_info_callback(const SSL *ssl, int where, int ret) {
+ UNUSED(ret);
+
+ if (0 != (where & SSL_CB_HANDSHAKE_START)) {
+ connection *con = SSL_get_app_data(ssl);
+ ++con->renegotiations;
+ } else if (0 != (where & SSL_CB_HANDSHAKE_DONE)) {
+ ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
+ }
+}
#endif
-handler_t network_server_handle_fdevent(void *s, void *context, int revents) {
- server *srv = (server *)s;
+static handler_t network_server_handle_fdevent(server *srv, void *context, int revents) {
server_socket *srv_socket = (server_socket *)context;
connection *con;
int loops = 0;
-
+
UNUSED(context);
-
- if (revents != FDEVENT_IN) {
- log_error_write(srv, __FILE__, __LINE__, "sdd",
+
+ if (0 == (revents & FDEVENT_IN)) {
+ log_error_write(srv, __FILE__, __LINE__, "sdd",
"strange event for server socket",
srv_socket->fd,
revents);
@@ -44,12 +65,12 @@ handler_t network_server_handle_fdevent(void *s, void *context, int revents) {
/* accept()s at most 100 connections directly
*
- * we jump out after 100 to give the waiting connections a chance */
+ * we jump out after 100 to give the waiting connections a chance */
for (loops = 0; loops < 100 && NULL != (con = connection_accept(srv, srv_socket)); loops++) {
handler_t r;
-
+
connection_state_machine(srv, con);
-
+
switch(r = plugins_call_handle_joblist(srv, con)) {
case HANDLER_FINISHED:
case HANDLER_GO_ON:
@@ -62,7 +83,54 @@ handler_t network_server_handle_fdevent(void *s, void *context, int revents) {
return HANDLER_GO_ON;
}
-int network_server_init(server *srv, buffer *host_token, specific_config *s) {
+#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
+static int network_ssl_servername_callback(SSL *ssl, int *al, server *srv) {
+ const char *servername;
+ connection *con = (connection *) SSL_get_app_data(ssl);
+ UNUSED(al);
+
+ buffer_copy_string(con->uri.scheme, "https");
+
+ if (NULL == (servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) {
+#if 0
+ /* this "error" just means the client didn't support it */
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ "failed to get TLS server name");
+#endif
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+ buffer_copy_string(con->tlsext_server_name, servername);
+ buffer_to_lower(con->tlsext_server_name);
+
+ /* Sometimes this is still set, confusing COMP_HTTP_HOST */
+ buffer_reset(con->uri.authority);
+
+ config_cond_cache_reset(srv, con);
+ config_setup_connection(srv, con);
+
+ config_patch_connection(srv, con, COMP_SERVER_SOCKET);
+ config_patch_connection(srv, con, COMP_HTTP_SCHEME);
+ config_patch_connection(srv, con, COMP_HTTP_HOST);
+
+ if (NULL == con->conf.ssl_ctx) {
+ /* ssl_ctx <=> pemfile was set <=> ssl_ctx got patched: so this should never happen */
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ "null SSL_CTX for TLS server name", con->tlsext_server_name);
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ /* switch to new SSL_CTX in reaction to a client's server_name extension */
+ if (con->conf.ssl_ctx != SSL_set_SSL_CTX(ssl, con->conf.ssl_ctx)) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ "failed to set SSL_CTX for TLS server name", con->tlsext_server_name);
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ return SSL_TLSEXT_ERR_OK;
+}
+#endif
+
+static int network_server_init(server *srv, buffer *host_token, specific_config *s) {
int val;
socklen_t addr_len;
server_socket *srv_socket;
@@ -72,18 +140,14 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) {
buffer *b;
int is_unix_domain_socket = 0;
int fd;
-
-#ifdef SO_ACCEPTFILTER
- struct accept_filter_arg afa;
-#endif
#ifdef __WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
-
+
wVersionRequested = MAKEWORD( 2, 2 );
-
+
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
/* Tell the user that we could not find a usable */
@@ -91,37 +155,38 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) {
return -1;
}
#endif
-
+
srv_socket = calloc(1, sizeof(*srv_socket));
srv_socket->fd = -1;
-
+ srv_socket->fde_ndx = -1;
+
srv_socket->srv_token = buffer_init();
buffer_copy_string_buffer(srv_socket->srv_token, host_token);
-
+
b = buffer_init();
buffer_copy_string_buffer(b, host_token);
-
- /* ipv4:port
+
+ /* ipv4:port
* [ipv6]:port
*/
if (NULL == (sp = strrchr(b->ptr, ':'))) {
log_error_write(srv, __FILE__, __LINE__, "sb", "value of $SERVER[\"socket\"] has to be \"ip:port\".", b);
-
- return -1;
+
+ goto error_free_socket;
}
-
+
host = b->ptr;
-
+
/* check for [ and ] */
if (b->ptr[0] == '[' && *(sp-1) == ']') {
*(sp-1) = '\0';
host++;
-
+
s->use_ipv6 = 1;
}
-
+
*(sp++) = '\0';
-
+
port = strtol(sp, NULL, 10);
if (host[0] == '/') {
@@ -129,57 +194,62 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) {
is_unix_domain_socket = 1;
} else if (port == 0 || port > 65535) {
log_error_write(srv, __FILE__, __LINE__, "sd", "port out of range:", port);
-
- return -1;
+
+ goto error_free_socket;
}
-
+
if (*host == '\0') host = NULL;
if (is_unix_domain_socket) {
#ifdef HAVE_SYS_UN_H
srv_socket->addr.plain.sa_family = AF_UNIX;
-
+
if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
- return -1;
+ goto error_free_socket;
}
#else
log_error_write(srv, __FILE__, __LINE__, "s",
"ERROR: Unix Domain sockets are not supported.");
- return -1;
+ goto error_free_socket;
#endif
}
#ifdef HAVE_IPV6
if (s->use_ipv6) {
srv_socket->addr.plain.sa_family = AF_INET6;
-
+
if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
- return -1;
+ goto error_free_socket;
}
srv_socket->use_ipv6 = 1;
}
#endif
-
+
if (srv_socket->fd == -1) {
srv_socket->addr.plain.sa_family = AF_INET;
if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
- return -1;
+ goto error_free_socket;
}
}
-
+
+#ifdef FD_CLOEXEC
+ /* set FD_CLOEXEC now, fdevent_fcntl_set is called later; needed for pipe-logger forks */
+ fcntl(srv_socket->fd, F_SETFD, FD_CLOEXEC);
+#endif
+
/* */
srv->cur_fds = srv_socket->fd;
-
+
val = 1;
if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt failed:", strerror(errno));
- return -1;
+ log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt(SO_REUSEADDR) failed:", strerror(errno));
+ goto error_free_socket;
}
-
+
switch(srv_socket->addr.plain.sa_family) {
#ifdef HAVE_IPV6
case AF_INET6:
@@ -187,26 +257,37 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) {
srv_socket->addr.ipv6.sin6_family = AF_INET6;
if (host == NULL) {
srv_socket->addr.ipv6.sin6_addr = in6addr_any;
+ log_error_write(srv, __FILE__, __LINE__, "s", "warning: please use server.use-ipv6 only for hostnames, not without server.bind / empty address; your config will break if the kernel default for IPV6_V6ONLY changes");
} else {
struct addrinfo hints, *res;
int r;
-
+
+ if (s->set_v6only) {
+ val = 1;
+ if (-1 == setsockopt(srv_socket->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt(IPV6_V6ONLY) failed:", strerror(errno));
+ goto error_free_socket;
+ }
+ } else {
+ log_error_write(srv, __FILE__, __LINE__, "s", "warning: server.set-v6only will be removed soon, update your config to have different sockets for ipv4 and ipv6");
+ }
+
memset(&hints, 0, sizeof(hints));
-
+
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
-
+
if (0 != (r = getaddrinfo(host, NULL, &hints, &res))) {
- log_error_write(srv, __FILE__, __LINE__,
- "sssss", "getaddrinfo failed: ",
+ log_error_write(srv, __FILE__, __LINE__,
+ "sssss", "getaddrinfo failed: ",
gai_strerror(r), "'", host, "'");
-
- return -1;
+
+ goto error_free_socket;
}
-
+
memcpy(&(srv_socket->addr), res->ai_addr, res->ai_addrlen);
-
+
freeaddrinfo(res);
}
srv_socket->addr.ipv6.sin6_port = htons(port);
@@ -221,50 +302,50 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) {
} else {
struct hostent *he;
if (NULL == (he = gethostbyname(host))) {
- log_error_write(srv, __FILE__, __LINE__,
- "sds", "gethostbyname failed: ",
+ log_error_write(srv, __FILE__, __LINE__,
+ "sds", "gethostbyname failed: ",
h_errno, host);
- return -1;
+ goto error_free_socket;
}
-
+
if (he->h_addrtype != AF_INET) {
log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
- return -1;
+ goto error_free_socket;
}
-
+
if (he->h_length != sizeof(struct in_addr)) {
log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
- return -1;
+ goto error_free_socket;
}
-
+
memcpy(&(srv_socket->addr.ipv4.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
}
srv_socket->addr.ipv4.sin_port = htons(port);
-
+
addr_len = sizeof(struct sockaddr_in);
-
+
break;
case AF_UNIX:
srv_socket->addr.un.sun_family = AF_UNIX;
strcpy(srv_socket->addr.un.sun_path, host);
-
+
#ifdef SUN_LEN
addr_len = SUN_LEN(&srv_socket->addr.un);
#else
/* stevens says: */
- addr_len = strlen(host) + sizeof(srv_socket->addr.un.sun_family);
+ addr_len = strlen(host) + 1 + sizeof(srv_socket->addr.un.sun_family);
#endif
/* check if the socket exists and try to connect to it. */
if (-1 != (fd = connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
close(fd);
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "server socket is still in use:",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "server socket is still in use:",
host);
- return -1;
+ goto error_free_socket;
}
/* connect failed */
@@ -275,112 +356,63 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) {
case ENOENT:
break;
default:
- log_error_write(srv, __FILE__, __LINE__, "sds",
- "testing socket failed:",
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "testing socket failed:",
host, strerror(errno));
- return -1;
+ goto error_free_socket;
}
break;
default:
- addr_len = 0;
-
- return -1;
+ goto error_free_socket;
}
-
+
if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
switch(srv_socket->addr.plain.sa_family) {
case AF_UNIX:
- log_error_write(srv, __FILE__, __LINE__, "sds",
- "can't bind to socket:",
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "can't bind to socket:",
host, strerror(errno));
break;
default:
- log_error_write(srv, __FILE__, __LINE__, "ssds",
- "can't bind to port:",
+ log_error_write(srv, __FILE__, __LINE__, "ssds",
+ "can't bind to port:",
host, port, strerror(errno));
break;
}
- return -1;
+ goto error_free_socket;
}
-
+
if (-1 == listen(srv_socket->fd, 128 * 8)) {
log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed: ", strerror(errno));
- return -1;
+ goto error_free_socket;
}
-
+
if (s->is_ssl) {
#ifdef USE_OPENSSL
- if (srv->ssl_is_init == 0) {
- SSL_load_error_strings();
- SSL_library_init();
- srv->ssl_is_init = 1;
-
- if (0 == RAND_status()) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
- "not enough entropy in the pool");
- return -1;
- }
- }
-
- if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
- ERR_error_string(ERR_get_error(), NULL));
- return -1;
- }
-
- if (buffer_is_empty(s->ssl_pemfile)) {
+ if (NULL == (srv_socket->ssl_ctx = s->ssl_ctx)) {
log_error_write(srv, __FILE__, __LINE__, "s", "ssl.pemfile has to be set");
- return -1;
- }
-
- if (!buffer_is_empty(s->ssl_ca_file)) {
- if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) {
- log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
- ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
- return -1;
- }
- }
-
- if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
- log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
- ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
- return -1;
- }
-
- if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
- log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
- ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
- return -1;
- }
-
- if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) {
- log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
- "Private key does not match the certificate public key, reason:",
- ERR_error_string(ERR_get_error(), NULL),
- s->ssl_pemfile);
- return -1;
+ goto error_free_socket;
}
- srv_socket->ssl_ctx = s->ssl_ctx;
#else
-
- buffer_free(srv_socket->srv_token);
- free(srv_socket);
-
- buffer_free(b);
-
- log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
"ssl requested but openssl support is not compiled in");
-
- return -1;
+
+ goto error_free_socket;
+#endif
+#ifdef TCP_DEFER_ACCEPT
+ } else if (s->defer_accept) {
+ int v = s->defer_accept;
+ if (-1 == setsockopt(srv_socket->fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &v, sizeof(v))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "can't set TCP_DEFER_ACCEPT: ", strerror(errno));
+ }
#endif
} else {
#ifdef SO_ACCEPTFILTER
- /*
- * FreeBSD accf_http filter
- *
- */
+ /* FreeBSD accf_http filter */
+ struct accept_filter_arg afa;
memset(&afa, 0, sizeof(afa));
strcpy(afa.af_name, "httpready");
if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
@@ -390,10 +422,9 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) {
}
#endif
}
-
+
srv_socket->is_ssl = s->is_ssl;
- srv_socket->fde_ndx = -1;
-
+
if (srv->srv_sockets.size == 0) {
srv->srv_sockets.size = 4;
srv->srv_sockets.used = 0;
@@ -402,36 +433,53 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) {
srv->srv_sockets.size += 4;
srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket));
}
-
+
srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;
-
+
buffer_free(b);
-
+
return 0;
+
+error_free_socket:
+ if (srv_socket->fd != -1) {
+ /* check if server fd are already registered */
+ if (srv_socket->fde_ndx != -1) {
+ fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
+ fdevent_unregister(srv->ev, srv_socket->fd);
+ }
+
+ close(srv_socket->fd);
+ }
+ buffer_free(srv_socket->srv_token);
+ free(srv_socket);
+
+ buffer_free(b);
+
+ return -1;
}
int network_close(server *srv) {
size_t i;
for (i = 0; i < srv->srv_sockets.used; i++) {
server_socket *srv_socket = srv->srv_sockets.ptr[i];
-
+
if (srv_socket->fd != -1) {
/* check if server fd are already registered */
if (srv_socket->fde_ndx != -1) {
fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
fdevent_unregister(srv->ev, srv_socket->fd);
}
-
+
close(srv_socket->fd);
}
-
+
buffer_free(srv_socket->srv_token);
-
+
free(srv_socket);
}
-
+
free(srv->srv_sockets.ptr);
-
+
return 0;
}
@@ -448,11 +496,62 @@ int network_init(server *srv) {
buffer *b;
size_t i;
network_backend_t backend;
-
- struct nb_map {
- network_backend_t nb;
- const char *name;
- } network_backends[] = {
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+#ifndef OPENSSL_NO_ECDH
+ EC_KEY *ecdh;
+ int nid;
+#endif
+#endif
+
+#ifdef USE_OPENSSL
+ DH *dh;
+ BIO *bio;
+
+ /* 1024-bit MODP Group with 160-bit prime order subgroup (RFC5114)
+ * -----BEGIN DH PARAMETERS-----
+ * MIIBDAKBgQCxC4+WoIDgHd6S3l6uXVTsUsmfvPsGo8aaap3KUtI7YWBz4oZ1oj0Y
+ * mDjvHi7mUsAT7LSuqQYRIySXXDzUm4O/rMvdfZDEvXCYSI6cIZpzck7/1vrlZEc4
+ * +qMaT/VbzMChUa9fDci0vUW/N982XBpl5oz9p21NpwjfH7K8LkpDcQKBgQCk0cvV
+ * w/00EmdlpELvuZkF+BBN0lisUH/WQGz/FCZtMSZv6h5cQVZLd35pD1UE8hMWAhe0
+ * sBuIal6RVH+eJ0n01/vX07mpLuGQnQ0iY/gKdqaiTAh6CR9THb8KAWm2oorWYqTR
+ * jnOvoy13nVkY0IvIhY9Nzvl8KiSFXm7rIrOy5QICAKA=
+ * -----END DH PARAMETERS-----
+ */
+
+ static const unsigned char dh1024_p[]={
+ 0xB1,0x0B,0x8F,0x96,0xA0,0x80,0xE0,0x1D,0xDE,0x92,0xDE,0x5E,
+ 0xAE,0x5D,0x54,0xEC,0x52,0xC9,0x9F,0xBC,0xFB,0x06,0xA3,0xC6,
+ 0x9A,0x6A,0x9D,0xCA,0x52,0xD2,0x3B,0x61,0x60,0x73,0xE2,0x86,
+ 0x75,0xA2,0x3D,0x18,0x98,0x38,0xEF,0x1E,0x2E,0xE6,0x52,0xC0,
+ 0x13,0xEC,0xB4,0xAE,0xA9,0x06,0x11,0x23,0x24,0x97,0x5C,0x3C,
+ 0xD4,0x9B,0x83,0xBF,0xAC,0xCB,0xDD,0x7D,0x90,0xC4,0xBD,0x70,
+ 0x98,0x48,0x8E,0x9C,0x21,0x9A,0x73,0x72,0x4E,0xFF,0xD6,0xFA,
+ 0xE5,0x64,0x47,0x38,0xFA,0xA3,0x1A,0x4F,0xF5,0x5B,0xCC,0xC0,
+ 0xA1,0x51,0xAF,0x5F,0x0D,0xC8,0xB4,0xBD,0x45,0xBF,0x37,0xDF,
+ 0x36,0x5C,0x1A,0x65,0xE6,0x8C,0xFD,0xA7,0x6D,0x4D,0xA7,0x08,
+ 0xDF,0x1F,0xB2,0xBC,0x2E,0x4A,0x43,0x71,
+ };
+
+ static const unsigned char dh1024_g[]={
+ 0xA4,0xD1,0xCB,0xD5,0xC3,0xFD,0x34,0x12,0x67,0x65,0xA4,0x42,
+ 0xEF,0xB9,0x99,0x05,0xF8,0x10,0x4D,0xD2,0x58,0xAC,0x50,0x7F,
+ 0xD6,0x40,0x6C,0xFF,0x14,0x26,0x6D,0x31,0x26,0x6F,0xEA,0x1E,
+ 0x5C,0x41,0x56,0x4B,0x77,0x7E,0x69,0x0F,0x55,0x04,0xF2,0x13,
+ 0x16,0x02,0x17,0xB4,0xB0,0x1B,0x88,0x6A,0x5E,0x91,0x54,0x7F,
+ 0x9E,0x27,0x49,0xF4,0xD7,0xFB,0xD7,0xD3,0xB9,0xA9,0x2E,0xE1,
+ 0x90,0x9D,0x0D,0x22,0x63,0xF8,0x0A,0x76,0xA6,0xA2,0x4C,0x08,
+ 0x7A,0x09,0x1F,0x53,0x1D,0xBF,0x0A,0x01,0x69,0xB6,0xA2,0x8A,
+ 0xD6,0x62,0xA4,0xD1,0x8E,0x73,0xAF,0xA3,0x2D,0x77,0x9D,0x59,
+ 0x18,0xD0,0x8B,0xC8,0x85,0x8F,0x4D,0xCE,0xF9,0x7C,0x2A,0x24,
+ 0x85,0x5E,0x6E,0xEB,0x22,0xB3,0xB2,0xE5,
+ };
+#endif
+
+ struct nb_map {
+ network_backend_t nb;
+ const char *name;
+ } network_backends[] = {
/* lowest id wins */
#if defined USE_LINUX_SENDFILE
{ NETWORK_BACKEND_LINUX_SENDFILE, "linux-sendfile" },
@@ -469,18 +568,218 @@ int network_init(server *srv) {
{ NETWORK_BACKEND_WRITE, "write" },
{ NETWORK_BACKEND_UNSET, NULL }
};
-
+
+#ifdef USE_OPENSSL
+ /* load SSL certificates */
+ for (i = 0; i < srv->config_context->used; i++) {
+ specific_config *s = srv->config_storage[i];
+#ifndef SSL_OP_NO_COMPRESSION
+# define SSL_OP_NO_COMPRESSION 0
+#endif
+ long ssloptions =
+ SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_NO_COMPRESSION;
+
+ if (buffer_is_empty(s->ssl_pemfile)) continue;
+
+#ifdef OPENSSL_NO_TLSEXT
+ {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ if (COMP_HTTP_HOST == dc->comp) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ "can't use ssl.pemfile with $HTTP[\"host\"], openssl version does not support TLS extensions");
+ return -1;
+ }
+ }
+#endif
+
+ if (srv->ssl_is_init == 0) {
+ SSL_load_error_strings();
+ SSL_library_init();
+ OpenSSL_add_all_algorithms();
+ srv->ssl_is_init = 1;
+
+ if (0 == RAND_status()) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ "not enough entropy in the pool");
+ return -1;
+ }
+ }
+
+ if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+
+ SSL_CTX_set_options(s->ssl_ctx, ssloptions);
+ SSL_CTX_set_info_callback(s->ssl_ctx, ssl_info_callback);
+
+ if (!s->ssl_use_sslv2) {
+ /* disable SSLv2 */
+ if (!(SSL_OP_NO_SSLv2 & SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_SSLv2))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+ }
+
+ if (!s->ssl_use_sslv3) {
+ /* disable SSLv3 */
+ if (!(SSL_OP_NO_SSLv3 & SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_SSLv3))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+ }
+
+ if (!buffer_is_empty(s->ssl_cipher_list)) {
+ /* Disable support for low encryption ciphers */
+ if (SSL_CTX_set_cipher_list(s->ssl_ctx, s->ssl_cipher_list->ptr) != 1) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+
+ if (s->ssl_honor_cipher_order) {
+ SSL_CTX_set_options(s->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
+ }
+ }
+
+ /* Support for Diffie-Hellman key exchange */
+ if (!buffer_is_empty(s->ssl_dh_file)) {
+ /* DH parameters from file */
+ bio = BIO_new_file((char *) s->ssl_dh_file->ptr, "r");
+ if (bio == NULL) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL: Unable to open file", s->ssl_dh_file->ptr);
+ return -1;
+ }
+ dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+ BIO_free(bio);
+ if (dh == NULL) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL: PEM_read_bio_DHparams failed", s->ssl_dh_file->ptr);
+ return -1;
+ }
+ } else {
+ /* Default DH parameters from RFC5114 */
+ dh = DH_new();
+ if (dh == NULL) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "SSL: DH_new () failed");
+ return -1;
+ }
+ dh->p = BN_bin2bn(dh1024_p,sizeof(dh1024_p), NULL);
+ dh->g = BN_bin2bn(dh1024_g,sizeof(dh1024_g), NULL);
+ dh->length = 160;
+ if ((dh->p == NULL) || (dh->g == NULL)) {
+ DH_free(dh);
+ log_error_write(srv, __FILE__, __LINE__, "s", "SSL: BN_bin2bn () failed");
+ return -1;
+ }
+ }
+ SSL_CTX_set_tmp_dh(s->ssl_ctx,dh);
+ SSL_CTX_set_options(s->ssl_ctx,SSL_OP_SINGLE_DH_USE);
+ DH_free(dh);
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+#ifndef OPENSSL_NO_ECDH
+ /* Support for Elliptic-Curve Diffie-Hellman key exchange */
+ if (!buffer_is_empty(s->ssl_ec_curve)) {
+ /* OpenSSL only supports the "named curves" from RFC 4492, section 5.1.1. */
+ nid = OBJ_sn2nid((char *) s->ssl_ec_curve->ptr);
+ if (nid == 0) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL: Unknown curve name", s->ssl_ec_curve->ptr);
+ return -1;
+ }
+ } else {
+ /* Default curve */
+ nid = OBJ_sn2nid("prime256v1");
+ }
+ ecdh = EC_KEY_new_by_curve_name(nid);
+ if (ecdh == NULL) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL: Unable to create curve", s->ssl_ec_curve->ptr);
+ return -1;
+ }
+ SSL_CTX_set_tmp_ecdh(s->ssl_ctx,ecdh);
+ SSL_CTX_set_options(s->ssl_ctx,SSL_OP_SINGLE_ECDH_USE);
+ EC_KEY_free(ecdh);
+#endif
+#endif
+
+ if (!buffer_is_empty(s->ssl_ca_file)) {
+ if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
+ return -1;
+ }
+ if (s->ssl_verifyclient) {
+ STACK_OF(X509_NAME) *certs = SSL_load_client_CA_file(s->ssl_ca_file->ptr);
+ if (!certs) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
+ }
+ if (SSL_CTX_set_session_id_context(s->ssl_ctx, (void*) &srv, sizeof(srv)) != 1) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+ SSL_CTX_set_client_CA_list(s->ssl_ctx, certs);
+ SSL_CTX_set_verify(
+ s->ssl_ctx,
+ SSL_VERIFY_PEER | (s->ssl_verifyclient_enforce ? SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0),
+ NULL
+ );
+ SSL_CTX_set_verify_depth(s->ssl_ctx, s->ssl_verifyclient_depth);
+ }
+ } else if (s->ssl_verifyclient) {
+ log_error_write(
+ srv, __FILE__, __LINE__, "s",
+ "SSL: You specified ssl.verifyclient.activate but no ca_file"
+ );
+ }
+
+ if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
+ return -1;
+ }
+
+ if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
+ return -1;
+ }
+
+ if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) {
+ log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
+ "Private key does not match the certificate public key, reason:",
+ ERR_error_string(ERR_get_error(), NULL),
+ s->ssl_pemfile);
+ return -1;
+ }
+ SSL_CTX_set_default_read_ahead(s->ssl_ctx, 1);
+ SSL_CTX_set_mode(s->ssl_ctx, SSL_CTX_get_mode(s->ssl_ctx) | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+
+# ifndef OPENSSL_NO_TLSEXT
+ if (!SSL_CTX_set_tlsext_servername_callback(s->ssl_ctx, network_ssl_servername_callback) ||
+ !SSL_CTX_set_tlsext_servername_arg(s->ssl_ctx, srv)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ "failed to initialize TLS servername callback, openssl library does not support TLS servername extension");
+ return -1;
+ }
+# endif
+ }
+#endif
+
b = buffer_init();
-
+
buffer_copy_string_buffer(b, srv->srvconf.bindhost);
- buffer_append_string(b, ":");
+ buffer_append_string_len(b, CONST_STR_LEN(":"));
buffer_append_long(b, srv->srvconf.port);
-
+
if (0 != network_server_init(srv, b, srv->config_storage[0])) {
return -1;
}
buffer_free(b);
-
+
#ifdef USE_OPENSSL
srv->network_ssl_backend_write = network_write_chunkqueue_openssl;
#endif
@@ -500,8 +799,8 @@ int network_init(server *srv) {
if (NULL == network_backends[i].name) {
/* we don't know it */
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "server.network-backend has a unknown value:",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "server.network-backend has a unknown value:",
srv->srvconf.network_backend);
return -1;
@@ -519,17 +818,17 @@ int network_init(server *srv) {
#endif
#ifdef USE_LINUX_SENDFILE
case NETWORK_BACKEND_LINUX_SENDFILE:
- srv->network_backend_write = network_write_chunkqueue_linuxsendfile;
+ srv->network_backend_write = network_write_chunkqueue_linuxsendfile;
break;
#endif
#ifdef USE_FREEBSD_SENDFILE
case NETWORK_BACKEND_FREEBSD_SENDFILE:
- srv->network_backend_write = network_write_chunkqueue_freebsdsendfile;
+ srv->network_backend_write = network_write_chunkqueue_freebsdsendfile;
break;
#endif
#ifdef USE_SOLARIS_SENDFILEV
case NETWORK_BACKEND_SOLARIS_SENDFILEV:
- srv->network_backend_write = network_write_chunkqueue_solarissendfilev;
+ srv->network_backend_write = network_write_chunkqueue_solarissendfilev;
break;
#endif
default:
@@ -540,63 +839,85 @@ int network_init(server *srv) {
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
specific_config *s = srv->config_storage[i];
-
+ size_t j;
+
/* not our stage */
if (COMP_SERVER_SOCKET != dc->comp) continue;
-
- if (dc->cond != CONFIG_COND_EQ) {
- log_error_write(srv, __FILE__, __LINE__, "s", "only == is allowed for $SERVER[\"socket\"].");
-
- return -1;
+
+ if (dc->cond != CONFIG_COND_EQ) continue;
+
+ /* check if we already know this socket,
+ * if yes, don't init it */
+ for (j = 0; j < srv->srv_sockets.used; j++) {
+ if (buffer_is_equal(srv->srv_sockets.ptr[j]->srv_token, dc->string)) {
+ break;
+ }
}
-
- if (0 != network_server_init(srv, dc->string, s)) {
- return -1;
+
+ if (j == srv->srv_sockets.used) {
+ if (0 != network_server_init(srv, dc->string, s)) return -1;
}
}
-
-
+
return 0;
}
int network_register_fdevents(server *srv) {
size_t i;
-
+
if (-1 == fdevent_reset(srv->ev)) {
return -1;
}
-
+
/* register fdevents after reset */
for (i = 0; i < srv->srv_sockets.used; i++) {
server_socket *srv_socket = srv->srv_sockets.ptr[i];
-
+
fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
- fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
+ fdevent_event_set(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
}
return 0;
}
-int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
+int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq, off_t max_bytes) {
int ret = -1;
off_t written = 0;
-#ifdef TCP_CORK
+#ifdef TCP_CORK
int corked = 0;
#endif
server_socket *srv_socket = con->srv_socket;
- if (con->conf.global_kbytes_per_second &&
- *(con->conf.global_bytes_per_second_cnt_ptr) > con->conf.global_kbytes_per_second * 1024) {
- /* we reached the global traffic limit */
+ if (con->conf.global_kbytes_per_second) {
+ off_t limit = con->conf.global_kbytes_per_second * 1024 - *(con->conf.global_bytes_per_second_cnt_ptr);
+ if (limit <= 0) {
+ /* we reached the global traffic limit */
+
+ con->traffic_limit_reached = 1;
+ joblist_append(srv, con);
+
+ return 1;
+ } else {
+ if (max_bytes > limit) max_bytes = limit;
+ }
+ }
+
+ if (con->conf.kbytes_per_second) {
+ off_t limit = con->conf.kbytes_per_second * 1024 - con->bytes_written_cur_second;
+ if (limit <= 0) {
+ /* we reached the traffic limit */
- con->traffic_limit_reached = 1;
- joblist_append(srv, con);
+ con->traffic_limit_reached = 1;
+ joblist_append(srv, con);
- return 1;
- }
+ return 1;
+ } else {
+ if (max_bytes > limit) max_bytes = limit;
+ }
+ }
written = cq->bytes_out;
-#ifdef TCP_CORK
+#ifdef TCP_CORK
/* Linux: put a cork into the socket as we want to combine the write() calls
* but only if we really have multiple chunks
*/
@@ -605,20 +926,20 @@ int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
}
#endif
-
+
if (srv_socket->is_ssl) {
#ifdef USE_OPENSSL
- ret = srv->network_ssl_backend_write(srv, con, con->ssl, cq);
+ ret = srv->network_ssl_backend_write(srv, con, con->ssl, cq, max_bytes);
#endif
} else {
- ret = srv->network_backend_write(srv, con, con->fd, cq);
+ ret = srv->network_backend_write(srv, con, con->fd, cq, max_bytes);
}
-
+
if (ret >= 0) {
chunkqueue_remove_finished_chunks(cq);
ret = chunkqueue_is_empty(cq) ? 0 : 1;
}
-
+
#ifdef TCP_CORK
if (corked) {
corked = 0;
@@ -631,13 +952,6 @@ int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
con->bytes_written_cur_second += written;
*(con->conf.global_bytes_per_second_cnt_ptr) += written;
-
- if (con->conf.kbytes_per_second &&
- (con->bytes_written_cur_second > con->conf.kbytes_per_second * 1024)) {
- /* we reached the traffic limit */
-
- con->traffic_limit_reached = 1;
- joblist_append(srv, con);
- }
+
return ret;
}
diff --git a/src/network.h b/src/network.h
index 99c7596..d9d4e7a 100644
--- a/src/network.h
+++ b/src/network.h
@@ -3,7 +3,7 @@
#include "server.h"
-int network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
+int network_write_chunkqueue(server *srv, connection *con, chunkqueue *c, off_t max_bytes);
int network_init(server *srv);
int network_close(server *srv);
diff --git a/src/network_backends.h b/src/network_backends.h
index 94650a7..5813253 100644
--- a/src/network_backends.h
+++ b/src/network_backends.h
@@ -2,8 +2,9 @@
#define _NETWORK_BACKENDS_H_
#ifdef HAVE_CONFIG_H
-#include "config.h"
+# include "config.h"
#endif
+#include "settings.h"
#include <sys/types.h>
@@ -14,7 +15,7 @@
# include <sys/uio.h>
#endif
-#if defined HAVE_SYS_UIO_H && defined HAVE_SENDFILE && defined HAVE_WRITEV && defined(__FreeBSD__)
+#if defined HAVE_SYS_UIO_H && defined HAVE_SENDFILE && defined HAVE_WRITEV && (defined(__FreeBSD__) || defined(__DragonFly__))
# define USE_FREEBSD_SENDFILE
# include <sys/uio.h>
#endif
@@ -30,7 +31,7 @@
# include <sys/uio.h>
#endif
-#if defined HAVE_SYS_MMAN_H && defined HAVE_MMAP
+#if defined HAVE_SYS_MMAN_H && defined HAVE_MMAP && defined ENABLE_MMAP
# define USE_MMAP
# include <sys/mman.h>
/* NetBSD 1.3.x needs it */
@@ -45,14 +46,19 @@
#include "base.h"
+/* return values:
+ * >= 0 : no error
+ * -1 : error (on our side)
+ * -2 : remote close
+ */
-int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq);
-int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq);
-int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
-int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
-int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq);
+int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes);
+int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes);
+int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes);
+int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes);
+int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes);
#ifdef USE_OPENSSL
-int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq);
+int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq, off_t max_bytes);
#endif
#endif
diff --git a/src/network_freebsd_sendfile.c b/src/network_freebsd_sendfile.c
index a6994c0..7b165fc 100644
--- a/src/network_freebsd_sendfile.c
+++ b/src/network_freebsd_sendfile.c
@@ -2,6 +2,11 @@
#ifdef USE_FREEBSD_SENDFILE
+#include "network.h"
+#include "fdevent.h"
+#include "log.h"
+#include "stat_cache.h"
+
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
@@ -18,46 +23,38 @@
#include <string.h>
#include <stdlib.h>
-#include "network.h"
-#include "fdevent.h"
-#include "log.h"
-#include "stat_cache.h"
-
#ifndef UIO_MAXIOV
-# ifdef __FreeBSD__
-/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */
+# if defined(__FreeBSD__) || defined(__DragonFly__)
+/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */
# define UIO_MAXIOV 1024
# endif
#endif
-int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
+int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes) {
chunk *c;
- size_t chunks_written = 0;
-
- for(c = cq->first; c; c = c->next, chunks_written++) {
+
+ for(c = cq->first; (max_bytes > 0) && (NULL != c); c = c->next) {
int chunk_finished = 0;
-
+
switch(c->type) {
case MEM_CHUNK: {
char * offset;
- size_t toSend;
+ off_t toSend;
ssize_t r;
-
+
size_t num_chunks, i;
struct iovec chunks[UIO_MAXIOV];
chunk *tc;
size_t num_bytes = 0;
-
- /* we can't send more then SSIZE_MAX bytes in one chunk */
-
- /* build writev list
- *
+
+ /* build writev list
+ *
* 1. limit: num_chunks < UIO_MAXIOV
- * 2. limit: num_bytes < SSIZE_MAX
+ * 2. limit: num_bytes < max_bytes
*/
for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
-
+
for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
if (tc->mem->used == 0) {
chunks[i].iov_base = tc->mem->ptr;
@@ -65,143 +62,160 @@ int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int f
} else {
offset = tc->mem->ptr + tc->offset;
toSend = tc->mem->used - 1 - tc->offset;
-
+
chunks[i].iov_base = offset;
-
+
/* protect the return value of writev() */
- if (toSend > SSIZE_MAX ||
- num_bytes + toSend > SSIZE_MAX) {
- chunks[i].iov_len = SSIZE_MAX - num_bytes;
-
+ if (toSend > max_bytes ||
+ (off_t) num_bytes + toSend > max_bytes) {
+ chunks[i].iov_len = max_bytes - num_bytes;
+
num_chunks = i + 1;
break;
} else {
chunks[i].iov_len = toSend;
}
-
+
num_bytes += toSend;
}
}
-
+
if ((r = writev(fd, chunks, num_chunks)) < 0) {
switch (errno) {
case EAGAIN:
case EINTR:
r = 0;
break;
+ case ENOTCONN:
case EPIPE:
case ECONNRESET:
return -2;
default:
- log_error_write(srv, __FILE__, __LINE__, "ssd",
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
"writev failed:", strerror(errno), fd);
-
+
return -1;
}
r = 0;
}
-
+
/* check which chunks have been written */
cq->bytes_out += r;
-
+ max_bytes -= r;
+
for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
if (r >= (ssize_t)chunks[i].iov_len) {
/* written */
r -= chunks[i].iov_len;
tc->offset += chunks[i].iov_len;
-
+
if (chunk_finished) {
/* skip the chunks from further touches */
- chunks_written++;
c = c->next;
} else {
/* chunks_written + c = c->next is done in the for()*/
- chunk_finished++;
+ chunk_finished = 1;
}
} else {
/* partially written */
-
+
tc->offset += r;
chunk_finished = 0;
-
+
break;
}
}
-
+
break;
}
case FILE_CHUNK: {
off_t offset, r;
- size_t toSend;
+ off_t toSend;
stat_cache_entry *sce = NULL;
- int ifd;
-
+
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
log_error_write(srv, __FILE__, __LINE__, "sb",
strerror(errno), c->file.name);
return -1;
}
-
+
offset = c->file.start + c->offset;
- /* limit the toSend to 2^31-1 bytes in a chunk */
- toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
- ((1 << 30) - 1) : c->file.length - c->offset;
-
- if (offset > sce->st.st_size) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
-
- return -1;
- }
-
- if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
-
- return -1;
+ toSend = c->file.length - c->offset;
+ if (toSend > max_bytes) toSend = max_bytes;
+
+ if (-1 == c->file.fd) {
+ if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
+
+ return -1;
+ }
+
+#ifdef FD_CLOEXEC
+ fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
+#endif
}
-
+
r = 0;
-
+
/* FreeBSD sendfile() */
- if (-1 == sendfile(ifd, fd, offset, toSend, NULL, &r, 0)) {
+ if (-1 == sendfile(c->file.fd, fd, offset, toSend, NULL, &r, 0)) {
switch(errno) {
case EAGAIN:
- break;
+ case EINTR:
+ /* for EAGAIN/EINTR r still contains the sent bytes */
+ break; /* try again later */
+ case EPIPE:
case ENOTCONN:
- close(ifd);
return -2;
default:
log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
- close(ifd);
return -1;
}
+ } else if (r == 0) {
+ /* We got an event to write but we wrote nothing
+ *
+ * - the file shrinked -> error
+ * - the remote side closed inbetween -> remote-close */
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
+ /* file is gone ? */
+ return -1;
+ }
+
+ if (offset >= sce->st.st_size) {
+ /* file shrinked, close the connection */
+ return -1;
+ }
+
+ return -2;
}
- close(ifd);
-
+
c->offset += r;
cq->bytes_out += r;
-
+ max_bytes -= r;
+
if (c->offset == c->file.length) {
chunk_finished = 1;
}
-
+
break;
}
default:
-
+
log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
-
+
return -1;
}
-
+
if (!chunk_finished) {
/* not finished yet */
-
+
break;
}
}
- return chunks_written;
+ return 0;
}
#endif
diff --git a/src/network_linux_sendfile.c b/src/network_linux_sendfile.c
index 5752385..9105603 100644
--- a/src/network_linux_sendfile.c
+++ b/src/network_linux_sendfile.c
@@ -1,6 +1,12 @@
#include "network_backends.h"
#ifdef USE_LINUX_SENDFILE
+
+#include "network.h"
+#include "fdevent.h"
+#include "log.h"
+#include "stat_cache.h"
+
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
@@ -16,41 +22,37 @@
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
+#include <fcntl.h>
-#include "network.h"
-#include "fdevent.h"
-#include "log.h"
-#include "stat_cache.h"
+/* on linux 2.4.29 + debian/ubuntu we have crashes if this is enabled */
+#undef HAVE_POSIX_FADVISE
-int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
+int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes) {
chunk *c;
- size_t chunks_written = 0;
-
- for(c = cq->first; c; c = c->next, chunks_written++) {
+
+ for(c = cq->first; (max_bytes > 0) && (NULL != c); c = c->next) {
int chunk_finished = 0;
-
+
switch(c->type) {
case MEM_CHUNK: {
char * offset;
- size_t toSend;
+ off_t toSend;
ssize_t r;
-
+
size_t num_chunks, i;
struct iovec chunks[UIO_MAXIOV];
chunk *tc;
size_t num_bytes = 0;
-
- /* we can't send more then SSIZE_MAX bytes in one chunk */
-
- /* build writev list
- *
+
+ /* build writev list
+ *
* 1. limit: num_chunks < UIO_MAXIOV
- * 2. limit: num_bytes < SSIZE_MAX
+ * 2. limit: num_bytes < max_bytes
*/
- for (num_chunks = 0, tc = c;
- tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV;
+ for (num_chunks = 0, tc = c;
+ tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV;
tc = tc->next, num_chunks++);
-
+
for (tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
if (tc->mem->used == 0) {
chunks[i].iov_base = tc->mem->ptr;
@@ -58,24 +60,24 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd,
} else {
offset = tc->mem->ptr + tc->offset;
toSend = tc->mem->used - 1 - tc->offset;
-
+
chunks[i].iov_base = offset;
-
+
/* protect the return value of writev() */
- if (toSend > SSIZE_MAX ||
- num_bytes + toSend > SSIZE_MAX) {
- chunks[i].iov_len = SSIZE_MAX - num_bytes;
-
+ if (toSend > max_bytes ||
+ (off_t) num_bytes + toSend > max_bytes) {
+ chunks[i].iov_len = max_bytes - num_bytes;
+
num_chunks = i + 1;
break;
} else {
chunks[i].iov_len = toSend;
}
-
+
num_bytes += toSend;
}
}
-
+
if ((r = writev(fd, chunks, num_chunks)) < 0) {
switch (errno) {
case EAGAIN:
@@ -86,102 +88,131 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd,
case ECONNRESET:
return -2;
default:
- log_error_write(srv, __FILE__, __LINE__, "ssd",
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
"writev failed:", strerror(errno), fd);
-
+
return -1;
}
}
-
+
/* check which chunks have been written */
cq->bytes_out += r;
+ max_bytes -= r;
for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
if (r >= (ssize_t)chunks[i].iov_len) {
/* written */
r -= chunks[i].iov_len;
tc->offset += chunks[i].iov_len;
-
+
if (chunk_finished) {
/* skip the chunks from further touches */
- chunks_written++;
c = c->next;
} else {
/* chunks_written + c = c->next is done in the for()*/
- chunk_finished++;
+ chunk_finished = 1;
}
} else {
/* partially written */
-
+
tc->offset += r;
chunk_finished = 0;
-
+
break;
}
}
-
+
break;
}
case FILE_CHUNK: {
ssize_t r;
off_t offset;
- size_t toSend;
+ off_t toSend;
stat_cache_entry *sce = NULL;
-
- if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
- strerror(errno), c->file.name);
- return -1;
- }
-
+
offset = c->file.start + c->offset;
- /* limit the toSend to 2^31-1 bytes in a chunk */
- toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
- ((1 << 30) - 1) : c->file.length - c->offset;
-
- if (offset > sce->st.st_size) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
-
- return -1;
- }
-
- /* open file if not already opened */
+ toSend = c->file.length - c->offset;
+ if (toSend > max_bytes) toSend = max_bytes;
+
+ /* open file if not already opened */
if (-1 == c->file.fd) {
if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
-
+
return -1;
}
#ifdef FD_CLOEXEC
fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
#endif
+#ifdef HAVE_POSIX_FADVISE
+ /* tell the kernel that we want to stream the file */
+ if (-1 == posix_fadvise(c->file.fd, 0, 0, POSIX_FADV_SEQUENTIAL)) {
+ if (ENOSYS != errno) {
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "posix_fadvise failed:", strerror(errno), c->file.fd);
+ }
+ }
+#endif
}
-
- /* Linux sendfile() */
+
if (-1 == (r = sendfile(fd, c->file.fd, &offset, toSend))) {
switch (errno) {
case EAGAIN:
case EINTR:
+ /* ok, we can't send more, let's try later again */
r = 0;
break;
case EPIPE:
case ECONNRESET:
return -2;
default:
- log_error_write(srv, __FILE__, __LINE__, "ssd",
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
"sendfile failed:", strerror(errno), fd);
return -1;
}
- }
+ } else if (r == 0) {
+ int oerrno = errno;
+ /* We got an event to write but we wrote nothing
+ *
+ * - the file shrinked -> error
+ * - the remote side closed inbetween -> remote-close */
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
+ /* file is gone ? */
+ return -1;
+ }
+
+ if (offset > sce->st.st_size) {
+ /* file shrinked, close the connection */
+ errno = oerrno;
+
+ return -1;
+ }
- if (r == 0) {
- /* we got a event to write put we couldn't. remote side closed ? */
+ errno = oerrno;
return -2;
}
-
+
+#ifdef HAVE_POSIX_FADVISE
+#if 0
+#define K * 1024
+#define M * 1024 K
+#define READ_AHEAD 4 M
+ /* check if we need a new chunk */
+ if ((c->offset & ~(READ_AHEAD - 1)) != ((c->offset + r) & ~(READ_AHEAD - 1))) {
+ /* tell the kernel that we want to stream the file */
+ if (-1 == posix_fadvise(c->file.fd, (c->offset + r) & ~(READ_AHEAD - 1), READ_AHEAD, POSIX_FADV_NOREUSE)) {
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "posix_fadvise failed:", strerror(errno), c->file.fd);
+ }
+ }
+#endif
+#endif
+
c->offset += r;
cq->bytes_out += r;
-
+ max_bytes -= r;
+
if (c->offset == c->file.length) {
chunk_finished = 1;
@@ -192,24 +223,24 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd,
c->file.fd = -1;
}
}
-
+
break;
}
default:
-
+
log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
-
+
return -1;
}
-
+
if (!chunk_finished) {
/* not finished yet */
-
+
break;
}
}
- return chunks_written;
+ return 0;
}
#endif
diff --git a/src/network_openssl.c b/src/network_openssl.c
index b6a1b2f..7bed710 100644
--- a/src/network_openssl.c
+++ b/src/network_openssl.c
@@ -1,6 +1,12 @@
#include "network_backends.h"
#ifdef USE_OPENSSL
+
+#include "network.h"
+#include "fdevent.h"
+#include "log.h"
+#include "stat_cache.h"
+
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
@@ -18,22 +24,16 @@
#include <stdlib.h>
#include <assert.h>
-#include "network.h"
-#include "fdevent.h"
-#include "log.h"
-#include "stat_cache.h"
-
-# include <openssl/ssl.h>
-# include <openssl/err.h>
+# include <openssl/ssl.h>
+# include <openssl/err.h>
-int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq) {
+int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq, off_t max_bytes) {
int ssl_r;
chunk *c;
- size_t chunks_written = 0;
/* this is a 64k sendbuffer
*
- * it has to stay at the same location all the time to satisfy the needs
+ * it has to stay at the same location all the time to satisfy the needs
* of SSL_write to pass the SAME parameter in case of a _WANT_WRITE
*
* the buffer is allocated once, is NOT realloced and is NOT freed at shutdown
@@ -43,14 +43,14 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu
* In reality we would like to use mmap() but we don't have a guarantee that
* we get the same mmap() address for each call. On openbsd the mmap() address
* even randomized.
- * That means either we keep the mmap() open or we do a read() into a
- * constant buffer
+ * That means either we keep the mmap() open or we do a read() into a
+ * constant buffer
* */
#define LOCAL_SEND_BUFSIZE (64 * 1024)
static char *local_send_buffer = NULL;
/* the remote side closed the connection before without shutdown request
- * - IE
+ * - IE
* - wget
* if keep-alive is disabled */
@@ -58,34 +58,43 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu
SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
}
- for(c = cq->first; c; c = c->next) {
+ for(c = cq->first; (max_bytes > 0) && (NULL != c); c = c->next) {
int chunk_finished = 0;
-
+
switch(c->type) {
case MEM_CHUNK: {
char * offset;
- size_t toSend;
+ off_t toSend;
ssize_t r;
-
- if (c->mem->used == 0) {
+
+ if (c->mem->used == 0 || c->mem->used == 1) {
chunk_finished = 1;
break;
}
-
+
offset = c->mem->ptr + c->offset;
toSend = c->mem->used - 1 - c->offset;
-
+ if (toSend > max_bytes) toSend = max_bytes;
+
/**
* SSL_write man-page
- *
+ *
* WARNING
* When an SSL_write() operation has to be repeated because of
* SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be
* repeated with the same arguments.
- *
+ *
*/
-
- if ((r = SSL_write(ssl, offset, toSend)) <= 0) {
+
+ ERR_clear_error();
+ r = SSL_write(ssl, offset, toSend);
+
+ if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client");
+ return -1;
+ }
+
+ if (r <= 0) {
unsigned long err;
switch ((ssl_r = SSL_get_error(ssl, r))) {
@@ -95,7 +104,7 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu
/* perhaps we have error waiting in our error-queue */
if (0 != (err = ERR_get_error())) {
do {
- log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
+ log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
ssl_r, r,
ERR_error_string(err, NULL));
} while((err = ERR_get_error()));
@@ -103,45 +112,47 @@ 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:",
+ log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
ssl_r, r, errno,
strerror(errno));
break;
}
} else {
/* neither error-queue nor errno ? */
- log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
+ log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
ssl_r, r, errno,
strerror(errno));
}
-
+
return -1;
case SSL_ERROR_ZERO_RETURN:
/* clean shutdown on the remote side */
-
+
if (r == 0) return -2;
-
+
/* fall through */
default:
while((err = ERR_get_error())) {
- log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
+ log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
ssl_r, r,
ERR_error_string(err, NULL));
}
-
+
return -1;
}
} else {
c->offset += r;
cq->bytes_out += r;
+ max_bytes -= r;
}
-
+
if (c->offset == (off_t)c->mem->used - 1) {
chunk_finished = 1;
}
-
+
break;
}
case FILE_CHUNK: {
@@ -150,7 +161,7 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu
stat_cache_entry *sce = NULL;
int ifd;
int write_wait = 0;
-
+
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
log_error_write(srv, __FILE__, __LINE__, "sb",
strerror(errno), c->file.name);
@@ -164,13 +175,14 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu
do {
off_t offset = c->file.start + c->offset;
- off_t toSend = c->file.length - c->offset;
+ off_t toSend = c->file.length - c->offset;
+ if (toSend > max_bytes) toSend = max_bytes;
if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
-
+
if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "open failed:", strerror(errno));
-
+
return -1;
}
@@ -183,10 +195,18 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu
}
s = local_send_buffer;
-
+
close(ifd);
-
- if ((r = SSL_write(ssl, s, toSend)) <= 0) {
+
+ ERR_clear_error();
+ r = SSL_write(ssl, s, toSend);
+
+ if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client");
+ return -1;
+ }
+
+ if (r <= 0) {
unsigned long err;
switch ((ssl_r = SSL_get_error(ssl, r))) {
@@ -197,7 +217,7 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu
/* perhaps we have error waiting in our error-queue */
if (0 != (err = ERR_get_error())) {
do {
- log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
+ log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
ssl_r, r,
ERR_error_string(err, NULL));
} while((err = ERR_get_error()));
@@ -205,64 +225,64 @@ 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:",
+ log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
ssl_r, r, errno,
strerror(errno));
break;
}
} else {
/* neither error-queue nor errno ? */
- log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
+ log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
ssl_r, r, errno,
strerror(errno));
}
-
+
return -1;
case SSL_ERROR_ZERO_RETURN:
/* clean shutdown on the remote side */
-
+
if (r == 0) return -2;
-
+
/* fall thourgh */
default:
while((err = ERR_get_error())) {
- log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
+ log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
ssl_r, r,
ERR_error_string(err, NULL));
}
-
+
return -1;
}
} else {
c->offset += r;
cq->bytes_out += r;
+ max_bytes -= r;
}
-
+
if (c->offset == c->file.length) {
chunk_finished = 1;
}
- } while(!chunk_finished && !write_wait);
-
+ } while (!chunk_finished && !write_wait && max_bytes > 0);
+
break;
}
default:
log_error_write(srv, __FILE__, __LINE__, "s", "type not known");
-
+
return -1;
}
-
+
if (!chunk_finished) {
/* not finished yet */
-
+
break;
}
-
- chunks_written++;
}
- return chunks_written;
+ return 0;
}
#endif
diff --git a/src/network_solaris_sendfilev.c b/src/network_solaris_sendfilev.c
index 0ab669f..2003200 100644
--- a/src/network_solaris_sendfilev.c
+++ b/src/network_solaris_sendfilev.c
@@ -2,6 +2,11 @@
#ifdef USE_SOLARIS_SENDFILEV
+#include "network.h"
+#include "fdevent.h"
+#include "log.h"
+#include "stat_cache.h"
+
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
@@ -19,53 +24,47 @@
#include <stdlib.h>
#include <limits.h>
-#include "network.h"
-#include "fdevent.h"
-#include "log.h"
-#include "stat_cache.h"
-
#ifndef UIO_MAXIOV
-#define UIO_MAXIOV IOV_MAX
+# define UIO_MAXIOV IOV_MAX
#endif
/**
- * a very simple sendfilev() interface for solaris which can be optimised a lot more
+ * a very simple sendfilev() interface for solaris which can be optimised a lot more
* as solaris sendfilev() supports 'sending everythin in one syscall()'
- *
- * If you want such an interface and need the performance, just give me an account on
- * a solaris box.
+ *
+ * If you want such an interface and need the performance, just give me an account on
+ * a solaris box.
* - jan@kneschke.de
*/
-int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq) {
+int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes) {
chunk *c;
- size_t chunks_written = 0;
-
- for(c = cq->first; c; c = c->next, chunks_written++) {
+
+ for(c = cq->first; (max_bytes > 0) && (NULL != c); c = c->next) {
int chunk_finished = 0;
-
+
switch(c->type) {
case MEM_CHUNK: {
char * offset;
- size_t toSend;
+ off_t toSend;
ssize_t r;
-
+
size_t num_chunks, i;
struct iovec chunks[UIO_MAXIOV];
chunk *tc;
-
+
size_t num_bytes = 0;
-
+
/* we can't send more then SSIZE_MAX bytes in one chunk */
-
- /* build writev list
- *
+
+ /* build writev list
+ *
* 1. limit: num_chunks < UIO_MAXIOV
* 2. limit: num_bytes < SSIZE_MAX
*/
for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
-
+
for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
if (tc->mem->used == 0) {
chunks[i].iov_base = tc->mem->ptr;
@@ -73,24 +72,24 @@ int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int
} else {
offset = tc->mem->ptr + tc->offset;
toSend = tc->mem->used - 1 - tc->offset;
-
+
chunks[i].iov_base = offset;
-
+
/* protect the return value of writev() */
- if (toSend > SSIZE_MAX ||
- num_bytes + toSend > SSIZE_MAX) {
- chunks[i].iov_len = SSIZE_MAX - num_bytes;
-
+ if (toSend > max_bytes ||
+ (off_t) num_bytes + toSend > max_bytes) {
+ chunks[i].iov_len = max_bytes - num_bytes;
+
num_chunks = i + 1;
break;
} else {
chunks[i].iov_len = toSend;
}
-
+
num_bytes += toSend;
}
}
-
+
if ((r = writev(fd, chunks, num_chunks)) < 0) {
switch (errno) {
case EAGAIN:
@@ -101,68 +100,68 @@ int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int
case ECONNRESET:
return -2;
default:
- log_error_write(srv, __FILE__, __LINE__, "ssd",
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
"writev failed:", strerror(errno), fd);
-
+
return -1;
}
}
-
+
/* check which chunks have been written */
cq->bytes_out += r;
-
+
for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
if (r >= (ssize_t)chunks[i].iov_len) {
/* written */
r -= chunks[i].iov_len;
tc->offset += chunks[i].iov_len;
-
+
if (chunk_finished) {
/* skip the chunks from further touches */
- chunks_written++;
c = c->next;
} else {
/* chunks_written + c = c->next is done in the for()*/
- chunk_finished++;
+ chunk_finished = 1;
}
} else {
/* partially written */
-
+
tc->offset += r;
chunk_finished = 0;
-
+
break;
}
}
-
+
break;
}
case FILE_CHUNK: {
ssize_t r;
- off_t offset;
- size_t toSend, written;
+ off_t offset, toSend;
+ size_t written;
sendfilevec_t fvec;
stat_cache_entry *sce = NULL;
int ifd;
-
+
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
log_error_write(srv, __FILE__, __LINE__, "sb",
strerror(errno), c->file.name);
return -1;
}
-
+
offset = c->file.start + c->offset;
toSend = c->file.length - c->offset;
-
+ if (toSend > max_bytes) toSend = max_bytes;
+
if (offset > sce->st.st_size) {
log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
-
+
return -1;
}
if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
-
+
return -1;
}
@@ -170,44 +169,45 @@ int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int
fvec.sfv_flag = 0;
fvec.sfv_off = offset;
fvec.sfv_len = toSend;
-
+
/* Solaris sendfilev() */
if (-1 == (r = sendfilev(fd, &fvec, 1, &written))) {
if (errno != EAGAIN) {
log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
-
+
close(ifd);
return -1;
}
-
+
r = 0;
}
-
+
close(ifd);
c->offset += written;
cq->bytes_out += written;
-
+ max_bytes -= written;
+
if (c->offset == c->file.length) {
chunk_finished = 1;
}
-
+
break;
}
default:
-
+
log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
-
+
return -1;
}
-
+
if (!chunk_finished) {
/* not finished yet */
-
+
break;
}
}
- return chunks_written;
+ return 0;
}
#endif
diff --git a/src/network_write.c b/src/network_write.c
index 90fc2ac..6aa6cfa 100644
--- a/src/network_write.c
+++ b/src/network_write.c
@@ -1,11 +1,4 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
+#include "network_backends.h"
#include "network.h"
#include "fdevent.h"
@@ -14,57 +7,78 @@
#include "sys-socket.h"
-#include "network_backends.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
#ifdef HAVE_SYS_FILIO_H
# include <sys/filio.h>
#endif
#ifdef HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>
+# include <sys/resource.h>
#endif
-int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq) {
+int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes) {
chunk *c;
- size_t chunks_written = 0;
-
- for(c = cq->first; c; c = c->next) {
+
+ for(c = cq->first; (max_bytes > 0) && (NULL != c); c = c->next) {
int chunk_finished = 0;
-
+
switch(c->type) {
case MEM_CHUNK: {
char * offset;
- size_t toSend;
+ off_t toSend;
ssize_t r;
-
+
if (c->mem->used == 0) {
chunk_finished = 1;
break;
}
-
+
offset = c->mem->ptr + c->offset;
toSend = c->mem->used - 1 - c->offset;
-#ifdef __WIN32
+ if (toSend > max_bytes) toSend = max_bytes;
+
+#ifdef __WIN32
if ((r = send(fd, offset, toSend, 0)) < 0) {
- log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
-
+ /* no error handling for windows... */
+ log_error_write(srv, __FILE__, __LINE__, "ssd", "send failed: ", strerror(errno), fd);
+
return -1;
}
#else
if ((r = write(fd, offset, toSend)) < 0) {
- log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
-
- return -1;
+ switch (errno) {
+ case EAGAIN:
+ case EINTR:
+ r = 0;
+ break;
+ case EPIPE:
+ case ECONNRESET:
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "write failed:", strerror(errno), fd);
+
+ return -1;
+ }
}
#endif
-
+
c->offset += r;
cq->bytes_out += r;
-
+ max_bytes -= r;
+
if (c->offset == (off_t)c->mem->used - 1) {
chunk_finished = 1;
}
-
+
break;
}
case FILE_CHUNK: {
@@ -73,92 +87,127 @@ int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqu
#endif
ssize_t r;
off_t offset;
- size_t toSend;
+ off_t toSend;
stat_cache_entry *sce = NULL;
int ifd;
-
+
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
log_error_write(srv, __FILE__, __LINE__, "sb",
strerror(errno), c->file.name);
return -1;
}
-
+
offset = c->file.start + c->offset;
toSend = c->file.length - c->offset;
-
+
+ if (toSend > max_bytes) toSend = max_bytes;
+
if (offset > sce->st.st_size) {
log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
-
+
return -1;
}
if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
-
+
return -1;
}
-
-#if defined USE_MMAP
+
+#ifdef USE_MMAP
if (MAP_FAILED == (p = mmap(0, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "mmap failed: ", strerror(errno));
close(ifd);
-
+
return -1;
}
close(ifd);
if ((r = write(fd, p + offset, toSend)) <= 0) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "write failed: ", strerror(errno));
- munmap(p, sce->st.st_size);
- return -1;
+ switch (errno) {
+ case EAGAIN:
+ case EINTR:
+ r = 0;
+ break;
+ case EPIPE:
+ case ECONNRESET:
+ munmap(p, sce->st.st_size);
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "write failed:", strerror(errno), fd);
+ munmap(p, sce->st.st_size);
+
+ return -1;
+ }
}
-
+
munmap(p, sce->st.st_size);
-#else
+#else /* USE_MMAP */
buffer_prepare_copy(srv->tmp_buf, toSend);
-
+
lseek(ifd, offset, SEEK_SET);
if (-1 == (toSend = read(ifd, srv->tmp_buf->ptr, toSend))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno));
close(ifd);
-
+
return -1;
}
close(ifd);
- if (-1 == (r = send(fd, srv->tmp_buf->ptr, toSend, 0))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "write: ", strerror(errno));
-
+#ifdef __WIN32
+ if ((r = send(fd, srv->tmp_buf->ptr, toSend, 0)) < 0) {
+ /* no error handling for windows... */
+ log_error_write(srv, __FILE__, __LINE__, "ssd", "send failed: ", strerror(errno), fd);
+
return -1;
}
-#endif
+#else /* __WIN32 */
+ if ((r = write(fd, srv->tmp_buf->ptr, toSend)) < 0) {
+ switch (errno) {
+ case EAGAIN:
+ case EINTR:
+ r = 0;
+ break;
+ case EPIPE:
+ case ECONNRESET:
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "write failed:", strerror(errno), fd);
+
+ return -1;
+ }
+ }
+#endif /* __WIN32 */
+#endif /* USE_MMAP */
+
c->offset += r;
cq->bytes_out += r;
-
+ max_bytes -= r;
+
if (c->offset == c->file.length) {
chunk_finished = 1;
}
-
+
break;
}
default:
-
+
log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
-
+
return -1;
}
-
+
if (!chunk_finished) {
/* not finished yet */
-
+
break;
}
-
- chunks_written++;
}
- return chunks_written;
+ return 0;
}
#if 0
diff --git a/src/network_writev.c b/src/network_writev.c
index fcd06c4..d21cc4f 100644
--- a/src/network_writev.c
+++ b/src/network_writev.c
@@ -2,6 +2,11 @@
#ifdef USE_WRITEV
+#include "network.h"
+#include "fdevent.h"
+#include "log.h"
+#include "stat_cache.h"
+
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
@@ -21,63 +26,53 @@
#include <stdio.h>
#include <assert.h>
-#include "network.h"
-#include "fdevent.h"
-#include "log.h"
-#include "stat_cache.h"
-
-#ifndef UIO_MAXIOV
-# if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__)
-/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */
-# define UIO_MAXIOV 1024
-# elif defined(__sgi)
-/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */
-# define UIO_MAXIOV 512
-# elif defined(__sun)
-/* Solaris (and SunOS?) defines IOV_MAX instead */
-# ifndef IOV_MAX
-# define UIO_MAXIOV 16
-# else
-# define UIO_MAXIOV IOV_MAX
-# endif
-# elif defined(IOV_MAX)
-# define UIO_MAXIOV IOV_MAX
-# else
-# error UIO_MAXIOV nor IOV_MAX are defined
-# endif
-#endif
-
#if 0
#define LOCAL_BUFFERING 1
#endif
-int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq) {
+int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes) {
chunk *c;
- size_t chunks_written = 0;
-
- for(c = cq->first; c; c = c->next) {
+
+ for(c = cq->first; (max_bytes > 0) && (NULL != c); c = c->next) {
int chunk_finished = 0;
-
+
switch(c->type) {
case MEM_CHUNK: {
char * offset;
- size_t toSend;
+ off_t toSend;
ssize_t r;
-
+
size_t num_chunks, i;
- struct iovec chunks[UIO_MAXIOV];
+ struct iovec *chunks;
chunk *tc;
size_t num_bytes = 0;
-
- /* we can't send more then SSIZE_MAX bytes in one chunk */
-
- /* build writev list
- *
- * 1. limit: num_chunks < UIO_MAXIOV
- * 2. limit: num_bytes < SSIZE_MAX
+#if defined(_SC_IOV_MAX) /* IRIX, MacOS X, FreeBSD, Solaris, ... */
+ const size_t max_chunks = sysconf(_SC_IOV_MAX);
+#elif defined(IOV_MAX) /* Linux x86 (glibc-2.3.6-3) */
+ const size_t max_chunks = IOV_MAX;
+#elif defined(MAX_IOVEC) /* Linux ia64 (glibc-2.3.3-98.28) */
+ const size_t max_chunks = MAX_IOVEC;
+#elif defined(UIO_MAXIOV) /* Linux x86 (glibc-2.2.5-233) */
+ const size_t max_chunks = UIO_MAXIOV;
+#elif (defined(__FreeBSD__) && __FreeBSD_version < 500000) || defined(__DragonFly__) || defined(__APPLE__)
+ /* - FreeBSD 4.x
+ * - MacOS X 10.3.x
+ * (covered in -DKERNEL)
+ * */
+ const size_t max_chunks = 1024; /* UIO_MAXIOV value from sys/uio.h */
+#else
+#error "sysconf() doesnt return _SC_IOV_MAX ..., check the output of 'man writev' for the EINVAL error and send the output to jan@kneschke.de"
+#endif
+
+ /* build writev list
+ *
+ * 1. limit: num_chunks < max_chunks
+ * 2. limit: num_bytes < max_bytes
*/
- for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
-
+ for (num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < max_chunks; num_chunks++, tc = tc->next);
+
+ chunks = calloc(num_chunks, sizeof(*chunks));
+
for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
if (tc->mem->used == 0) {
chunks[i].iov_base = tc->mem->ptr;
@@ -85,24 +80,24 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq
} else {
offset = tc->mem->ptr + tc->offset;
toSend = tc->mem->used - 1 - tc->offset;
-
+
chunks[i].iov_base = offset;
-
+
/* protect the return value of writev() */
- if (toSend > SSIZE_MAX ||
- num_bytes + toSend > SSIZE_MAX) {
- chunks[i].iov_len = SSIZE_MAX - num_bytes;
-
+ if (toSend > max_bytes ||
+ (off_t) num_bytes + toSend > max_bytes) {
+ chunks[i].iov_len = max_bytes - num_bytes;
+
num_chunks = i + 1;
break;
} else {
chunks[i].iov_len = toSend;
}
-
+
num_bytes += toSend;
}
}
-
+
if ((r = writev(fd, chunks, num_chunks)) < 0) {
switch (errno) {
case EAGAIN:
@@ -111,43 +106,46 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq
break;
case EPIPE:
case ECONNRESET:
+ free(chunks);
return -2;
default:
- log_error_write(srv, __FILE__, __LINE__, "ssd",
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
"writev failed:", strerror(errno), fd);
-
+
+ free(chunks);
return -1;
}
}
-
+
cq->bytes_out += r;
+ max_bytes -= r;
/* check which chunks have been written */
-
+
for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
if (r >= (ssize_t)chunks[i].iov_len) {
/* written */
r -= chunks[i].iov_len;
tc->offset += chunks[i].iov_len;
-
+
if (chunk_finished) {
/* skip the chunks from further touches */
- chunks_written++;
c = c->next;
} else {
/* chunks_written + c = c->next is done in the for()*/
- chunk_finished++;
+ chunk_finished = 1;
}
} else {
/* partially written */
-
+
tc->offset += r;
chunk_finished = 0;
break;
}
}
-
+ free(chunks);
+
break;
}
case FILE_CHUNK: {
@@ -159,7 +157,7 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq
#define KByte * 1024
#define MByte * 1024 KByte
#define GByte * 1024 MByte
- const off_t we_want_to_mmap = 512 KByte;
+ const off_t we_want_to_mmap = 512 KByte;
char *start = NULL;
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
@@ -169,16 +167,16 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq
}
abs_offset = c->file.start + c->offset;
-
+
if (abs_offset > sce->st.st_size) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
"file was shrinked:", c->file.name);
-
+
return -1;
}
- /* mmap the buffer
- * - first mmap
+ /* mmap the buffer
+ * - first mmap
* - new mmap as the we are at the end of the last one */
if (c->file.mmap.start == MAP_FAILED ||
abs_offset == (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
@@ -188,7 +186,7 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq
* adaptive mem-mapping
* the problem:
* we mmap() the whole file. If someone has alot large files and 32bit
- * machine the virtual address area will be unrun and we will have a failing
+ * machine the virtual address area will be unrun and we will have a failing
* mmap() call.
* solution:
* only mmap 16M in one chunk and move the window as soon as we have finished
@@ -234,7 +232,7 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq
if (-1 == c->file.fd) { /* open the file if not already open */
if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->file.name, strerror(errno));
-
+
return -1;
}
#ifdef FD_CLOEXEC
@@ -242,10 +240,10 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq
#endif
}
- if (MAP_FAILED == (c->file.mmap.start = mmap(0, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) {
+ if (MAP_FAILED == (c->file.mmap.start = mmap(NULL, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) {
/* close it here, otherwise we'd have to set FD_CLOEXEC */
- log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
+ log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
strerror(errno), c->file.name, c->file.fd);
return -1;
@@ -257,10 +255,12 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq
#else
#ifdef HAVE_MADVISE
/* don't advise files < 64Kb */
- if (c->file.mmap.length > (64 KByte) &&
- 0 != madvise(c->file.mmap.start, c->file.mmap.length, MADV_WILLNEED)) {
- log_error_write(srv, __FILE__, __LINE__, "ssbd", "madvise failed:",
- strerror(errno), c->file.name, c->file.fd);
+ if (c->file.mmap.length > (64 KByte)) {
+ /* darwin 7 is returning EINVAL all the time and I don't know how to
+ * detect this at runtime.i
+ *
+ * ignore the return value for now */
+ madvise(c->file.mmap.start, c->file.mmap.length, MADV_WILLNEED);
}
#endif
#endif
@@ -272,15 +272,17 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq
toSend = (c->file.mmap.offset + c->file.mmap.length) - (abs_offset);
if (toSend < 0) {
- log_error_write(srv, __FILE__, __LINE__, "soooo",
+ log_error_write(srv, __FILE__, __LINE__, "soooo",
"toSend is negative:",
toSend,
c->file.mmap.length,
abs_offset,
- c->file.mmap.offset);
+ c->file.mmap.offset);
assert(toSend < 0);
}
+ if (toSend > max_bytes) toSend = max_bytes;
+
#ifdef LOCAL_BUFFERING
start = c->mem->ptr;
#else
@@ -297,16 +299,17 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq
case ECONNRESET:
return -2;
default:
- log_error_write(srv, __FILE__, __LINE__, "ssd",
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
"write failed:", strerror(errno), fd);
-
+
return -1;
}
}
-
+
c->offset += r;
cq->bytes_out += r;
-
+ max_bytes -= r;
+
if (c->offset == c->file.length) {
chunk_finished = 1;
@@ -316,26 +319,24 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq
c->file.mmap.start = MAP_FAILED;
}
}
-
+
break;
}
default:
-
+
log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
-
+
return -1;
}
-
+
if (!chunk_finished) {
/* not finished yet */
-
+
break;
}
-
- chunks_written++;
}
- return chunks_written;
+ return 0;
}
#endif
diff --git a/src/plugin.c b/src/plugin.c
index e74d8b0..55f8b03 100644
--- a/src/plugin.c
+++ b/src/plugin.c
@@ -1,39 +1,36 @@
+#include "plugin.h"
+#include "log.h"
+
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
-#include "plugin.h"
-#include "log.h"
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
#ifdef HAVE_VALGRIND_VALGRIND_H
-#include <valgrind/valgrind.h>
+# include <valgrind/valgrind.h>
#endif
#ifndef __WIN32
-#include <dlfcn.h>
+# include <dlfcn.h>
#endif
/*
- *
+ *
* if you change this enum to add a new callback, be sure
* - that PLUGIN_FUNC_SIZEOF is the last entry
* - that you add PLUGIN_TO_SLOT twice:
- * 1. as callback-dispatcher
+ * 1. as callback-dispatcher
* 2. in plugins_call_init()
- *
+ *
*/
typedef struct {
PLUGIN_DATA;
} plugin_data;
-typedef enum {
+typedef enum {
PLUGIN_FUNC_UNSET,
- PLUGIN_FUNC_HANDLE_URI_CLEAN,
- PLUGIN_FUNC_HANDLE_URI_RAW,
+ PLUGIN_FUNC_HANDLE_URI_CLEAN,
+ PLUGIN_FUNC_HANDLE_URI_RAW,
PLUGIN_FUNC_HANDLE_REQUEST_DONE,
PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
PLUGIN_FUNC_HANDLE_TRIGGER,
@@ -44,18 +41,18 @@ typedef enum {
PLUGIN_FUNC_HANDLE_DOCROOT,
PLUGIN_FUNC_HANDLE_PHYSICAL,
PLUGIN_FUNC_CONNECTION_RESET,
- PLUGIN_FUNC_INIT,
+ PLUGIN_FUNC_INIT,
PLUGIN_FUNC_CLEANUP,
PLUGIN_FUNC_SET_DEFAULTS,
-
+
PLUGIN_FUNC_SIZEOF
} plugin_t;
static plugin *plugin_init(void) {
plugin *p;
-
+
p = calloc(1, sizeof(*p));
-
+
return p;
}
@@ -67,7 +64,7 @@ static void plugin_free(plugin *p) {
#endif
#ifndef LIGHTTPD_STATIC
- if (use_dlclose && p->lib) {
+ if (use_dlclose && p->lib) {
#ifdef __WIN32
FreeLibrary(p->lib);
#else
@@ -75,7 +72,7 @@ static void plugin_free(plugin *p) {
#endif
}
#endif
-
+
free(p);
}
@@ -89,17 +86,17 @@ static int plugins_register(server *srv, plugin *p) {
srv->plugins.size += 4;
srv->plugins.ptr = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps));
}
-
+
ps = srv->plugins.ptr;
ps[srv->plugins.used++] = p;
-
+
return 0;
}
/**
- *
- *
- *
+ *
+ *
+ *
*/
#ifdef LIGHTTPD_STATIC
@@ -123,28 +120,35 @@ int plugins_load(server *srv) {
plugin *p;
int (*init)(plugin *pl);
const char *error;
- size_t i;
-
+ size_t i, j;
+
for (i = 0; i < srv->srvconf.modules->used; i++) {
data_string *d = (data_string *)srv->srvconf.modules->data[i];
char *modules = d->value->ptr;
-
+
+ for (j = 0; j < i; j++) {
+ if (buffer_is_equal(d->value, ((data_string *) srv->srvconf.modules->data[j])->value)) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "Cannot load plugin", d->value, "more than once, please fix your config (we may not accept such configs in future releases");
+ continue;
+ }
+ }
+
buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
- buffer_append_string(srv->tmp_buf, "/");
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("/"));
buffer_append_string(srv->tmp_buf, modules);
#if defined(__WIN32) || defined(__CYGWIN__)
- buffer_append_string(srv->tmp_buf, ".dll");
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".dll"));
#else
- buffer_append_string(srv->tmp_buf, ".so");
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".so"));
#endif
-
+
p = plugin_init();
#ifdef __WIN32
if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) {
LPVOID lpMsgBuf;
FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
@@ -152,28 +156,28 @@ int plugins_load(server *srv) {
(LPTSTR) &lpMsgBuf,
0, NULL );
- log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
lpMsgBuf, srv->tmp_buf);
-
+
plugin_free(p);
-
+
return -1;
}
-#else
- if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_LAZY))) {
- log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
+#else
+ if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_NOW|RTLD_GLOBAL))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
srv->tmp_buf, dlerror());
-
+
plugin_free(p);
-
+
return -1;
}
-
+
#endif
buffer_reset(srv->tmp_buf);
buffer_copy_string(srv->tmp_buf, modules);
- buffer_append_string(srv->tmp_buf, "_plugin_init");
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("_plugin_init"));
#ifdef __WIN32
init = GetProcAddress(p->lib, srv->tmp_buf->ptr);
@@ -181,7 +185,7 @@ int plugins_load(server *srv) {
if (init == NULL) {
LPVOID lpMsgBuf;
FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
@@ -190,28 +194,28 @@ int plugins_load(server *srv) {
0, NULL );
log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf);
-
+
plugin_free(p);
return -1;
}
#else
#if 1
- init = (int (*)(plugin *))dlsym(p->lib, srv->tmp_buf->ptr);
+ init = (int (*)(plugin *))(intptr_t)dlsym(p->lib, srv->tmp_buf->ptr);
#else
*(void **)(&init) = dlsym(p->lib, srv->tmp_buf->ptr);
#endif
if ((error = dlerror()) != NULL) {
log_error_write(srv, __FILE__, __LINE__, "s", error);
-
+
plugin_free(p);
return -1;
}
-
+
#endif
if ((*init)(p)) {
log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin init failed" );
-
+
plugin_free(p);
return -1;
}
@@ -220,7 +224,7 @@ int plugins_load(server *srv) {
#endif
plugins_register(srv, p);
}
-
+
return 0;
}
#endif
@@ -253,8 +257,8 @@ int plugins_load(server *srv) {
}
/**
- * plugins that use
- *
+ * plugins that use
+ *
* - server *srv
* - connection *con
* - void *p_d (plugin_data *)
@@ -301,12 +305,12 @@ PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset)
}
/**
- * plugins that use
- *
+ * plugins that use
+ *
* - server *srv
* - void *p_d (plugin_data *)
*/
-
+
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger)
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup)
PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup)
@@ -314,18 +318,18 @@ PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults)
#undef PLUGIN_TO_SLOT
-#if 0
+#if 0
/**
- *
+ *
* special handler
- *
+ *
*/
handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
size_t i;
plugin **ps;
-
+
ps = srv->plugins.ptr;
-
+
for (i = 0; i < srv->plugins.used; i++) {
plugin *p = ps[i];
if (p->handle_fdevent) {
@@ -344,34 +348,34 @@ handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
}
}
}
-
+
return HANDLER_GO_ON;
}
#endif
/**
- *
+ *
* - call init function of all plugins to init the plugin-internals
* - added each plugin that supports has callback to the corresponding slot
- *
+ *
* - is only called once.
*/
handler_t plugins_call_init(server *srv) {
size_t i;
plugin **ps;
-
+
ps = srv->plugins.ptr;
-
+
/* fill slots */
-
+
srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
-
+
for (i = 0; i < srv->plugins.used; i++) {
size_t j;
/* check which calls are supported */
-
+
plugin *p = ps[i];
-
+
#define PLUGIN_TO_SLOT(x, y) \
if (p->y) { \
plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \
@@ -384,11 +388,11 @@ handler_t plugins_call_init(server *srv) {
slot[j] = p;\
break;\
}\
- }
-
-
- PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
- PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
+ }
+
+
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done);
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
@@ -402,19 +406,19 @@ handler_t plugins_call_init(server *srv) {
PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup);
PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults);
#undef PLUGIN_TO_SLOT
-
+
if (p->init) {
if (NULL == (p->data = p->init())) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
"plugin-init failed for module", p->name);
return HANDLER_ERROR;
}
-
+
/* used for con->mode, DIRECT == 0, plugins above that */
((plugin_data *)(p->data))->id = i + 1;
-
+
if (p->version != LIGHTTPD_VERSION_ID) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
"plugin-version doesn't match lighttpd-version for", p->name);
return HANDLER_ERROR;
}
@@ -422,29 +426,29 @@ handler_t plugins_call_init(server *srv) {
p->data = NULL;
}
}
-
+
return HANDLER_GO_ON;
}
void plugins_free(server *srv) {
size_t i;
plugins_call_cleanup(srv);
-
+
for (i = 0; i < srv->plugins.used; i++) {
plugin *p = ((plugin **)srv->plugins.ptr)[i];
-
+
plugin_free(p);
}
-
+
for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
-
+
if (slot) free(slot);
}
-
+
free(srv->plugin_slots);
srv->plugin_slots = NULL;
-
+
free(srv->plugins.ptr);
srv->plugins.ptr = NULL;
srv->plugins.used = 0;
diff --git a/src/plugin.h b/src/plugin.h
index b43129a..cadce54 100644
--- a/src/plugin.h
+++ b/src/plugin.h
@@ -11,7 +11,7 @@
static handler_t x(server *srv, connection *con, void *p_d)
#define INIT_FUNC(x) \
- static void *x()
+ static void *x(void)
#define FREE_FUNC SERVER_FUNC
#define TRIGGER_FUNC SERVER_FUNC
@@ -25,19 +25,19 @@
#define URIHANDLER_FUNC CONNECTION_FUNC
#define PLUGIN_DATA size_t id
-
+
typedef struct {
size_t version;
-
+
buffer *name; /* name of the plugin */
-
+
void *(* init) ();
handler_t (* set_defaults) (server *srv, void *p_d);
handler_t (* cleanup) (server *srv, void *p_d);
/* is called ... */
handler_t (* handle_trigger) (server *srv, void *p_d); /* once a second */
handler_t (* handle_sighup) (server *srv, void *p_d); /* at a signup */
-
+
handler_t (* handle_uri_raw) (server *srv, connection *con, void *p_d); /* after uri_raw is set */
handler_t (* handle_uri_clean) (server *srv, connection *con, void *p_d); /* after uri is set */
handler_t (* handle_docroot) (server *srv, connection *con, void *p_d); /* getting the document-root */
@@ -45,18 +45,18 @@ typedef struct {
handler_t (* handle_request_done) (server *srv, connection *con, void *p_d); /* at the end of a request */
handler_t (* handle_connection_close)(server *srv, connection *con, void *p_d); /* at the end of a connection */
handler_t (* handle_joblist) (server *srv, connection *con, void *p_d); /* after all events are handled */
-
-
-
- handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);
-
- /* when a handler for the request
+
+
+
+ handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);
+
+ /* when a handler for the request
* has to be found
*/
handler_t (* handle_subrequest) (server *srv, connection *con, void *p_d); /* */
handler_t (* connection_reset) (server *srv, connection *con, void *p_d); /* */
void *data;
-
+
/* dlopen handle */
void *lib;
} plugin;
diff --git a/src/proc_open.c b/src/proc_open.c
index ecea815..e9393e0 100644
--- a/src/proc_open.c
+++ b/src/proc_open.c
@@ -1,15 +1,17 @@
+#include "proc_open.h"
+
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
+#include <string.h>
#include <errno.h>
-#include "proc_open.h"
#ifdef WIN32
-#include <io.h>
-#include <fcntl.h>
+# include <io.h>
+# include <fcntl.h>
#else
-#include <sys/wait.h>
-#include <unistd.h>
+# include <sys/wait.h>
+# include <unistd.h>
#endif
@@ -148,11 +150,14 @@ int proc_open(proc_handler_t *proc, const char *command) {
STARTUPINFO si;
BOOL procok;
SECURITY_ATTRIBUTES security;
- const char *shell;
+ const char *shell = NULL;
+ const char *windir = NULL;
buffer *cmdline;
- if (NULL == (shell = getenv(SHELLENV))) {
- fprintf(stderr, "env %s is required", SHELLENV);
+ if (NULL == (shell = getenv(SHELLENV)) &&
+ NULL == (windir = getenv("SystemRoot")) &&
+ NULL == (windir = getenv("windir"))) {
+ fprintf(stderr, "One of %s,%%SystemRoot,%%windir is required", SHELLENV);
return -1;
}
@@ -177,17 +182,23 @@ int proc_open(proc_handler_t *proc, const char *command) {
memset(&pi, 0, sizeof(pi));
cmdline = buffer_init();
- buffer_append_string(cmdline, shell);
+ if (shell) {
+ buffer_append_string(cmdline, shell);
+ } else {
+ buffer_append_string(cmdline, windir);
+ buffer_append_string_len(cmdline, CONST_STR_LEN("\\system32\\cmd.exe"));
+ }
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");
+ fprintf(stderr, "failed to CreateProcess: %s", cmdline->ptr);
+ buffer_free(cmdline);
return -1;
}
+ buffer_free(cmdline);
proc->child = pi.hProcess;
CloseHandle(pi.hThread);
@@ -226,8 +237,7 @@ int proc_open(proc_handler_t *proc, const char *command) {
const char *shell;
if (NULL == (shell = getenv(SHELLENV))) {
- fprintf(stderr, "env %s is required", SHELLENV);
- return -1;
+ shell = "/bin/sh";
}
if (proc_open_pipes(proc) != 0) {
@@ -247,7 +257,8 @@ int proc_open(proc_handler_t *proc, const char *command) {
*/
proc_close_parents(proc);
- execl(shell, shell, "-c", command, NULL);
+ execl(shell, shell, "-c", command, (char *)NULL);
+ fprintf(stderr, "failed to execute shell: %s -c %s: %s\n", shell, command, strerror(errno));
_exit(127);
} else if (child < 0) {
@@ -279,31 +290,40 @@ static void proc_read_fd_to_buffer(int fd, buffer *b) {
}
/* }}} */
/* {{{ proc_open_buffer */
-int proc_open_buffer(proc_handler_t *proc, const char *command, buffer *in, buffer *out, buffer *err) {
-
- UNUSED(err);
+int proc_open_buffer(const char *command, buffer *in, buffer *out, buffer *err) {
+ proc_handler_t proc;
- if (proc_open(proc, command) != 0) {
+ if (proc_open(&proc, command) != 0) {
return -1;
}
if (in) {
- if (write(proc->in.fd, (void *)in->ptr, in->used) < 0) {
+ if (write(proc.in.fd, (void *)in->ptr, in->used) < 0) {
perror("error writing pipe");
return -1;
}
}
- pipe_close(&proc->in);
+ pipe_close(&proc.in);
if (out) {
- proc_read_fd_to_buffer(proc->out.fd, out);
+ proc_read_fd_to_buffer(proc.out.fd, out);
}
- pipe_close(&proc->out);
+ pipe_close(&proc.out);
if (err) {
- proc_read_fd_to_buffer(proc->err.fd, err);
+ proc_read_fd_to_buffer(proc.err.fd, err);
+ } else {
+ buffer *tmp = buffer_init();
+ proc_read_fd_to_buffer(proc.err.fd, tmp);
+ if (tmp->used > 0 && write(2, (void*)tmp->ptr, tmp->used) < 0) {
+ perror("error writing pipe");
+ return -1;
+ }
+ buffer_free(tmp);
}
- pipe_close(&proc->err);
+ pipe_close(&proc.err);
+
+ proc_close(&proc);
return 0;
}
@@ -311,7 +331,7 @@ int proc_open_buffer(proc_handler_t *proc, const char *command, buffer *in, buff
/* {{{ test */
#ifdef DEBUG_PROC_OPEN
-int main() {
+int main(void) {
proc_handler_t proc;
buffer *in = buffer_init(), *out = buffer_init(), *err = buffer_init();
int wstatus;
@@ -358,7 +378,7 @@ int main() {
RESET();
fprintf(stdout, "test: echo 321 with read\n"); fflush(stdout);
- if (proc_open_buffer(&proc, "echo 321", NULL, out, err) != 0) {
+ if (proc_open_buffer("echo 321", NULL, out, err) != 0) {
ERROR_OUT();
}
fprintf(stdout, "result: ->%s<-\n\n", out->ptr); fflush(stdout);
@@ -366,7 +386,7 @@ int main() {
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) {
+ if (proc_open_buffer(CMD_CAT, in, out, err) != 0) {
ERROR_OUT();
}
fprintf(stdout, "result: ->%s<-\n\n", out->ptr); fflush(stdout);
diff --git a/src/proc_open.h b/src/proc_open.h
index e07421a..af70738 100644
--- a/src/proc_open.h
+++ b/src/proc_open.h
@@ -22,4 +22,4 @@ typedef struct {
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);
+int proc_open_buffer(const char *command, buffer *in, buffer *out, buffer *err);
diff --git a/src/request.c b/src/request.c
index db58671..8c6c170 100644
--- a/src/request.c
+++ b/src/request.c
@@ -1,3 +1,7 @@
+#include "request.h"
+#include "keyvalue.h"
+#include "log.h"
+
#include <sys/stat.h>
#include <limits.h>
@@ -6,19 +10,15 @@
#include <stdio.h>
#include <ctype.h>
-#include "request.h"
-#include "keyvalue.h"
-#include "log.h"
-
static int request_check_hostname(server *srv, connection *con, buffer *host) {
enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL;
size_t i;
int label_len = 0;
size_t host_len;
char *colon;
- int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
+ int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
int level = 0;
-
+
UNUSED(srv);
UNUSED(con);
@@ -32,33 +32,33 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) {
* IPv6address = "[" ... "]"
* port = *digit
*/
-
+
/* no Host: */
if (!host || host->used == 0) return 0;
-
+
host_len = host->used - 1;
-
+
/* IPv6 adress */
if (host->ptr[0] == '[') {
char *c = host->ptr + 1;
int colon_cnt = 0;
-
+
/* check portnumber */
for (; *c && *c != ']'; c++) {
if (*c == ':') {
if (++colon_cnt > 7) {
return -1;
}
- } else if (!light_isxdigit(*c)) {
+ } else if (!light_isxdigit(*c) && '.' != *c) {
return -1;
}
}
-
+
/* missing ] */
if (!*c) {
return -1;
}
-
+
/* check port */
if (*(c+1) == ':') {
for (c += 2; *c; c++) {
@@ -69,39 +69,50 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) {
}
return 0;
}
-
+
if (NULL != (colon = memchr(host->ptr, ':', host_len))) {
char *c = colon + 1;
-
+
/* check portnumber */
for (; *c; c++) {
if (!light_isdigit(*c)) return -1;
}
-
+
/* remove the port from the host-len */
host_len = colon - host->ptr;
}
-
+
/* Host is empty */
if (host_len == 0) return -1;
-
+
+ /* if the hostname ends in a "." strip it */
+ if (host->ptr[host_len-1] == '.') {
+ /* shift port info one left */
+ if (NULL != colon) memmove(colon-1, colon, host->used - host_len);
+ else host->ptr[host_len-1] = '\0';
+ host_len -= 1;
+ host->used -= 1;
+ }
+
+ if (host_len == 0) return -1;
+
/* scan from the right and skip the \0 */
- for (i = host_len - 1; i + 1 > 0; i--) {
+ for (i = host_len; i-- > 0; ) {
const char c = host->ptr[i];
switch (stage) {
- case TOPLABEL:
+ case TOPLABEL:
if (c == '.') {
/* only switch stage, if this is not the last character */
if (i != host_len - 1) {
if (label_len == 0) {
return -1;
}
-
+
/* check the first character at right of the dot */
if (is_ip == 0) {
- if (!light_isalpha(host->ptr[i+1])) {
- return -1;
+ if (!light_isalnum(host->ptr[i+1])) {
+ return -1;
}
} else if (!light_isdigit(host->ptr[i+1])) {
is_ip = 0;
@@ -111,9 +122,9 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) {
/* just digits */
is_ip = 1;
}
-
+
stage = DOMAINLABEL;
-
+
label_len = 0;
level++;
} else if (i == 0) {
@@ -122,7 +133,7 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) {
}
} else if (i == 0) {
/* the first character of the hostname */
- if (!light_isalpha(c)) {
+ if (!light_isalnum(c)) {
return -1;
}
label_len++;
@@ -135,7 +146,7 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) {
}
label_len++;
}
-
+
break;
case DOMAINLABEL:
if (is_ip == 1) {
@@ -143,7 +154,7 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) {
if (label_len == 0) {
return -1;
}
-
+
label_len = 0;
level++;
} else if (!light_isdigit(c)) {
@@ -156,12 +167,12 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) {
if (label_len == 0) {
return -1;
}
-
+
/* c is either - or alphanum here */
if ('-' == host->ptr[i+1]) {
return -1;
}
-
+
label_len = 0;
level++;
} else if (i == 0) {
@@ -176,20 +187,20 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) {
label_len++;
}
}
-
+
break;
}
}
-
+
/* a IP has to consist of 4 parts */
if (is_ip == 1 && level != 3) {
return -1;
}
-
+
if (label_len == 0) {
return -1;
}
-
+
return 0;
}
@@ -197,73 +208,76 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) {
#define DUMP_HEADER
#endif
-int http_request_split_value(array *vals, buffer *b) {
- char *s;
+static int http_request_split_value(array *vals, buffer *b) {
size_t i;
int state = 0;
- /*
- * parse
- *
+
+ const char *current;
+ const char *token_start = NULL, *token_end = NULL;
+ /*
+ * parse
+ *
* val1, val2, val3, val4
- *
+ *
* into a array (more or less a explode() incl. striping of whitespaces
*/
-
+
if (b->used == 0) return 0;
-
- s = b->ptr;
-
- for (i =0; i < b->used - 1; ) {
- char *start = NULL, *end = NULL;
+
+ current = b->ptr;
+ for (i = 0; i < b->used; ++i, ++current) {
data_string *ds;
-
+
switch (state) {
- case 0: /* ws */
-
- /* skip ws */
- for (; (*s == ' ' || *s == '\t') && i < b->used - 1; i++, s++);
-
-
- state = 1;
- break;
- case 1: /* value */
- start = s;
-
- for (; *s != ',' && i < b->used - 1; i++, s++);
- end = s - 1;
-
- for (; (*end == ' ' || *end == '\t') && end > start; end--);
-
- if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) {
- ds = data_string_init();
+ case 0: /* find start of a token */
+ switch (*current) {
+ case ' ':
+ case '\t': /* skip white space */
+ case ',': /* skip empty token */
+ break;
+ case '\0': /* end of string */
+ return 0;
+ default:
+ /* found real data, switch to state 1 to find the end of the token */
+ token_start = token_end = current;
+ state = 1;
+ break;
}
+ break;
+ case 1: /* find end of token and last non white space character */
+ switch (*current) {
+ case ' ':
+ case '\t':
+ /* space - don't update token_end */
+ break;
+ case ',':
+ case '\0': /* end of string also marks the end of a token */
+ if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) {
+ ds = data_string_init();
+ }
+
+ buffer_copy_string_len(ds->value, token_start, token_end-token_start+1);
+ array_insert_unique(vals, (data_unset *)ds);
- buffer_copy_string_len(ds->value, start, end-start+1);
- array_insert_unique(vals, (data_unset *)ds);
-
- if (*s == ',') {
state = 0;
- i++;
- s++;
- } else {
- /* end of string */
-
- state = 2;
+ break;
+ default:
+ /* no white space, update token_end to include current character */
+ token_end = current;
+ break;
}
break;
- default:
- i++;
- break;
}
}
+
return 0;
}
-int request_uri_is_valid_char(unsigned char c) {
+static int request_uri_is_valid_char(unsigned char c) {
if (c <= 32) return 0;
if (c == 127) return 0;
if (c == 255) return 0;
-
+
return 1;
}
@@ -271,28 +285,28 @@ int http_request_parse(server *srv, connection *con) {
char *uri = NULL, *proto = NULL, *method = NULL, con_length_set;
int is_key = 1, key_len = 0, is_ws_after_key = 0, in_folding;
char *value = NULL, *key = NULL;
-
+ char *reqline_host = NULL;
+ int reqline_hostlen = 0;
+
enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_KEEPALIVE, HTTP_CONNECTION_CLOSE } keep_alive_set = HTTP_CONNECTION_UNSET;
-
+
int line = 0;
-
+
int request_line_stage = 0;
size_t i, first;
-
+
int done = 0;
-
- data_string *ds = NULL;
-
- /*
- * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
- * Option : "^([-a-zA-Z]+): (.+)$"
+
+ /*
+ * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
+ * Option : "^([-a-zA-Z]+): (.+)$"
* End : "^$"
*/
if (con->conf.log_request_header) {
- log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
- "fd:", con->fd,
- "request-len:", con->request.request->used,
+ log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
+ "fd:", con->fd,
+ "request-len:", con->request.request->used,
"\n", con->request.request);
}
@@ -300,13 +314,13 @@ int http_request_parse(server *srv, connection *con) {
con->request.request->ptr[0] == '\r' &&
con->request.request->ptr[1] == '\n') {
/* we are in keep-alive and might get \r\n after a previous POST request.*/
-
+
buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, con->request.request->used - 1 - 2);
} else {
/* fill the local request buffer */
buffer_copy_string_buffer(con->parse_request, con->request.request);
}
-
+
keep_alive_set = 0;
con_length_set = 0;
@@ -318,67 +332,109 @@ int http_request_parse(server *srv, connection *con) {
* */
for (i = 0, first = 0; i < con->parse_request->used && line == 0; i++) {
char *cur = con->parse_request->ptr + i;
-
+
switch(*cur) {
- case '\r':
+ case '\r':
if (con->parse_request->ptr[i+1] == '\n') {
http_method_t r;
char *nuri = NULL;
size_t j;
-
+
/* \r\n -> \0\0 */
con->parse_request->ptr[i] = '\0';
con->parse_request->ptr[i+1] = '\0';
-
+
buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i);
-
+
if (request_line_stage != 2) {
con->http_status = 400;
con->response.keep_alive = 0;
con->keep_alive = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400");
+
if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400");
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
}
return 0;
}
-
+
proto = con->parse_request->ptr + first;
-
+
*(uri - 1) = '\0';
*(proto - 1) = '\0';
-
+
/* we got the first one :) */
if (-1 == (r = get_http_method_key(method))) {
con->http_status = 501;
con->response.keep_alive = 0;
con->keep_alive = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501");
+
if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
+
+ return 0;
+ }
+
+ con->request.http_method = r;
+
+ /*
+ * RFC2616 says:
+ *
+ * HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
+ *
+ * */
+ if (0 == strncmp(proto, "HTTP/", sizeof("HTTP/") - 1)) {
+ char * major = proto + sizeof("HTTP/") - 1;
+ char * minor = strchr(major, '.');
+ char *err = NULL;
+ int major_num = 0, minor_num = 0;
+
+ int invalid_version = 0;
+
+ if (NULL == minor || /* no dot */
+ minor == major || /* no major */
+ *(minor + 1) == '\0' /* no minor */) {
+ invalid_version = 1;
+ } else {
+ *minor = '\0';
+ major_num = strtol(major, &err, 10);
+
+ if (*err != '\0') invalid_version = 1;
+
+ *minor++ = '.';
+ minor_num = strtol(minor, &err, 10);
+
+ if (*err != '\0') invalid_version = 1;
+ }
+
+ if (invalid_version) {
+ con->http_status = 400;
+ con->keep_alive = 0;
+
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
}
-
- return 0;
- }
-
- con->request.http_method = r;
-
- if (0 == strncmp(proto, "HTTP/1.", sizeof("HTTP/1.") - 1)) {
- if (proto[7] == '1') {
+ return 0;
+ }
+
+ if (major_num == 1 && minor_num == 1) {
con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0;
- } else if (proto[7] == '0') {
+ } else if (major_num == 1 && minor_num == 0) {
con->request.http_version = HTTP_VERSION_1_0;
- } else {
+ } else {
con->http_status = 505;
- log_error_write(srv, __FILE__, __LINE__, "s", "unknown HTTP version -> 505");
if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "unknown HTTP version -> 505");
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
@@ -389,62 +445,69 @@ int http_request_parse(server *srv, connection *con) {
con->http_status = 400;
con->keep_alive = 0;
- log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
if (srv->srvconf.log_request_header_on_error) {
- log_error_write(srv, __FILE__, __LINE__, "Sb",
- "request-header:\n",
- con->request.request);
- }
+ log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
return 0;
}
-
+
if (0 == strncmp(uri, "http://", 7) &&
NULL != (nuri = strchr(uri + 7, '/'))) {
- /* ignore the host-part */
-
+ reqline_host = uri + 7;
+ reqline_hostlen = nuri - reqline_host;
+
+ buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
+ } else if (0 == strncmp(uri, "https://", 8) &&
+ NULL != (nuri = strchr(uri + 8, '/'))) {
+ reqline_host = uri + 8;
+ reqline_hostlen = nuri - reqline_host;
+
buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
} else {
/* everything looks good so far */
buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
}
-
+
/* check uri for invalid characters */
for (j = 0; j < con->request.uri->used - 1; j++) {
if (!request_uri_is_valid_char(con->request.uri->ptr[j])) {
unsigned char buf[2];
con->http_status = 400;
con->keep_alive = 0;
-
- buf[0] = con->request.uri->ptr[j];
- buf[1] = '\0';
-
- if (con->request.uri->ptr[j] > 32 &&
- con->request.uri->ptr[j] != 127) {
- /* the character is printable -> print it */
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "invalid character in URI -> 400",
- buf);
- } else {
- /* a control-character, print ascii-code */
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "invalid character in URI -> 400",
- con->request.uri->ptr[j]);
- }
-
+
if (srv->srvconf.log_request_header_on_error) {
+ buf[0] = con->request.uri->ptr[j];
+ buf[1] = '\0';
+
+ if (con->request.uri->ptr[j] > 32 &&
+ con->request.uri->ptr[j] != 127) {
+ /* the character is printable -> print it */
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "invalid character in URI -> 400",
+ buf);
+ } else {
+ /* a control-character, print ascii-code */
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "invalid character in URI -> 400",
+ con->request.uri->ptr[j]);
+ }
+
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
}
-
+
return 0;
}
}
-
+
buffer_copy_string_buffer(con->request.orig_uri, con->request.uri);
-
+
con->http_status = 0;
-
+
i++;
line++;
first = i+1;
@@ -452,14 +515,14 @@ int http_request_parse(server *srv, connection *con) {
break;
case ' ':
switch(request_line_stage) {
- case 0:
+ case 0:
/* GET|POST|... */
- method = con->parse_request->ptr + first;
+ method = con->parse_request->ptr + first;
first = i + 1;
break;
case 1:
/* /foobar/... */
- uri = con->parse_request->ptr + first;
+ uri = con->parse_request->ptr + first;
first = i + 1;
break;
default:
@@ -467,21 +530,21 @@ int http_request_parse(server *srv, connection *con) {
con->http_status = 400;
con->response.keep_alive = 0;
con->keep_alive = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
+
if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
}
return 0;
}
-
+
request_line_stage++;
break;
}
}
-
+
in_folding = 0;
if (con->request.uri->used == 1) {
@@ -489,8 +552,8 @@ int http_request_parse(server *srv, connection *con) {
con->response.keep_alive = 0;
con->keep_alive = 0;
- log_error_write(srv, __FILE__, __LINE__, "s", "no uri specified -> 400");
if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "no uri specified -> 400");
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
@@ -498,30 +561,43 @@ int http_request_parse(server *srv, connection *con) {
return 0;
}
-
+ if (reqline_host) {
+ /* Insert as host header */
+ data_string *ds;
+
+ if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
+ ds = data_string_init();
+ }
+
+ buffer_copy_string_len(ds->key, CONST_STR_LEN("Host"));
+ buffer_copy_string_len(ds->value, reqline_host, reqline_hostlen);
+ array_insert_unique(con->request.headers, (data_unset *)ds);
+ con->request.http_host = ds->value;
+ }
+
for (; i < con->parse_request->used && !done; i++) {
char *cur = con->parse_request->ptr + i;
-
+
if (is_key) {
size_t j;
int got_colon = 0;
-
+
/**
* 1*<any CHAR except CTLs or separators>
* CTLs == 0-31 + 127
- *
+ *
*/
switch(*cur) {
case ':':
is_key = 0;
-
+
value = cur + 1;
-
+
if (is_ws_after_key == 0) {
key_len = i - first;
}
is_ws_after_key = 0;
-
+
break;
case '(':
case ')':
@@ -542,8 +618,8 @@ int http_request_parse(server *srv, connection *con) {
con->http_status = 400;
con->keep_alive = 0;
con->response.keep_alive = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "sbsds",
+
+ log_error_write(srv, __FILE__, __LINE__, "sbsds",
"invalid character in key", con->request.request, cur, *cur, "-> 400");
return 0;
case ' ':
@@ -552,13 +628,13 @@ int http_request_parse(server *srv, connection *con) {
is_key = 0;
in_folding = 1;
value = cur;
-
+
break;
}
-
-
+
+
key_len = i - first;
-
+
/* skip every thing up to the : */
for (j = 1; !got_colon; j++) {
switch(con->parse_request->ptr[j + i]) {
@@ -567,40 +643,51 @@ int http_request_parse(server *srv, connection *con) {
/* skip WS */
continue;
case ':':
- /* ok, done */
-
+ /* ok, done; handle the colon the usual way */
+
i += j - 1;
got_colon = 1;
-
+ is_ws_after_key = 1; /* we already know the key length */
+
break;
default:
/* error */
-
- log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400");
-
+
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
+
con->http_status = 400;
con->response.keep_alive = 0;
con->keep_alive = 0;
-
+
return 0;
}
}
-
+
break;
case '\r':
if (con->parse_request->ptr[i+1] == '\n' && i == first) {
/* End of Header */
con->parse_request->ptr[i] = '\0';
con->parse_request->ptr[i+1] = '\0';
-
+
i++;
-
+
done = 1;
-
+
break;
} else {
- log_error_write(srv, __FILE__, __LINE__, "s", "CR without LF -> 400");
-
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "CR without LF -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
+
con->http_status = 400;
con->keep_alive = 0;
con->response.keep_alive = 0;
@@ -641,10 +728,16 @@ int http_request_parse(server *srv, connection *con) {
con->http_status = 400;
con->keep_alive = 0;
con->response.keep_alive = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "sbsds",
+
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsds",
"CTL character in key", con->request.request, cur, *cur, "-> 400");
-
+
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
+
return 0;
default:
/* ok */
@@ -652,30 +745,64 @@ int http_request_parse(server *srv, connection *con) {
}
} else {
switch(*cur) {
- case '\r':
+ case '\r':
if (con->parse_request->ptr[i+1] == '\n') {
+ data_string *ds = NULL;
+
/* End of Headerline */
con->parse_request->ptr[i] = '\0';
con->parse_request->ptr[i+1] = '\0';
-
+
if (in_folding) {
- if (!ds) {
+ buffer *key_b;
+ /**
+ * we use a evil hack to handle the line-folding
+ *
+ * As array_insert_unique() deletes 'ds' in the case of a duplicate
+ * ds points somewhere and we get a evil crash. As a solution we keep the old
+ * "key" and get the current value from the hash and append us
+ *
+ * */
+
+ if (!key || !key_len) {
/* 400 */
-
- log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400");
-
+
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400");
+
+ log_error_write(srv, __FILE__, __LINE__, "Sb",
+ "request-header:\n",
+ con->request.request);
+ }
+
+
con->http_status = 400;
con->keep_alive = 0;
con->response.keep_alive = 0;
return 0;
}
- buffer_append_string(ds->value, value);
+
+ key_b = buffer_init();
+ buffer_copy_string_len(key_b, key, key_len);
+
+ if (NULL != (ds = (data_string *)array_get_element(con->request.headers, key_b->ptr))) {
+ buffer_append_string(ds->value, value);
+ }
+
+ buffer_free(key_b);
} else {
int s_len;
key = con->parse_request->ptr + first;
-
+
s_len = cur - value;
-
+
+ /* strip trailing white-spaces */
+ for (; s_len > 0 &&
+ (value[s_len - 1] == ' ' ||
+ value[s_len - 1] == '\t'); s_len--);
+
+ value[s_len] = '\0';
+
if (s_len > 0) {
int cmp = 0;
if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
@@ -683,86 +810,87 @@ int http_request_parse(server *srv, connection *con) {
}
buffer_copy_string_len(ds->key, key, key_len);
buffer_copy_string_len(ds->value, value, s_len);
-
- /* retreive values
- *
- *
+
+ /* retreive values
+ *
+ *
* the list of options is sorted to simplify the search
*/
-
+
if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
array *vals;
size_t vi;
-
+
/* split on , */
-
+
vals = srv->split_vals;
array_reset(vals);
-
+
http_request_split_value(vals, ds->value);
-
+
for (vi = 0; vi < vals->used; vi++) {
data_string *dsv = (data_string *)vals->data[vi];
-
+
if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
-
+
break;
} else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
keep_alive_set = HTTP_CONNECTION_CLOSE;
-
+
break;
}
}
-
+
} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
char *err;
unsigned long int r;
size_t j;
-
+
if (con_length_set) {
con->http_status = 400;
con->keep_alive = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "s",
- "duplicate Content-Length-header -> 400");
+
if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "duplicate Content-Length-header -> 400");
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
}
+ array_insert_unique(con->request.headers, (data_unset *)ds);
return 0;
}
-
+
if (ds->value->used == 0) SEGFAULT();
-
+
for (j = 0; j < ds->value->used - 1; j++) {
char c = ds->value->ptr[j];
if (!isdigit((unsigned char)c)) {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
"content-length broken:", ds->value, "-> 400");
-
+
con->http_status = 400;
con->keep_alive = 0;
-
+
array_insert_unique(con->request.headers, (data_unset *)ds);
return 0;
}
}
-
+
r = strtoul(ds->value->ptr, &err, 10);
-
+
if (*err == '\0') {
con_length_set = 1;
con->request.content_length = r;
} else {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
"content-length broken:", ds->value, "-> 400");
-
+
con->http_status = 400;
con->keep_alive = 0;
-
+
array_insert_unique(con->request.headers, (data_unset *)ds);
return 0;
}
@@ -773,23 +901,24 @@ int http_request_parse(server *srv, connection *con) {
} else {
con->http_status = 400;
con->keep_alive = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "s",
- "duplicate Content-Type-header -> 400");
+
if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "duplicate Content-Type-header -> 400");
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
}
+ array_insert_unique(con->request.headers, (data_unset *)ds);
return 0;
}
} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
- /* HTTP 2616 8.2.3
+ /* HTTP 2616 8.2.3
* Expect: 100-continue
- *
+ *
* -> (10.1.1) 100 (read content, process request, send final status-code)
* -> (10.4.18) 417 (close)
- *
+ *
* (not handled at all yet, we always send 417 here)
*
* What has to be added ?
@@ -798,26 +927,32 @@ int http_request_parse(server *srv, connection *con) {
* header
*
*/
-
- con->http_status = 417;
- con->keep_alive = 0;
-
- array_insert_unique(con->request.headers, (data_unset *)ds);
- return 0;
+
+ if (srv->srvconf.reject_expect_100_with_417 && 0 == buffer_caseless_compare(CONST_BUF_LEN(ds->value), CONST_STR_LEN("100-continue"))) {
+ con->http_status = 417;
+ con->keep_alive = 0;
+ array_insert_unique(con->request.headers, (data_unset *)ds);
+ return 0;
+ }
} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
- if (!con->request.http_host) {
+ if (reqline_host) {
+ /* ignore all host: headers as we got the host in the request line */
+ ds->free((data_unset*) ds);
+ ds = NULL;
+ } else if (!con->request.http_host) {
con->request.http_host = ds->value;
} else {
con->http_status = 400;
con->keep_alive = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "s",
- "duplicate Host-header -> 400");
+
if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "duplicate Host-header -> 400");
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
}
+ array_insert_unique(con->request.headers, (data_unset *)ds);
return 0;
}
} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
@@ -829,17 +964,21 @@ int http_request_parse(server *srv, connection *con) {
} else if (0 == strcasecmp(con->request.http_if_modified_since,
ds->value->ptr)) {
/* ignore it if they are the same */
+
+ ds->free((data_unset *)ds);
+ ds = NULL;
} else {
con->http_status = 400;
con->keep_alive = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "s",
- "duplicate If-Modified-Since header -> 400");
+
if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "duplicate If-Modified-Since header -> 400");
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
}
+ array_insert_unique(con->request.headers, (data_unset *)ds);
return 0;
}
} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
@@ -847,59 +986,58 @@ int http_request_parse(server *srv, connection *con) {
if (!con->request.http_if_none_match) {
con->request.http_if_none_match = ds->value->ptr;
} else {
- con->http_status = 400;
- con->keep_alive = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "s",
- "duplicate If-None-Match-header -> 400");
- if (srv->srvconf.log_request_header_on_error) {
- log_error_write(srv, __FILE__, __LINE__, "Sb",
- "request-header:\n",
- con->request.request);
- }
- return 0;
+ ds->free((data_unset*) ds);
+ ds = NULL;
}
} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
if (!con->request.http_range) {
/* bytes=.*-.* */
-
+
if (0 == strncasecmp(ds->value->ptr, "bytes=", 6) &&
NULL != strchr(ds->value->ptr+6, '-')) {
-
+
/* if dup, only the first one will survive */
con->request.http_range = ds->value->ptr + 6;
}
} else {
con->http_status = 400;
con->keep_alive = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "s",
- "duplicate Host-header -> 400");
+
if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "duplicate Range-header -> 400");
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
}
+ array_insert_unique(con->request.headers, (data_unset *)ds);
return 0;
}
}
-
- array_insert_unique(con->request.headers, (data_unset *)ds);
+
+ if (ds) array_insert_unique(con->request.headers, (data_unset *)ds);
} else {
/* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
}
}
-
+
i++;
first = i+1;
is_key = 1;
- value = 0;
- key_len = 0;
+ value = NULL;
+#if 0
+ /**
+ * for Bug 1230 keep the key_len a live
+ */
+ key_len = 0;
+#endif
in_folding = 0;
} else {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
- "CR without LF", con->request.request, "-> 400");
-
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "CR without LF", con->request.request, "-> 400");
+ }
+
con->http_status = 400;
con->keep_alive = 0;
con->response.keep_alive = 0;
@@ -911,34 +1049,45 @@ int http_request_parse(server *srv, connection *con) {
/* strip leading WS */
if (value == cur) value = cur+1;
default:
+ if (*cur >= 0 && *cur < 32 && *cur != '\t') {
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "invalid char in header", (int)*cur, "-> 400");
+ }
+
+ con->http_status = 400;
+ con->keep_alive = 0;
+
+ return 0;
+ }
break;
}
}
}
-
+
con->header_len = i;
-
+
/* do some post-processing */
if (con->request.http_version == HTTP_VERSION_1_1) {
if (keep_alive_set != HTTP_CONNECTION_CLOSE) {
/* no Connection-Header sent */
-
+
/* HTTP/1.1 -> keep-alive default TRUE */
con->keep_alive = 1;
} else {
con->keep_alive = 0;
}
-
+
/* RFC 2616, 14.23 */
if (con->request.http_host == NULL ||
buffer_is_empty(con->request.http_host)) {
con->http_status = 400;
con->response.keep_alive = 0;
con->keep_alive = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
+
if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
@@ -948,21 +1097,21 @@ int http_request_parse(server *srv, connection *con) {
} else {
if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
/* no Connection-Header sent */
-
+
/* HTTP/1.0 -> keep-alive default FALSE */
con->keep_alive = 1;
} else {
con->keep_alive = 0;
}
}
-
+
/* check hostname field if it is set */
if (NULL != con->request.http_host &&
0 != request_check_hostname(srv, con, con->request.http_host)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "Invalid Hostname -> 400");
-
+
if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "Invalid Hostname -> 400");
log_error_write(srv, __FILE__, __LINE__, "Sb",
"request-header:\n",
con->request.request);
@@ -971,21 +1120,20 @@ int http_request_parse(server *srv, connection *con) {
con->http_status = 400;
con->response.keep_alive = 0;
con->keep_alive = 0;
-
+
return 0;
}
switch(con->request.http_method) {
case HTTP_METHOD_GET:
case HTTP_METHOD_HEAD:
- case HTTP_METHOD_OPTIONS:
/* content-length is forbidden for those */
if (con_length_set && con->request.content_length != 0) {
/* content-length is missing */
- log_error_write(srv, __FILE__, __LINE__, "s",
- "GET/HEAD/OPTIONS with content-length -> 400");
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "GET/HEAD with content-length -> 400");
+
con->keep_alive = 0;
-
con->http_status = 400;
return 0;
}
@@ -994,10 +1142,10 @@ int http_request_parse(server *srv, connection *con) {
/* content-length is required for them */
if (!con_length_set) {
/* content-length is missing */
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"POST-request, but content-length missing -> 411");
+
con->keep_alive = 0;
-
con->http_status = 411;
return 0;
@@ -1007,42 +1155,42 @@ int http_request_parse(server *srv, connection *con) {
/* the may have a content-length */
break;
}
-
-
+
+
/* check if we have read post data */
if (con_length_set) {
/* don't handle more the SSIZE_MAX bytes in content-length */
if (con->request.content_length > SSIZE_MAX) {
- con->http_status = 413;
+ con->http_status = 413;
con->keep_alive = 0;
- log_error_write(srv, __FILE__, __LINE__, "sds",
- "request-size too long:", con->request.content_length, "-> 413");
+ log_error_write(srv, __FILE__, __LINE__, "sos",
+ "request-size too long:", (off_t) con->request.content_length, "-> 413");
return 0;
}
/* divide by 1024 as srvconf.max_request_size is in kBytes */
if (srv->srvconf.max_request_size != 0 &&
(con->request.content_length >> 10) > srv->srvconf.max_request_size) {
- /* the request body itself is larger then
+ /* the request body itself is larger then
* our our max_request_size
*/
-
+
con->http_status = 413;
con->keep_alive = 0;
-
- log_error_write(srv, __FILE__, __LINE__, "sds",
- "request-size too long:", con->request.content_length, "-> 413");
+
+ log_error_write(srv, __FILE__, __LINE__, "sos",
+ "request-size too long:", (off_t) con->request.content_length, "-> 413");
return 0;
}
-
-
+
+
/* we have content */
if (con->request.content_length != 0) {
return 1;
}
}
-
+
return 0;
}
@@ -1050,9 +1198,9 @@ int http_request_header_finished(server *srv, connection *con) {
UNUSED(srv);
if (con->request.request->used < 5) return 0;
-
+
if (0 == memcmp(con->request.request->ptr + con->request.request->used - 5, "\r\n\r\n", 4)) return 1;
if (NULL != strstr(con->request.request->ptr, "\r\n\r\n")) return 1;
-
+
return 0;
}
diff --git a/src/response.c b/src/response.c
index d955cec..fd1ab19 100644
--- a/src/response.c
+++ b/src/response.c
@@ -1,3 +1,14 @@
+#include "response.h"
+#include "keyvalue.h"
+#include "log.h"
+#include "stat_cache.h"
+#include "chunk.h"
+
+#include "configfile.h"
+#include "connections.h"
+
+#include "plugin.h"
+
#include <sys/types.h>
#include <sys/stat.h>
@@ -13,176 +24,269 @@
#include <stdio.h>
-#include "response.h"
-#include "keyvalue.h"
-#include "log.h"
-#include "stat_cache.h"
-#include "chunk.h"
-
-#include "connections.h"
-
-#include "plugin.h"
-
#include "sys-socket.h"
+#include "version.h"
int http_response_write_header(server *srv, connection *con) {
buffer *b;
size_t i;
int have_date = 0;
int have_server = 0;
-
+
b = chunkqueue_get_prepend_buffer(con->write_queue);
-
+
if (con->request.http_version == HTTP_VERSION_1_1) {
- BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
+ buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.1 "));
} else {
- BUFFER_COPY_STRING_CONST(b, "HTTP/1.0 ");
+ buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.0 "));
}
buffer_append_long(b, con->http_status);
- BUFFER_APPEND_STRING_CONST(b, " ");
+ buffer_append_string_len(b, CONST_STR_LEN(" "));
buffer_append_string(b, get_http_status_name(con->http_status));
-
+
+ /* disable keep-alive if requested */
+ if (con->request_count > con->conf.max_keep_alive_requests || 0 == con->conf.max_keep_alive_idle) {
+ con->keep_alive = 0;
+ } else {
+ con->keep_alive_idle = con->conf.max_keep_alive_idle;
+ }
+
if (con->request.http_version != HTTP_VERSION_1_1 || con->keep_alive == 0) {
- BUFFER_APPEND_STRING_CONST(b, "\r\nConnection: ");
- buffer_append_string(b, con->keep_alive ? "keep-alive" : "close");
+ if (con->keep_alive) {
+ response_header_overwrite(srv, con, CONST_STR_LEN("Connection"), CONST_STR_LEN("keep-alive"));
+ } else {
+ response_header_overwrite(srv, con, CONST_STR_LEN("Connection"), CONST_STR_LEN("close"));
+ }
}
-
+
if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
- BUFFER_APPEND_STRING_CONST(b, "\r\nTransfer-Encoding: chunked");
+ response_header_overwrite(srv, con, CONST_STR_LEN("Transfer-Encoding"), CONST_STR_LEN("chunked"));
}
-
-
+
+
/* add all headers */
for (i = 0; i < con->response.headers->used; i++) {
data_string *ds;
-
+
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)) {
- 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;
+ 0 != strncasecmp(ds->key->ptr, CONST_STR_LEN("X-LIGHTTPD-")) &&
+ 0 != strncasecmp(ds->key->ptr, CONST_STR_LEN("X-Sendfile"))) {
+ if (0 == strcasecmp(ds->key->ptr, "Date")) have_date = 1;
+ if (0 == strcasecmp(ds->key->ptr, "Server")) have_server = 1;
+ if (0 == strcasecmp(ds->key->ptr, "Content-Encoding") && 304 == con->http_status) continue;
- BUFFER_APPEND_STRING_CONST(b, "\r\n");
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n"));
buffer_append_string_buffer(b, ds->key);
- BUFFER_APPEND_STRING_CONST(b, ": ");
- buffer_append_string_buffer(b, ds->value);
+ buffer_append_string_len(b, CONST_STR_LEN(": "));
#if 0
- log_error_write(srv, __FILE__, __LINE__, "bb",
- ds->key, ds->value);
+ /**
+ * the value might contain newlines, encode them with at least one white-space
+ */
+ buffer_append_string_encoded(b, CONST_BUF_LEN(ds->value), ENCODING_HTTP_HEADER);
+#else
+ buffer_append_string_buffer(b, ds->value);
#endif
}
}
-
+
if (!have_date) {
/* HTTP/1.1 requires a Date: header */
- BUFFER_APPEND_STRING_CONST(b, "\r\nDate: ");
-
+ buffer_append_string_len(b, CONST_STR_LEN("\r\nDate: "));
+
/* cache the generated timestamp */
if (srv->cur_ts != srv->last_generated_date_ts) {
buffer_prepare_copy(srv->ts_date_str, 255);
-
- strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
+
+ strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
"%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts)));
-
+
srv->ts_date_str->used = strlen(srv->ts_date_str->ptr) + 1;
-
+
srv->last_generated_date_ts = srv->cur_ts;
}
-
+
buffer_append_string_buffer(b, srv->ts_date_str);
}
if (!have_server) {
if (buffer_is_empty(con->conf.server_tag)) {
- BUFFER_APPEND_STRING_CONST(b, "\r\nServer: " PACKAGE_NAME "/" PACKAGE_VERSION);
- } else {
- BUFFER_APPEND_STRING_CONST(b, "\r\nServer: ");
- buffer_append_string_buffer(b, con->conf.server_tag);
+ buffer_append_string_len(b, CONST_STR_LEN("\r\nServer: " PACKAGE_DESC));
+ } else if (con->conf.server_tag->used > 1) {
+ buffer_append_string_len(b, CONST_STR_LEN("\r\nServer: "));
+ buffer_append_string_encoded(b, CONST_BUF_LEN(con->conf.server_tag), ENCODING_HTTP_HEADER);
}
}
-
- BUFFER_APPEND_STRING_CONST(b, "\r\n\r\n");
-
-
+
+ buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n"));
+
+
con->bytes_header = b->used - 1;
-
+
if (con->conf.log_response_header) {
log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b);
}
-
+
return 0;
}
+#ifdef USE_OPENSSL
+static void https_add_ssl_entries(connection *con) {
+ X509 *xs;
+ X509_NAME *xn;
+ X509_NAME_ENTRY *xe;
+ int i, nentries;
+
+ if (
+ SSL_get_verify_result(con->ssl) != X509_V_OK
+ || !(xs = SSL_get_peer_certificate(con->ssl))
+ ) {
+ return;
+ }
+
+ xn = X509_get_subject_name(xs);
+ for (i = 0, nentries = X509_NAME_entry_count(xn); i < nentries; ++i) {
+ int xobjnid;
+ const char * xobjsn;
+ data_string *envds;
+
+ if (!(xe = X509_NAME_get_entry(xn, i))) {
+ continue;
+ }
+ xobjnid = OBJ_obj2nid((ASN1_OBJECT*)X509_NAME_ENTRY_get_object(xe));
+ xobjsn = OBJ_nid2sn(xobjnid);
+ if (!xobjsn) {
+ continue;
+ }
+
+ if (NULL == (envds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
+ envds = data_string_init();
+ }
+ buffer_copy_string_len(envds->key, CONST_STR_LEN("SSL_CLIENT_S_DN_"));
+ buffer_append_string(envds->key, xobjsn);
+ buffer_copy_string_len(
+ envds->value,
+ (const char *)xe->value->data, xe->value->length
+ );
+ /* pick one of the exported values as "authed user", for example
+ * ssl.verifyclient.username = "SSL_CLIENT_S_DN_UID" or "SSL_CLIENT_S_DN_emailAddress"
+ */
+ if (buffer_is_equal(con->conf.ssl_verifyclient_username, envds->key)) {
+ buffer_copy_string_buffer(con->authed_user, envds->value);
+ }
+ array_insert_unique(con->environment, (data_unset *)envds);
+ }
+ if (con->conf.ssl_verifyclient_export_cert) {
+ BIO *bio;
+ if (NULL != (bio = BIO_new(BIO_s_mem()))) {
+ data_string *envds;
+ int n;
+
+ PEM_write_bio_X509(bio, xs);
+ n = BIO_pending(bio);
+
+ if (NULL == (envds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
+ envds = data_string_init();
+ }
+
+ buffer_copy_string_len(envds->key, CONST_STR_LEN("SSL_CLIENT_CERT"));
+ buffer_prepare_copy(envds->value, n+1);
+ BIO_read(bio, envds->value->ptr, n);
+ BIO_free(bio);
+ envds->value->ptr[n] = '\0';
+ envds->value->used = n+1;
+ array_insert_unique(con->environment, (data_unset *)envds);
+ }
+ }
+ X509_free(xs);
+}
+#endif
handler_t http_response_prepare(server *srv, connection *con) {
handler_t r;
-
+
/* looks like someone has already done a decision */
- if (con->mode == DIRECT &&
+ if (con->mode == DIRECT &&
(con->http_status != 0 && con->http_status != 200)) {
/* remove a packets in the queue */
if (con->file_finished == 0) {
chunkqueue_reset(con->write_queue);
}
-
+
return HANDLER_FINISHED;
}
-
+
/* no decision yet, build conf->filename */
if (con->mode == DIRECT && con->physical.path->used == 0) {
char *qstr;
/* we only come here when we have the parse the full request again
- *
- * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
+ *
+ * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
* problem here as mod_setenv might get called multiple times
*
* fastcgi-auth might lead to a COMEBACK too
* fastcgi again dead server too
*
* mod_compress might add headers twice too
- *
+ *
* */
-
+
+ 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");
}
config_patch_connection(srv, con, COMP_SERVER_SOCKET); /* SERVERsocket */
-
+
/**
* prepare strings
- *
- * - uri.path_raw
+ *
+ * - uri.path_raw
* - uri.path (secure)
* - uri.query
- *
+ *
*/
-
- /**
+
+ /**
* Name according to RFC 2396
- *
+ *
* - scheme
* - authority
* - path
* - query
- *
- * (scheme)://(authority)(path)?(query)
- *
- *
+ *
+ * (scheme)://(authority)(path)?(query)#fragment
+ *
+ *
*/
-
- buffer_copy_string(con->uri.scheme, con->conf.is_ssl ? "https" : "http");
+
+ if (con->conf.is_ssl) {
+ buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("https"));
+ } else {
+ buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("http"));
+ }
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_LANGUAGE); /* Accept-Language: */
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, '#'))) {
+ con->request.uri->used = qstr - con->request.uri->ptr;
+ con->request.uri->ptr[con->request.uri->used++] = '\0';
+ }
+
/** extract query string from request.uri */
if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) {
buffer_copy_string (con->uri.query, qstr + 1);
@@ -200,22 +304,16 @@ handler_t http_response_prepare(server *srv, connection *con) {
log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path : ", con->uri.path_raw);
log_error_write(srv, __FILE__, __LINE__, "sb", "URI-query : ", con->uri.query);
}
-
- /* disable keep-alive if requested */
-
- if (con->request_count > con->conf.max_keep_alive_requests) {
- con->keep_alive = 0;
- }
-
-
+
+
/**
- *
- * call plugins
- *
+ *
+ * call plugins
+ *
* - based on the raw URL
- *
+ *
*/
-
+
switch(r = plugins_call_handle_uri_raw(srv, con)) {
case HANDLER_GO_ON:
break;
@@ -229,14 +327,14 @@ handler_t http_response_prepare(server *srv, connection *con) {
break;
}
- /* build filename
+ /* build filename
*
* - decode url-encodings (e.g. %20 -> ' ')
* - remove path-modifiers (e.g. /../)
*/
-
-
-
+
+
+
if (con->request.http_method == HTTP_METHOD_OPTIONS &&
con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
/* OPTIONS * ... */
@@ -252,16 +350,28 @@ handler_t http_response_prepare(server *srv, connection *con) {
log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path : ", con->uri.path);
}
+#ifdef USE_OPENSSL
+ if (con->conf.is_ssl && con->conf.ssl_verifyclient) {
+ https_add_ssl_entries(con);
+ }
+#endif
+
/**
- *
- * call plugins
- *
+ *
+ * call plugins
+ *
* - based on the clean URL
- *
+ *
*/
-
+
config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */
-
+ config_patch_connection(srv, con, COMP_HTTP_QUERY_STRING); /* HTTPqs */
+
+ /* do we have to downgrade to 1.0 ? */
+ if (!con->conf.allow_http11) {
+ con->request.http_version = HTTP_VERSION_1_0;
+ }
+
switch(r = plugins_call_handle_uri_clean(srv, con)) {
case HANDLER_GO_ON:
break;
@@ -274,11 +384,11 @@ handler_t http_response_prepare(server *srv, connection *con) {
log_error_write(srv, __FILE__, __LINE__, "");
break;
}
-
+
if (con->request.http_method == HTTP_METHOD_OPTIONS &&
con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
/* option requests are handled directly without checking of the path */
-
+
response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
con->http_status = 200;
@@ -288,38 +398,74 @@ handler_t http_response_prepare(server *srv, connection *con) {
}
/***
- *
- * border
- *
+ *
+ * border
+ *
* logical filename (URI) becomes a physical filename here
- *
- *
- *
+ *
+ *
+ *
*/
-
-
-
-
+
+
+
+
/* 1. stat()
* ... ISREG() -> ok, go on
* ... ISDIR() -> index-file -> redirect
- *
- * 2. pathinfo()
+ *
+ * 2. pathinfo()
* ... ISREG()
- *
+ *
* 3. -> 404
- *
+ *
*/
-
+
/*
* SEARCH DOCUMENT ROOT
*/
-
+
/* set a default */
-
+
buffer_copy_string_buffer(con->physical.doc_root, con->conf.document_root);
buffer_copy_string_buffer(con->physical.rel_path, con->uri.path);
-
+
+#if defined(__WIN32) || defined(__CYGWIN__)
+ /* strip dots from the end and spaces
+ *
+ * windows/dos handle those filenames as the same file
+ *
+ * foo == foo. == foo..... == "foo... " == "foo.. ./"
+ *
+ * This will affect in some cases PATHINFO
+ *
+ * on native windows we could prepend the filename with \\?\ to circumvent
+ * this behaviour. I have no idea how to push this through cygwin
+ *
+ * */
+
+ if (con->physical.rel_path->used > 1) {
+ buffer *b = con->physical.rel_path;
+ size_t i;
+
+ if (b->used > 2 &&
+ b->ptr[b->used-2] == '/' &&
+ (b->ptr[b->used-3] == ' ' ||
+ b->ptr[b->used-3] == '.')) {
+ b->ptr[b->used--] = '\0';
+ }
+
+ for (i = b->used - 2; b->used > 1; i--) {
+ if (b->ptr[i] == ' ' ||
+ b->ptr[i] == '.') {
+ b->ptr[b->used--] = '\0';
+ } else {
+ break;
+ }
+ }
+ }
+#endif
+
if (con->conf.log_request_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "-- before doc_root");
log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root);
@@ -341,9 +487,9 @@ handler_t http_response_prepare(server *srv, connection *con) {
log_error_write(srv, __FILE__, __LINE__, "");
break;
}
-
- /* MacOS X and Windows can't distiguish between upper and lower-case
- *
+
+ /* MacOS X and Windows can't distiguish between upper and lower-case
+ *
* convert to lower-case
*/
if (con->conf.force_lowercase_filenames) {
@@ -354,13 +500,13 @@ handler_t http_response_prepare(server *srv, connection *con) {
if (buffer_is_empty(con->server_name)) {
buffer_copy_string_buffer(con->server_name, con->uri.authority);
}
-
- /**
- * create physical filename
+
+ /**
+ * create physical filename
* -> physical.path = docroot + rel_path
- *
+ *
*/
-
+
buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
BUFFER_APPEND_SLASH(con->physical.path);
buffer_copy_string_buffer(con->physical.basedir, con->physical.path);
@@ -390,7 +536,7 @@ handler_t http_response_prepare(server *srv, connection *con) {
log_error_write(srv, __FILE__, __LINE__, "");
break;
}
-
+
if (con->conf.log_request_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "-- logical -> physical");
log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root);
@@ -398,41 +544,57 @@ handler_t http_response_prepare(server *srv, connection *con) {
log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
}
}
-
- /*
+
+ /*
* Noone catched away the file from normal path of execution yet (like mod_access)
- *
+ *
* Go on and check of the file exists at all
*/
-
+
if (con->mode == DIRECT) {
char *slash = NULL;
char *pathinfo = NULL;
int found = 0;
stat_cache_entry *sce = NULL;
-
+
if (con->conf.log_request_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "-- handling physical path");
log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
}
-
+
if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
/* file exists */
-
+
if (con->conf.log_request_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "-- file found");
log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
}
-
+#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
if (S_ISDIR(sce->st.st_mode)) {
- if (con->physical.path->ptr[con->physical.path->used - 2] != '/') {
+ if (con->uri.path->ptr[con->uri.path->used - 2] != '/') {
/* redirect to .../ */
-
+
http_response_redirect_to_directory(srv, con);
-
+
return HANDLER_FINISHED;
}
+#ifdef HAVE_LSTAT
+ } else if (!S_ISREG(sce->st.st_mode) && !sce->is_symlink) {
+#else
} else if (!S_ISREG(sce->st.st_mode)) {
+#endif
/* any special handling of non-reg files ?*/
@@ -441,14 +603,16 @@ handler_t http_response_prepare(server *srv, connection *con) {
switch (errno) {
case EACCES:
con->http_status = 403;
-
+
if (con->conf.log_request_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied");
log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
}
-
+
buffer_reset(con->physical.path);
return HANDLER_FINISHED;
+ case ENAMETOOLONG:
+ /* file name to be read was too long. return 404 */
case ENOENT:
con->http_status = 404;
@@ -466,74 +630,85 @@ handler_t http_response_prepare(server *srv, connection *con) {
/* we have no idea what happend. let's tell the user so. */
con->http_status = 500;
buffer_reset(con->physical.path);
-
+
log_error_write(srv, __FILE__, __LINE__, "ssbsb",
"file not found ... or so: ", strerror(errno),
con->uri.path,
"->", con->physical.path);
-
+
return HANDLER_FINISHED;
}
-
+
/* not found, perhaps PATHINFO */
-
+
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;
}
-
+
if (pathinfo != NULL) {
*pathinfo = '\0';
}
slash = strrchr(srv->tmp_buf->ptr, '/');
-
+
if (pathinfo != NULL) {
/* restore '/' */
*pathinfo = '/';
}
-
+
if (slash) pathinfo = slash;
- } while ((found == 0) && (slash != NULL) && (slash - srv->tmp_buf->ptr > con->physical.basedir->used - 2));
-
+ } while ((found == 0) && (slash != NULL) && ((size_t)(slash - srv->tmp_buf->ptr) > (con->physical.basedir->used - 2)));
+
if (found == 0) {
/* no it really doesn't exists */
con->http_status = 404;
-
+
if (con->conf.log_file_not_found) {
log_error_write(srv, __FILE__, __LINE__, "sbsb",
"file not found:", con->uri.path,
"->", con->physical.path);
}
-
+
buffer_reset(con->physical.path);
-
+
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);
-
+
/*
* shorten uri.path
*/
-
+
con->uri.path->used -= strlen(pathinfo);
con->uri.path->ptr[con->uri.path->used - 1] = '\0';
}
-
+
if (con->conf.log_request_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "-- after pathinfo check");
log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
@@ -541,12 +716,12 @@ handler_t http_response_prepare(server *srv, connection *con) {
log_error_write(srv, __FILE__, __LINE__, "sb", "Pathinfo :", con->request.pathinfo);
}
}
-
+
if (con->conf.log_request_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "-- handling subrequest");
log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
}
-
+
/* call the handlers */
switch(r = plugins_call_handle_subrequest_start(srv, con)) {
case HANDLER_GO_ON:
@@ -557,21 +732,27 @@ handler_t http_response_prepare(server *srv, connection *con) {
if (con->conf.log_request_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "-- subrequest finished");
}
-
+
/* something strange happend */
return r;
}
-
+
/* 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;
}
-
+
}
-
+
switch(r = plugins_call_handle_subrequest(srv, con)) {
case HANDLER_GO_ON:
/* request was not handled, looks like we are done */
@@ -582,7 +763,7 @@ handler_t http_response_prepare(server *srv, connection *con) {
/* something strange happend */
return r;
}
-
+
/* can't happen */
return HANDLER_COMEBACK;
}
diff --git a/src/response.h b/src/response.h
index c9ff234..289add8 100644
--- a/src/response.h
+++ b/src/response.h
@@ -1,15 +1,16 @@
#ifndef _RESPONSE_H_
#define _RESPONSE_H_
-#include <time.h>
-
#include "server.h"
+#include <time.h>
+
int http_response_parse(server *srv, connection *con);
int http_response_write_header(server *srv, connection *con);
int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen);
int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen);
+int response_header_append(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen);
handler_t http_response_prepare(server *srv, connection *con);
int http_response_redirect_to_directory(server *srv, connection *con);
diff --git a/src/server.c b/src/server.c
index 9eb9eb4..590a9d5 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1,3 +1,20 @@
+#include "server.h"
+#include "buffer.h"
+#include "network.h"
+#include "log.h"
+#include "keyvalue.h"
+#include "response.h"
+#include "request.h"
+#include "chunk.h"
+#include "http_chunk.h"
+#include "fdevent.h"
+#include "connections.h"
+#include "stat_cache.h"
+#include "plugin.h"
+#include "joblist.h"
+#include "network_backends.h"
+#include "version.h"
+
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
@@ -14,44 +31,33 @@
#include <stdio.h>
-#include "server.h"
-#include "buffer.h"
-#include "network.h"
-#include "log.h"
-#include "keyvalue.h"
-#include "response.h"
-#include "request.h"
-#include "chunk.h"
-#include "http_chunk.h"
-#include "fdevent.h"
-#include "connections.h"
-#include "stat_cache.h"
-#include "plugin.h"
-#include "joblist.h"
-
#ifdef HAVE_GETOPT_H
-#include <getopt.h>
+# include <getopt.h>
#endif
#ifdef HAVE_VALGRIND_VALGRIND_H
-#include <valgrind/valgrind.h>
+# include <valgrind/valgrind.h>
#endif
#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
+# include <sys/wait.h>
#endif
#ifdef HAVE_PWD_H
-#include <grp.h>
-#include <pwd.h>
+# include <grp.h>
+# include <pwd.h>
#endif
#ifdef HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>
+# include <sys/resource.h>
#endif
#ifdef HAVE_SYS_PRCTL_H
-#include <sys/prctl.h>
+# include <sys/prctl.h>
+#endif
+
+#ifdef USE_OPENSSL
+# include <openssl/err.h>
#endif
#ifndef __sgi
@@ -59,35 +65,76 @@
/* #define USE_ALARM */
#endif
+#ifdef HAVE_GETUID
+# ifndef HAVE_ISSETUGID
+
+static int l_issetugid(void) {
+ return (geteuid() != getuid() || getegid() != getgid());
+}
+
+# define issetugid l_issetugid
+# endif
+#endif
+
static volatile sig_atomic_t srv_shutdown = 0;
static volatile sig_atomic_t graceful_shutdown = 0;
static volatile sig_atomic_t handle_sig_alarm = 1;
static volatile sig_atomic_t handle_sig_hup = 0;
+static volatile sig_atomic_t forwarded_sig_hup = 0;
#if defined(HAVE_SIGACTION) && defined(SA_SIGINFO)
+static volatile siginfo_t last_sigterm_info;
+static volatile siginfo_t last_sighup_info;
+
static void sigaction_handler(int sig, siginfo_t *si, void *context) {
- UNUSED(si);
+ static siginfo_t empty_siginfo;
UNUSED(context);
- switch (sig) {
- case SIGTERM: srv_shutdown = 1; break;
- case SIGINT:
- if (graceful_shutdown) srv_shutdown = 1;
- else graceful_shutdown = 1;
+ if (!si) si = &empty_siginfo;
- break;
- case SIGALRM: handle_sig_alarm = 1; break;
- case SIGHUP: handle_sig_hup = 1; break;
- case SIGCHLD: break;
+ switch (sig) {
+ case SIGTERM:
+ srv_shutdown = 1;
+ last_sigterm_info = *si;
+ break;
+ case SIGINT:
+ if (graceful_shutdown) {
+ srv_shutdown = 1;
+ } else {
+ graceful_shutdown = 1;
+ }
+ last_sigterm_info = *si;
+
+ break;
+ case SIGALRM:
+ handle_sig_alarm = 1;
+ break;
+ case SIGHUP:
+ /**
+ * we send the SIGHUP to all procs in the process-group
+ * this includes ourself
+ *
+ * make sure we only send it once and don't create a
+ * infinite loop
+ */
+ if (!forwarded_sig_hup) {
+ handle_sig_hup = 1;
+ last_sighup_info = *si;
+ } else {
+ forwarded_sig_hup = 0;
+ }
+ break;
+ case SIGCHLD:
+ break;
}
}
#elif defined(HAVE_SIGNAL) || defined(HAVE_SIGACTION)
static void signal_handler(int sig) {
switch (sig) {
case SIGTERM: srv_shutdown = 1; break;
- case SIGINT:
+ case SIGINT:
if (graceful_shutdown) srv_shutdown = 1;
- else graceful_shutdown = 1;
+ else graceful_shutdown = 1;
break;
case SIGALRM: handle_sig_alarm = 1; break;
@@ -109,27 +156,26 @@ static void daemonize(void) {
signal(SIGTSTP, SIG_IGN);
#endif
if (0 != fork()) exit(0);
-
+
if (-1 == setsid()) exit(0);
signal(SIGHUP, SIG_IGN);
if (0 != fork()) exit(0);
-
+
if (0 != chdir("/")) exit(0);
-
- umask(0);
}
#endif
static server *server_init(void) {
int i;
-
+ FILE *frandom = NULL;
+
server *srv = calloc(1, sizeof(*srv));
assert(srv);
#define CLEAN(x) \
srv->x = buffer_init();
-
+
CLEAN(response_header);
CLEAN(parse_full_path);
CLEAN(ts_debug_str);
@@ -139,66 +185,84 @@ static server *server_init(void) {
CLEAN(tmp_buf);
srv->empty_string = buffer_init_string("");
CLEAN(cond_check_buf);
-
+
CLEAN(srvconf.errorlog_file);
+ CLEAN(srvconf.breakagelog_file);
CLEAN(srvconf.groupname);
CLEAN(srvconf.username);
CLEAN(srvconf.changeroot);
CLEAN(srvconf.bindhost);
CLEAN(srvconf.event_handler);
CLEAN(srvconf.pid_file);
-
+
CLEAN(tmp_chunk_len);
#undef CLEAN
-
+
#define CLEAN(x) \
srv->x = array_init();
-
+
CLEAN(config_context);
CLEAN(config_touched);
CLEAN(status);
#undef CLEAN
-
+
for (i = 0; i < FILE_CACHE_MAX; i++) {
+ srv->mtime_cache[i].mtime = (time_t)-1;
srv->mtime_cache[i].str = buffer_init();
}
-
+
+ if ((NULL != (frandom = fopen("/dev/urandom", "rb")) || NULL != (frandom = fopen("/dev/random", "rb")))
+ && 1 == fread(srv->entropy, sizeof(srv->entropy), 1, frandom)) {
+ unsigned int e;
+ memcpy(&e, srv->entropy, sizeof(e) < sizeof(srv->entropy) ? sizeof(e) : sizeof(srv->entropy));
+ srand(e);
+ srv->is_real_entropy = 1;
+ } else {
+ unsigned int j;
+ srand(time(NULL) ^ getpid());
+ srv->is_real_entropy = 0;
+ for (j = 0; j < sizeof(srv->entropy); j++)
+ srv->entropy[j] = rand();
+ }
+ if (frandom) fclose(frandom);
+
srv->cur_ts = time(NULL);
srv->startup_ts = srv->cur_ts;
-
+
srv->conns = calloc(1, sizeof(*srv->conns));
assert(srv->conns);
-
+
srv->joblist = calloc(1, sizeof(*srv->joblist));
assert(srv->joblist);
-
+
srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue));
assert(srv->fdwaitqueue);
-
+
srv->srvconf.modules = array_init();
srv->srvconf.modules_dir = buffer_init_string(LIBRARY_DIR);
srv->srvconf.network_backend = buffer_init();
srv->srvconf.upload_tempdirs = array_init();
-
+ srv->srvconf.reject_expect_100_with_417 = 1;
+
/* use syslog */
- srv->errorlog_fd = -1;
- srv->errorlog_mode = ERRORLOG_STDERR;
+ srv->errorlog_fd = STDERR_FILENO;
+ srv->errorlog_mode = ERRORLOG_FD;
srv->split_vals = array_init();
-
+
return srv;
}
static void server_free(server *srv) {
size_t i;
-
+
for (i = 0; i < FILE_CACHE_MAX; i++) {
buffer_free(srv->mtime_cache[i].str);
}
-
+
#define CLEAN(x) \
buffer_free(srv->x);
-
+
CLEAN(response_header);
CLEAN(parse_full_path);
CLEAN(ts_debug_str);
@@ -208,8 +272,9 @@ static void server_free(server *srv) {
CLEAN(tmp_buf);
CLEAN(empty_string);
CLEAN(cond_check_buf);
-
+
CLEAN(srvconf.errorlog_file);
+ CLEAN(srvconf.breakagelog_file);
CLEAN(srvconf.groupname);
CLEAN(srvconf.username);
CLEAN(srvconf.changeroot);
@@ -217,7 +282,8 @@ static void server_free(server *srv) {
CLEAN(srvconf.event_handler);
CLEAN(srvconf.pid_file);
CLEAN(srvconf.modules_dir);
-
+ CLEAN(srvconf.network_backend);
+
CLEAN(tmp_chunk_len);
#undef CLEAN
@@ -225,48 +291,64 @@ static void server_free(server *srv) {
fdevent_unregister(srv->ev, srv->fd);
#endif
fdevent_free(srv->ev);
-
+
free(srv->conns);
-
+
if (srv->config_storage) {
for (i = 0; i < srv->config_context->used; i++) {
specific_config *s = srv->config_storage[i];
if (!s) continue;
-
+
buffer_free(s->document_root);
buffer_free(s->server_name);
buffer_free(s->server_tag);
buffer_free(s->ssl_pemfile);
buffer_free(s->ssl_ca_file);
+ buffer_free(s->ssl_cipher_list);
+ buffer_free(s->ssl_dh_file);
+ buffer_free(s->ssl_ec_curve);
buffer_free(s->error_handler);
buffer_free(s->errorfile_prefix);
array_free(s->mimetypes);
-
+ buffer_free(s->ssl_verifyclient_username);
+#ifdef USE_OPENSSL
+ SSL_CTX_free(s->ssl_ctx);
+#endif
free(s);
}
free(srv->config_storage);
srv->config_storage = NULL;
}
-
+
#define CLEAN(x) \
array_free(srv->x);
-
+
CLEAN(config_context);
CLEAN(config_touched);
CLEAN(status);
+ CLEAN(srvconf.upload_tempdirs);
#undef CLEAN
-
+
joblist_free(srv, srv->joblist);
fdwaitqueue_free(srv, srv->fdwaitqueue);
-
+
if (srv->stat_cache) {
stat_cache_free(srv->stat_cache);
}
array_free(srv->srvconf.modules);
array_free(srv->split_vals);
-
+
+#ifdef USE_OPENSSL
+ if (srv->ssl_is_init) {
+ CRYPTO_cleanup_all_ex_data();
+ ERR_free_strings();
+ ERR_remove_state(0);
+ EVP_cleanup();
+ }
+#endif
+
free(srv);
}
@@ -276,21 +358,166 @@ static void show_version (void) {
#else
# define TEXT_SSL
#endif
- char *b = PACKAGE_NAME "-" PACKAGE_VERSION TEXT_SSL \
+ char *b = PACKAGE_DESC TEXT_SSL \
" - a light and fast webserver\n" \
"Build-Date: " __DATE__ " " __TIME__ "\n";
;
-#undef TEXT_SSL
+#undef TEXT_SSL
write(STDOUT_FILENO, b, strlen(b));
}
+static void show_features (void) {
+ const char features[] = ""
+#ifdef USE_SELECT
+ "\t+ select (generic)\n"
+#else
+ "\t- select (generic)\n"
+#endif
+#ifdef USE_POLL
+ "\t+ poll (Unix)\n"
+#else
+ "\t- poll (Unix)\n"
+#endif
+#ifdef USE_LINUX_SIGIO
+ "\t+ rt-signals (Linux 2.4+)\n"
+#else
+ "\t- rt-signals (Linux 2.4+)\n"
+#endif
+#ifdef USE_LINUX_EPOLL
+ "\t+ epoll (Linux 2.6)\n"
+#else
+ "\t- epoll (Linux 2.6)\n"
+#endif
+#ifdef USE_SOLARIS_DEVPOLL
+ "\t+ /dev/poll (Solaris)\n"
+#else
+ "\t- /dev/poll (Solaris)\n"
+#endif
+#ifdef USE_SOLARIS_PORT
+ "\t+ eventports (Solaris)\n"
+#else
+ "\t- eventports (Solaris)\n"
+#endif
+#ifdef USE_FREEBSD_KQUEUE
+ "\t+ kqueue (FreeBSD)\n"
+#else
+ "\t- kqueue (FreeBSD)\n"
+#endif
+#ifdef USE_LIBEV
+ "\t+ libev (generic)\n"
+#else
+ "\t- libev (generic)\n"
+#endif
+ "\nNetwork handler:\n\n"
+#if defined USE_LINUX_SENDFILE
+ "\t+ linux-sendfile\n"
+#else
+ "\t- linux-sendfile\n"
+#endif
+#if defined USE_FREEBSD_SENDFILE
+ "\t+ freebsd-sendfile\n"
+#else
+ "\t- freebsd-sendfile\n"
+#endif
+#if defined USE_SOLARIS_SENDFILEV
+ "\t+ solaris-sendfilev\n"
+#else
+ "\t- solaris-sendfilev\n"
+#endif
+#if defined USE_WRITEV
+ "\t+ writev\n"
+#else
+ "\t- writev\n"
+#endif
+ "\t+ write\n"
+#ifdef USE_MMAP
+ "\t+ mmap support\n"
+#else
+ "\t- mmap support\n"
+#endif
+ "\nFeatures:\n\n"
+#ifdef HAVE_IPV6
+ "\t+ IPv6 support\n"
+#else
+ "\t- IPv6 support\n"
+#endif
+#if defined HAVE_ZLIB_H && defined HAVE_LIBZ
+ "\t+ zlib support\n"
+#else
+ "\t- zlib support\n"
+#endif
+#if defined HAVE_BZLIB_H && defined HAVE_LIBBZ2
+ "\t+ bzip2 support\n"
+#else
+ "\t- bzip2 support\n"
+#endif
+#ifdef HAVE_LIBCRYPT
+ "\t+ crypt support\n"
+#else
+ "\t- crypt support\n"
+#endif
+#ifdef USE_OPENSSL
+ "\t+ SSL Support\n"
+#else
+ "\t- SSL Support\n"
+#endif
+#ifdef HAVE_LIBPCRE
+ "\t+ PCRE support\n"
+#else
+ "\t- PCRE support\n"
+#endif
+#ifdef HAVE_MYSQL
+ "\t+ mySQL support\n"
+#else
+ "\t- mySQL support\n"
+#endif
+#if defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER)
+ "\t+ LDAP support\n"
+#else
+ "\t- LDAP support\n"
+#endif
+#ifdef HAVE_MEMCACHE_H
+ "\t+ memcached support\n"
+#else
+ "\t- memcached support\n"
+#endif
+#ifdef HAVE_FAM_H
+ "\t+ FAM support\n"
+#else
+ "\t- FAM support\n"
+#endif
+#ifdef HAVE_LUA_H
+ "\t+ LUA support\n"
+#else
+ "\t- LUA support\n"
+#endif
+#ifdef HAVE_LIBXML_H
+ "\t+ xml support\n"
+#else
+ "\t- xml support\n"
+#endif
+#ifdef HAVE_SQLITE3_H
+ "\t+ SQLite support\n"
+#else
+ "\t- SQLite support\n"
+#endif
+#ifdef HAVE_GDBM_H
+ "\t+ GDBM support\n"
+#else
+ "\t- GDBM support\n"
+#endif
+ "\n";
+ show_version();
+ printf("\nEvent Handlers:\n\n%s", features);
+}
+
static void show_help (void) {
#ifdef USE_OPENSSL
# define TEXT_SSL " (ssl)"
#else
# define TEXT_SSL
#endif
- char *b = PACKAGE_NAME "-" PACKAGE_VERSION TEXT_SSL " ("__DATE__ " " __TIME__ ")" \
+ char *b = PACKAGE_DESC TEXT_SSL " ("__DATE__ " " __TIME__ ")" \
" - a light and fast webserver\n" \
"usage:\n" \
" -f <name> filename of the config-file\n" \
@@ -299,10 +526,11 @@ static void show_help (void) {
" -t test the config-file, and exit\n" \
" -D don't go to background (default: go to background)\n" \
" -v show version\n" \
+" -V show compile-time features\n" \
" -h show this help\n" \
"\n"
;
-#undef TEXT_SSL
+#undef TEXT_SSL
#undef TEXT_IPV6
write(STDOUT_FILENO, b, strlen(b));
}
@@ -322,27 +550,27 @@ int main (int argc, char **argv) {
#ifdef HAVE_GETRLIMIT
struct rlimit rlim;
#endif
-
+
#ifdef USE_ALARM
struct itimerval interval;
-
+
interval.it_interval.tv_sec = 1;
interval.it_interval.tv_usec = 0;
interval.it_value.tv_sec = 1;
interval.it_value.tv_usec = 0;
#endif
-
-
+
+
/* for nice %b handling in strfime() */
setlocale(LC_TIME, "C");
-
+
if (NULL == (srv = server_init())) {
fprintf(stderr, "did this really happen?\n");
return -1;
}
-
+
/* init structs done */
-
+
srv->srvconf.port = 0;
#ifdef HAVE_GETUID
i_am_root = (getuid() == 0);
@@ -350,11 +578,18 @@ int main (int argc, char **argv) {
i_am_root = 0;
#endif
srv->srvconf.dont_daemonize = 0;
-
- while(-1 != (o = getopt(argc, argv, "f:m:hvDpt"))) {
+
+ while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
switch(o) {
- case 'f':
- if (config_read(srv, optarg)) {
+ case 'f':
+ if (srv->config_storage) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "Can only read one config file. Use the include command to use multiple config files.");
+
+ server_free(srv);
+ return -1;
+ }
+ if (config_read(srv, optarg)) {
server_free(srv);
return -1;
}
@@ -366,27 +601,28 @@ int main (int argc, char **argv) {
case 't': test_config = 1; break;
case 'D': srv->srvconf.dont_daemonize = 1; break;
case 'v': show_version(); return 0;
+ case 'V': show_features(); return 0;
case 'h': show_help(); return 0;
- default:
+ default:
show_help();
server_free(srv);
return -1;
}
}
-
+
if (!srv->config_storage) {
log_error_write(srv, __FILE__, __LINE__, "s",
"No configuration available. Try using -f option.");
-
+
server_free(srv);
return -1;
}
-
+
if (print_config) {
data_unset *dc = srv->config_context->data[0];
if (dc) {
dc->print(dc, 0);
- fprintf(stderr, "\n");
+ fprintf(stdout, "\n");
} else {
/* shouldn't happend */
fprintf(stderr, "global config not found\n");
@@ -401,62 +637,51 @@ int main (int argc, char **argv) {
server_free(srv);
return 0;
}
-
+
/* close stdin and stdout, as they are not needed */
- /* move stdin to /dev/null */
- if (-1 != (fd = open("/dev/null", O_RDONLY))) {
- close(STDIN_FILENO);
- dup2(fd, STDIN_FILENO);
- close(fd);
- }
-
- /* move stdout to /dev/null */
- if (-1 != (fd = open("/dev/null", O_WRONLY))) {
- close(STDOUT_FILENO);
- dup2(fd, STDOUT_FILENO);
- close(fd);
- }
-
+ openDevNull(STDIN_FILENO);
+ openDevNull(STDOUT_FILENO);
+
if (0 != config_set_defaults(srv)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"setting default values failed");
server_free(srv);
return -1;
}
-
+
/* UID handling */
#ifdef HAVE_GETUID
- if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
+ if (!i_am_root && issetugid()) {
/* we are setuid-root */
-
- log_error_write(srv, __FILE__, __LINE__, "s",
+
+ log_error_write(srv, __FILE__, __LINE__, "s",
"Are you nuts ? Don't apply a SUID bit to this binary");
-
+
server_free(srv);
return -1;
}
#endif
-
+
/* check document-root */
if (srv->config_storage[0]->document_root->used <= 1) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"document-root is not set\n");
-
+
server_free(srv);
-
+
return -1;
}
-
+
if (plugins_load(srv)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"loading plugins finally failed");
-
+
plugins_free(srv);
server_free(srv);
-
+
return -1;
}
-
+
/* open pid file BEFORE chroot */
if (srv->srvconf.pid_file->used) {
if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
@@ -466,18 +691,18 @@ int main (int argc, char **argv) {
"opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
return -1;
}
-
+
if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
log_error_write(srv, __FILE__, __LINE__, "sbs",
"stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
}
-
+
if (!S_ISREG(st.st_mode)) {
log_error_write(srv, __FILE__, __LINE__, "sb",
"pid-file exists and isn't regular file:", srv->srvconf.pid_file);
return -1;
}
-
+
if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
log_error_write(srv, __FILE__, __LINE__, "sbs",
"opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
@@ -504,7 +729,7 @@ int main (int argc, char **argv) {
#ifdef HAVE_VALGRIND_VALGRIND_H
if (RUNNING_ON_VALGRIND) use_rlimit = 0;
#endif
-
+
#ifdef HAVE_GETRLIMIT
if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
log_error_write(srv, __FILE__, __LINE__,
@@ -512,13 +737,13 @@ int main (int argc, char **argv) {
strerror(errno));
return -1;
}
-
+
if (use_rlimit && srv->srvconf.max_fds) {
/* set rlimits */
-
+
rlim.rlim_cur = srv->srvconf.max_fds;
rlim.rlim_max = srv->srvconf.max_fds;
-
+
if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
log_error_write(srv, __FILE__, __LINE__,
"ss", "couldn't set 'max filedescriptors'",
@@ -527,11 +752,8 @@ 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;
+ srv->max_fds = rlim.rlim_cur < ((int)FD_SETSIZE) - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
} else {
srv->max_fds = rlim.rlim_cur;
}
@@ -544,34 +766,34 @@ int main (int argc, char **argv) {
#endif
if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
/* don't raise the limit above FD_SET_SIZE */
- if (srv->max_fds > FD_SETSIZE - 200) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ if (srv->max_fds > ((int)FD_SETSIZE) - 200) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"can't raise max filedescriptors above", FD_SETSIZE - 200,
"if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
return -1;
}
}
-
+
#ifdef HAVE_PWD_H
/* set user and group */
if (srv->srvconf.username->used) {
if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
"can't find username", srv->srvconf.username);
return -1;
}
-
+
if (pwd->pw_uid == 0) {
log_error_write(srv, __FILE__, __LINE__, "s",
"I will not set uid to 0\n");
return -1;
}
}
-
+
if (srv->srvconf.groupname->used) {
if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
"can't find groupname", srv->srvconf.groupname);
return -1;
}
@@ -581,15 +803,28 @@ int main (int argc, char **argv) {
return -1;
}
}
-#endif
+#endif
/* we need root-perms for port < 1024 */
if (0 != network_init(srv)) {
plugins_free(srv);
server_free(srv);
-
+
return -1;
}
-#ifdef HAVE_CHROOT
+#ifdef HAVE_PWD_H
+ /*
+ * Change group before chroot, when we have access
+ * to /etc/group
+ * */
+ if (NULL != grp) {
+ 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();
@@ -605,15 +840,14 @@ 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 (NULL != pwd) {
+ setuid(pwd->pw_uid);
}
- if (srv->srvconf.username->used && srv->srvconf.groupname->used)
- initgroups(srv->srvconf.username->ptr, grp->gr_gid);
- if (srv->srvconf.username->used) setuid(pwd->pw_uid);
#endif
-#ifdef HAVE_PRCTL
+#if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE)
+ /**
+ * on IRIX 6.5.30 they have prctl() but no DUMPABLE
+ */
if (srv->srvconf.enable_cores) {
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
}
@@ -628,8 +862,24 @@ int main (int argc, char **argv) {
return -1;
}
+ /**
+ * we are not root can can't increase the fd-limit, but we can reduce it
+ */
+ if (srv->srvconf.max_fds && srv->srvconf.max_fds < rlim.rlim_cur) {
+ /* set rlimits */
+
+ rlim.rlim_cur = srv->srvconf.max_fds;
+
+ if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
+ log_error_write(srv, __FILE__, __LINE__,
+ "ss", "couldn't set 'max filedescriptors'",
+ strerror(errno));
+ return -1;
+ }
+ }
+
if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
- srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
+ srv->max_fds = rlim.rlim_cur < ((int)FD_SETSIZE) - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
} else {
srv->max_fds = rlim.rlim_cur;
}
@@ -643,71 +893,83 @@ int main (int argc, char **argv) {
#endif
if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
/* don't raise the limit above FD_SET_SIZE */
- if (srv->max_fds > FD_SETSIZE - 200) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ if (srv->max_fds > ((int)FD_SETSIZE) - 200) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"can't raise max filedescriptors above", FD_SETSIZE - 200,
"if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
return -1;
}
}
-
+
if (0 != network_init(srv)) {
plugins_free(srv);
server_free(srv);
-
+
return -1;
}
}
/* set max-conns */
- if (srv->srvconf.max_conns > srv->max_fds) {
- /* we can't have more connections than max-fds */
- srv->max_conns = srv->max_fds;
+ if (srv->srvconf.max_conns > srv->max_fds/2) {
+ /* we can't have more connections than max-fds/2 */
+ log_error_write(srv, __FILE__, __LINE__, "sdd", "can't have more connections than fds/2: ", srv->srvconf.max_conns, srv->max_fds);
+ srv->max_conns = srv->max_fds/2;
} else if (srv->srvconf.max_conns) {
/* otherwise respect the wishes of the user */
srv->max_conns = srv->srvconf.max_conns;
} else {
- /* or use the default */
- srv->max_conns = srv->max_fds;
+ /* or use the default: we really don't want to hit max-fds */
+ srv->max_conns = srv->max_fds/3;
}
-
+
if (HANDLER_GO_ON != plugins_call_init(srv)) {
log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down.");
-
+
plugins_free(srv);
network_close(srv);
server_free(srv);
-
+
return -1;
}
-#ifdef HAVE_FORK
+#ifdef HAVE_FORK
/* network is up, let's deamonize ourself */
if (srv->srvconf.dont_daemonize == 0) daemonize();
#endif
srv->gid = getgid();
srv->uid = getuid();
-
+
/* write pid file */
if (pid_fd != -1) {
buffer_copy_long(srv->tmp_buf, getpid());
- buffer_append_string(srv->tmp_buf, "\n");
+ buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("\n"));
write(pid_fd, srv->tmp_buf->ptr, srv->tmp_buf->used - 1);
close(pid_fd);
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.");
-
+
plugins_free(srv);
network_close(srv);
server_free(srv);
-
+
return -1;
}
-
+
/* dump unused config-keys */
for (i = 0; i < srv->config_context->used; i++) {
array *config = ((data_config *)srv->config_context->data[i])->value;
@@ -715,43 +977,42 @@ int main (int argc, char **argv) {
for (j = 0; config && j < config->used; j++) {
data_unset *du = config->data[j];
-
+
/* all var.* is known as user defined variable */
if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) {
continue;
}
if (NULL == array_get_element(srv->config_touched, du->key->ptr)) {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
"WARNING: unknown config-key:",
du->key,
"(ignored)");
}
}
}
-
+
+ if (srv->config_unsupported) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "Configuration contains unsupported keys. Going down.");
+ }
+
if (srv->config_deprecated) {
- log_error_write(srv, __FILE__, __LINE__, "s",
+ log_error_write(srv, __FILE__, __LINE__, "s",
"Configuration contains deprecated keys. Going down.");
-
- plugins_free(srv);
- network_close(srv);
- server_free(srv);
-
- return -1;
}
-
- if (-1 == log_error_open(srv)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "opening errorlog failed, dying");
-
+
+ if (srv->config_unsupported || srv->config_deprecated) {
plugins_free(srv);
network_close(srv);
server_free(srv);
+
return -1;
}
-
-
+
+
+
+
#ifdef HAVE_SIGACTION
memset(&act, 0, sizeof(act));
act.sa_handler = SIG_IGN;
@@ -771,7 +1032,7 @@ int main (int argc, char **argv) {
sigaction(SIGHUP, &act, NULL);
sigaction(SIGALRM, &act, NULL);
sigaction(SIGCHLD, &act, NULL);
-
+
#elif defined(HAVE_SIGNAL)
/* ignore the SIGPIPE from sendfile() */
signal(SIGPIPE, SIG_IGN);
@@ -782,25 +1043,25 @@ int main (int argc, char **argv) {
signal(SIGCHLD, signal_handler);
signal(SIGINT, signal_handler);
#endif
-
+
#ifdef USE_ALARM
signal(SIGALRM, signal_handler);
-
+
/* setup periodic timer (1 second) */
if (setitimer(ITIMER_REAL, &interval, NULL)) {
log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed");
return -1;
}
-
+
getitimer(ITIMER_REAL, &interval);
#endif
-#ifdef HAVE_FORK
+#ifdef HAVE_FORK
/* start watcher and workers */
num_childs = srv->srvconf.max_worker;
if (num_childs > 0) {
int child = 0;
- while (!child && !srv_shutdown) {
+ while (!child && !srv_shutdown && !graceful_shutdown) {
if (num_childs > 0) {
switch (fork()) {
case -1:
@@ -814,24 +1075,80 @@ int main (int argc, char **argv) {
}
} else {
int status;
- wait(&status);
- num_childs++;
+
+ if (-1 != wait(&status)) {
+ /**
+ * one of our workers went away
+ */
+ num_childs++;
+ } else {
+ switch (errno) {
+ case EINTR:
+ /**
+ * if we receive a SIGHUP we have to close our logs ourself as we don't
+ * have the mainloop who can help us here
+ */
+ if (handle_sig_hup) {
+ handle_sig_hup = 0;
+
+ log_error_cycle(srv);
+
+ /**
+ * forward to all procs in the process-group
+ *
+ * we also send it ourself
+ */
+ if (!forwarded_sig_hup) {
+ forwarded_sig_hup = 1;
+ kill(0, SIGHUP);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
}
}
- if (srv_shutdown) {
- kill(0, SIGTERM);
+
+ /**
+ * for the parent this is the exit-point
+ */
+ if (!child) {
+ /**
+ * kill all children too
+ */
+ if (graceful_shutdown) {
+ kill(0, SIGINT);
+ } else if (srv_shutdown) {
+ kill(0, SIGTERM);
+ }
+
+ log_error_close(srv);
+ network_close(srv);
+ connections_free(srv);
+ plugins_free(srv);
+ server_free(srv);
+ return 0;
}
- if (!child) return 0;
}
#endif
- if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) {
+ if (NULL == (srv->ev = fdevent_init(srv, srv->max_fds + 1, srv->event_handler))) {
log_error_write(srv, __FILE__, __LINE__,
"s", "fdevent_init failed");
return -1;
}
- /*
- * kqueue() is called here, select resets its internals,
+
+ /* libev backend overwrites our SIGCHLD handler and calls waitpid on SIGCHLD; we want our own SIGCHLD handling. */
+#ifdef HAVE_SIGACTION
+ sigaction(SIGCHLD, &act, NULL);
+#elif defined(HAVE_SIGNAL)
+ signal(SIGCHLD, signal_handler);
+#endif
+
+ /*
+ * kqueue() is called here, select resets its internals,
* all server sockets get their handlers
*
* */
@@ -839,7 +1156,7 @@ int main (int argc, char **argv) {
plugins_free(srv);
network_close(srv);
server_free(srv);
-
+
return -1;
}
@@ -854,6 +1171,8 @@ int main (int argc, char **argv) {
/* setup FAM */
if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "could not open a fam connection, dieing.");
return -1;
}
#ifdef HAVE_FAMNOEXISTS
@@ -862,7 +1181,7 @@ int main (int argc, char **argv) {
srv->stat_cache->fam_fcce_ndx = -1;
fdevent_register(srv->ev, FAMCONNECTION_GETFD(srv->stat_cache->fam), stat_cache_handle_fdevent, NULL);
- fdevent_event_add(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN);
+ fdevent_event_set(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN);
}
#endif
@@ -884,16 +1203,16 @@ int main (int argc, char **argv) {
int n;
size_t ndx;
time_t min_ts;
-
+
if (handle_sig_hup) {
handler_t r;
-
+
/* reset notification */
handle_sig_hup = 0;
-
-
+
+
/* cycle logfiles */
-
+
switch(r = plugins_call_handle_sighup(srv)) {
case HANDLER_GO_ON:
break;
@@ -901,30 +1220,41 @@ int main (int argc, char **argv) {
log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
break;
}
-
+
if (-1 == log_error_cycle(srv)) {
log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
-
+
return -1;
+ } else {
+#ifdef HAVE_SIGACTION
+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
+ "logfiles cycled UID =",
+ last_sighup_info.si_uid,
+ "PID =",
+ last_sighup_info.si_pid);
+#else
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "logfiles cycled");
+#endif
}
}
-
+
if (handle_sig_alarm) {
/* a new second */
-
+
#ifdef USE_ALARM
/* reset notification */
handle_sig_alarm = 0;
#endif
-
+
/* get current time */
min_ts = time(NULL);
-
+
if (min_ts != srv->cur_ts) {
int cs = 0;
connections *conns = srv->conns;
handler_t r;
-
+
switch(r = plugins_call_handle_trigger(srv)) {
case HANDLER_GO_ON:
break;
@@ -935,21 +1265,21 @@ int main (int argc, char **argv) {
log_error_write(srv, __FILE__, __LINE__, "d", r);
break;
}
-
+
/* trigger waitpid */
srv->cur_ts = min_ts;
-
- /* cleanup stat-cache */
+
+ /* cleanup stat-cache */
stat_cache_trigger_cleanup(srv);
/**
- * check all connections for timeouts
- *
+ * check all connections for timeouts
+ *
*/
for (ndx = 0; ndx < conns->used; ndx++) {
int changed = 0;
connection *con;
int t_diff;
-
+
con = conns->ptr[ndx];
if (con->state == CON_STATE_READ ||
@@ -958,17 +1288,17 @@ int main (int argc, char **argv) {
if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
/* time - out */
#if 0
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"connection closed - read-timeout:", con->fd);
#endif
connection_set_state(srv, con, CON_STATE_ERROR);
changed = 1;
}
} else {
- if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
+ if (srv->cur_ts - con->read_idle_ts > con->keep_alive_idle) {
/* time - out */
#if 0
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"connection closed - read-timeout:", con->fd);
#endif
connection_set_state(srv, con, CON_STATE_ERROR);
@@ -976,20 +1306,20 @@ int main (int argc, char **argv) {
}
}
}
-
+
if ((con->state == CON_STATE_WRITE) &&
- (con->write_request_ts != 0)) {
+ (con->write_request_ts != 0)) {
#if 0
if (srv->cur_ts - con->write_request_ts > 60) {
- log_error_write(srv, __FILE__, __LINE__, "sdd",
+ log_error_write(srv, __FILE__, __LINE__, "sdd",
"connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts);
}
#endif
-
+
if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
/* time - out */
-#if 1
- log_error_write(srv, __FILE__, __LINE__, "sbsosds",
+ if (con->conf.log_timeouts) {
+ log_error_write(srv, __FILE__, __LINE__, "sbsosds",
"NOTE: a request for",
con->request.uri,
"timed out after writing",
@@ -997,42 +1327,47 @@ int main (int argc, char **argv) {
"bytes. We waited",
(int)con->conf.max_write_idle,
"seconds. If this a problem increase server.max-write-idle");
-#endif
+ }
connection_set_state(srv, con, CON_STATE_ERROR);
changed = 1;
}
}
+
+ if (con->state == CON_STATE_CLOSE && (srv->cur_ts - con->close_timeout_ts > HTTP_LINGER_TIMEOUT)) {
+ changed = 1;
+ }
+
/* we don't like div by zero */
if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
-
- if (con->traffic_limit_reached &&
- (con->conf.kbytes_per_second == 0 ||
+
+ if (con->traffic_limit_reached &&
+ (con->conf.kbytes_per_second == 0 ||
((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
/* enable connection again */
con->traffic_limit_reached = 0;
-
+
changed = 1;
}
-
+
if (changed) {
connection_state_machine(srv, con);
}
con->bytes_written_cur_second = 0;
*(con->conf.global_bytes_per_second_cnt_ptr) = 0;
-
+
#if 0
if (cs == 0) {
fprintf(stderr, "connection-state: ");
cs = 1;
}
-
+
fprintf(stderr, "c[%d,%d]: %s ",
con->fd,
con->fcgi.fd,
connection_get_state(con->state));
#endif
}
-
+
if (cs == 1) fprintf(stderr, "\n");
}
}
@@ -1040,25 +1375,25 @@ int main (int argc, char **argv) {
if (srv->sockets_disabled) {
/* our server sockets are disabled, why ? */
- if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
- (srv->conns->used < srv->max_conns * 0.9) &&
+ if ((srv->cur_fds + srv->want_fds < srv->max_fds * 8 / 10) && /* we have enough unused fds */
+ (srv->conns->used <= srv->max_conns * 9 / 10) &&
(0 == graceful_shutdown)) {
for (i = 0; i < srv->srv_sockets.used; i++) {
server_socket *srv_socket = srv->srv_sockets.ptr[i];
- fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
+ fdevent_event_set(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
}
-
+
log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
-
+
srv->sockets_disabled = 0;
}
} else {
- if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
- (srv->conns->used > srv->max_conns) || /* out of connections */
- (graceful_shutdown)) { /* graceful_shutdown */
+ if ((srv->cur_fds + srv->want_fds > srv->max_fds * 9 / 10) || /* out of fds */
+ (srv->conns->used >= srv->max_conns) || /* out of connections */
+ (graceful_shutdown)) { /* graceful_shutdown */
/* disable server-fds */
-
+
for (i = 0; i < srv->srv_sockets.used; i++) {
server_socket *srv_socket = srv->srv_sockets.ptr[i];
fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
@@ -1075,17 +1410,30 @@ int main (int argc, char **argv) {
srv_socket->fd = -1;
/* network_close() will cleanup after us */
+
+ if (srv->srvconf.pid_file->used &&
+ srv->srvconf.changeroot->used == 0) {
+ if (0 != unlink(srv->srvconf.pid_file->ptr)) {
+ if (errno != EACCES && errno != EPERM) {
+ log_error_write(srv, __FILE__, __LINE__, "sbds",
+ "unlink failed for:",
+ srv->srvconf.pid_file,
+ errno,
+ strerror(errno));
+ }
+ }
+ }
}
}
-
+
if (graceful_shutdown) {
log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
- } else if (srv->conns->used > srv->max_conns) {
+ } else if (srv->conns->used >= srv->max_conns) {
log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
} else {
log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
}
-
+
srv->sockets_disabled = 1;
}
}
@@ -1095,16 +1443,16 @@ int main (int argc, char **argv) {
* we are ready to terminate without harming anyone */
srv_shutdown = 1;
}
-
+
/* we still have some fds to share */
- if (srv->want_fds) {
+ if (srv->want_fds) {
/* check the fdwaitqueue for waiting fds */
int free_fds = srv->max_fds - srv->cur_fds - 16;
connection *con;
-
+
for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
connection_state_machine(srv, con);
-
+
srv->want_fds--;
}
}
@@ -1115,27 +1463,29 @@ int main (int argc, char **argv) {
int fd_ndx;
#if 0
if (n > 0) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
+ log_error_write(srv, __FILE__, __LINE__, "sd",
"polls:", n);
}
-#endif
+#endif
fd_ndx = -1;
do {
fdevent_handler handler;
void *context;
handler_t r;
-
+
fd_ndx = fdevent_event_next_fdndx (srv->ev, fd_ndx);
+ if (-1 == fd_ndx) break; /* not all fdevent handlers know how many fds got an event */
+
revents = fdevent_event_get_revent (srv->ev, fd_ndx);
fd = fdevent_event_get_fd (srv->ev, fd_ndx);
handler = fdevent_get_handler(srv->ev, fd);
context = fdevent_get_context(srv->ev, fd);
-
+
/* connection_handle_fdevent needs a joblist_append */
#if 0
- log_error_write(srv, __FILE__, __LINE__, "sdd",
+ log_error_write(srv, __FILE__, __LINE__, "sdd",
"event for", fd, revents);
-#endif
+#endif
switch (r = (*handler)(srv, context, revents)) {
case HANDLER_FINISHED:
case HANDLER_GO_ON:
@@ -1152,17 +1502,17 @@ int main (int argc, char **argv) {
}
} while (--n > 0);
} else if (n < 0 && errno != EINTR) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "fdevent_poll failed:",
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "fdevent_poll failed:",
strerror(errno));
}
-
+
for (ndx = 0; ndx < srv->joblist->used; ndx++) {
connection *con = srv->joblist->ptr[ndx];
handler_t r;
-
+
connection_state_machine(srv, con);
-
+
switch(r = plugins_call_handle_joblist(srv, con)) {
case HANDLER_FINISHED:
case HANDLER_GO_ON:
@@ -1171,32 +1521,44 @@ int main (int argc, char **argv) {
log_error_write(srv, __FILE__, __LINE__, "d", r);
break;
}
-
+
con->in_joblist = 0;
}
-
+
srv->joblist->used = 0;
}
-
+
if (srv->srvconf.pid_file->used &&
- srv->srvconf.changeroot->used == 0) {
+ srv->srvconf.changeroot->used == 0 &&
+ 0 == graceful_shutdown) {
if (0 != unlink(srv->srvconf.pid_file->ptr)) {
if (errno != EACCES && errno != EPERM) {
- log_error_write(srv, __FILE__, __LINE__, "sbds",
- "unlink failed for:",
+ log_error_write(srv, __FILE__, __LINE__, "sbds",
+ "unlink failed for:",
srv->srvconf.pid_file,
errno,
strerror(errno));
}
}
}
-
+
+#ifdef HAVE_SIGACTION
+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
+ "server stopped by UID =",
+ last_sigterm_info.si_uid,
+ "PID =",
+ last_sigterm_info.si_pid);
+#else
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "server stopped");
+#endif
+
/* clean-up */
log_error_close(srv);
network_close(srv);
connections_free(srv);
plugins_free(srv);
server_free(srv);
-
+
return 0;
}
diff --git a/src/settings.h b/src/settings.h
index f0c6354..137a0a8 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -1,6 +1,14 @@
#ifndef _LIGHTTPD_SETTINGS_H_
#define _LIGHTTPD_SETTINGS_H_
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+
+#ifndef __USE_GNU
+# define __USE_GNU /* a hack in my eyes, <fcntl.h> F_SETSIG should work with _GNU_SOURCE */
+#endif
+
#define BV(x) (1 << x)
#define INET_NTOP_CACHE_MAX 4
@@ -9,28 +17,33 @@
/**
* max size of a buffer which will just be reset
* to ->used = 0 instead of really freeing the buffer
- *
+ *
* 64kB (no real reason, just a guess)
*/
#define BUFFER_MAX_REUSE_SIZE (4 * 1024)
+/* both should be way smaller than SSIZE_MAX :) */
+#define MAX_READ_LIMIT (256*1024)
+#define MAX_WRITE_LIMIT (256*1024)
+
/**
* max size of the HTTP request header
- *
+ *
* 32k should be enough for everything (just a guess)
- *
+ *
*/
#define MAX_HTTP_REQUEST_HEADER (32 * 1024)
-typedef enum { HANDLER_UNSET,
- HANDLER_GO_ON,
+typedef enum { HANDLER_UNSET,
+ HANDLER_GO_ON,
HANDLER_FINISHED,
- HANDLER_COMEBACK,
- HANDLER_WAIT_FOR_EVENT,
+ HANDLER_COMEBACK,
+ HANDLER_WAIT_FOR_EVENT,
HANDLER_ERROR,
HANDLER_WAIT_FOR_FD
} handler_t;
+#define HTTP_LINGER_TIMEOUT 5
/* we use it in a enum */
#ifdef TRUE
diff --git a/src/spawn-fcgi.c b/src/spawn-fcgi.c
deleted file mode 100644
index 99fc31a..0000000
--- a/src/spawn-fcgi.c
+++ /dev/null
@@ -1,431 +0,0 @@
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-
-#ifdef HAVE_PWD_H
-#include <grp.h>
-#include <pwd.h>
-#endif
-
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#endif
-
-#define FCGI_LISTENSOCK_FILENO 0
-
-#ifndef UNIX_PATH_MAX
-# define UNIX_PATH_MAX 108
-#endif
-
-#include "sys-socket.h"
-
-#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-
-/* for solaris 2.5 and netbsd 1.3.x */
-#ifndef HAVE_SOCKLEN_T
-typedef int socklen_t;
-#endif
-
-#ifdef HAVE_SYS_UN_H
-int fcgi_spawn_connection(char *appPath, 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 };
-
- struct sockaddr_un fcgi_addr_un;
- struct sockaddr_in fcgi_addr_in;
- struct sockaddr *fcgi_addr;
-
- socklen_t servlen;
-
- if (child_count < 2) {
- child_count = 5;
- }
-
- if (child_count > 256) {
- child_count = 256;
- }
-
-
- if (unixsocket) {
- memset(&fcgi_addr, 0, sizeof(fcgi_addr));
-
- fcgi_addr_un.sun_family = AF_UNIX;
- strcpy(fcgi_addr_un.sun_path, unixsocket);
-
-#ifdef SUN_LEN
- servlen = SUN_LEN(&fcgi_addr_un);
-#else
- /* stevens says: */
- servlen = strlen(fcgi_addr_un.sun_path) + sizeof(fcgi_addr_un.sun_family);
-#endif
- socket_type = AF_UNIX;
- fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
- } else {
- fcgi_addr_in.sin_family = AF_INET;
- fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
- fcgi_addr_in.sin_port = htons(port);
- servlen = sizeof(fcgi_addr_in);
-
- socket_type = AF_INET;
- fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
- }
-
- 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;
-
- if (unixsocket) unlink(unixsocket);
-
- close(fcgi_fd);
-
- /* reopen socket */
- if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
- fprintf(stderr, "%s.%d\n",
- __FILE__, __LINE__);
- return -1;
- }
-
- val = 1;
- if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
- fprintf(stderr, "%s.%d\n",
- __FILE__, __LINE__);
- return -1;
- }
-
- /* create socket */
- if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
- fprintf(stderr, "%s.%d: bind failed: %s\n",
- __FILE__, __LINE__,
- strerror(errno));
- return -1;
- }
-
- if (-1 == listen(fcgi_fd, 1024)) {
- fprintf(stderr, "%s.%d: fd = -1\n",
- __FILE__, __LINE__);
- return -1;
- }
-
- if (!nofork) {
- child = fork();
- } else {
- child = 0;
- }
-
- 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);
-
- if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
- close(FCGI_LISTENSOCK_FILENO);
- dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
- close(fcgi_fd);
- }
-
- /* we don't need the client socket */
- for (i = 3; i < 256; i++) {
- close(i);
- }
-
- /* create environment */
-
- putenv(cgi_childs);
-
- /* fork and replace shell */
- b = malloc(strlen("exec ") + strlen(appPath) + 1);
- strcpy(b, "exec ");
- strcat(b, appPath);
-
- /* exec the cgi */
- execl("/bin/sh", "sh", "-c", b, NULL);
-
- 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:
- 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);
- }
- }
-
- break;
- }
- } else {
- fprintf(stderr, "%s.%d: socket is already used, can't spawn\n",
- __FILE__, __LINE__);
- return -1;
- }
-
- close(fcgi_fd);
-
- return 0;
-}
-
-
-void show_version () {
- char *b = "spawn-fcgi" "-" PACKAGE_VERSION \
-" - spawns fastcgi processes\n"
-;
- write(1, b, strlen(b));
-}
-
-void show_help () {
- char *b = "spawn-fcgi" "-" PACKAGE_VERSION \
-" - spawns fastcgi processes\n" \
-"usage:\n" \
-" -f <fcgiapp> filename of the fcgi-application\n" \
-" -p <port> bind to tcp-port\n" \
-" -s <path> bind to unix-domain socket\n" \
-" -C <childs> (PHP only) numbers of childs to spawn (default 5)\n" \
-" -P <path> name of PID-file for spawed process\n" \
-" -n no fork (for daemontools)\n" \
-" -v show version\n" \
-" -h show this help\n" \
-"(root only)\n" \
-" -c <dir> chroot to directory\n" \
-" -u <user> change to user-id\n" \
-" -g <group> change to group-id\n" \
-;
- write(1, b, strlen(b));
-}
-
-
-int main(int argc, char **argv) {
- char *fcgi_app = NULL, *changeroot = NULL, *username = NULL,
- *groupname = NULL, *unixsocket = NULL, *pid_file = NULL;
- unsigned short port = 0;
- int child_count = 5;
- int i_am_root, o;
- int pid_fd = -1;
- int nofork = 0;
-
- i_am_root = (getuid() == 0);
-
- while(-1 != (o = getopt(argc, argv, "c:f:g:hnp:u:vC:s:P:"))) {
- switch(o) {
- case 'f': fcgi_app = optarg; 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;
- case 'c': if (i_am_root) { changeroot = optarg; }/* chroot() */ break;
- case 'u': if (i_am_root) { username = optarg; } /* set user */ break;
- case 'g': if (i_am_root) { groupname = optarg; } /* set group */ break;
- case 'n': nofork = 1; break;
- case 'P': pid_file = optarg; /* PID file */ break;
- case 'v': show_version(); return 0;
- case 'h': show_help(); return 0;
- default:
- show_help();
- return -1;
- }
- }
-
- if (fcgi_app == NULL || (port == 0 && unixsocket == NULL)) {
- show_help();
- return -1;
- }
-
- if (unixsocket && port) {
- fprintf(stderr, "%s.%d: %s\n",
- __FILE__, __LINE__,
- "either a unix domain socket or a tcp-port, but not both\n");
-
- return -1;
- }
-
- if (unixsocket && strlen(unixsocket) > UNIX_PATH_MAX - 1) {
- fprintf(stderr, "%s.%d: %s\n",
- __FILE__, __LINE__,
- "path of the unix socket is too long\n");
-
- return -1;
- }
-
- /* UID handling */
- if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
- /* we are setuid-root */
-
- fprintf(stderr, "%s.%d: %s\n",
- __FILE__, __LINE__,
- "Are you nuts ? Don't apply a SUID bit to this binary\n");
-
- return -1;
- }
-
- if (pid_file &&
- (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)))) {
- struct stat st;
- if (errno != EEXIST) {
- fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
- __FILE__, __LINE__,
- pid_file, strerror(errno));
-
- return -1;
- }
-
- /* ok, file exists */
-
- if (0 != stat(pid_file, &st)) {
- fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n",
- __FILE__, __LINE__,
- pid_file, strerror(errno));
-
- return -1;
- }
-
- /* is it a regular file ? */
-
- if (!S_ISREG(st.st_mode)) {
- fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n",
- __FILE__, __LINE__,
- pid_file);
-
- return -1;
- }
-
- if (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
- fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
- __FILE__, __LINE__,
- pid_file, strerror(errno));
-
- return -1;
- }
- }
-
- if (i_am_root) {
- struct group *grp = NULL;
- struct passwd *pwd = NULL;
-
- /* set user and group */
-
- if (username) {
- if (NULL == (pwd = getpwnam(username))) {
- fprintf(stderr, "%s.%d: %s, %s\n",
- __FILE__, __LINE__,
- "can't find username", username);
- return -1;
- }
-
- if (pwd->pw_uid == 0) {
- fprintf(stderr, "%s.%d: %s\n",
- __FILE__, __LINE__,
- "I will not set uid to 0\n");
- return -1;
- }
- }
-
- if (groupname) {
- if (NULL == (grp = getgrnam(groupname))) {
- fprintf(stderr, "%s.%d: %s %s\n",
- __FILE__, __LINE__,
- "can't find groupname",
- groupname);
- return -1;
- }
- if (grp->gr_gid == 0) {
- fprintf(stderr, "%s.%d: %s\n",
- __FILE__, __LINE__,
- "I will not set gid to 0\n");
- return -1;
- }
- }
-
- if (changeroot) {
- if (-1 == chroot(changeroot)) {
- fprintf(stderr, "%s.%d: %s %s\n",
- __FILE__, __LINE__,
- "chroot failed: ", strerror(errno));
- return -1;
- }
- if (-1 == chdir("/")) {
- fprintf(stderr, "%s.%d: %s %s\n",
- __FILE__, __LINE__,
- "chdir failed: ", strerror(errno));
- return -1;
- }
- }
-
- /* drop root privs */
- if (groupname) {
- setgid(grp->gr_gid);
- setgroups(0, NULL);
- }
- if (username) setuid(pwd->pw_uid);
- }
-
- return fcgi_spawn_connection(fcgi_app, port, unixsocket, child_count, pid_fd, nofork);
-}
-#else
-int main() {
- return -1;
-}
-#endif
diff --git a/src/splaytree.c b/src/splaytree.c
index 3a80910..51aa0ca 100644
--- a/src/splaytree.c
+++ b/src/splaytree.c
@@ -46,9 +46,9 @@
Addison-Wesley, 1993, pp 367-375
*/
+#include "splaytree.h"
#include <stdlib.h>
#include <assert.h>
-#include "splaytree.h"
#define compare(i,j) ((i)-(j))
/* This is the comparison. */
@@ -56,19 +56,18 @@
#define node_size splaytree_size
-/* Splay using the key i (which may or may not be in the tree.)
- * The starting root is t, and the tree used is defined by rat
+/* Splay using the key i (which may or may not be in the tree.)
+ * The starting root is t, and the tree used is defined by rat
* size fields are maintained */
splay_tree * splaytree_splay (splay_tree *t, int i) {
splay_tree N, *l, *r, *y;
- int comp, root_size, l_size, r_size;
-
+ int comp, l_size, r_size;
+
if (t == NULL) return t;
N.left = N.right = NULL;
l = r = &N;
- root_size = node_size(t);
l_size = r_size = 0;
-
+
for (;;) {
comp = compare(i, t->key);
if (comp < 0) {
@@ -120,7 +119,7 @@ splay_tree * splaytree_splay (splay_tree *t, int i) {
y->size = r_size;
r_size -= 1+node_size(y->right);
}
-
+
l->right = t->left; /* assemble */
r->left = t->right;
t->left = N.right;
@@ -187,7 +186,8 @@ splay_tree * splaytree_delete(splay_tree *t, int i) {
}
}
-splay_tree *find_rank(int r, splay_tree *t) {
+#if 0
+static splay_tree *find_rank(int r, splay_tree *t) {
/* Returns a pointer to the node in the tree with the given rank. */
/* Returns NULL if there is no such node. */
/* Does not change the tree. To guarantee logarithmic behavior, */
@@ -206,5 +206,4 @@ splay_tree *find_rank(int r, splay_tree *t) {
}
}
}
-
-
+#endif
diff --git a/src/splaytree.h b/src/splaytree.h
index 98e4234..4be1523 100644
--- a/src/splaytree.h
+++ b/src/splaytree.h
@@ -19,6 +19,6 @@ splay_tree * splaytree_size(splay_tree *t);
/* This macro returns the size of a node. Unlike "x->size", */
/* it works even if x=NULL. The test could be avoided by using */
/* a special version of NULL which was a real node with size 0. */
-
+
#endif
diff --git a/src/stat_cache.c b/src/stat_cache.c
index 148f4c8..3edaeeb 100644
--- a/src/stat_cache.c
+++ b/src/stat_cache.c
@@ -1,4 +1,7 @@
-#define _GNU_SOURCE
+#include "log.h"
+#include "stat_cache.h"
+#include "fdevent.h"
+#include "etag.h"
#include <sys/types.h>
#include <sys/stat.h>
@@ -11,13 +14,8 @@
#include <fcntl.h>
#include <assert.h>
-#include "log.h"
-#include "stat_cache.h"
-#include "fdevent.h"
-#include "etag.h"
-
#ifdef HAVE_ATTR_ATTRIBUTES_H
-#include <attr/attributes.h>
+# include <attr/attributes.h>
#endif
#ifdef HAVE_FAM_H
@@ -36,7 +34,7 @@
#endif
#ifndef HAVE_LSTAT
-#define lstat stat
+# define lstat stat
#endif
#if 0
@@ -52,8 +50,8 @@
*
* if we get a change-event from FAM, we increment the version in the FAM->dir mapping
*
- * if the stat()-cache is queried we check if the version id for the directory is the
- * same and return immediatly.
+ * if the stat()-cache is queried we check if the version id for the directory is the
+ * same and return immediatly.
*
*
* What we need:
@@ -62,17 +60,17 @@
* - for each FAMRequest we have to find the version in the directory cache (index as userdata)
*
* stat <<-> directory <-> FAMRequest
- *
- * if file is deleted, directory is dirty, file is rechecked ...
+ *
+ * if file is deleted, directory is dirty, file is rechecked ...
* if directory is deleted, directory mapping is removed
- *
+ *
* */
#ifdef HAVE_FAM_H
typedef struct {
FAMRequest *req;
FAMConnection *fc;
-
+
buffer *name;
int version;
@@ -83,16 +81,16 @@ typedef struct {
* - we need a hash
* - the hash-key is used as sorting criteria for a tree
* - a splay-tree is used as we can use the caching effect of it
- */
+ */
/* we want to cleanup the stat-cache every few seconds, let's say 10
*
* - remove entries which are outdated since 30s
* - remove entries which are fresh but havn't been used since 60s
* - if we don't have a stat-cache entry for a directory, release it from the monitor
- */
+ */
-#ifdef DEBUG_STAT_CACHE
+#ifdef DEBUG_STAT_CACHE
typedef struct {
int *ptr;
@@ -105,15 +103,16 @@ static fake_keys ctrl;
stat_cache *stat_cache_init(void) {
stat_cache *fc = NULL;
-
+
fc = calloc(1, sizeof(*fc));
-
+
fc->dir_name = buffer_init();
+ fc->hash_key = buffer_init();
#ifdef HAVE_FAM_H
fc->fam = calloc(1, sizeof(*fc->fam));
#endif
-#ifdef DEBUG_STAT_CACHE
+#ifdef DEBUG_STAT_CACHE
ctrl.size = 0;
#endif
@@ -122,24 +121,24 @@ stat_cache *stat_cache_init(void) {
static stat_cache_entry * stat_cache_entry_init(void) {
stat_cache_entry *sce = NULL;
-
+
sce = calloc(1, sizeof(*sce));
-
+
sce->name = buffer_init();
sce->etag = buffer_init();
sce->content_type = buffer_init();
-
+
return sce;
}
static void stat_cache_entry_free(void *data) {
stat_cache_entry *sce = data;
if (!sce) return;
-
+
buffer_free(sce->etag);
buffer_free(sce->name);
buffer_free(sce->content_type);
-
+
free(sce);
}
@@ -148,22 +147,22 @@ static fam_dir_entry * fam_dir_entry_init(void) {
fam_dir_entry *fam_dir = NULL;
fam_dir = calloc(1, sizeof(*fam_dir));
-
+
fam_dir->name = buffer_init();
-
+
return fam_dir;
}
static void fam_dir_entry_free(void *data) {
fam_dir_entry *fam_dir = data;
-
+
if (!fam_dir) return;
-
+
FAMCancelMonitor(fam_dir->fc, fam_dir->req);
-
+
buffer_free(fam_dir->name);
free(fam_dir->req);
-
+
free(fam_dir);
}
#endif
@@ -174,7 +173,7 @@ void stat_cache_free(stat_cache *sc) {
splay_tree *node = sc->files;
osize = sc->files->size;
-
+
stat_cache_entry_free(node->data);
sc->files = splaytree_delete(sc->files, node->key);
@@ -182,17 +181,18 @@ void stat_cache_free(stat_cache *sc) {
}
buffer_free(sc->dir_name);
+ buffer_free(sc->hash_key);
#ifdef HAVE_FAM_H
while (sc->dirs) {
int osize;
splay_tree *node = sc->dirs;
-
+
osize = sc->dirs->size;
fam_dir_entry_free(node->data);
sc->dirs = splaytree_delete(sc->dirs, node->key);
-
+
if (osize == 1) {
assert(NULL == sc->dirs);
} else {
@@ -212,7 +212,7 @@ void stat_cache_free(stat_cache *sc) {
static int stat_cache_attr_get(buffer *buf, char *name) {
int attrlen;
int ret;
-
+
attrlen = 1024;
buffer_prepare_copy(buf, attrlen);
attrlen--;
@@ -238,9 +238,8 @@ static uint32_t hashme(buffer *str) {
}
#ifdef HAVE_FAM_H
-handler_t stat_cache_handle_fdevent(void *_srv, void *_fce, int revent) {
+handler_t stat_cache_handle_fdevent(server *srv, void *_fce, int revent) {
size_t i;
- server *srv = _srv;
stat_cache *sc = srv->stat_cache;
size_t events;
@@ -251,15 +250,15 @@ handler_t stat_cache_handle_fdevent(void *_srv, void *_fce, int revent) {
sc->fam) {
events = FAMPending(sc->fam);
-
+
for (i = 0; i < events; i++) {
FAMEvent fe;
fam_dir_entry *fam_dir;
splay_tree *node;
- int ndx;
-
+ int ndx, j;
+
FAMNextEvent(sc->fam, &fe);
-
+
/* handle event */
switch(fe.code) {
@@ -274,20 +273,25 @@ handler_t stat_cache_handle_fdevent(void *_srv, void *_fce, int revent) {
/* file/dir is still here */
if (fe.code == FAMChanged) break;
- buffer_copy_string(sc->dir_name, fe.filename);
+ /* we have 2 versions, follow and no-follow-symlink */
+
+ for (j = 0; j < 2; j++) {
+ buffer_copy_string(sc->hash_key, fe.filename);
+ buffer_append_long(sc->hash_key, j);
- ndx = hashme(sc->dir_name);
+ ndx = hashme(sc->hash_key);
- sc->dirs = splaytree_splay(sc->dirs, ndx);
- node = sc->dirs;
-
- if (node && (node->key == ndx)) {
- int osize = splaytree_size(sc->dirs);
+ sc->dirs = splaytree_splay(sc->dirs, ndx);
+ node = sc->dirs;
- fam_dir_entry_free(node->data);
- sc->dirs = splaytree_delete(sc->dirs, ndx);
+ if (node && (node->key == ndx)) {
+ int osize = splaytree_size(sc->dirs);
- assert(osize - 1 == splaytree_size(sc->dirs));
+ fam_dir_entry_free(node->data);
+ sc->dirs = splaytree_delete(sc->dirs, ndx);
+
+ assert(osize - 1 == splaytree_size(sc->dirs));
+ }
}
break;
default:
@@ -308,7 +312,7 @@ handler_t stat_cache_handle_fdevent(void *_srv, void *_fce, int revent) {
sc->fam = NULL;
}
-
+
return HANDLER_GO_ON;
}
@@ -328,11 +332,25 @@ static int buffer_copy_dirname(buffer *dst, buffer *file) {
}
#endif
+#ifdef HAVE_LSTAT
+static int stat_cache_lstat(server *srv, buffer *dname, struct stat *lst) {
+ if (lstat(dname->ptr, lst) == 0) {
+ return S_ISLNK(lst->st_mode) ? 0 : 1;
+ }
+ else {
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "lstat failed for:",
+ dname, strerror(errno));
+ };
+ return -1;
+}
+#endif
+
/***
*
*
*
- * returns:
+ * returns:
* - HANDLER_FINISHED on cache-miss (don't forget to reopen the file)
* - HANDLER_ERROR on stat() failed -> see errno for problem
*/
@@ -348,41 +366,45 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
struct stat st;
size_t k;
int fd;
-#ifdef DEBUG_STAT_CACHE
+ struct stat lst;
+#ifdef DEBUG_STAT_CACHE
size_t i;
#endif
int file_ndx;
splay_tree *file_node = NULL;
- *ret_sce = NULL;
+ *ret_sce = NULL;
- /*
+ /*
* check if the directory for this file has changed
*/
sc = srv->stat_cache;
- file_ndx = hashme(name);
+ buffer_copy_string_buffer(sc->hash_key, name);
+ buffer_append_long(sc->hash_key, con->conf.follow_symlink);
+
+ file_ndx = hashme(sc->hash_key);
sc->files = splaytree_splay(sc->files, file_ndx);
-#ifdef DEBUG_STAT_CACHE
+#ifdef DEBUG_STAT_CACHE
for (i = 0; i < ctrl.used; i++) {
if (ctrl.ptr[i] == file_ndx) break;
}
#endif
if (sc->files && (sc->files->key == file_ndx)) {
-#ifdef DEBUG_STAT_CACHE
+#ifdef DEBUG_STAT_CACHE
/* it was in the cache */
assert(i < ctrl.used);
#endif
-
- /* we have seen this file already and
+
+ /* we have seen this file already and
* don't stat() it again in the same second */
file_node = sc->files;
-
+
sce = file_node->data;
/* check if the name is the same, we might have a collision */
@@ -390,7 +412,7 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
if (buffer_is_equal(name, sce->name)) {
if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) {
if (sce->stat_ts == srv->cur_ts) {
- *ret_sce = sce;
+ *ret_sce = sce;
return HANDLER_GO_ON;
}
}
@@ -400,17 +422,18 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
* file_node is used by the FAM check below to see if we know this file
* and if we can save a stat().
*
- * BUT, the sce is not reset here as the entry into the cache is ok, we
+ * BUT, the sce is not reset here as the entry into the cache is ok, we
* it is just not pointing to our requested file.
- *
+ *
* */
file_node = NULL;
}
} else {
-#ifdef DEBUG_STAT_CACHE
+#ifdef DEBUG_STAT_CACHE
if (i != ctrl.used) {
- fprintf(stderr, "%s.%d: %08x was already inserted but not found in cache, %s\n", __FILE__, __LINE__, file_ndx, name->ptr);
+ log_error_write(srv, __FILE__, __LINE__, "xSB",
+ file_ndx, "was already inserted but not found in cache, ", name);
}
assert(i == ctrl.used);
#endif
@@ -420,27 +443,32 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
/* dir-check */
if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
if (0 != buffer_copy_dirname(sc->dir_name, name)) {
- SEGFAULT();
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "no '/' found in filename:", name);
+ return HANDLER_ERROR;
}
- dir_ndx = hashme(sc->dir_name);
-
+ buffer_copy_string_buffer(sc->hash_key, sc->dir_name);
+ buffer_append_long(sc->hash_key, con->conf.follow_symlink);
+
+ dir_ndx = hashme(sc->hash_key);
+
sc->dirs = splaytree_splay(sc->dirs, dir_ndx);
-
+
if (sc->dirs && (sc->dirs->key == dir_ndx)) {
dir_node = sc->dirs;
}
-
+
if (dir_node && file_node) {
/* we found a file */
-
+
sce = file_node->data;
fam_dir = dir_node->data;
-
+
if (fam_dir->version == sce->dir_version) {
/* the stat()-cache entry is still ok */
-
- *ret_sce = sce;
+
+ *ret_sce = sce;
return HANDLER_GO_ON;
}
}
@@ -448,18 +476,23 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
#endif
/*
- * *lol*
+ * *lol*
* - open() + fstat() on a named-pipe results in a (intended) hang.
- * - stat() if regualar file + open() to see if we can read from it is better
+ * - stat() if regular file + open() to see if we can read from it is better
*
* */
-
if (-1 == stat(name->ptr, &st)) {
return HANDLER_ERROR;
}
if (S_ISREG(st.st_mode)) {
+ /* fix broken stat/open for symlinks to reg files with appended slash on freebsd,osx */
+ if (name->ptr[name->used-2] == '/') {
+ errno = ENOTDIR;
+ return HANDLER_ERROR;
+ }
+
/* try to open the file to check if we can read it */
if (-1 == (fd = open(name->ptr, O_RDONLY))) {
return HANDLER_ERROR;
@@ -468,17 +501,15 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
}
if (NULL == sce) {
- int osize = 0;
-
- if (sc->files) {
- osize = sc->files->size;
- }
+#ifdef DEBUG_STAT_CACHE
+ int osize = splaytree_size(sc->files);
+#endif
sce = stat_cache_entry_init();
buffer_copy_string_buffer(sce->name, name);
-
- sc->files = splaytree_insert(sc->files, file_ndx, sce);
-#ifdef DEBUG_STAT_CACHE
+
+ sc->files = splaytree_insert(sc->files, file_ndx, sce);
+#ifdef DEBUG_STAT_CACHE
if (ctrl.size == 0) {
ctrl.size = 16;
ctrl.used = 0;
@@ -499,47 +530,100 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
sce->st = st;
sce->stat_ts = srv->cur_ts;
- /* catch the obvious symlinks
+ /* catch the obvious symlinks
*
* this is not a secure check as we still have a race-condition between
- * the stat() and the open. We can only solve this by
+ * the stat() and the open. We can only solve this by
* 1. open() the file
* 2. fstat() the fd
*
* and keeping the file open for the rest of the time. But this can
* only be done at network level.
- *
+ *
+ * per default it is not a symlink
* */
- if (S_ISLNK(st.st_mode) && !con->conf.follow_symlink) {
- return HANDLER_ERROR;
- }
+#ifdef HAVE_LSTAT
+ sce->is_symlink = 0;
+
+ /* we want to only check for symlinks if we should block symlinks.
+ */
+ if (!con->conf.follow_symlink) {
+ if (stat_cache_lstat(srv, name, &lst) == 0) {
+#ifdef DEBUG_STAT_CACHE
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "found symlink", name);
+#endif
+ sce->is_symlink = 1;
+ }
+
+ /*
+ * we assume "/" can not be symlink, so
+ * skip the symlink stuff if our path is /
+ **/
+ else if ((name->used > 2)) {
+ buffer *dname;
+ char *s_cur;
+
+ dname = buffer_init();
+ buffer_copy_string_buffer(dname, name);
+
+ while ((s_cur = strrchr(dname->ptr,'/'))) {
+ *s_cur = '\0';
+ dname->used = s_cur - dname->ptr + 1;
+ if (dname->ptr == s_cur) {
+#ifdef DEBUG_STAT_CACHE
+ log_error_write(srv, __FILE__, __LINE__, "s", "reached /");
+#endif
+ break;
+ }
+#ifdef DEBUG_STAT_CACHE
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "checking if", dname, "is a symlink");
+#endif
+ if (stat_cache_lstat(srv, dname, &lst) == 0) {
+ sce->is_symlink = 1;
+#ifdef DEBUG_STAT_CACHE
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "found symlink", dname);
+#endif
+ break;
+ };
+ };
+ buffer_free(dname);
+ };
+ };
+#endif
- if (S_ISREG(st.st_mode)) {
+ if (S_ISREG(st.st_mode)) {
/* determine mimetype */
buffer_reset(sce->content_type);
-
- for (k = 0; k < con->conf.mimetypes->used; k++) {
- data_string *ds = (data_string *)con->conf.mimetypes->data[k];
- buffer *type = ds->key;
-
- if (type->used == 0) continue;
-
- /* check if the right side is the same */
- if (type->used > name->used) continue;
-
- if (0 == strncasecmp(name->ptr + name->used - type->used, type->ptr, type->used - 1)) {
- buffer_copy_string_buffer(sce->content_type, ds->value);
- break;
- }
- }
- etag_create(sce->etag, &(sce->st));
#ifdef HAVE_XATTR
- if (buffer_is_empty(sce->content_type)) {
+ if (con->conf.use_xattr) {
stat_cache_attr_get(sce->content_type, name->ptr);
}
#endif
+ /* xattr did not set a content-type. ask the config */
+ if (buffer_is_empty(sce->content_type)) {
+ for (k = 0; k < con->conf.mimetypes->used; k++) {
+ data_string *ds = (data_string *)con->conf.mimetypes->data[k];
+ buffer *type = ds->key;
+
+ if (type->used == 0) continue;
+
+ /* check if the right side is the same */
+ if (type->used > name->used) continue;
+
+ if (0 == strncasecmp(name->ptr + name->used - type->used, type->ptr, type->used - 1)) {
+ buffer_copy_string_buffer(sce->content_type, ds->value);
+ break;
+ }
+ }
+ }
+ etag_create(sce->etag, &(sce->st), con->etag_flags);
+ } else if (S_ISDIR(st.st_mode)) {
+ etag_create(sce->etag, &(sce->st), con->etag_flags);
}
-
+
#ifdef HAVE_FAM_H
if (sc->fam &&
(srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM)) {
@@ -549,19 +633,20 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
fam_dir->fc = sc->fam;
buffer_copy_string_buffer(fam_dir->name, sc->dir_name);
-
+
fam_dir->version = 1;
-
+
fam_dir->req = calloc(1, sizeof(FAMRequest));
-
- if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr,
+
+ if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr,
fam_dir->req, fam_dir)) {
-
- log_error_write(srv, __FILE__, __LINE__, "sbs",
- "monitoring dir failed:",
+
+ log_error_write(srv, __FILE__, __LINE__, "sbsbs",
+ "monitoring dir failed:",
fam_dir->name,
+ "file:", name,
FamErrlist[FAMErrno]);
-
+
fam_dir_entry_free(fam_dir);
} else {
int osize = 0;
@@ -570,7 +655,7 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
osize = sc->dirs->size;
}
- sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir);
+ sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir);
assert(sc->dirs);
assert(sc->dirs->data == fam_dir);
assert(osize == (sc->dirs->size - 1));
@@ -578,9 +663,9 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
} else {
fam_dir = dir_node->data;
}
-
+
/* bind the fam_fc to the stat() cache entry */
-
+
if (fam_dir) {
sce->dir_version = fam_dir->version;
sce->dir_ndx = dir_ndx;
@@ -594,11 +679,11 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
}
/**
- * remove stat() from cache which havn't been stat()ed for
+ * remove stat() from cache which havn't been stat()ed for
* more than 10 seconds
- *
*
- * walk though the stat-cache, collect the ids which are too old
+ *
+ * walk though the stat-cache, collect the ids which are too old
* and remove them in a second loop
*/
@@ -639,9 +724,9 @@ int stat_cache_trigger_cleanup(server *srv) {
sc->files = splaytree_splay(sc->files, ndx);
node = sc->files;
-
+
if (node && (node->key == ndx)) {
-#ifdef DEBUG_STAT_CACHE
+#ifdef DEBUG_STAT_CACHE
size_t j;
int osize = splaytree_size(sc->files);
stat_cache_entry *sce = node->data;
@@ -649,7 +734,7 @@ int stat_cache_trigger_cleanup(server *srv) {
stat_cache_entry_free(node->data);
sc->files = splaytree_delete(sc->files, ndx);
-#ifdef DEBUG_STAT_CACHE
+#ifdef DEBUG_STAT_CACHE
for (j = 0; j < ctrl.used; j++) {
if (ctrl.ptr[j] == ndx) {
ctrl.ptr[j] = ctrl.ptr[--ctrl.used];
diff --git a/src/stat_cache.h b/src/stat_cache.h
index e6f7796..7b80cce 100644
--- a/src/stat_cache.h
+++ b/src/stat_cache.h
@@ -7,7 +7,7 @@ stat_cache *stat_cache_init(void);
void stat_cache_free(stat_cache *fc);
handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_cache_entry **fce);
-handler_t stat_cache_handle_fdevent(void *_srv, void *_fce, int revent);
+handler_t stat_cache_handle_fdevent(server *srv, void *_fce, int revent);
int stat_cache_trigger_cleanup(server *srv);
#endif
diff --git a/src/status_counter.c b/src/status_counter.c
new file mode 100644
index 0000000..ab130da
--- /dev/null
+++ b/src/status_counter.c
@@ -0,0 +1,61 @@
+#include "status_counter.h"
+
+#include <stdlib.h>
+
+/**
+ * The status array can carry all the status information you want
+ * the key to the array is <module-prefix>.<name>
+ * and the values are counters
+ *
+ * example:
+ * fastcgi.backends = 10
+ * fastcgi.active-backends = 6
+ * fastcgi.backend.<key>.load = 24
+ * fastcgi.backend.<key>....
+ *
+ * fastcgi.backend.<key>.disconnects = ...
+ */
+
+data_integer *status_counter_get_counter(server *srv, const char *s, size_t len) {
+ data_integer *di;
+
+ if (NULL == (di = (data_integer *)array_get_element(srv->status, s))) {
+ /* not found, create it */
+
+ if (NULL == (di = (data_integer *)array_get_unused_element(srv->status, TYPE_INTEGER))) {
+ di = data_integer_init();
+ }
+ buffer_copy_string_len(di->key, s, len);
+ di->value = 0;
+
+ array_insert_unique(srv->status, (data_unset *)di);
+ }
+ return di;
+}
+
+/* dummies of the statistic framework functions
+ * they will be moved to a statistics.c later */
+int status_counter_inc(server *srv, const char *s, size_t len) {
+ data_integer *di = status_counter_get_counter(srv, s, len);
+
+ di->value++;
+
+ return 0;
+}
+
+int status_counter_dec(server *srv, const char *s, size_t len) {
+ data_integer *di = status_counter_get_counter(srv, s, len);
+
+ if (di->value > 0) di->value--;
+
+ return 0;
+}
+
+int status_counter_set(server *srv, const char *s, size_t len, int val) {
+ data_integer *di = status_counter_get_counter(srv, s, len);
+
+ di->value = val;
+
+ return 0;
+}
+
diff --git a/src/status_counter.h b/src/status_counter.h
new file mode 100644
index 0000000..ba5e76f
--- /dev/null
+++ b/src/status_counter.h
@@ -0,0 +1,14 @@
+#ifndef _STATUS_COUNTER_H_
+#define _STATUS_COUNTER_H_
+
+#include "array.h"
+#include "base.h"
+
+#include <sys/types.h>
+
+data_integer *status_counter_get_counter(server *srv, const char *s, size_t len);
+int status_counter_inc(server *srv, const char *s, size_t len);
+int status_counter_dec(server *srv, const char *s, size_t len);
+int status_counter_set(server *srv, const char *s, size_t len, int val);
+
+#endif
diff --git a/src/stream.c b/src/stream.c
index ecaadc1..c29a5ca 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -1,14 +1,11 @@
+#include "stream.h"
+
#include <sys/types.h>
#include <sys/stat.h>
-#include <unistd.h>
+#include <unistd.h>
#include <fcntl.h>
-#include "stream.h"
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
#include "sys-mmap.h"
#ifndef O_BINARY
@@ -25,33 +22,33 @@ int stream_open(stream *f, buffer *fn) {
#endif
f->start = NULL;
-
+
if (-1 == stat(fn->ptr, &st)) {
return -1;
}
-
+
f->size = st.st_size;
#ifdef HAVE_MMAP
if (-1 == (fd = open(fn->ptr, O_RDONLY | O_BINARY))) {
return -1;
}
-
- f->start = mmap(0, f->size, PROT_READ, MAP_SHARED, fd, 0);
-
+
+ f->start = mmap(NULL, f->size, PROT_READ, MAP_SHARED, fd, 0);
+
close(fd);
-
+
if (MAP_FAILED == f->start) {
return -1;
}
#elif defined __WIN32
- fh = CreateFile(fn->ptr,
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_READONLY,
+ fh = CreateFile(fn->ptr,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_READONLY,
NULL);
if (!fh) return -1;
@@ -64,19 +61,20 @@ int stream_open(stream *f, buffer *fn) {
NULL);
if (!mh) {
+/*
LPVOID lpMsgBuf;
FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
-
+*/
return -1;
}
-
+
p = MapViewOfFile(mh,
FILE_MAP_READ,
0,
@@ -87,9 +85,9 @@ int stream_open(stream *f, buffer *fn) {
f->start = p;
#else
-# error no mmap found
+# error no mmap found
#endif
-
+
return 0;
}
diff --git a/src/sys-socket.h b/src/sys-socket.h
index cc6e649..f35699d 100644
--- a/src/sys-socket.h
+++ b/src/sys-socket.h
@@ -8,6 +8,7 @@
#define ECONNRESET WSAECONNRESET
#define EINPROGRESS WSAEINPROGRESS
#define EALREADY WSAEALREADY
+#define ECONNABORTED WSAECONNABORTED
#define ioctl ioctlsocket
#define hstrerror(x) ""
#else
diff --git a/src/version.h b/src/version.h
new file mode 100644
index 0000000..e05b654
--- /dev/null
+++ b/src/version.h
@@ -0,0 +1,12 @@
+#ifndef _VERSION_H_
+#define _VERSION_H_
+
+#ifdef HAVE_VERSION_H
+# include "versionstamp.h"
+#else
+# define REPO_VERSION ""
+#endif
+
+#define PACKAGE_DESC PACKAGE_NAME "/" PACKAGE_VERSION REPO_VERSION
+
+#endif