diff options
author | Arno Töll <arno@debian.org> | 2012-11-21 23:03:41 +0100 |
---|---|---|
committer | Arno Töll <arno@debian.org> | 2012-11-21 23:03:41 +0100 |
commit | 6a6df8dc258631c6eaccb03bf08845241f6dfa4a (patch) | |
tree | 01eee8de64a85e5e2fef929050663ea2d3c850bd | |
parent | ec2cb646eff482dfe32955d01781b01211b0a77c (diff) | |
download | lighttpd-6a6df8dc258631c6eaccb03bf08845241f6dfa4a.tar.gz |
Imported Upstream version 1.4.12upstream/1.4.12
44 files changed, 1997 insertions, 658 deletions
@@ -3,13 +3,18 @@ NEWS ==== -- 1.4.12 - +- 1.4.12 - 2006-09-23 * added experimental LOCK support for webdav * added Content-Range support for PUT in webdav * added support for += on empty arrays in config-files * added ssl.cipher-list and ssl.use-sslv2 * added $HTTP["querystring"] conditional + * added mod_magnet as long-term replacement for mod_cml + * added work-around for a Opera Bug with SSL + Chunked-Encoding + * changed --print-config to print to stdout instead of stderr + * changed no longer use 0600 for new files with webdav. umask is + honored. Make sure you have set a proper umask. * fixed upload hangs with SSL * fixed connection drops with SSL (aka bad retry) * fixed path traversal with \ on cygwin @@ -23,6 +28,8 @@ NEWS * fixed empty FCGI_STDERR packets * fixed conditional server.allow-http-11 * fixed handling of follow-symlink + lstat() + * fixed SIGHUP handling if max-workers is used + * fixed "Software caused connection abort" messages on FreeBSD - 1.4.11 - 2006-03-09 @@ -26723,8 +26723,8 @@ fi fi -echo "$as_me:$LINENO: checking for lua" >&5 -echo $ECHO_N "checking for lua... $ECHO_C" >&6 +echo "$as_me:$LINENO: checking if lua-support is requested" >&5 +echo $ECHO_N "checking if lua-support is requested... $ECHO_C" >&6 # Check whether --with-lua or --without-lua was given. if test "${with_lua+set}" = set; then @@ -27036,12 +27036,12 @@ if test -n "$PKG_CONFIG"; then pkg_cv_LUA_CFLAGS="$LUA_CFLAGS" else if test -n "$PKG_CONFIG" && \ - { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"lua\"") >&5 - ($PKG_CONFIG --exists --print-errors "lua") 2>&5 + { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"lua >= 5.0\"") >&5 + ($PKG_CONFIG --exists --print-errors "lua >= 5.0") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then - pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "lua" 2>/dev/null` + pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "lua >= 5.0" 2>/dev/null` else pkg_failed=yes fi @@ -27054,12 +27054,12 @@ if test -n "$PKG_CONFIG"; then pkg_cv_LUA_LIBS="$LUA_LIBS" else if test -n "$PKG_CONFIG" && \ - { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"lua\"") >&5 - ($PKG_CONFIG --exists --print-errors "lua") 2>&5 + { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"lua >= 5.0\"") >&5 + ($PKG_CONFIG --exists --print-errors "lua >= 5.0") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then - pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "lua" 2>/dev/null` + pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "lua >= 5.0" 2>/dev/null` else pkg_failed=yes fi @@ -27078,14 +27078,14 @@ else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then - LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "lua"` + LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "lua >= 5.0"` else - LUA_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "lua"` + LUA_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "lua >= 5.0"` fi # Put the nasty error message in config.log where it belongs echo "$LUA_PKG_ERRORS" >&5 - { { echo "$as_me:$LINENO: error: Package requirements (lua) were not met: + { { echo "$as_me:$LINENO: error: Package requirements (lua >= 5.0) were not met: $LUA_PKG_ERRORS @@ -27096,7 +27096,7 @@ Alternatively, you may set the environment variables LUA_CFLAGS and LUA_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " >&5 -echo "$as_me: error: Package requirements (lua) were not met: +echo "$as_me: error: Package requirements (lua >= 5.0) were not met: $LUA_PKG_ERRORS @@ -30527,7 +30527,7 @@ else no_build="$no_build $plugins" fi -plugins="mod_cml" +plugins="mod_cml mod_magnet" if test ! "x$LUA_LIBS" = x; then do_build="$do_build $plugins" else diff --git a/configure.in b/configure.in index 1d879ab..74bca03 100644 --- a/configure.in +++ b/configure.in @@ -375,7 +375,7 @@ if test "$WITH_MEMCACHE" != "no"; then fi dnl Check for lua -AC_MSG_CHECKING(for lua) +AC_MSG_CHECKING(if lua-support is requested) AC_ARG_WITH(lua, AC_HELP_STRING([--with-lua],[lua engine for mod_cml]), [WITH_LUA=$withval],[WITH_LUA=no]) @@ -400,7 +400,7 @@ if test "$WITH_LUA" != "no"; then if test x"$LUA_LIBS" = x; then # try pkgconfig - PKG_CHECK_MODULES(LUA, lua, [ + PKG_CHECK_MODULES(LUA, lua >= 5.0, [ AC_DEFINE([HAVE_LUA], [1], [liblua]) AC_DEFINE([HAVE_LUA_H], [1], [lua.h]) ]) @@ -557,7 +557,7 @@ else no_build="$no_build $plugins" fi -plugins="mod_cml" +plugins="mod_cml mod_magnet" if test ! "x$LUA_LIBS" = x; then do_build="$do_build $plugins" else diff --git a/src/Makefile.am b/src/Makefile.am index ffec47e..3381100 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -46,7 +46,7 @@ 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 @@ -86,6 +86,12 @@ 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) +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 mod_cml_la_CFLAGS = $(AM_CFLAGS) $(LUA_CFLAGS) @@ -240,7 +246,8 @@ 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 DEFS= @DEFS@ -DLIBRARY_DIR="\"$(libdir)\"" diff --git a/src/Makefile.in b/src/Makefile.in index 7a316ce..ff69c2a 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -16,7 +16,7 @@ -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_flv_streaming_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) +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_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) $(proc_open_SOURCES) $(spawn_fcgi_SOURCES) srcdir = @srcdir@ top_srcdir = @top_srcdir@ @@ -84,7 +84,8 @@ am__liblightcomp_la_SOURCES_DIST = buffer.c log.c keyvalue.c chunk.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 + 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 \ @@ -111,7 +112,7 @@ 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) @NO_RDYNAMIC_TRUE@am_liblightcomp_la_rpath = -rpath $(libdir) @@ -163,6 +164,11 @@ mod_flv_streaming_la_OBJECTS = $(am_mod_flv_streaming_la_OBJECTS) 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_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_mysql_vhost_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) am_mod_mysql_vhost_la_OBJECTS = mod_mysql_vhost_la-mod_mysql_vhost.lo @@ -236,7 +242,8 @@ am__lighttpd_SOURCES_DIST = server.c response.c connections.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 + 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) \ @@ -254,7 +261,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) \ @@ -291,24 +298,7 @@ SOURCES = $(liblightcomp_la_SOURCES) $(mod_access_la_SOURCES) \ $(mod_dirlisting_la_SOURCES) $(mod_evasive_la_SOURCES) \ $(mod_evhost_la_SOURCES) $(mod_expire_la_SOURCES) \ $(mod_fastcgi_la_SOURCES) $(mod_flv_streaming_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) -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_flv_streaming_la_SOURCES) $(mod_indexfile_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) \ @@ -317,8 +307,27 @@ DIST_SOURCES = $(am__liblightcomp_la_SOURCES_DIST) \ $(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) $(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_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) \ + $(am__lighttpd_SOURCES_DIST) $(proc_open_SOURCES) \ + $(spawn_fcgi_SOURCES) HEADERS = $(noinst_HEADERS) ETAGS = etags CTAGS = ctags @@ -480,7 +489,7 @@ 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) @@ -491,7 +500,7 @@ spawn_fcgi_SOURCES = spawn-fcgi.c #mod_httptls_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined #mod_httptls_la_LIBADD = $(common_libadd) lib_LTLIBRARIES = $(am__append_1) mod_flv_streaming.la mod_evasive.la \ - mod_webdav.la mod_cml.la mod_trigger_b4_dl.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 \ @@ -515,6 +524,10 @@ mod_webdav_la_SOURCES = mod_webdav.c 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_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 @@ -609,7 +622,8 @@ 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 lighttpd_SOURCES = $(src) lighttpd_LDADD = $(PCRE_LIB) $(DL_LIB) $(SENDFILE_LIB) $(ATTR_LIB) $(common_libadd) $(SSL_LIB) $(FAM_LIBS) @@ -722,6 +736,8 @@ mod_flv_streaming.la: $(mod_flv_streaming_la_OBJECTS) $(mod_flv_streaming_la_DEP $(LINK) -rpath $(libdir) $(mod_flv_streaming_la_LDFLAGS) $(mod_flv_streaming_la_OBJECTS) $(mod_flv_streaming_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_magnet.la: $(mod_magnet_la_OBJECTS) $(mod_magnet_la_DEPENDENCIES) + $(LINK) -rpath $(libdir) $(mod_magnet_la_LDFLAGS) $(mod_magnet_la_OBJECTS) $(mod_magnet_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) @@ -905,6 +921,7 @@ 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)/log.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@ @@ -924,6 +941,8 @@ distclean-compile: @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@ @@ -959,6 +978,7 @@ distclean-compile: @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: @@ -1248,6 +1268,13 @@ liblightcomp_la-splaytree.lo: splaytree.c @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 +liblightcomp_la-status_counter.lo: status_counter.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-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@ then mv -f "$(DEPDIR)/liblightcomp_la-status_counter.Tpo" "$(DEPDIR)/liblightcomp_la-status_counter.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-status_counter.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ 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@ $(LIBTOOL) --tag=CC --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 @@ -1269,6 +1296,20 @@ mod_cml_la-mod_cml_funcs.lo: mod_cml_funcs.c @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 +mod_magnet_la-mod_magnet.lo: mod_magnet.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --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@ then mv -f "$(DEPDIR)/mod_magnet_la-mod_magnet.Tpo" "$(DEPDIR)/mod_magnet_la-mod_magnet.Plo"; else rm -f "$(DEPDIR)/mod_magnet_la-mod_magnet.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ 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@ $(LIBTOOL) --tag=CC --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@ if $(LIBTOOL) --tag=CC --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@ then mv -f "$(DEPDIR)/mod_magnet_la-mod_magnet_cache.Tpo" "$(DEPDIR)/mod_magnet_la-mod_magnet_cache.Plo"; else rm -f "$(DEPDIR)/mod_magnet_la-mod_magnet_cache.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ 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@ $(LIBTOOL) --tag=CC --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 diff --git a/src/array.c b/src/array.c index 14afa28..3e1b32d 100644 --- a/src/array.c +++ b/src/array.c @@ -231,7 +231,7 @@ int array_insert_unique(array *a, data_unset *str) { void array_print_indent(int depth) { int i; for (i = 0; i < depth; i ++) { - fprintf(stderr, " "); + fprintf(stdout, " "); } } @@ -275,20 +275,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,24 +296,24 @@ 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; } @@ -229,6 +229,7 @@ typedef struct { FAMConnection *fam; int fam_fcce_ndx; #endif + buffer *hash_key; /* temp-store for the hash-key */ } stat_cache; typedef struct { @@ -407,7 +408,7 @@ typedef struct { #ifdef USE_OPENSSL SSL *ssl; - int is_ssl_error_want; + buffer *ssl_error_want_reuse_buffer; #endif } connection; diff --git a/src/chunk.c b/src/chunk.c index 3903428..776d59e 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -194,6 +194,22 @@ int chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) { return 0; } +int chunkqueue_append_buffer_weak(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; + 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; @@ -209,6 +225,7 @@ int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) { return 0; } + int chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) { chunk *c; @@ -355,7 +372,7 @@ 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; diff --git a/src/chunk.h b/src/chunk.h index ddc8617..3893919 100644 --- a/src/chunk.h +++ b/src/chunk.h @@ -51,6 +51,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 6d5132a..5d1c8ec 100644 --- a/src/configfile-glue.c +++ b/src/configfile-glue.c @@ -54,14 +54,14 @@ int config_insert_values_internal(server *srv, array *ca, const config_values_t 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:", + "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; } @@ -72,7 +72,7 @@ int config_insert_values_internal(server *srv, array *ca, const config_values_t 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; } @@ -88,7 +88,7 @@ int config_insert_values_internal(server *srv, array *ca, const config_values_t 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); + log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected a short:", cv[i].key, ds->value); return -1; } @@ -269,7 +269,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat 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; } diff --git a/src/configparser.c b/src/configparser.c index bc1a2ec..266a1c7 100644 --- a/src/configparser.c +++ b/src/configparser.c @@ -174,8 +174,8 @@ typedef union { #define configparserARG_PDECL ,config_t *ctx #define configparserARG_FETCH config_t *ctx = yypParser->ctx #define configparserARG_STORE yypParser->ctx = ctx -#define YYNSTATE 62 -#define YYNRULE 39 +#define YYNSTATE 63 +#define YYNRULE 40 #define YYERRORSYMBOL 26 #define YYERRSYMDT yy95 #define YY_NO_ACTION (YYNSTATE+YYNRULE+2) @@ -230,61 +230,63 @@ typedef union { ** yy_default[] Default action for each state. */ static YYACTIONTYPE yy_action[] = { - /* 0 */ 2, 3, 4, 5, 13, 14, 62, 15, 7, 44, - /* 10 */ 20, 86, 16, 45, 28, 48, 40, 10, 39, 25, - /* 20 */ 22, 49, 45, 8, 15, 102, 1, 20, 28, 18, - /* 30 */ 57, 59, 19, 25, 22, 39, 19, 61, 98, 45, - /* 40 */ 20, 6, 23, 24, 26, 28, 35, 57, 59, 12, - /* 50 */ 25, 22, 28, 27, 36, 87, 29, 25, 22, 33, - /* 60 */ 15, 30, 31, 20, 28, 38, 9, 17, 37, 25, - /* 70 */ 22, 39, 42, 43, 10, 45, 11, 53, 54, 55, - /* 80 */ 56, 28, 52, 57, 59, 34, 25, 22, 28, 27, - /* 90 */ 32, 88, 41, 25, 22, 33, 28, 48, 46, 28, - /* 100 */ 48, 25, 22, 58, 25, 22, 60, 21, 19, 47, - /* 110 */ 51, 50, 25, 22, 88, 88, 93, + /* 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 */ 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, 5, 40, 41, 12, 5, 14, 11, 16, - /* 40 */ 4, 1, 6, 7, 8, 35, 36, 24, 25, 28, - /* 50 */ 40, 41, 35, 36, 37, 15, 39, 40, 41, 42, - /* 60 */ 1, 9, 10, 4, 35, 36, 38, 2, 3, 40, - /* 70 */ 41, 12, 28, 14, 46, 16, 13, 20, 21, 22, - /* 80 */ 23, 35, 36, 24, 25, 11, 40, 41, 35, 36, - /* 90 */ 37, 13, 13, 40, 41, 42, 35, 36, 17, 35, - /* 100 */ 36, 40, 41, 42, 40, 41, 42, 35, 5, 18, - /* 110 */ 43, 19, 40, 41, 47, 47, 13, + /* 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 (-5) static signed char yy_shift_ofst[] = { - /* 0 */ -5, 6, -5, -5, -5, 40, -4, 8, -3, -5, - /* 10 */ 63, -5, 23, -5, -5, -5, 65, 36, 31, 36, - /* 20 */ -5, -5, -5, -5, -5, -5, 36, 27, -5, 52, - /* 30 */ -5, 36, -5, 74, 36, 31, -5, 36, 31, 78, - /* 40 */ 79, -5, 59, -5, -5, 81, 91, 36, 31, 92, - /* 50 */ 57, 36, 103, -5, -5, -5, -5, 36, -5, 36, - /* 60 */ -5, -5, + /* 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 (-37) static signed char yy_reduce_ofst[] = { - /* 0 */ -2, -29, -37, -37, -37, -36, -37, -37, 28, -37, - /* 10 */ -37, 21, -29, -37, -37, -37, -37, -7, -37, 72, + /* 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, 53, -37, -37, 10, -37, -37, 29, -37, -37, - /* 40 */ -37, 44, -29, -37, -37, -37, -37, -21, -37, -37, - /* 50 */ 67, 46, -37, -37, -37, -37, -37, 61, -37, 64, - /* 60 */ -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 */ 64, 101, 63, 65, 66, 101, 67, 101, 101, 90, - /* 10 */ 101, 64, 101, 68, 69, 70, 101, 101, 71, 101, - /* 20 */ 73, 74, 76, 77, 78, 79, 101, 84, 75, 101, - /* 30 */ 80, 82, 81, 101, 101, 85, 83, 101, 72, 101, - /* 40 */ 101, 64, 101, 89, 91, 101, 101, 101, 98, 101, - /* 50 */ 101, 101, 101, 94, 95, 96, 97, 101, 99, 101, - /* 60 */ 100, 92, + /* 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])) @@ -407,27 +409,28 @@ static const char *yyRuleName[] = { /* 15 */ "value ::= STRING", /* 16 */ "value ::= INTEGER", /* 17 */ "value ::= array", - /* 18 */ "array ::= LPARAN aelements RPARAN", - /* 19 */ "aelements ::= aelements COMMA aelement", - /* 20 */ "aelements ::= aelements COMMA", - /* 21 */ "aelements ::= aelement", - /* 22 */ "aelement ::= expression", - /* 23 */ "aelement ::= stringop ARRAY_ASSIGN expression", - /* 24 */ "eols ::= EOL", - /* 25 */ "eols ::=", - /* 26 */ "globalstart ::= GLOBAL", - /* 27 */ "global ::= globalstart LCURLY metalines RCURLY", - /* 28 */ "condlines ::= condlines eols ELSE condline", - /* 29 */ "condlines ::= condline", - /* 30 */ "condline ::= context LCURLY metalines RCURLY", - /* 31 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression", - /* 32 */ "cond ::= EQ", - /* 33 */ "cond ::= MATCH", - /* 34 */ "cond ::= NE", - /* 35 */ "cond ::= NOMATCH", - /* 36 */ "stringop ::= expression", - /* 37 */ "include ::= INCLUDE stringop", - /* 38 */ "include_shell ::= INCLUDE_SHELL stringop", + /* 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 */ @@ -512,42 +515,42 @@ static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){ case 25: #line 142 "./configparser.y" { buffer_free((yypminor->yy0)); } -#line 515 "configparser.c" +#line 518 "configparser.c" break; case 35: #line 133 "./configparser.y" { (yypminor->yy41)->free((yypminor->yy41)); } -#line 520 "configparser.c" +#line 523 "configparser.c" break; case 36: #line 134 "./configparser.y" { (yypminor->yy41)->free((yypminor->yy41)); } -#line 525 "configparser.c" +#line 528 "configparser.c" break; case 37: #line 135 "./configparser.y" { (yypminor->yy41)->free((yypminor->yy41)); } -#line 530 "configparser.c" +#line 533 "configparser.c" break; case 39: #line 136 "./configparser.y" { array_free((yypminor->yy40)); } -#line 535 "configparser.c" +#line 538 "configparser.c" break; case 40: #line 137 "./configparser.y" { array_free((yypminor->yy40)); } -#line 540 "configparser.c" +#line 543 "configparser.c" break; case 41: #line 138 "./configparser.y" { buffer_free((yypminor->yy43)); } -#line 545 "configparser.c" +#line 548 "configparser.c" break; case 42: #line 139 "./configparser.y" { buffer_free((yypminor->yy43)); } -#line 550 "configparser.c" +#line 553 "configparser.c" break; default: break; /* If no destructor action specified: do nothing */ } @@ -741,6 +744,7 @@ static struct { { 35, 1 }, { 35, 1 }, { 35, 1 }, + { 40, 2 }, { 40, 3 }, { 39, 3 }, { 39, 2 }, @@ -816,7 +820,7 @@ static void yy_reduce( case 5: #line 116 "./configparser.y" { yymsp[-1].minor.yy78 = NULL; } -#line 819 "configparser.c" +#line 823 "configparser.c" yy_destructor(1,&yymsp[0].minor); break; case 6: @@ -851,7 +855,7 @@ static void yy_reduce( buffer_free(yymsp[-2].minor.yy43); yymsp[-2].minor.yy43 = NULL; } -#line 854 "configparser.c" +#line 858 "configparser.c" yy_destructor(2,&yymsp[-1].minor); break; case 10: @@ -894,7 +898,7 @@ static void yy_reduce( yymsp[-2].minor.yy43 = NULL; yymsp[0].minor.yy41 = NULL; } -#line 897 "configparser.c" +#line 901 "configparser.c" yy_destructor(3,&yymsp[-1].minor); break; case 11: @@ -910,7 +914,7 @@ static void yy_reduce( yymsp[0].minor.yy0 = NULL; } } -#line 913 "configparser.c" +#line 917 "configparser.c" break; case 12: #line 217 "./configparser.y" @@ -923,7 +927,7 @@ static void yy_reduce( yymsp[0].minor.yy41->free(yymsp[0].minor.yy41); yymsp[0].minor.yy41 = NULL; } -#line 926 "configparser.c" +#line 930 "configparser.c" yy_destructor(5,&yymsp[-1].minor); break; case 13: @@ -932,7 +936,7 @@ static void yy_reduce( yygotominor.yy41 = yymsp[0].minor.yy41; yymsp[0].minor.yy41 = NULL; } -#line 935 "configparser.c" +#line 939 "configparser.c" break; case 14: #line 232 "./configparser.y" @@ -961,7 +965,7 @@ static void yy_reduce( buffer_free(yymsp[0].minor.yy43); yymsp[0].minor.yy43 = NULL; } -#line 964 "configparser.c" +#line 968 "configparser.c" break; case 15: #line 258 "./configparser.y" @@ -971,7 +975,7 @@ static void yy_reduce( buffer_free(yymsp[0].minor.yy0); yymsp[0].minor.yy0 = NULL; } -#line 974 "configparser.c" +#line 978 "configparser.c" break; case 16: #line 265 "./configparser.y" @@ -981,7 +985,7 @@ static void yy_reduce( buffer_free(yymsp[0].minor.yy0); yymsp[0].minor.yy0 = NULL; } -#line 984 "configparser.c" +#line 988 "configparser.c" break; case 17: #line 271 "./configparser.y" @@ -991,20 +995,29 @@ static void yy_reduce( ((data_array *)(yygotominor.yy41))->value = yymsp[0].minor.yy40; yymsp[0].minor.yy40 = NULL; } -#line 994 "configparser.c" +#line 998 "configparser.c" break; case 18: #line 277 "./configparser.y" { + yygotominor.yy40 = array_init(); +} +#line 1005 "configparser.c" + yy_destructor(8,&yymsp[-1].minor); + yy_destructor(9,&yymsp[0].minor); + break; + case 19: +#line 280 "./configparser.y" +{ yygotominor.yy40 = yymsp[-1].minor.yy40; yymsp[-1].minor.yy40 = NULL; } -#line 1002 "configparser.c" +#line 1015 "configparser.c" yy_destructor(8,&yymsp[-2].minor); yy_destructor(9,&yymsp[0].minor); break; - case 19: -#line 282 "./configparser.y" + case 20: +#line 285 "./configparser.y" { if (buffer_is_empty(yymsp[0].minor.yy41->key) || NULL == array_get_element(yymsp[-2].minor.yy40, yymsp[0].minor.yy41->key->ptr)) { @@ -1021,37 +1034,37 @@ static void yy_reduce( yygotominor.yy40 = yymsp[-2].minor.yy40; yymsp[-2].minor.yy40 = NULL; } -#line 1024 "configparser.c" +#line 1037 "configparser.c" yy_destructor(10,&yymsp[-1].minor); break; - case 20: -#line 299 "./configparser.y" + case 21: +#line 302 "./configparser.y" { yygotominor.yy40 = yymsp[-1].minor.yy40; yymsp[-1].minor.yy40 = NULL; } -#line 1033 "configparser.c" +#line 1046 "configparser.c" yy_destructor(10,&yymsp[0].minor); break; - case 21: -#line 304 "./configparser.y" + case 22: +#line 307 "./configparser.y" { yygotominor.yy40 = array_init(); array_insert_unique(yygotominor.yy40, yymsp[0].minor.yy41); yymsp[0].minor.yy41 = NULL; } -#line 1043 "configparser.c" +#line 1056 "configparser.c" break; - case 22: -#line 310 "./configparser.y" + case 23: +#line 313 "./configparser.y" { yygotominor.yy41 = yymsp[0].minor.yy41; yymsp[0].minor.yy41 = NULL; } -#line 1051 "configparser.c" +#line 1064 "configparser.c" break; - case 23: -#line 314 "./configparser.y" + case 24: +#line 317 "./configparser.y" { buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43); buffer_free(yymsp[-2].minor.yy43); @@ -1060,27 +1073,27 @@ static void yy_reduce( yygotominor.yy41 = yymsp[0].minor.yy41; yymsp[0].minor.yy41 = NULL; } -#line 1063 "configparser.c" +#line 1076 "configparser.c" yy_destructor(11,&yymsp[-1].minor); break; - case 24: - yy_destructor(1,&yymsp[0].minor); - break; case 25: + yy_destructor(1,&yymsp[0].minor); break; case 26: -#line 326 "./configparser.y" + break; + case 27: +#line 329 "./configparser.y" { data_config *dc; dc = (data_config *)array_get_element(ctx->srv->config_context, "global"); assert(dc); configparser_push(ctx, dc, 0); } -#line 1079 "configparser.c" +#line 1092 "configparser.c" yy_destructor(12,&yymsp[0].minor); break; - case 27: -#line 333 "./configparser.y" + case 28: +#line 336 "./configparser.y" { data_config *cur; @@ -1091,14 +1104,14 @@ static void yy_reduce( yygotominor.yy0 = cur; } -#line 1094 "configparser.c" +#line 1107 "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 28: -#line 344 "./configparser.y" + case 29: +#line 347 "./configparser.y" { assert(yymsp[-3].minor.yy78->context_ndx < yymsp[0].minor.yy78->context_ndx); yymsp[0].minor.yy78->prev = yymsp[-3].minor.yy78; @@ -1107,20 +1120,20 @@ static void yy_reduce( yymsp[-3].minor.yy78 = NULL; yymsp[0].minor.yy78 = NULL; } -#line 1110 "configparser.c" +#line 1123 "configparser.c" /* No destructor defined for eols */ yy_destructor(15,&yymsp[-1].minor); break; - case 29: -#line 353 "./configparser.y" + case 30: +#line 356 "./configparser.y" { yygotominor.yy78 = yymsp[0].minor.yy78; yymsp[0].minor.yy78 = NULL; } -#line 1120 "configparser.c" +#line 1133 "configparser.c" break; - case 30: -#line 358 "./configparser.y" + case 31: +#line 361 "./configparser.y" { data_config *cur; @@ -1131,14 +1144,14 @@ static void yy_reduce( yygotominor.yy78 = cur; } -#line 1134 "configparser.c" +#line 1147 "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 31: -#line 369 "./configparser.y" + case 32: +#line 372 "./configparser.y" { data_config *dc; buffer *b, *rvalue, *op; @@ -1274,45 +1287,45 @@ static void yy_reduce( yymsp[0].minor.yy41->free(yymsp[0].minor.yy41); yymsp[0].minor.yy41 = NULL; } -#line 1277 "configparser.c" +#line 1290 "configparser.c" yy_destructor(16,&yymsp[-6].minor); yy_destructor(18,&yymsp[-4].minor); yy_destructor(19,&yymsp[-2].minor); break; - case 32: -#line 504 "./configparser.y" + case 33: +#line 507 "./configparser.y" { yygotominor.yy27 = CONFIG_COND_EQ; } -#line 1287 "configparser.c" +#line 1300 "configparser.c" yy_destructor(20,&yymsp[0].minor); break; - case 33: -#line 507 "./configparser.y" + case 34: +#line 510 "./configparser.y" { yygotominor.yy27 = CONFIG_COND_MATCH; } -#line 1295 "configparser.c" +#line 1308 "configparser.c" yy_destructor(21,&yymsp[0].minor); break; - case 34: -#line 510 "./configparser.y" + case 35: +#line 513 "./configparser.y" { yygotominor.yy27 = CONFIG_COND_NE; } -#line 1303 "configparser.c" +#line 1316 "configparser.c" yy_destructor(22,&yymsp[0].minor); break; - case 35: -#line 513 "./configparser.y" + case 36: +#line 516 "./configparser.y" { yygotominor.yy27 = CONFIG_COND_NOMATCH; } -#line 1311 "configparser.c" +#line 1324 "configparser.c" yy_destructor(23,&yymsp[0].minor); break; - case 36: -#line 517 "./configparser.y" + case 37: +#line 520 "./configparser.y" { yygotominor.yy43 = NULL; if (ctx->ok) { @@ -1329,10 +1342,10 @@ static void yy_reduce( yymsp[0].minor.yy41->free(yymsp[0].minor.yy41); yymsp[0].minor.yy41 = NULL; } -#line 1332 "configparser.c" +#line 1345 "configparser.c" break; - case 37: -#line 534 "./configparser.y" + case 38: +#line 537 "./configparser.y" { if (ctx->ok) { if (0 != config_parse_file(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) { @@ -1342,11 +1355,11 @@ static void yy_reduce( yymsp[0].minor.yy43 = NULL; } } -#line 1345 "configparser.c" +#line 1358 "configparser.c" yy_destructor(24,&yymsp[-1].minor); break; - case 38: -#line 544 "./configparser.y" + case 39: +#line 547 "./configparser.y" { if (ctx->ok) { if (0 != config_parse_cmd(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) { @@ -1356,7 +1369,7 @@ static void yy_reduce( yymsp[0].minor.yy43 = NULL; } } -#line 1359 "configparser.c" +#line 1372 "configparser.c" yy_destructor(25,&yymsp[-1].minor); break; }; @@ -1390,7 +1403,7 @@ static void yy_parse_failed( ctx->ok = 0; -#line 1393 "configparser.c" +#line 1406 "configparser.c" configparserARG_STORE; /* Suppress warning about unused %extra_argument variable */ } diff --git a/src/configparser.y b/src/configparser.y index 2e9c819..122f424 100644 --- a/src/configparser.y +++ b/src/configparser.y @@ -274,6 +274,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; diff --git a/src/connections.c b/src/connections.c index fc67e59..4e5a4fb 100644 --- a/src/connections.c +++ b/src/connections.c @@ -190,51 +190,129 @@ static void dump_packet(const unsigned char *data, size_t len) { } #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; + buffer *b = NULL; -#ifdef USE_OPENSSL - if (srv_sock->is_ssl) { - /* don't resize the buffer if we were in SSL_ERROR_WANT_* */ - if (!con->is_ssl_error_want) { - b = chunkqueue_get_append_buffer(con->read_queue); + if (!con->conf.is_ssl) return -1; + + /* don't resize the buffer if we were in SSL_ERROR_WANT_* */ + + do { + if (!con->ssl_error_want_reuse_buffer) { + b = buffer_init(); buffer_prepare_copy(b, SSL_pending(con->ssl) + (16 * 1024)); /* the pending bytes + 16kb */ + + /* overwrite everything with 0 */ + memset(b->ptr, 0, b->size); } else { - /* we have to get the last buffer */ - chunk *c; + b = con->ssl_error_want_reuse_buffer; + } - for (c = con->read_queue->first; c && c->next; c = c->next); + len = SSL_read(con->ssl, b->ptr, b->size - 1); + con->ssl_error_want_reuse_buffer = NULL; /* reuse it only once */ - if (!c) { - b = chunkqueue_get_append_buffer(con->read_queue); - buffer_prepare_copy(b, SSL_pending(con->ssl) + (16 * 1024)); /* the pending bytes + 16kb */ - } else { - log_error_write(srv, __FILE__, __LINE__, "s", - "(debug) re-using last buffer after a SSL_ERROR_WANT_READ - good, please report this to jan@kneschke.de"); + if (len > 0) { + b->used = len; + b->ptr[b->used++] = '\0'; + + /* we move the buffer to the chunk-queue, no need to free it */ - b = c->mem; - } + chunkqueue_append_buffer_weak(con->read_queue, b); + con->bytes_read += len; + b = NULL; } - len = SSL_read(con->ssl, b->ptr, b->size - 1); - con->is_ssl_error_want = 0; /* reset */ - } else { - if (ioctl(con->fd, FIONREAD, &toread)) { - log_error_write(srv, __FILE__, __LINE__, "sd", - "unexpected end-of-file:", - con->fd); - return -1; + } while (len > 0); + + + if (len < 0) { + switch ((r = SSL_get_error(con->ssl, len))) { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + con->is_readable = 0; + con->ssl_error_want_reuse_buffer = b; + + b = NULL; + + /* we have to steal the buffer from the queue-queue */ + 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(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 */ + 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)); + } + break; } - b = chunkqueue_get_append_buffer(con->read_queue); - buffer_prepare_copy(b, toread); + + connection_set_state(srv, con, CON_STATE_ERROR); - len = read(con->fd, b->ptr, b->size - 1); + buffer_free(b); + + return -1; + } else if (len == 0) { + con->is_readable = 0; + /* the other end close the connection -> KEEP-ALIVE */ + + /* pipelining */ + buffer_free(b); + + return -2; + } + + return 0; +#else + return -1; +#endif +} + +static int connection_handle_read(server *srv, connection *con) { + int len; + buffer *b; + int toread; + + if (con->conf.is_ssl) { + return connection_handle_read_ssl(srv, con); } -#elif defined(__WIN32) + +#if defined(__WIN32) b = chunkqueue_get_append_buffer(con->read_queue); buffer_prepare_copy(b, 4 * 1024); len = recv(con->fd, b->ptr, b->size - 1, 0); @@ -254,73 +332,6 @@ static int connection_handle_read(server *srv, connection *con) { 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: - case SSL_ERROR_WANT_WRITE: - con->is_ssl_error_want = 1; - 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(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 */ - 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)); - } - break; - } - } else { - 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); - } - } -#else if (errno == EAGAIN) return 0; if (errno == EINTR) { /* we have been interrupted before we could read */ @@ -332,7 +343,7 @@ static int connection_handle_read(server *srv, connection *con) { /* 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; @@ -803,7 +814,10 @@ int connection_reset(server *srv, connection *con) { #endif #ifdef USE_OPENSSL - con->is_ssl_error_want = 0; + if (con->ssl_error_want_reuse_buffer) { + buffer_free(con->ssl_error_want_reuse_buffer); + con->ssl_error_want_reuse_buffer = NULL; + } #endif con->header_len = 0; @@ -815,59 +829,17 @@ int connection_reset(server *srv, connection *con) { } /** - * - * 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; + 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; @@ -876,15 +848,8 @@ int connection_handle_read_state(server *srv, connection *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; } @@ -927,99 +892,107 @@ int connection_handle_read_state(server *srv, connection *con) { } } - /* 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) { + /* 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; !last_chunk && c; c = c->next) { buffer b; + size_t i; 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; + + for (i = 0; !last_chunk && i < b.used; i++) { + char ch = b.ptr[i]; + size_t have_chars = 0; + + switch (ch) { + case '\r': + /* we have to do a 4 char lookup */ + have_chars = b.used - i - 1; + + if (have_chars >= 4) { + /* all chars are in this buffer */ + + if (0 == strncmp(b.ptr + i, "\r\n\r\n", 4)) { + /* found */ + last_chunk = c; + last_offset = i + 4; + + break; + } + } else { + chunk *lookahead_chunk = c->next; + size_t missing_chars; + /* looks like the following chars are not in the same chunk */ + + missing_chars = 4 - have_chars; + + if (lookahead_chunk && lookahead_chunk->type == MEM_CHUNK) { + /* is the chunk long enough to contain the other chars ? */ + + if (lookahead_chunk->mem->used > missing_chars) { + if (0 == strncmp(b.ptr + i, "\r\n\r\n", have_chars) && + 0 == strncmp(lookahead_chunk->mem->ptr, "\r\n\r\n" + have_chars, missing_chars)) { + + last_chunk = lookahead_chunk; + last_offset = missing_chars + 1; + + break; + } + } else { + /* a splited \r \n */ + return -1; + } + } + } + + break; + } } - } else { - /* have to take care of overlapping header terminators */ - - size_t l = con->request.request->used - 2; - char *s = con->request.request->ptr; - buffer b; - - b.ptr = c->mem->ptr + c->offset; - b.used = c->mem->used - c->offset; + } + + /* found */ + if (last_chunk) { + buffer_reset(con->request.request); + + for (c = cq->first; c; c = c->next) { + buffer b; - 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; + b.ptr = c->mem->ptr + c->offset; + b.used = c->mem->used - c->offset; - 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); + if (c == last_chunk) { + b.used = last_offset + 1; + } + + buffer_append_string_buffer(con->request.request, &b); - /* 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 (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 */ @@ -1143,6 +1116,12 @@ int connection_handle_read_state(server *srv, connection *con) { 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); return 0; @@ -1261,8 +1240,17 @@ connection *connection_accept(server *srv, server_socket *srv_socket) { 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; + default: log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), errno); } return NULL; @@ -1354,6 +1342,12 @@ int connection_state_machine(server *srv, connection *con) { 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 */ diff --git a/src/data_config.c b/src/data_config.c index 8b3735e..03595a3 100644 --- a/src/data_config.c +++ b/src/data_config.c @@ -58,13 +58,13 @@ static void data_config_print(const data_unset *d, int depth) { 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,42 +75,42 @@ 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); } } diff --git a/src/data_count.c b/src/data_count.c index ca51f67..fbc35e0 100644 --- a/src/data_count.c +++ b/src/data_count.c @@ -45,7 +45,7 @@ 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); } diff --git a/src/data_fastcgi.c b/src/data_fastcgi.c index 714b290..ad981bf 100644 --- a/src/data_fastcgi.c +++ b/src/data_fastcgi.c @@ -44,7 +44,7 @@ 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); } diff --git a/src/data_integer.c b/src/data_integer.c index 96d1d0a..c557b90 100644 --- a/src/data_integer.c +++ b/src/data_integer.c @@ -42,7 +42,7 @@ 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); } diff --git a/src/data_string.c b/src/data_string.c index d9325da..391af9e 100644 --- a/src/data_string.c +++ b/src/data_string.c @@ -71,7 +71,7 @@ static void data_string_print(const data_unset *d, int depth) { data_string *ds = (data_string *)d; UNUSED(depth); - fprintf(stderr, "\"%s\"", ds->value->used ? ds->value->ptr : ""); + fprintf(stdout, "\"%s\"", ds->value->used ? ds->value->ptr : ""); } diff --git a/src/http_auth.c b/src/http_auth.c index d4de212..0d4637e 100644 --- a/src/http_auth.c +++ b/src/http_auth.c @@ -37,17 +37,6 @@ # include "md5.h" #endif - -#ifdef USE_PAM -#include <security/pam_appl.h> -#include <security/pam_misc.h> - -static struct pam_conv conv = { - misc_conv, - NULL -}; -#endif - handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s); static const char base64_pad = '='; @@ -509,33 +498,6 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p 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) { #ifdef USE_LDAP LDAP *ldap; diff --git a/src/http_auth.h b/src/http_auth.h index 0b664fa..b69007e 100644 --- a/src/http_auth.h +++ b/src/http_auth.h @@ -9,9 +9,13 @@ # 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 */ diff --git a/src/http_chunk.c b/src/http_chunk.c index c128bf1..281e86b 100644 --- a/src/http_chunk.c +++ b/src/http_chunk.c @@ -100,8 +100,7 @@ int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t 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); } diff --git a/src/mod_auth.c b/src/mod_auth.c index 7810437..b075a2b 100644 --- a/src/mod_auth.c +++ b/src/mod_auth.c @@ -193,20 +193,20 @@ static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) { /* 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; } diff --git a/src/mod_cml_lua.c b/src/mod_cml_lua.c index 76e979f..ded53b8 100644 --- a/src/mod_cml_lua.c +++ b/src/mod_cml_lua.c @@ -31,6 +31,7 @@ typedef char HASHHEX[HASHHEXLEN+1]; #include <lua.h> #include <lualib.h> +#include <lauxlib.h> typedef struct { stream st; @@ -220,14 +221,9 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { 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); diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c index e64351a..4f7260b 100644 --- a/src/mod_fastcgi.c +++ b/src/mod_fastcgi.c @@ -23,6 +23,7 @@ #include "inet_ntop_cache.h" #include "stat_cache.h" +#include "status_counter.h" #include <fastcgi.h> #include <stdio.h> @@ -363,49 +364,6 @@ typedef struct { /* ok, we need a prototype */ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents); -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; -} - 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); diff --git a/src/mod_magnet.c b/src/mod_magnet.c new file mode 100644 index 0000000..a2f6185 --- /dev/null +++ b/src/mod_magnet.c @@ -0,0 +1,746 @@ +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <setjmp.h> + +#include "base.h" +#include "log.h" +#include "buffer.h" + +#include "plugin.h" + +#include "mod_magnet_cache.h" +#include "response.h" +#include "stat_cache.h" +#include "status_counter.h" + +#ifdef HAVE_LUA_H +#include <lua.h> +#include <lauxlib.h> + +#define MAGNET_CONFIG_RAW_URL "magnet.attract-raw-url-to" +#define MAGNET_CONFIG_PHYSICAL_PATH "magnet.attract-physical-path-to" +#define MAGNET_RESTART_REQUEST 99 + +/* plugin config for all request/connections */ + +static jmp_buf exceptionjmp; + +typedef struct { + array *url_raw; + array *physical_path; +} plugin_config; + +typedef struct { + PLUGIN_DATA; + + script_cache *cache; + + buffer *encode_buf; + + plugin_config **config_storage; + + plugin_config conf; +} plugin_data; + +/* init the plugin data */ +INIT_FUNC(mod_magnet_init) { + plugin_data *p; + + p = calloc(1, sizeof(*p)); + + p->cache = script_cache_init(); + p->encode_buf = buffer_init(); + + return p; +} + +/* detroy the plugin data */ +FREE_FUNC(mod_magnet_free) { + plugin_data *p = p_d; + + UNUSED(srv); + + if (!p) return HANDLER_GO_ON; + + if (p->config_storage) { + size_t i; + + for (i = 0; i < srv->config_context->used; i++) { + plugin_config *s = p->config_storage[i]; + + if (!s) continue; + + array_free(s->url_raw); + array_free(s->physical_path); + + free(s); + } + free(p->config_storage); + } + + script_cache_free(p->cache); + buffer_free(p->encode_buf); + + free(p); + + return HANDLER_GO_ON; +} + +/* handle plugin config and check values */ + +SETDEFAULTS_FUNC(mod_magnet_set_defaults) { + plugin_data *p = p_d; + size_t i = 0; + + config_values_t cv[] = { + { MAGNET_CONFIG_RAW_URL, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ + { MAGNET_CONFIG_PHYSICAL_PATH, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ + { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } + }; + + if (!p) return HANDLER_ERROR; + + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); + + for (i = 0; i < srv->config_context->used; i++) { + plugin_config *s; + + s = calloc(1, sizeof(plugin_config)); + s->url_raw = array_init(); + s->physical_path = array_init(); + + cv[0].destination = s->url_raw; + cv[1].destination = s->physical_path; + + p->config_storage[i] = s; + + if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { + return HANDLER_ERROR; + } + } + + return HANDLER_GO_ON; +} + +#define PATCH(x) \ + p->conf.x = s->x; +static int mod_magnet_patch_connection(server *srv, connection *con, plugin_data *p) { + size_t i, j; + plugin_config *s = p->config_storage[0]; + + PATCH(url_raw); + PATCH(physical_path); + + /* skip the first, the global context */ + for (i = 1; i < srv->config_context->used; i++) { + data_config *dc = (data_config *)srv->config_context->data[i]; + s = p->config_storage[i]; + + /* condition didn't match */ + if (!config_check_cond(srv, con, dc)) continue; + + /* merge config */ + for (j = 0; j < dc->value->used; j++) { + data_unset *du = dc->value->data[j]; + + if (buffer_is_equal_string(du->key, CONST_STR_LEN(MAGNET_CONFIG_RAW_URL))) { + PATCH(url_raw); + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(MAGNET_CONFIG_PHYSICAL_PATH))) { + PATCH(physical_path); + } + } + } + + return 0; +} +#undef PATCH + +static int magnet_print(lua_State *L) { + const char *s = luaL_checkstring(L, 1); + server *srv; + + lua_pushstring(L, "lighty.srv"); + lua_gettable(L, LUA_REGISTRYINDEX); + srv = lua_touserdata(L, -1); + lua_pop(L, 1); + + log_error_write(srv, __FILE__, __LINE__, "ss", + "(lua-print)", s); + + return 0; +} + +static int magnet_atpanic(lua_State *L) { + const char *s = luaL_checkstring(L, 1); + server *srv; + + lua_pushstring(L, "lighty.srv"); + lua_gettable(L, LUA_REGISTRYINDEX); + srv = lua_touserdata(L, -1); + lua_pop(L, 1); + + log_error_write(srv, __FILE__, __LINE__, "ss", + "(lua-atpanic)", s); + + longjmp(exceptionjmp, 1); +} + +static int magnet_reqhdr_get(lua_State *L) { + server *srv; + connection *con; + data_string *ds; + + const char *key = luaL_checkstring(L, 2); + + lua_pushstring(L, "lighty.srv"); + lua_gettable(L, LUA_REGISTRYINDEX); + srv = lua_touserdata(L, -1); + lua_pop(L, 1); + + lua_pushstring(L, "lighty.con"); + lua_gettable(L, LUA_REGISTRYINDEX); + con = lua_touserdata(L, -1); + lua_pop(L, 1); + + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, key))) { + if (ds->value->used) { + lua_pushlstring(L, ds->value->ptr, ds->value->used - 1); + } else { + lua_pushnil(L); + } + } else { + lua_pushnil(L); + } + return 1; +} + +static int magnet_status_get(lua_State *L) { + data_integer *di; + server *srv; + size_t key_len = 0; + + const char *key = luaL_checklstring(L, 2, &key_len); + + lua_pushstring(L, "lighty.srv"); + lua_gettable(L, LUA_REGISTRYINDEX); + srv = lua_touserdata(L, -1); + lua_pop(L, 1); + + di = status_counter_get_counter(srv, key, key_len); + + lua_pushnumber(L, (double)di->value); + + return 1; +} + +static int magnet_status_set(lua_State *L) { + size_t key_len = 0; + server *srv; + + const char *key = luaL_checklstring(L, 2, &key_len); + int counter = luaL_checkint(L, 3); + + lua_pushstring(L, "lighty.srv"); + lua_gettable(L, LUA_REGISTRYINDEX); + srv = lua_touserdata(L, -1); + lua_pop(L, 1); + + status_counter_set(srv, key, key_len, counter); + + return 0; +} + +typedef struct { + const char *name; + enum { + MAGNET_ENV_UNSET, + + MAGNET_ENV_PHYICAL_PATH, + MAGNET_ENV_PHYICAL_REL_PATH, + MAGNET_ENV_PHYICAL_DOC_ROOT, + + MAGNET_ENV_URI_PATH, + MAGNET_ENV_URI_PATH_RAW, + MAGNET_ENV_URI_SCHEME, + MAGNET_ENV_URI_AUTHORITY, + MAGNET_ENV_URI_QUERY, + + MAGNET_ENV_REQUEST_METHOD, + MAGNET_ENV_REQUEST_URI, + MAGNET_ENV_REQUEST_PROTOCOL + } type; +} magnet_env_t; + +static buffer *magnet_env_get_buffer(server *srv, connection *con, const char *key) { + buffer *dest = NULL; + size_t i; + + const magnet_env_t env[] = { + { "physical.path", MAGNET_ENV_PHYICAL_PATH }, + { "physical.rel-path", MAGNET_ENV_PHYICAL_REL_PATH }, + { "physical.doc-root", MAGNET_ENV_PHYICAL_DOC_ROOT }, + + { "uri.path", MAGNET_ENV_URI_PATH }, + { "uri.path-raw", MAGNET_ENV_URI_PATH_RAW }, + { "uri.scheme", MAGNET_ENV_URI_SCHEME }, + { "uri.authority", MAGNET_ENV_URI_AUTHORITY }, + { "uri.query", MAGNET_ENV_URI_QUERY }, + + { "request.method", MAGNET_ENV_REQUEST_METHOD }, + { "request.uri", MAGNET_ENV_REQUEST_URI }, + { "request.protocol", MAGNET_ENV_REQUEST_PROTOCOL }, + + { NULL, MAGNET_ENV_UNSET } + }; + + + /** + * map all internal variables to lua + * + */ + + for (i = 0; env[i].name; i++) { + if (0 == strcmp(key, env[i].name)) break; + } + + switch (env[i].type) { + case MAGNET_ENV_PHYICAL_PATH: dest = con->physical.path; break; + case MAGNET_ENV_PHYICAL_REL_PATH: dest = con->physical.rel_path; break; + case MAGNET_ENV_PHYICAL_DOC_ROOT: dest = con->physical.doc_root; break; + + case MAGNET_ENV_URI_PATH: dest = con->uri.path; break; + case MAGNET_ENV_URI_PATH_RAW: dest = con->uri.path_raw; break; + case MAGNET_ENV_URI_SCHEME: dest = con->uri.scheme; break; + case MAGNET_ENV_URI_AUTHORITY: dest = con->uri.authority; break; + case MAGNET_ENV_URI_QUERY: dest = con->uri.query; break; + + case MAGNET_ENV_REQUEST_METHOD: break; + case MAGNET_ENV_REQUEST_URI: dest = con->request.uri; break; + case MAGNET_ENV_REQUEST_PROTOCOL: break; + + case MAGNET_ENV_UNSET: break; + } + + return dest; +} + +static int magnet_env_get(lua_State *L) { + server *srv; + connection *con; + + const char *key = luaL_checkstring(L, 2); + buffer *dest = NULL; + + lua_pushstring(L, "lighty.srv"); + lua_gettable(L, LUA_REGISTRYINDEX); + srv = lua_touserdata(L, -1); + lua_pop(L, 1); + + lua_pushstring(L, "lighty.con"); + lua_gettable(L, LUA_REGISTRYINDEX); + con = lua_touserdata(L, -1); + lua_pop(L, 1); + + dest = magnet_env_get_buffer(srv, con, key); + + if (dest && dest->used) { + lua_pushlstring(L, dest->ptr, dest->used - 1); + } else { + lua_pushnil(L); + } + + return 1; +} + +static int magnet_env_set(lua_State *L) { + server *srv; + connection *con; + + const char *key = luaL_checkstring(L, 2); + const char *val = luaL_checkstring(L, 3); + buffer *dest = NULL; + + lua_pushstring(L, "lighty.srv"); + lua_gettable(L, LUA_REGISTRYINDEX); + srv = lua_touserdata(L, -1); + lua_pop(L, 1); + + lua_pushstring(L, "lighty.con"); + lua_gettable(L, LUA_REGISTRYINDEX); + con = lua_touserdata(L, -1); + lua_pop(L, 1); + + if (NULL != (dest = magnet_env_get_buffer(srv, con, key))) { + buffer_copy_string(dest, val); + } else { + /* couldn't save */ + + return luaL_error(L, "couldn't store '%s' in lighty.env[]", key); + } + + return 0; +} + + +static int magnet_copy_response_header(server *srv, connection *con, plugin_data *p, lua_State *L) { + /** + * 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) { + /** + * get the environment of the function + */ + + assert(lua_isfunction(L, -1)); + lua_getfenv(L, -1); /* -1 is the function */ + + lua_getfield(L, -1, "lighty"); /* lighty.* from the env */ + assert(lua_istable(L, -1)); + + lua_getfield(L, -1, "content"); /* lighty.content */ + if (lua_istable(L, -1)) { + int i; + /* header is found, and is a table */ + + for (i = 1; ; i++) { + lua_rawgeti(L, -1, i); + + /* -1 is the value and should be the value ... aka a table */ + if (lua_isstring(L, -1)) { + size_t s_len = 0; + const char *s = lua_tolstring(L, -1, &s_len); + + chunkqueue_append_mem(con->write_queue, s, s_len + 1); + } else if (lua_istable(L, -1)) { + lua_getfield(L, -1, "filename"); + lua_getfield(L, -2, "length"); + lua_getfield(L, -3, "offset"); + + if (lua_isstring(L, -3)) { /* filename has to be a string */ + buffer *fn = buffer_init(); + stat_cache_entry *sce; + + buffer_copy_string(fn, lua_tostring(L, -3)); + + if (HANDLER_GO_ON == stat_cache_get_entry(srv, con, fn, &sce)) { + off_t off = 0; + off_t len = 0; + + if (lua_isnumber(L, -1)) { + off = lua_tonumber(L, -1); + } + + if (lua_isnumber(L, -2)) { + len = lua_tonumber(L, -2); + } else { + len = sce->st.st_size; + } + + if (off < 0) { + return luaL_error(L, "offset for '%s' is negative", fn->ptr); + } + + if (len < off) { + return luaL_error(L, "offset > length for '%s'", fn->ptr); + } + + chunkqueue_append_file(con->write_queue, fn, off, len - off); + } + + buffer_free(fn); + } else { + lua_pop(L, 3 + 2); /* correct the stack */ + + return luaL_error(L, "content[%d] is a table and requires the field \"filename\"", i); + } + + lua_pop(L, 3); + } else if (lua_isnil(L, -1)) { + /* oops, end of list */ + + lua_pop(L, 1); + + break; + } else { + lua_pop(L, 4); + + return luaL_error(L, "content[%d] is neither a string nor a table: ", i); + } + + lua_pop(L, 1); /* pop the content[...] table */ + } + } else { + return luaL_error(L, "lighty.content has to be a table"); + } + lua_pop(L, 1); /* pop the header-table */ + lua_pop(L, 1); /* pop the lighty-table */ + lua_pop(L, 1); /* php the function env */ + + return 0; +} + +static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, buffer *name) { + lua_State *L; + int lua_return_value = -1; + /* get the script-context */ + + + L = script_cache_get_script(srv, con, p->cache, name); + + if (lua_isstring(L, -1)) { + log_error_write(srv, __FILE__, __LINE__, + "sbss", + "loading script", + name, + "failed:", + lua_tostring(L, -1)); + + lua_pop(L, 1); + + assert(lua_gettop(L) == 0); /* only the function should be on the stack */ + + con->http_status = 500; + + return HANDLER_FINISHED; + } + + lua_pushstring(L, "lighty.srv"); + lua_pushlightuserdata(L, srv); + lua_settable(L, LUA_REGISTRYINDEX); /* registery[<id>] = srv */ + + lua_pushstring(L, "lighty.con"); + lua_pushlightuserdata(L, con); + lua_settable(L, LUA_REGISTRYINDEX); /* registery[<id>] = con */ + + lua_atpanic(L, magnet_atpanic); + + /** + * we want to create empty environment for our script + * + * setmetatable({}, {__index = _G}) + * + * if a function, symbol is not defined in our env, __index will lookup + * in the global env. + * + * all variables created in the script-env will be thrown + * away at the end of the script run. + */ + lua_newtable(L); /* my empty environment aka {} (sp += 1) */ + + /* we have to overwrite the print function */ + lua_pushcfunction(L, magnet_print); /* (sp += 1) */ + lua_setfield(L, -2, "print"); /* -1 is the env we want to set(sp -= 1) */ + + /** + * lighty.request[] has the HTTP-request headers + * lighty.content[] is a table of string/file + * lighty.header[] is a array to set response headers + */ + + lua_newtable(L); /* lighty.* (sp += 1) */ + + lua_newtable(L); /* {} (sp += 1) */ + lua_newtable(L); /* the meta-table for the request-table (sp += 1) */ + lua_pushcfunction(L, magnet_reqhdr_get); /* (sp += 1) */ + lua_setfield(L, -2, "__index"); /* (sp -= 1) */ + lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */ + lua_setfield(L, -2, "request"); /* content = {} (sp -= 1) */ + + lua_newtable(L); /* {} (sp += 1) */ + lua_newtable(L); /* the meta-table for the request-table (sp += 1) */ + lua_pushcfunction(L, magnet_env_get); /* (sp += 1) */ + lua_setfield(L, -2, "__index"); /* (sp -= 1) */ + lua_pushcfunction(L, magnet_env_set); /* (sp += 1) */ + lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */ + lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */ + lua_setfield(L, -2, "env"); /* content = {} (sp -= 1) */ + + lua_newtable(L); /* {} (sp += 1) */ + lua_newtable(L); /* the meta-table for the request-table (sp += 1) */ + lua_pushcfunction(L, magnet_status_get); /* (sp += 1) */ + lua_setfield(L, -2, "__index"); /* (sp -= 1) */ + lua_pushcfunction(L, magnet_status_set); /* (sp += 1) */ + lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */ + lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */ + lua_setfield(L, -2, "status"); /* content = {} (sp -= 1) */ + + /* add empty 'content' and 'header' tables */ + lua_newtable(L); /* {} (sp += 1) */ + lua_setfield(L, -2, "content"); /* content = {} (sp -= 1) */ + + lua_newtable(L); /* {} (sp += 1) */ + lua_setfield(L, -2, "header"); /* header = {} (sp -= 1) */ + + lua_pushinteger(L, MAGNET_RESTART_REQUEST); + lua_setfield(L, -2, "RESTART_REQUEST"); + + lua_setfield(L, -2, "lighty"); /* lighty.* (sp -= 1) */ + + lua_newtable(L); /* the meta-table for the new env (sp += 1) */ + lua_pushvalue(L, LUA_GLOBALSINDEX); /* (sp += 1) */ + lua_setfield(L, -2, "__index"); /* { __index = _G } (sp -= 1) */ + lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) (sp -= 1) */ + + + lua_setfenv(L, -2); /* on the stack should be a modified env (sp -= 1) */ + + if (lua_pcall(L, 0, 1, 0)) { + log_error_write(srv, __FILE__, __LINE__, + "ss", + "lua_pcall():", + lua_tostring(L, -1)); + lua_pop(L, 1); /* remove the error-msg and the function copy from the stack */ + + assert(lua_gettop(L) == 1); /* only the function should be on the stack */ + + con->http_status = 500; + + return HANDLER_FINISHED; + } + + /* we should have the function-copy and the return value on the stack */ + assert(lua_gettop(L) == 2); + + if (lua_isnumber(L, -1)) { + /* if the ret-value is a number, take it */ + lua_return_value = (int)lua_tonumber(L, -1); + } + lua_pop(L, 1); /* pop the ret-value */ + + magnet_copy_response_header(srv, con, p, L); + + if (lua_return_value > 99) { + con->http_status = lua_return_value; + con->file_finished = 1; + + /* try { ...*/ + if (0 == setjmp(exceptionjmp)) { + magnet_attach_content(srv, con, p, L); + } else { + /* } catch () { */ + con->http_status = 500; + } + + assert(lua_gettop(L) == 1); /* only the function should be on the stack */ + + /* we are finished */ + return HANDLER_FINISHED; + } else if (MAGNET_RESTART_REQUEST == lua_return_value) { + assert(lua_gettop(L) == 1); /* only the function should be on the stack */ + + return HANDLER_COMEBACK; + } else { + assert(lua_gettop(L) == 1); /* only the function should be on the stack */ + + return HANDLER_GO_ON; + } +} + +static handler_t magnet_attract_array(server *srv, connection *con, plugin_data *p, array *files) { + size_t i; + + /* no filename set */ + if (files->used == 0) return HANDLER_GO_ON; + + /** + * execute all files and jump out on the first !HANDLER_GO_ON + */ + for (i = 0; i < files->used; i++) { + data_string *ds = (data_string *)files->data[i]; + handler_t ret; + + if (buffer_is_empty(ds->value)) continue; + + ret = magnet_attract(srv, con, p, ds->value); + + if (ret != HANDLER_GO_ON) return ret; + } + + return HANDLER_GO_ON; +} + +URIHANDLER_FUNC(mod_magnet_uri_handler) { + plugin_data *p = p_d; + + mod_magnet_patch_connection(srv, con, p); + + return magnet_attract_array(srv, con, p, p->conf.url_raw); +} + +URIHANDLER_FUNC(mod_magnet_physical) { + plugin_data *p = p_d; + + mod_magnet_patch_connection(srv, con, p); + + return magnet_attract_array(srv, con, p, p->conf.physical_path); +} + + +/* this function is called at dlopen() time and inits the callbacks */ + +int mod_magnet_plugin_init(plugin *p) { + p->version = LIGHTTPD_VERSION_ID; + p->name = buffer_init_string("magnet"); + + p->init = mod_magnet_init; + p->handle_uri_clean = mod_magnet_uri_handler; + p->handle_physical = mod_magnet_physical; + p->set_defaults = mod_magnet_set_defaults; + p->cleanup = mod_magnet_free; + + p->data = NULL; + + return 0; +} + +#else +int mod_magnet_plugin_init(plugin *p) { + return -1; +} +#endif diff --git a/src/mod_magnet_cache.c b/src/mod_magnet_cache.c new file mode 100644 index 0000000..e2f5d84 --- /dev/null +++ b/src/mod_magnet_cache.c @@ -0,0 +1,137 @@ +#include <stdlib.h> +#include <time.h> +#include <assert.h> + +#include "mod_magnet_cache.h" +#include "stat_cache.h" + +#ifdef HAVE_LUA_H +#include <lualib.h> +#include <lauxlib.h> + +script *script_init() { + script *sc; + + sc = calloc(1, sizeof(*sc)); + sc->name = buffer_init(); + sc->etag = buffer_init(); + + return sc; +} + +void script_free(script *sc) { + if (!sc) return; + + lua_pop(sc->L, 1); /* the function copy */ + + buffer_free(sc->name); + buffer_free(sc->etag); + + lua_close(sc->L); + + free(sc); +} + +script_cache *script_cache_init() { + script_cache *p; + + p = calloc(1, sizeof(*p)); + + return p; +} + +void script_cache_free(script_cache *p) { + size_t i; + + if (!p) return; + + for (i = 0; i < p->used; i++) { + script_free(p->ptr[i]); + } + + free(p->ptr); + + free(p); +} + +lua_State *script_cache_get_script(server *srv, connection *con, script_cache *cache, buffer *name) { + size_t i; + script *sc = NULL; + stat_cache_entry *sce; + + for (i = 0; i < cache->used; i++) { + sc = cache->ptr[i]; + + if (buffer_is_equal(name, sc->name)) { + sc->last_used = time(NULL); + + /* oops, the script failed last time */ + + if (lua_gettop(sc->L) == 0) break; + + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, sc->name, &sce)) { + lua_pop(sc->L, 1); /* pop the old function */ + break; + } + + if (!buffer_is_equal(sce->etag, sc->etag)) { + /* the etag is outdated, reload the function */ + lua_pop(sc->L, 1); + break; + } + + assert(lua_isfunction(sc->L, -1)); + lua_pushvalue(sc->L, -1); /* copy the function-reference */ + + return sc->L; + } + + sc = NULL; + } + + /* if the script was script already loaded but either got changed or + * failed to load last time */ + if (sc == NULL) { + sc = script_init(); + + if (cache->size == 0) { + cache->size = 16; + cache->ptr = malloc(cache->size * sizeof(*(cache->ptr))); + } else if (cache->used == cache->size) { + cache->size += 16; + cache->ptr = realloc(cache->ptr, cache->size * sizeof(*(cache->ptr))); + } + + cache->ptr[cache->used++] = sc; + + buffer_copy_string_buffer(sc->name, name); + + sc->L = luaL_newstate(); + luaL_openlibs(sc->L); + } + + sc->last_used = time(NULL); + + if (0 != luaL_loadfile(sc->L, name->ptr)) { + /* oops, an error, return it */ + + return sc->L; + } + + if (HANDLER_GO_ON == stat_cache_get_entry(srv, con, sc->name, &sce)) { + buffer_copy_string_buffer(sc->etag, sce->etag); + } + + /** + * pcall() needs the function on the stack + * + * as pcall() will pop the script from the stack when done, we have to + * duplicate it here + */ + assert(lua_isfunction(sc->L, -1)); + lua_pushvalue(sc->L, -1); /* copy the function-reference */ + + return sc->L; +} + +#endif 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..524071e 100644 --- a/src/mod_mysql_vhost.c +++ b/src/mod_mysql_vhost.c @@ -105,6 +105,7 @@ SERVER_FUNC(mod_mysql_vhost_cleanup) { buffer_free(s->mysock); buffer_free(s->mysql_pre); buffer_free(s->mysql_post); + buffer_free(s->hostname); free(s); } diff --git a/src/mod_ssi.c b/src/mod_ssi.c index d1e1b25..4fdae2f 100644 --- a/src/mod_ssi.c +++ b/src/mod_ssi.c @@ -722,6 +722,14 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, close(from_exec_fds[1]); /* wait for the client to end */ + + /* + * FIXME: if we get interrupted by a SIGCHILD we count this as error + * + * for now it only happened on OpenBSD. + * + * that leads to zombies and missing output + */ if (-1 == waitpid(pid, &status, 0)) { log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno)); } else if (WIFEXITED(status)) { diff --git a/src/mod_webdav.c b/src/mod_webdav.c index 2e67c96..3fd021f 100644 --- a/src/mod_webdav.c +++ b/src/mod_webdav.c @@ -668,7 +668,7 @@ static int webdav_copy_file(server *srv, connection *con, plugin_data *p, physic 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), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH))) { /* opening the destination failed for some reason */ switch(errno) { case EEXIST: @@ -1651,7 +1651,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) { return HANDLER_FINISHED; } - if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY, 0600))) { + if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH))) { switch (errno) { case ENOENT: con->http_status = 404; /* not found */ @@ -1675,9 +1675,9 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) { /* take what we have in the request-body and write it to a file */ /* if the file doesn't exist, create it */ - if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_TRUNC, 0600))) { + if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH))) { if (errno == ENOENT && - -1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0600))) { + -1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH))) { /* we can't open the file */ con->http_status = 403; @@ -1704,14 +1704,14 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) { -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) { log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno)); - return -1; + return HANDLER_ERROR; } 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); - return -1; + return HANDLER_ERROR; } c->file.mmap.length = c->file.length; diff --git a/src/network.c b/src/network.c index 6ba2743..5b21b83 100644 --- a/src/network.c +++ b/src/network.c @@ -381,7 +381,7 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) { return -1; } SSL_CTX_set_default_read_ahead(s->ssl_ctx, 1); - SSL_CTX_set_mode(s->ssl_ctx, SSL_get_mode(s->ssl_ctx) | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + SSL_CTX_set_mode(s->ssl_ctx, SSL_CTX_get_mode(s->ssl_ctx) | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); srv_socket->ssl_ctx = s->ssl_ctx; #else diff --git a/src/network_freebsd_sendfile.c b/src/network_freebsd_sendfile.c index a6994c0..f6f4d82 100644 --- a/src/network_freebsd_sendfile.c +++ b/src/network_freebsd_sendfile.c @@ -89,6 +89,7 @@ int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int f case EINTR: r = 0; break; + case ENOTCONN: case EPIPE: case ECONNRESET: return -2; diff --git a/src/network_openssl.c b/src/network_openssl.c index e624739..86043fa 100644 --- a/src/network_openssl.c +++ b/src/network_openssl.c @@ -58,6 +58,31 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN); } + /* evil hack for opera 9.01 and 8.54 and earlier + * + * opera hangs if the trainling 0\r\n\r\n is in a seperate SSL-packet + * + * we try to move the packet into the previous mem-chunk if possible + */ + if ((cq == con->write_queue) && + (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) && + (con->file_finished)) { + /* merge the last chunk into the previous chunk */ + + for(c = cq->first; c && c->next && c->next->next; c = c->next); + + if (c && + c->type == MEM_CHUNK && + c->next && + c->next->type == MEM_CHUNK && + c->next->mem->used == sizeof("0\r\n\r\n") && + 0 == strcmp(c->next->mem->ptr, "0\r\n\r\n")) { + buffer_append_string_buffer(c->mem, c->next->mem); + + c->next->mem->used = 0; + } + } + for(c = cq->first; c; c = c->next) { int chunk_finished = 0; diff --git a/src/network_writev.c b/src/network_writev.c index 96a2a4a..5fdec8c 100644 --- a/src/network_writev.c +++ b/src/network_writev.c @@ -26,27 +26,6 @@ #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 @@ -65,18 +44,31 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq ssize_t r; size_t num_chunks, i; - struct iovec chunks[UIO_MAXIOV]; + struct iovec *chunks; chunk *tc; size_t num_bytes = 0; - +#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; +#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 + /* we can't send more then SSIZE_MAX bytes in one chunk */ /* build writev list * - * 1. limit: num_chunks < UIO_MAXIOV + * 1. limit: num_chunks < max_chunks * 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 (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) { @@ -111,11 +103,13 @@ 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", "writev failed:", strerror(errno), fd); + free(chunks); return -1; } } @@ -147,6 +141,7 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq break; } } + free(chunks); break; } diff --git a/src/server.c b/src/server.c index 5a29a75..0222a22 100644 --- a/src/server.c +++ b/src/server.c @@ -286,9 +286,7 @@ static void show_version (void) { } static void show_features (void) { - show_version(); - printf("\nEvent Handlers:\n\n%s", - + const char features[] = "" #ifdef USE_SELECT "\t+ select (generic)\n" #else @@ -355,11 +353,6 @@ static void show_features (void) { #else "\t- crypt support\n" #endif -#ifdef USE_PAM - "\t+ PAM support\n" -#else - "\t- PAM support\n" -#endif #ifdef USE_OPENSSL "\t+ SSL Support\n" #else @@ -410,8 +403,9 @@ static void show_features (void) { #else "\t- GDBM support\n" #endif - "\n" - ); + "\n"; + show_version(); + printf("\nEvent Handlers:\n\n%s", features); } static void show_help (void) { @@ -518,7 +512,7 @@ int main (int argc, char **argv) { 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"); @@ -953,8 +947,9 @@ int main (int argc, char **argv) { } } else { int status; - wait(&status); - num_childs++; + + /* ignore EINTR */ + if (-1 != wait(&status)) num_childs++; } } if (srv_shutdown) { diff --git a/src/stat_cache.c b/src/stat_cache.c index 623e5ea..a4f31a4 100644 --- a/src/stat_cache.c +++ b/src/stat_cache.c @@ -39,7 +39,7 @@ #define lstat stat #endif -#if 1 +#if 0 /* enables debug code for testing if all nodes in the stat-cache as accessable */ #define DEBUG_STAT_CACHE #endif @@ -109,6 +109,7 @@ stat_cache *stat_cache_init(void) { 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 @@ -182,6 +183,7 @@ void stat_cache_free(stat_cache *sc) { } buffer_free(sc->dir_name); + buffer_free(sc->hash_key); #ifdef HAVE_FAM_H while (sc->dirs) { @@ -256,7 +258,7 @@ handler_t stat_cache_handle_fdevent(void *_srv, void *_fce, int revent) { FAMEvent fe; fam_dir_entry *fam_dir; splay_tree *node; - int ndx; + int ndx, j; FAMNextEvent(sc->fam, &fe); @@ -274,20 +276,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 */ - ndx = hashme(sc->dir_name); + for (j = 0; j < 2; j++) { + buffer_copy_string(sc->hash_key, fe.filename); + buffer_append_long(sc->hash_key, j); - sc->dirs = splaytree_splay(sc->dirs, ndx); - node = sc->dirs; - - if (node && (node->key == ndx)) { - int osize = splaytree_size(sc->dirs); - - fam_dir_entry_free(node->data); - sc->dirs = splaytree_delete(sc->dirs, ndx); + ndx = hashme(sc->hash_key); - assert(osize - 1 == splaytree_size(sc->dirs)); + sc->dirs = splaytree_splay(sc->dirs, ndx); + node = sc->dirs; + + if (node && (node->key == ndx)) { + int osize = 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: @@ -329,12 +336,12 @@ static int buffer_copy_dirname(buffer *dst, buffer *file) { #endif #ifdef HAVE_LSTAT -static int stat_cache_lstat(server *srv, char *dname, struct stat *lst) { - if (lstat(dname, lst) == 0) { +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__, "sss", + log_error_write(srv, __FILE__, __LINE__, "sbs", "lstat failed for:", dname, strerror(errno)); }; @@ -362,6 +369,7 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ struct stat st; size_t k; int fd; + struct stat lst; #ifdef DEBUG_STAT_CACHE size_t i; #endif @@ -377,7 +385,10 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ 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 @@ -436,8 +447,11 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ if (0 != buffer_copy_dirname(sc->dir_name, name)) { SEGFAULT(); } + + buffer_copy_string_buffer(sc->hash_key, sc->dir_name); + buffer_append_long(sc->hash_key, con->conf.follow_symlink); - dir_ndx = hashme(sc->dir_name); + dir_ndx = hashme(sc->hash_key); sc->dirs = splaytree_splay(sc->dirs, dir_ndx); @@ -522,49 +536,57 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ * 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 + * per default it is not a symlink * */ #ifdef HAVE_LSTAT sce->is_symlink = 0; - struct stat lst; - if (stat_cache_lstat(srv, name->ptr, &lst) == 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); + log_error_write(srv, __FILE__, __LINE__, "sb", + "found symlink", name); #endif - sce->is_symlink = 1; - } + sce->is_symlink = 1; + } - /* - * we assume "/" can not be symlink, so - * skip the symlink stuff if our path is / - **/ - else if ((name->used > 2)) { - char *dname, *s_cur; - - dname = strndup(name->ptr, name->used); - while ((s_cur = strrchr(dname,'/'))) { - *s_cur = '\0'; - if (dname == s_cur) { + /* + * 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 /"); + log_error_write(srv, __FILE__, __LINE__, "s", "reached /"); #endif - break; - } + break; + } #ifdef DEBUG_STAT_CACHE - log_error_write(srv, __FILE__, __LINE__, "sss", - "checking if", dname, "is a symlink"); + 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; + if (stat_cache_lstat(srv, dname, &lst) == 0) { + sce->is_symlink = 1; #ifdef DEBUG_STAT_CACHE - log_error_write(srv, __FILE__, __LINE__, "ss", - "found symlink", dname); + log_error_write(srv, __FILE__, __LINE__, "sb", + "found symlink", dname); #endif - break; + break; + }; }; + buffer_free(dname); }; - free(dname); }; #endif @@ -592,6 +614,8 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ stat_cache_attr_get(sce->content_type, name->ptr); } #endif + } else if (S_ISDIR(st.st_mode)) { + etag_create(sce->etag, &(sce->st)); } #ifdef HAVE_FAM_H diff --git a/src/status_counter.c b/src/status_counter.c new file mode 100644 index 0000000..3b345cd --- /dev/null +++ b/src/status_counter.c @@ -0,0 +1,60 @@ +#include <stdlib.h> + +#include "status_counter.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..431bd9c --- /dev/null +++ b/src/status_counter.h @@ -0,0 +1,14 @@ +#ifndef _STATUS_COUNTER_H_ +#define _STATUS_COUNTER_H_ + +#include <sys/types.h> + +#include "array.h" +#include "base.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/tests/LightyTest.pm b/tests/LightyTest.pm index 81f9292..0426d45 100755 --- a/tests/LightyTest.pm +++ b/tests/LightyTest.pm @@ -90,10 +90,12 @@ sub start_proc { $ENV{'SRCDIR'} = $self->{BASEDIR}.'/tests'; unlink($self->{LIGHTTPD_PIDFILE}); - if (1) { - system($self->{LIGHTTPD_PATH}." -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}); + if (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'strace') { + system("strace -tt -s 512 -o strace ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &"); + } elsif (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'valgrind') { + system("valgrind --tool=memcheck --show-reachable=yes --leak-check=yes --log-file=valgrind ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &"); } else { - system("valgrind --tool=memcheck --show-reachable=yes --leak-check=yes --logfile=foo ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{TESTDIR}."/tmp/cfg.file -m ".$self->{MODULES_PATH}." &"); + system($self->{LIGHTTPD_PATH}." -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}); } select(undef, undef, undef, 0.1); @@ -195,6 +197,9 @@ sub handle_http { } } + $t->{etag} = $resp_hdr{'etag'}; + $t->{date} = $resp_hdr{'date'}; + # check length if (defined $resp_hdr{"content-length"}) { $resp_body = substr($lines, 0, $resp_hdr{"content-length"}); diff --git a/tests/Makefile.am b/tests/Makefile.am index d4a9b10..584d9c9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -42,7 +42,10 @@ CONFS=fastcgi-10.conf \ request.t \ mod-ssi.t \ LightyTest.pm \ - mod-setenv.t + mod-setenv.t \ + lowercase.t \ + lowercase.conf \ + cachable.t TESTS_ENVIRONMENT=$(srcdir)/wrapper.sh $(srcdir) $(top_builddir) diff --git a/tests/Makefile.in b/tests/Makefile.in index feea307..93ac0f6 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -257,7 +257,10 @@ CONFS = fastcgi-10.conf \ request.t \ mod-ssi.t \ LightyTest.pm \ - mod-setenv.t + mod-setenv.t \ + lowercase.t \ + lowercase.conf \ + cachable.t TESTS_ENVIRONMENT = $(srcdir)/wrapper.sh $(srcdir) $(top_builddir) EXTRA_DIST = wrapper.sh lighttpd.conf \ diff --git a/tests/cachable.t b/tests/cachable.t new file mode 100755 index 0000000..74d9a4b --- /dev/null +++ b/tests/cachable.t @@ -0,0 +1,112 @@ +#!/usr/bin/env perl +BEGIN { + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s#/[^/]+$#/#; + unshift @INC, $srcdir; +} + +use strict; +use IO::Socket; +use Test::More tests => 12; +use LightyTest; + +my $tf = LightyTest->new(); +my $t; + +$tf->{CONFIGFILE} = 'lighttpd.conf'; + +ok($tf->start_proc == 0, "Starting lighttpd") or die(); + +## check if If-Modified-Since, If-None-Match works + +$t->{REQUEST} = ( <<EOF +GET / HTTP/1.0 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since'); + +$t->{REQUEST} = ( <<EOF +GET / HTTP/1.0 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Last-Modified' => ''} ]; +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since, comment'); + +my $now = $t->{date}; + +$t->{REQUEST} = ( <<EOF +GET / HTTP/1.0 +If-Modified-Since: $now +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since'); + +$t->{REQUEST} = ( <<EOF +GET / HTTP/1.0 +If-Modified-Since: $now; foo +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since, comment'); + +$t->{REQUEST} = ( <<EOF +GET / HTTP/1.0 +If-None-Match: foo +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+ETag' => ''} ]; +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match'); + +my $etag = $t->{etag}; + +$t->{REQUEST} = ( <<EOF +GET / HTTP/1.0 +If-None-Match: $etag +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match'); + +$t->{REQUEST} = ( <<EOF +GET / HTTP/1.0 +If-None-Match: $etag +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + old Last-Modified'); + +$t->{REQUEST} = ( <<EOF +GET / HTTP/1.0 +If-None-Match: $etag +If-Modified-Since: $now; foo +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag, Last-Modified + comment'); + +$t->{REQUEST} = ( <<EOF +GET / HTTP/1.0 +If-None-Match: Foo +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; +ok($tf->handle_http($t) == 0, 'Conditional GET - old ETAG + old Last-Modified'); + +$t->{REQUEST} = ( <<EOF +GET / HTTP/1.0 +If-None-Match: $etag +If-Modified-Since: $now foo +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 412 } ]; +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + Last-Modified + overlong timestamp'); + +ok($tf->stop_proc == 0, "Stopping lighttpd"); + diff --git a/tests/lowercase.conf b/tests/lowercase.conf new file mode 100644 index 0000000..60eb40f --- /dev/null +++ b/tests/lowercase.conf @@ -0,0 +1,80 @@ +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/" +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid" + +## bind to port (default: 80) +server.port = 2048 + +## bind to localhost (default: all interfaces) +server.bind = "localhost" +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log" + +server.force-lowercase-filenames = "enable" + +server.dir-listing = "enable" + +server.modules = ( + "mod_rewrite", + "mod_setenv", + "mod_secdownload", + "mod_access", + "mod_auth", + "mod_status", + "mod_expire", + "mod_redirect", + "mod_fastcgi", + "mod_cgi" ) + +server.indexfiles = ( "index.php", "index.html", + "index.htm", "default.htm" ) + + +######################## MODULE CONFIG ############################ + +mimetype.assign = ( ".png" => "image/png", + ".jpg" => "image/jpeg", + ".jpeg" => "image/jpeg", + ".gif" => "image/gif", + ".html" => "text/html", + ".htm" => "text/html", + ".pdf" => "application/pdf", + ".swf" => "application/x-shockwave-flash", + ".spl" => "application/futuresplash", + ".txt" => "text/plain", + ".tar.gz" => "application/x-tgz", + ".tgz" => "application/x-tgz", + ".gz" => "application/x-gzip", + ".c" => "text/plain", + ".conf" => "text/plain" ) + +fastcgi.debug = 0 +fastcgi.server = ( ".php" => ( ( "host" => "127.0.0.1", "port" => 1026, "broken-scriptfilename" => "enable" ) ), + "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) ) + ) + + +cgi.assign = ( ".pl" => "/usr/bin/perl", + ".cgi" => "/usr/bin/perl", + ".py" => "/usr/bin/python" ) + +auth.backend = "plain" +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user" + +auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd" + +$HTTP["host"] == "lowercase-auth" { + auth.require = ( "/image.jpg" => + ( + "method" => "digest", + "realm" => "download archiv", + "require" => "valid-user" + ) + ) +} + +$HTTP["host"] == "lowercase-deny" { + url.access-deny = ( ".jpg") +} + +$HTTP["host"] == "lowercase-exclude" { + static-file.exclude-extensions = ( ".jpg" ) +} diff --git a/tests/lowercase.t b/tests/lowercase.t new file mode 100755 index 0000000..e127cdd --- /dev/null +++ b/tests/lowercase.t @@ -0,0 +1,94 @@ +#!/usr/bin/env perl +BEGIN { + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s#/[^/]+$#/#; + unshift @INC, $srcdir; +} + +use strict; +use IO::Socket; +use Test::More tests => 10; +use LightyTest; + +my $tf = LightyTest->new(); +my $t; + +$tf->{CONFIGFILE} = 'lowercase.conf'; + +ok($tf->start_proc == 0, "Starting lighttpd") or die(); + +## check if lower-casing works + +$t->{REQUEST} = ( <<EOF +GET /image.JPG HTTP/1.0 +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; +ok($tf->handle_http($t) == 0, 'uppercase access'); + +$t->{REQUEST} = ( <<EOF +GET /image.jpg HTTP/1.0 +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; +ok($tf->handle_http($t) == 0, 'lowercase access'); + +## check that mod-auth works + +$t->{REQUEST} = ( <<EOF +GET /image.JPG HTTP/1.0 +Host: lowercase-auth +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ]; +ok($tf->handle_http($t) == 0, 'uppercase access'); + +$t->{REQUEST} = ( <<EOF +GET /image.jpg HTTP/1.0 +Host: lowercase-auth +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ]; +ok($tf->handle_http($t) == 0, 'lowercase access'); + + +## check that mod-staticfile exclude works +$t->{REQUEST} = ( <<EOF +GET /image.JPG HTTP/1.0 +Host: lowercase-exclude +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ]; +ok($tf->handle_http($t) == 0, 'upper case access to staticfile.exclude-extension'); + +$t->{REQUEST} = ( <<EOF +GET /image.jpg HTTP/1.0 +Host: lowercase-exclude +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ]; +ok($tf->handle_http($t) == 0, 'lowercase access'); + + +## check that mod-access exclude works +$t->{REQUEST} = ( <<EOF +GET /image.JPG HTTP/1.0 +Host: lowercase-deny +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ]; +ok($tf->handle_http($t) == 0, 'uppercase access to url.access-deny protected location'); + +$t->{REQUEST} = ( <<EOF +GET /image.jpg HTTP/1.0 +Host: lowercase-deny +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ]; +ok($tf->handle_http($t) == 0, 'lowercase access'); + + + +ok($tf->stop_proc == 0, "Stopping lighttpd"); + |